Skip to content

Commit

Permalink
sclang: introduce unixCmd for array of arguments
Browse files Browse the repository at this point in the history
fixes #1738
  • Loading branch information
miguel-negrao committed Feb 8, 2016
1 parent c7b8291 commit d008339
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 24 deletions.
18 changes: 18 additions & 0 deletions SCClassLibrary/Common/Collections/SequenceableCollection.sc
Original file line number Diff line number Diff line change
Expand Up @@ -1300,4 +1300,22 @@ SequenceableCollection : Collection {
}
}
}

unixCmd { arg action, postOutput = true;
if(this.notEmpty){
var pid;
pid = this.prUnixCmd(postOutput);
if(action.notNil) {
String.unixCmdActions.put(pid, action);
};
^pid;
} {
Error("Collection should have at least the filepath of the program to run.").throw
}
}

prUnixCmd { arg postOutput = true;
_ArrayPOpen
^this.primitiveFailed
}
}
47 changes: 36 additions & 11 deletions common/sc_popen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include <signal.h>
#include <unistd.h>
#include <paths.h>
#include <vector>
#include <array>
#include <string>

// allows for linking into a dylib on darwin
#if defined(__APPLE__) && !defined(SC_IPHONE)
Expand All @@ -30,11 +33,30 @@

FILE *
sc_popen(const char *command, pid_t *pidp, const char *type)
{
std::array<char*, 4> argv;
std::string str0 = "/bin/sh";
std::vector<char> v0( str0.begin(), str0.end() );
v0.push_back('\0');
argv[0] = v0.data();
std::string str1 = "-c";
std::vector<char> v1( str1.begin(), str1.end() );
v1.push_back('\0');
argv[1] = v1.data();
std::string str2 = command;
std::vector<char> v2( str2.begin(), str2.end() );
v2.push_back('\0');
argv[2] = v2.data();
argv[3] = nullptr;

return sc_popen_argv(v0.data(), argv.data(), pidp, type);
}

FILE *
sc_popen_argv(const char *filename, char *const argv[], pid_t *pidp, const char *type)
{
FILE *iop;
int pdes[2], pid, twoway;
char *argv[4];

/*
* Lite2 introduced two-way popen() pipes using _socketpair().
* FreeBSD's pipe() is bidirectional, so we use that.
Expand All @@ -45,21 +67,16 @@ sc_popen(const char *command, pid_t *pidp, const char *type)
} else {
twoway = 0;
if ((*type != 'r' && *type != 'w') || type[1])
return (NULL);
return (nullptr);
}
if (pipe(pdes) < 0)
return (NULL);

argv[0] = (char *)"sh";
argv[1] = (char *)"-c";
argv[2] = (char *)command;
argv[3] = NULL;
return (nullptr);

switch (pid = fork()) {
case -1: /* Error. */
(void)close(pdes[0]);
(void)close(pdes[1]);
return (NULL);
return (nullptr);
/* NOTREACHED */
case 0: /* Child. */
if (*type == 'r') {
Expand Down Expand Up @@ -87,7 +104,7 @@ sc_popen(const char *command, pid_t *pidp, const char *type)
(void)close(pdes[1]);
}

execve("/bin/sh", argv, environ);
execve(filename, argv, environ);
exit(127);
/* NOTREACHED */
}
Expand Down Expand Up @@ -328,4 +345,12 @@ sc_pclose(FILE *f, pid_t pid)
return exit_code;
}

FILE *
sc_popen_argv(const char *filename, char *const argv[], pid_t *pidp, const char *type)
{
printf("sc_popen_argv: not implemented\n");
return (nullptr);

}

#endif
1 change: 1 addition & 0 deletions common/sc_popen.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@
#endif

FILE * sc_popen(const char *command, pid_t *pidp, const char *type);
FILE * sc_popen_argv(const char *filename, char *const argv[], pid_t *pidp, const char *type);
int sc_pclose(FILE *iop, pid_t mPid);
102 changes: 89 additions & 13 deletions lang/LangPrimSource/PyrUnixPrim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,17 @@ Primitives for Unix.

#include "SC_Lock.h"

#include <vector>
#include <boost/filesystem.hpp>

#ifdef _WIN32
#include "SC_Win32Utils.h"
#else
#include <libgen.h>
#endif

using namespace boost::filesystem;

extern bool compiledOK;
PyrSymbol* s_unixCmdAction;

Expand Down Expand Up @@ -129,7 +134,7 @@ static void string_popen_thread_func(struct sc_process *process)
if(process->postOutput)
postfl("RESULT = %d\n", res);

free(process);
delete process;

gLangMutex.lock();
if(compiledOK) {
Expand All @@ -147,43 +152,113 @@ static void string_popen_thread_func(struct sc_process *process)
int prString_POpen(struct VMGlobals *g, int numArgsPushed);
int prString_POpen(struct VMGlobals *g, int numArgsPushed)
{
struct sc_process *process;
PyrSlot *a = g->sp - 1;
PyrSlot *b = g->sp;
int err;

if (!isKindOfSlot(a, class_string)) return errWrongType;

char *cmdline = (char*)malloc(slotRawObject(a)->size + 1);
err = slotStrVal(a, cmdline, slotRawObject(a)->size + 1);
if(err) {
free(cmdline);
return errFailed;
}
char *cmdline = new char[slotRawObject(a)->size + 1];
slotStrVal(a, cmdline, slotRawObject(a)->size + 1);

#ifdef SC_IPHONE
SetInt(a, 0);
return errNone;
#endif

process = (struct sc_process *)malloc(sizeof(struct sc_process));
sc_process *process = new sc_process;
process->stream = sc_popen(cmdline, &process->pid, "r");
setvbuf(process->stream, 0, _IONBF, 0);
pid_t pid = process->pid;

process->postOutput = IsTrue(b);

free(cmdline);
delete [] cmdline;

if(process->stream == NULL) {
delete process;
return errFailed;
}

thread thread(std::bind(string_popen_thread_func, process));
thread.detach();

SetInt(a, pid);
return errNone;
}

int prArrayPOpen(struct VMGlobals *g, int numArgsPushed);
int prArrayPOpen(struct VMGlobals *g, int numArgsPushed)
{
PyrObject *obj;

PyrSlot *a = g->sp - 1;
PyrSlot *b = g->sp;

#ifdef SC_IPHONE
SetInt(a, 0);
return errNone;
#endif

if (NotObj(a)) return errWrongType;

obj = slotRawObject(a);
if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances))
return errNotAnIndexableObject;

if( obj->size < 1)
return errFailed;

PyrSlot filenameSlot;
getIndexedSlot(obj, &filenameSlot, 0);
if (!isKindOfSlot(&filenameSlot, class_string)) return errWrongType;
char filename[PATH_MAX];
if (slotRawObject(&filenameSlot)->size > PATH_MAX - 1) return errFailed;
slotStrVal(&filenameSlot, filename, slotRawObject(&filenameSlot)->size + 1);

std::vector<char *> argv (obj->size + 1);

path p;
p /= filename;
std::string filenameOnly = p.filename().string();
std::vector<char> vfilenameOnly(filenameOnly.begin(), filenameOnly.end());
vfilenameOnly.push_back('\0');

argv[0] = vfilenameOnly.data();
argv[obj->size] = NULL;

if(obj->size > 1) {
for (int i=1; i<obj->size; ++i) {
PyrSlot argSlot;
getIndexedSlot(obj, &argSlot, i);
if (!isKindOfSlot(&argSlot, class_string)) return errWrongType;
char *arg = new char[slotRawObject(&argSlot)->size + 1];
slotStrVal(&argSlot, arg, slotRawObject(&argSlot)->size + 1);
argv[i] = arg;
}
}

sc_process *process = new sc_process;
process->stream = sc_popen_argv(filename, argv.data(), &process->pid, "r");
setvbuf(process->stream, 0, _IONBF, 0);
pid_t pid = process->pid;

process->postOutput = IsTrue(b);

if(process->stream == NULL) {
free(process);
delete process;
return errFailed;
}

thread thread(std::bind(string_popen_thread_func, process));
thread.detach();

SetInt(a, process->pid);
for (int i=1; i<obj->size; ++i) {
delete [] argv[i];
}

SetInt(a, pid);
return errNone;

}

int prPidRunning(VMGlobals *g, int numArgsPushed);
Expand Down Expand Up @@ -390,4 +465,5 @@ void initUnixPrimitives()
definePrimitive(base, index++, "_TimeSeed", prTimeSeed, 1, 0);
definePrimitive(base, index++, "_PidRunning", prPidRunning, 1, 0);
definePrimitive(base, index++, "_GetPid", prGetPid, 1, 0);
definePrimitive(base, index++, "_ArrayPOpen", prArrayPOpen, 2, 0);
}

0 comments on commit d008339

Please sign in to comment.