From 2ace11ed4cabe11894a62242b10213c485588a26 Mon Sep 17 00:00:00 2001 From: mark Date: Mon, 30 Jan 2006 19:44:42 +0000 Subject: [PATCH] Attempt to merge implementations --- posix/Makefile | 3 +- posix/ex.c | 177 ++++++++++++++++++++++++++++-------------------- w32api/Makefile | 3 +- w32api/ex.c | 167 +++++++++++++++++++++++++++------------------ 4 files changed, 207 insertions(+), 143 deletions(-) diff --git a/posix/Makefile b/posix/Makefile index bdcb00a..06531d0 100755 --- a/posix/Makefile +++ b/posix/Makefile @@ -2,7 +2,8 @@ CFLAGS = -std=c99 $(WARNINGS) $(DEFINES) $(INCLUDES) DEFINES = -D_POSIX_SOURCE -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L -U__STRICT_ANSI__ INCLUDES = -I$(LUA)/include -I. WARNINGS = -W -Wall -LUA = /home/mark/src/lang/lua/lua-5.1-rc2 +#LUA = /home/mark/src/lang/lua/lua-5.1-rc2 +LUA = /home/mark/src/lang/lua/lua51 ex.so: ex.o; $(CC) -shared -o $@ ex.o diff --git a/posix/ex.c b/posix/ex.c index 3aec41c..a5f4d71 100755 --- a/posix/ex.c +++ b/posix/ex.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -14,8 +14,6 @@ #include #include -#define debug(...) fprintf(stderr,__VA_ARGS__) - /* Generally useful function -- what luaL_checkudata() should do */ static void *luaL_checkuserdata(lua_State *L, int idx, const char *tname) @@ -27,7 +25,7 @@ static void *luaL_checkuserdata(lua_State *L, int idx, const char *tname) /* -- nil error */ -static int posix_error(lua_State *L) +static int push_error(lua_State *L) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); @@ -53,7 +51,7 @@ static int ex_setenv(lua_State *L) const char *nam = luaL_checkstring(L, 1); const char *val = luaL_checkstring(L, 2); if (-1 == setenv(nam, val, 1)) - return posix_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -63,7 +61,7 @@ static int ex_unsetenv(lua_State *L) { const char *nam = luaL_checkstring(L, 1); if (-1 == unsetenv(nam)) - return posix_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -74,7 +72,7 @@ static int ex_environ(lua_State *L) const char *nam, *val, *end; const char **env; lua_newtable(L); - for (env = environ; (nam = *env); env++) { + for (env = (const char **)environ; (nam = *env); env++) { end = strchr(val = strchr(nam, '=') + 1, '\0'); lua_pushlstring(L, nam, val - nam - 1); lua_pushlstring(L, val, end - val); @@ -98,7 +96,7 @@ static int ex_chdir(lua_State *L) { const char *pathname = luaL_checkstring(L, 1); if (-1 == chdir(pathname)) - return posix_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -108,7 +106,7 @@ static int ex_mkdir(lua_State *L) { const char *pathname = luaL_checkstring(L, 1); if (-1 == mkdir(pathname, 0777)) - return posix_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -118,7 +116,7 @@ static int ex_currentdir(lua_State *L) { char pathname[PATH_MAX + 1]; if (!getcwd(pathname, sizeof pathname)) - return posix_error(L); + return push_error(L); lua_pushstring(L, pathname); return 1; } @@ -143,7 +141,7 @@ static int file_lock(lua_State *L, FILE *f, const char *mode, long offset, long k.l_start = offset; k.l_len = length; if (-1 == fcntl(fileno(f), F_SETLK, &k)) - return posix_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -186,51 +184,87 @@ static int ex_pipe(lua_State *L) { int fd[2]; if (-1 == pipe(fd)) - return posix_error(L); + return push_error(L); return make_pipe(L, fdopen(fd[0], "r"), fdopen(fd[1], "w")); } /* ... argtab -- ... */ -static const char **build_args(lua_State *L) +static const char **build_vector(lua_State *L) { size_t i, n = lua_objlen(L, -1); - const char **argv = lua_newuserdata(L, (n + 2) * sizeof *argv); - /* ... argtab argv */ + const char **vec = lua_newuserdata(L, (n + 2) * sizeof *vec); + /* ... arr vec */ for (i = 0; i <= n; i++) { - lua_rawgeti(L, -2, i); /* ... argtab argv argi */ - argv[i] = lua_tostring(L, -1); - lua_pop(L, 1); /* ... argtab argv */ + lua_rawgeti(L, -2, i); /* ... arr vec elem */ + vec[i] = lua_tostring(L, -1); + lua_pop(L, 1); /* ... arr vec */ } - argv[n + 1] = 0; - lua_replace(L, -2); /* ... argv */ - return argv; + vec[n + 1] = 0; + lua_replace(L, -2); /* ... vector */ + return vec; +} + +struct spawn_params { + lua_State *L; + const char *command, **argv, **envp; + posix_spawn_file_actions_t file_actions; + int has_actions; +}; + +/* filename ... */ +static void spawn_param_filename(struct spawn_params *p) +{ + /* XXX confusing */ + p->command = luaL_checkstring(p->L, 1); +} + + +static void spawn_param_defaults(struct spawn_params *p) +{ + p->argv = lua_newuserdata(p->L, 2 * sizeof *p->argv); + p->argv[0] = p->command; + p->argv[1] = 0; + p->envp = (const char **)environ; + p->has_actions = 0; +} + +/* ... argtab */ +static void spawn_param_args(struct spawn_params *p) +{ + const char **argv = build_vector(p->L); + if (!argv[0]) argv[0] = p->command; + p->argv = argv; } -/* ... envtab -- */ -static const char **build_env(lua_State *L) +/* ... envtab/nil */ +static void spawn_param_env(struct spawn_params *p) { size_t i = 0; luaL_Buffer estr; - luaL_buffinit(L, &estr); - lua_newtable(L); /* ... envtab a */ - lua_pushnil(L); /* ... envtab a nil */ - for (i = 0; lua_next(L, -3); i++) {/* ... envtab a k v */ + if (lua_isnil(p->L, -1)) { + p->envp = (const char **)environ; + return; + } + luaL_buffinit(p->L, &estr); + lua_newtable(p->L); /* ... envtab arr */ + lua_pushnil(p->L); /* ... envtab arr nil */ + for (i = 0; lua_next(p->L, -3); i++) { /* ... envtab arr k v */ luaL_prepbuffer(&estr); - lua_pushvalue(L, -2); /* ... envtab a k v k */ + lua_pushvalue(p->L, -2); /* ... envtab arr k v k */ luaL_addvalue(&estr); luaL_putchar(&estr, '='); - lua_pop(L, 1); /* ... envtab a k v */ + lua_pop(p->L, 1); /* ... envtab arr k v */ luaL_addvalue(&estr); - lua_pop(L, 1); /* ... envtab a k */ - luaL_pushresult(&estr); /* ... envtab a k estr */ - lua_rawseti(L, -3, i); /* ... envtab a[n]=estr k */ - } /* ... envtab a */ - lua_replace(L, -2); /* ... a */ - return build_args(L); /* ... */ + lua_pop(p->L, 1); /* ... envtab arr k */ + luaL_pushresult(&estr); /* ... envtab arr k estr */ + lua_rawseti(p->L, -3, i); /* ... envtab arr[n]=estr k */ + } /* ... envtab arr */ + lua_replace(p->L, -2); /* ... arr */ + build_vector(p->L); /* ... arr */ } -/* */ +/* _ opts ... */ static int get_redirect(lua_State *L, posix_spawn_file_actions_t *file_actions, const char *stdname, int descriptor) { @@ -243,22 +277,38 @@ static int get_redirect(lua_State *L, posix_spawn_file_actions_t *file_actions, return ret; } +/* _ opts ... */ +static void spawn_param_redirects(struct spawn_params *p) +{ + posix_spawn_file_actions_init(&p->file_actions); + p->has_actions = 1; + get_redirect(p->L, &p->file_actions, "stdin", STDIN_FILENO); + get_redirect(p->L, &p->file_actions, "stdout", STDOUT_FILENO); + get_redirect(p->L, &p->file_actions, "stderr", STDERR_FILENO); +} + #define PROCESS_HANDLE "process" struct process { - pid_t pid; int status; + pid_t pid; }; +static int spawn_param_execute(struct spawn_params *p, struct process *proc) +{ + int ret; + proc->status = -1; + ret = posix_spawnp(&proc->pid, p->command, &p->file_actions, 0, (char *const *)p->argv, (char *const *)p->envp); + if (p->has_actions) + posix_spawn_file_actions_destroy(&p->file_actions); + return ret == 0; +} + /* filename [args-opts] -- true/nil,error */ /* args-opts -- true/nil,error */ static int ex_spawn(lua_State *L) { - const char *command; - const char **argv; - const char **envp; - posix_spawn_file_actions_t file_actions, *pactions = 0; + struct spawn_params params = {L}; struct process *proc; - int ret; if (lua_type(L, 1) == LUA_TTABLE) { lua_getfield(L, 1, "command"); /* opts ... cmd */ @@ -282,18 +332,14 @@ static int ex_spawn(lua_State *L) } } - /* XXX confusing */ - command = luaL_checkstring(L, 1); + /* get filename to execute */ + spawn_param_filename(¶ms); /* get arguments, environment, and redirections */ switch (lua_type(L, 2)) { default: luaL_argerror(L, 2, "expected options table"); break; case LUA_TNONE: - argv = lua_newuserdata(L, 2 * sizeof *argv); - argv[0] = command; - argv[1] = 0; - envp = (const char **)environ; - pactions = 0; + spawn_param_defaults(¶ms); break; case LUA_TTABLE: lua_getfield(L, 2, "args"); /* cmd opts ... argtab */ @@ -306,43 +352,24 @@ static int ex_spawn(lua_State *L) case LUA_TTABLE: if (lua_objlen(L, 2) > 0) luaL_error(L, "cannot specify both the args option and array values"); - argv = build_args(L); /* cmd opts ... */ - if (!argv[0]) argv[0] = command; + spawn_param_args(¶ms); /* cmd opts ... */ break; } - lua_getfield(L, 2, "env"); + lua_getfield(L, 2, "env"); /* cmd opts ... envtab */ switch (lua_type(L, -1)) { default: luaL_error(L, "env option must be a table"); break; case LUA_TNIL: - envp = (const char **)environ; - break; case LUA_TTABLE: - envp = build_env(L); /* cmd opts ... */ + spawn_param_env(¶ms); /* cmd opts ... */ break; } - posix_spawn_file_actions_init(&file_actions); - if (get_redirect(L, &file_actions, "stdin", STDIN_FILENO) - | get_redirect(L, &file_actions, "stdout", STDOUT_FILENO) - | get_redirect(L, &file_actions, "stderr", STDERR_FILENO)) { - pactions = &file_actions; - } - else { - posix_spawn_file_actions_destroy(&file_actions); - pactions = 0; - } + spawn_param_redirects(¶ms); } proc = lua_newuserdata(L, sizeof *proc); /* cmd opts ... proc */ luaL_getmetatable(L, PROCESS_HANDLE); /* cmd opts ... proc M */ lua_setmetatable(L, -2); /* cmd opts ... proc */ - proc->status = -1; - assert(argv && argv[0]); - assert(envp && envp[0]); - ret = posix_spawnp(&proc->pid, command, pactions, 0, (char *const *)argv, (char *const *)envp); - debug("returns %d:%ld\n", ret, (long)proc->pid); - if (pactions) - posix_spawn_file_actions_destroy(pactions); - if (0 != ret) - return posix_error(L); + if (!spawn_param_execute(¶ms, proc)) + return push_error(L); return 1; /* ... proc */ } @@ -353,7 +380,7 @@ static int process_wait(lua_State *L) if (p->status == -1) { int status; if (-1 == waitpid(p->pid, &status, 0)) - return posix_error(L); + return push_error(L); p->status = WEXITSTATUS(status); } lua_pushnumber(L, p->status); diff --git a/w32api/Makefile b/w32api/Makefile index 03dc2e1..59fb85c 100755 --- a/w32api/Makefile +++ b/w32api/Makefile @@ -3,7 +3,8 @@ CFLAGS = $(WARNINGS) $(DEFINES) $(INCLUDES) DEFINES = -DWIN32_LEAN_AND_MEAN INCLUDES = -I${LUA}/include WARNINGS = -W -Wall -Wno-missing-braces -LUA = /home/mark/src/lang/lua/lua-5.1-rc2 +#LUA = /home/mark/src/lang/lua/lua-5.1-rc2 +LUA = /home/mark/src/lang/lua/lua51 LUALIBS = -L$(LUA)/lib -llua51 ex.dll: ex.o diff --git a/w32api/ex.c b/w32api/ex.c index 3b4da1a..ff03835 100755 --- a/w32api/ex.c +++ b/w32api/ex.c @@ -12,8 +12,6 @@ #include #include -#define debug(...) fprintf(stderr,__VA_ARGS__) - /* Generally useful function -- what luaL_checkudata() should do */ static void *luaL_checkuserdata(lua_State *L, int idx, const char *tname) @@ -25,7 +23,7 @@ static void *luaL_checkuserdata(lua_State *L, int idx, const char *tname) /* -- nil error */ -static int windows_error(lua_State *L) +static int push_error(lua_State *L) { DWORD error = GetLastError(); char buffer[1024]; @@ -54,7 +52,7 @@ static int ex_getenv(lua_State *L) size_t len; len = GetEnvironmentVariable(nam, val, sizeof val); if (sizeof val < len) - return windows_error(L); + return push_error(L); else if (len == 0) lua_pushnil(L); else @@ -68,7 +66,7 @@ static int ex_setenv(lua_State *L) const char *nam = luaL_checkstring(L, 1); const char *val = luaL_checkstring(L, 2); if (!SetEnvironmentVariable(nam, val)) - return windows_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -78,7 +76,7 @@ static int ex_unsetenv(lua_State *L) { const char *nam = luaL_checkstring(L, 1); if (!SetEnvironmentVariable(nam, 0)) - return windows_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -89,13 +87,11 @@ static int ex_environ(lua_State *L) const char *nam, *val, *end; const char *envs; if (!(envs = GetEnvironmentStrings())) - return windows_error(L); + return push_error(L); lua_newtable(L); for (nam = envs; *nam; nam = end + 1) { - val = strchr(nam, '='); - end = strchr(val, '\0'); - lua_pushlstring(L, nam, val - nam); - val++; + end = strchr(val = strchr(nam, '=') + 1, '\0'); + lua_pushlstring(L, nam, val - nam - 1); lua_pushlstring(L, val, end - val); lua_settable(L, -3); } @@ -117,7 +113,7 @@ static int ex_chdir(lua_State *L) { const char *pathname = luaL_checkstring(L, 1); if (!SetCurrentDirectory(pathname)) - return windows_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -127,7 +123,7 @@ static int ex_mkdir(lua_State *L) { const char *pathname = luaL_checkstring(L, 1); if (!CreateDirectory(pathname, 0)) - return windows_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -138,7 +134,7 @@ static int ex_currentdir(lua_State *L) char pathname[PATH_MAX + 1]; size_t len; if (!(len = GetCurrentDirectory(sizeof pathname, pathname))) - return windows_error(L); + return push_error(L); lua_pushlstring(L, pathname, len); return 1; } @@ -174,7 +170,7 @@ static int file_lock(lua_State *L, FILE *f, const char *mode, long offset, long ret = flags ? LockFileEx(h, flags, 0, len.LowPart, len.HighPart, &ov) : UnlockFileEx(h, 0, len.LowPart, len.HighPart, &ov); if (!ret) - return windows_error(L); + return push_error(L); lua_pushboolean(L, 1); return 1; } @@ -217,17 +213,46 @@ static int ex_pipe(lua_State *L) { HANDLE ph[2]; if (0 == CreatePipe(ph+0, ph+1, 0, 0)) - return windows_error(L); + return push_error(L); return make_pipe(L, _fdopen(_open_osfhandle((long)ph[0], _O_RDONLY), "r"), _fdopen(_open_osfhandle((long)ph[1], _O_WRONLY), "w")); } +struct spawn_params { + lua_State *L; + const char *cmdline; + const char *environment; + STARTUPINFO si; +}; + static int needs_quoting(const char *s) { return s[0] != '"' && strchr(s, ' '); } +/* filename ... */ +static void spawn_param_filename(struct spawn_params *p) +{ + /* XXX luaL_checkstring is confusing here */ + p->cmdline = luaL_checkstring(p->L, 1); + if (needs_quoting(p->cmdline)) { + lua_pushliteral(p->L, "\""); /* cmd ... q */ + lua_pushvalue(p->L, 1); /* cmd ... q cmd */ + lua_pushvalue(p->L, -2); /* cmd ... q cmd q */ + lua_concat(p->L, 3); /* cmd ... "cmd" */ + lua_replace(p->L, 1); /* "cmd" ... */ + } +} + +/* -- */ +static void spawn_param_default(struct spawn_params *p) +{ + p->environment = 0; + memset(&p->si, 0, sizeof p->si); + p->si.cb = sizeof p->si; +} + /* {arg1,arg 2} => " arg1 \"arg2\"" */ static const char *concat_args(lua_State *L) { @@ -250,6 +275,16 @@ static const char *concat_args(lua_State *L) return lua_tostring(L, -1); } +/* cmd opts ... argtab */ +static void spawn_param_args(struct spawn_params *p) +{ + concat_args(p->L); /* cmd opts ... argstr */ + lua_pushvalue(p->L, 1); /* cmd opts ... argstr cmd */ + lua_replace(p->L, -2); /* cmd opts ... cmd argstr */ + lua_concat(p->L, 2); /* cmd opts ... cmdline */ + p->cmdline = lua_tostring(p->L, -1); +} + /* {nam1=val1,nam2=val2} => "nam1=val1\0nam2=val2\0" */ static const char *concat_env(lua_State *L) { @@ -274,7 +309,19 @@ static const char *concat_env(lua_State *L) return lua_tostring(L, -1); } -/* XXX document me */ +/* ... envtab */ +static void spawn_param_env(struct spawn_params *p) +{ + if (lua_isnil(p->L, -1)) { + p->environment = 0; + lua_pop(p->L, 1); + } + else { + p->environment = concat_env(p->L); + } +} + +/* _ opts ... */ static int get_redirect(lua_State *L, const char *stdname, HANDLE *ph) { int ret; @@ -288,22 +335,44 @@ static int get_redirect(lua_State *L, const char *stdname, HANDLE *ph) return ret; } +/* _ opts ... */ +static void spawn_param_redirect(struct spawn_params *p) +{ + p->si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + p->si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + p->si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (get_redirect(p->L, "stdin", &p->si.hStdInput) + | get_redirect(p->L, "stdout", &p->si.hStdOutput) + | get_redirect(p->L, "stderr", &p->si.hStdError)) + p->si.dwFlags = STARTF_USESTDHANDLES; +} + #define PROCESS_HANDLE "process" struct process { - HANDLE hProcess; int status; + HANDLE hProcess; }; +static int spawn_param_execute(struct spawn_params *p, struct process *proc) +{ + char *c = strdup(p->cmdline); + char *e = (char *)p->environment; // strdup(p->environment); + PROCESS_INFORMATION pi; + proc->status = -1; + /* XXX does CreateProcess modify its environment argument? */ + int ret = CreateProcess(0, c, 0, 0, 0, 0, e, 0, &p->si, &pi); + if (e) free(e); + free(c); + if (ret) proc->hProcess = pi.hProcess; + return ret; +} + /* filename [args-opts] -- true/nil,error */ /* args-opts -- true/nil,error */ static int ex_spawn(lua_State *L) { - const char *cmdline; - const char *environment; - struct process *p; - STARTUPINFO si = {sizeof si}; - PROCESS_INFORMATION pi; - BOOL ret; + struct spawn_params params = {L}; + struct process *proc; if (lua_type(L, 1) == LUA_TTABLE) { lua_getfield(L, 1, "command"); /* opts ... cmd */ @@ -328,21 +397,13 @@ static int ex_spawn(lua_State *L) } /* get command */ - /* XXX luaL_checkstring is confusing here */ - cmdline = luaL_checkstring(L, 1); - if (needs_quoting(cmdline)) { - lua_pushliteral(L, "\""); /* cmd ... q */ - lua_pushvalue(L, 1); /* cmd ... q cmd */ - lua_pushvalue(L, -2); /* cmd ... q cmd q */ - lua_concat(L, 3); /* cmd ... "cmd" */ - lua_replace(L, 1); /* "cmd" ... */ - } + spawn_param_filename(¶ms); /* get arguments, environment, and redirections */ switch (lua_type(L, 2)) { default: luaL_argerror(L, 2, "expected options table"); break; case LUA_TNONE: - environment = 0; + spawn_param_default(¶ms); break; case LUA_TTABLE: lua_getfield(L, 2, "args"); /* cmd opts ... argtab */ @@ -350,56 +411,30 @@ static int ex_spawn(lua_State *L) default: luaL_error(L, "args option must be an array"); break; case LUA_TNIL: lua_pop(L, 1); /* cmd opts ... */ - if (lua_objlen(L, 2) == 0) break; lua_pushvalue(L, 2); /* cmd opts ... opts */ if (0) /*FALLTHRU*/ case LUA_TTABLE: if (lua_objlen(L, 2) > 0) luaL_error(L, "cannot specify both the args option and array values"); - concat_args(L); /* cmd opts ... argstr */ - lua_pushvalue(L, 1); /* cmd opts ... argstr cmd */ - lua_replace(L, -2); /* cmd opts ... cmd argstr */ - lua_concat(L, 2); /* cmd opts ... cmdline */ - cmdline = lua_tostring(L, -1); + spawn_param_args(¶ms); break; } lua_getfield(L, 2, "env"); /* cmd opts ... envtab */ switch (lua_type(L, -1)) { default: luaL_error(L, "env option must be a table"); break; case LUA_TNIL: - environment = 0; - lua_pop(L, 1); /* cmd opts */ - break; case LUA_TTABLE: - environment = concat_env(L); /* cmd opts ... envstr */ + spawn_param_env(¶ms); break; } - si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - if (get_redirect(L, "stdin", &si.hStdInput) /* cmd opts ... in? */ - | get_redirect(L, "stdout", &si.hStdOutput) /* cmd opts ... out? */ - | get_redirect(L, "stderr", &si.hStdError)) /* cmd opts ... err? */ - si.dwFlags = STARTF_USESTDHANDLES; + spawn_param_redirect(¶ms); break; } - - p = lua_newuserdata(L, sizeof *p); /* cmd opts ... proc */ + proc = lua_newuserdata(L, sizeof *proc); /* cmd opts ... proc */ luaL_getmetatable(L, PROCESS_HANDLE); /* cmd opts ... proc M */ lua_setmetatable(L, -2); /* cmd opts ... proc */ - p->status = -1; - - /* XXX does CreateProcess modify its environment argument? */ - cmdline = strdup(cmdline); - if (environment) environment = strdup(environment); - debug("CreateProcess(%s)\n", cmdline); - ret = CreateProcess(0, (char *)cmdline, 0, 0, 0, 0, (char *)environment, 0, &si, &pi); -// if (environment) free((char *)environment); -// free((char *)cmdline); - - if (!ret) - return windows_error(L); - p->hProcess = pi.hProcess; + if (!spawn_param_execute(¶ms, proc)) + return push_error(L); return 1; /* ... proc */ }