|
|
@@ -11,16 +11,35 @@
|
|
|
#include "squirrel.h"
|
|
|
#include "sqstdblobimpl.h"
|
|
|
|
|
|
-static char buff[2048];
|
|
|
+#ifdef WIN32
|
|
|
+ #include <windows.h>
|
|
|
+#else
|
|
|
+ #ifdef __cplusplus
|
|
|
+ extern "C" {
|
|
|
+ #endif
|
|
|
+ #include <pty.h>
|
|
|
+ #include <unistd.h>
|
|
|
+ #include <termios.h>
|
|
|
+ #ifdef __cplusplus
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+#endif
|
|
|
+
|
|
|
+struct SQ_SpawnX {
|
|
|
+#ifdef WIN32
|
|
|
+ HANDLE hPipeRead,hWriteSubProcess;
|
|
|
+ PROCESS_INFORMATION pi;
|
|
|
+#else
|
|
|
+ int spawn_fd;
|
|
|
+ int pid;
|
|
|
+ struct termios tm;
|
|
|
+#endif // WIN32
|
|
|
+};
|
|
|
|
|
|
#ifdef WIN32
|
|
|
-#include <windows.h>
|
|
|
-static HANDLE hPipeRead,hWriteSubProcess;
|
|
|
|
|
|
-static SQRESULT sq_spawn_open(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_spawnx_open(HSQUIRRELVM v, SQ_SpawnX *self, const char *cmd)
|
|
|
{
|
|
|
- SQ_FUNC_VARS_NO_TOP(v);
|
|
|
- SQ_GET_STRING(v, 2, cmd);
|
|
|
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), 0, 0};
|
|
|
SECURITY_DESCRIPTOR sd;
|
|
|
STARTUPINFO si = {
|
|
|
@@ -28,7 +47,6 @@ static SQRESULT sq_spawn_open(HSQUIRRELVM v)
|
|
|
};
|
|
|
HANDLE hRead2,hPipeWrite;
|
|
|
BOOL running;
|
|
|
- PROCESS_INFORMATION pi;
|
|
|
HANDLE hProcess = GetCurrentProcess();
|
|
|
sa.bInheritHandle = TRUE;
|
|
|
sa.lpSecurityDescriptor = NULL;
|
|
|
@@ -39,7 +57,7 @@ static SQRESULT sq_spawn_open(HSQUIRRELVM v)
|
|
|
|
|
|
// Create pipe for output redirection
|
|
|
// read handle, write handle, security attributes, number of bytes reserved for pipe - 0 default
|
|
|
- CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0);
|
|
|
+ CreatePipe(&self->hPipeRead, &hPipeWrite, &sa, 0);
|
|
|
|
|
|
// Create pipe for input redirection. In this code, you do not
|
|
|
// redirect the output of the child process, but you need a handle
|
|
|
@@ -48,10 +66,10 @@ static SQRESULT sq_spawn_open(HSQUIRRELVM v)
|
|
|
|
|
|
hRead2 = NULL;
|
|
|
// read handle, write handle, security attributes, number of bytes reserved for pipe - 0 default
|
|
|
- CreatePipe(&hRead2, &hWriteSubProcess, &sa, 0);
|
|
|
+ CreatePipe(&hRead2, &self->hWriteSubProcess, &sa, 0);
|
|
|
|
|
|
- SetHandleInformation(hPipeRead, HANDLE_FLAG_INHERIT, 0);
|
|
|
- SetHandleInformation(hWriteSubProcess, HANDLE_FLAG_INHERIT, 0);
|
|
|
+ SetHandleInformation(self->hPipeRead, HANDLE_FLAG_INHERIT, 0);
|
|
|
+ SetHandleInformation(self->hWriteSubProcess, HANDLE_FLAG_INHERIT, 0);
|
|
|
|
|
|
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
|
|
|
si.wShowWindow = SW_HIDE;
|
|
|
@@ -61,62 +79,23 @@ static SQRESULT sq_spawn_open(HSQUIRRELVM v)
|
|
|
|
|
|
running = CreateProcess(
|
|
|
NULL,
|
|
|
- (char*)cmd,
|
|
|
+ (LPSTR)cmd,
|
|
|
NULL, NULL,
|
|
|
TRUE, CREATE_NEW_PROCESS_GROUP,
|
|
|
NULL,
|
|
|
NULL, // start directory
|
|
|
- &si, &pi);
|
|
|
+ &si, &self->pi);
|
|
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
CloseHandle(hRead2);
|
|
|
CloseHandle(hPipeWrite);
|
|
|
|
|
|
- if (running) {
|
|
|
- lua_pushnumber(L,(int)hPipeRead);
|
|
|
- } else {
|
|
|
- lua_pushnil(L);
|
|
|
- }
|
|
|
- return 1;
|
|
|
+ if (running) return 0;
|
|
|
+ return sq_throwerror(v, _SC("unable to spawn process"));
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_spawn_reads(HSQUIRRELVM v)
|
|
|
-{
|
|
|
- DWORD bytesRead;
|
|
|
- int res = ReadFile(hPipeRead,buff,sizeof(buff), &bytesRead, NULL);
|
|
|
- buff[bytesRead] = '\0';
|
|
|
- if (res == 0) {
|
|
|
- sq_pushnull(v);
|
|
|
- } else {
|
|
|
- sq_pushstring(L,buff, bytesRead);
|
|
|
- }
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static SQRESULT sq_spawn_writes(HSQUIRRELVM v)
|
|
|
-{
|
|
|
- SQ_FUNC_VARS_NO_TOP(v);
|
|
|
- SQ_GET_STRING(v, 2, str);
|
|
|
- DWORD bytesWrote;
|
|
|
- WriteFile(hWriteSubProcess,str,str_size,&bytesWrote, NULL);
|
|
|
- sq_pushinteger(v, bytesWrote);
|
|
|
- return 1;
|
|
|
-}
|
|
|
#else
|
|
|
|
|
|
-#ifdef __cplusplus
|
|
|
-extern "C" {
|
|
|
-#endif
|
|
|
-#include <pty.h>
|
|
|
-#include <unistd.h>
|
|
|
-#include <termios.h>
|
|
|
-#ifdef __cplusplus
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
-static int spawn_fd;
|
|
|
-
|
|
|
static char *quote_strtok(char *str, char str_delim)
|
|
|
{
|
|
|
// a specialized version of strtok() which treats quoted strings specially
|
|
|
@@ -139,13 +118,10 @@ static char *quote_strtok(char *str, char str_delim)
|
|
|
return str;
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_spawn_open(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_spawnx_open(HSQUIRRELVM v, SQ_SpawnX *self, const char *cmd)
|
|
|
{
|
|
|
- SQ_FUNC_VARS_NO_TOP(v);
|
|
|
- SQ_GET_STRING(v, 2, cmd);
|
|
|
const char *args[30];
|
|
|
- int pid, i = 0;
|
|
|
- struct termios tm;
|
|
|
+ int i = 0;
|
|
|
char* argline = strdup(cmd);
|
|
|
char* arg = quote_strtok(argline,'"');
|
|
|
if (arg == NULL) return 0;
|
|
|
@@ -155,51 +131,116 @@ static SQRESULT sq_spawn_open(HSQUIRRELVM v)
|
|
|
arg = quote_strtok(NULL,'"');
|
|
|
}
|
|
|
args[i] = NULL;
|
|
|
- memset(&tm,0,sizeof(tm));
|
|
|
- cfmakeraw(&tm);
|
|
|
+ memset(&self->tm,0,sizeof(self->tm));
|
|
|
+ cfmakeraw(&self->tm);
|
|
|
errno = 0;
|
|
|
- pid = forkpty(&spawn_fd,NULL,&tm,NULL);
|
|
|
- if (pid == 0) { // child
|
|
|
+ self->pid = forkpty(&self->spawn_fd,NULL,&self->tm,NULL);
|
|
|
+ if (self->pid == 0) { // child
|
|
|
execvp(args[0], (char*const*)args);
|
|
|
// if we get here, it's an error!
|
|
|
- perror("'unable to spawn process");
|
|
|
+ perror("unable to spawn process");
|
|
|
} else {
|
|
|
- sq_pushinteger(v,pid);
|
|
|
- //sq_pushstring(L,strerror(errno));
|
|
|
- return 1;
|
|
|
+ return 0;
|
|
|
}
|
|
|
- return 0;
|
|
|
+ return sq_throwerror(v, _SC("unable to spawn process"));
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static const SQChar sq_spawnx_TAG[] = _SC("SQ_SpawnX");
|
|
|
+
|
|
|
+static SQRESULT get_spawnx_instance(HSQUIRRELVM v, SQInteger idx, SQ_SpawnX **spawnx_st)
|
|
|
+{
|
|
|
+ if(sq_getinstanceup(v, idx, (SQUserPointer*)spawnx_st, (void*)sq_spawnx_TAG) != SQ_OK) return SQ_ERROR;
|
|
|
+ if(!*spawnx_st) return sq_throwerror(v, _SC("%s"), _SC("spawnx already closed"));
|
|
|
+ return SQ_OK;
|
|
|
+}
|
|
|
+
|
|
|
+#define GET_sq_spawnx_INSTANCE(v, idx) \
|
|
|
+ SQ_SpawnX *self=NULL; \
|
|
|
+ if(get_spawnx_instance(v, idx, &self) != SQ_OK) return SQ_ERROR;
|
|
|
+
|
|
|
+
|
|
|
+static SQRESULT sq_spawnx_releasehook(SQUserPointer p, SQInteger /*size*/, void */*ep*/)
|
|
|
+{
|
|
|
+ SQ_SpawnX *self = ((SQ_SpawnX *)p);
|
|
|
+ if(self)
|
|
|
+ {
|
|
|
+ sq_free(self, sizeof(SQ_SpawnX));
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static SQRESULT sq_spawnx_constructor(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ SQ_FUNC_VARS_NO_TOP(v);
|
|
|
+ SQ_GET_STRING(v, 2, cmd);
|
|
|
+
|
|
|
+ SQ_SpawnX *self = (SQ_SpawnX*)sq_malloc(sizeof(SQ_SpawnX));
|
|
|
+
|
|
|
+ _rc_ = sq_spawnx_open(v, self, cmd);
|
|
|
+
|
|
|
+ sq_setinstanceup(v,1,self);
|
|
|
+ sq_setreleasehook(v,1,sq_spawnx_releasehook);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_spawn_reads(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_spawnx_read(HSQUIRRELVM v)
|
|
|
{
|
|
|
- int sz = read(spawn_fd,buff,sizeof(buff));
|
|
|
- buff[sz] = '\0';
|
|
|
+ SQ_FUNC_VARS(v);
|
|
|
+ GET_sq_spawnx_INSTANCE(v, 1);
|
|
|
+ SQ_OPT_INTEGER(v, 2, read_sz, 2048);
|
|
|
+ SQChar *buf = sq_getscratchpad(v, read_sz);
|
|
|
+#ifdef WIN32
|
|
|
+ DWORD bytesRead;
|
|
|
+ int res = ReadFile(self->hPipeRead,buf,read_sz, &bytesRead, NULL);
|
|
|
+ if (res == 0) {
|
|
|
+ sq_pushnull(v);
|
|
|
+#else
|
|
|
+ int bytesRead = read(self->spawn_fd, buf, read_sz);
|
|
|
if (errno != 0) {
|
|
|
sq_pushinteger(v, errno);
|
|
|
//sq_pushstring(v,strerror(errno));
|
|
|
+#endif
|
|
|
} else {
|
|
|
- sq_pushstring(v,buff, sz);
|
|
|
+ sq_pushstring(v,buf, bytesRead);
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static SQRESULT sq_spawn_writes(HSQUIRRELVM v)
|
|
|
+static SQRESULT sq_spawnx_write(HSQUIRRELVM v)
|
|
|
{
|
|
|
SQ_FUNC_VARS_NO_TOP(v);
|
|
|
+ GET_sq_spawnx_INSTANCE(v, 1);
|
|
|
SQ_GET_STRING(v, 2, str);
|
|
|
- ssize_t n = write(spawn_fd,str,str_size);
|
|
|
+#ifdef WIN32
|
|
|
+ DWORD bytesWrote;
|
|
|
+ WriteFile(self->hWriteSubProcess,str,str_size,&bytesWrote, NULL);
|
|
|
+ sq_pushinteger(v, bytesWrote);
|
|
|
+#else
|
|
|
+ ssize_t n = write(self->spawn_fd,str,str_size);
|
|
|
sq_pushinteger(v, n);
|
|
|
+#endif
|
|
|
return 1;
|
|
|
}
|
|
|
+
|
|
|
+static SQRESULT sq_spawnx_pid(HSQUIRRELVM v)
|
|
|
+{
|
|
|
+ GET_sq_spawnx_INSTANCE(v, 1);
|
|
|
+#ifdef WIN32
|
|
|
+ sq_pushinteger(v, (int)(self->hPipeRead));
|
|
|
+#else
|
|
|
+ sq_pushinteger(v, self->pid);
|
|
|
#endif
|
|
|
+ return 1;
|
|
|
+}
|
|
|
|
|
|
-#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_spawn_##name,nparams,tycheck}
|
|
|
-static SQRegFunction sq_spawn_methods[] =
|
|
|
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_spawnx_##name,nparams,tycheck}
|
|
|
+static SQRegFunction sq_spawnx_methods[] =
|
|
|
{
|
|
|
- _DECL_FUNC(open,2,_SC(".s")),
|
|
|
- _DECL_FUNC(reads,1,_SC(".")),
|
|
|
- _DECL_FUNC(writes,2,_SC(".s")),
|
|
|
+ _DECL_FUNC(constructor,2,_SC(".s")),
|
|
|
+ _DECL_FUNC(read,-1,_SC("xi")),
|
|
|
+ _DECL_FUNC(write,2,_SC("xs")),
|
|
|
+ _DECL_FUNC(pid,1,_SC("x")),
|
|
|
{0,0}
|
|
|
};
|
|
|
|
|
|
@@ -209,10 +250,10 @@ extern "C" {
|
|
|
|
|
|
SQRESULT sqext_register_sq_spawnx(HSQUIRRELVM v)
|
|
|
{
|
|
|
- sq_pushliteral(v,_SC("sqspawnx"));
|
|
|
- sq_newtable(v);
|
|
|
- sq_insert_reg_funcs(v, sq_spawn_methods);
|
|
|
-
|
|
|
+ sq_pushstring(v, sq_spawnx_TAG, -1);
|
|
|
+ sq_newclass(v, SQFalse);
|
|
|
+ sq_settypetag(v,-1,(void*)sq_spawnx_TAG);
|
|
|
+ sq_insert_reg_funcs(v, sq_spawnx_methods);
|
|
|
sq_newslot(v,-3,SQTrue);
|
|
|
return 1;
|
|
|
}
|