diff --git a/w32api/osex.c b/w32api/osex.c index a62e40e..662be3f 100755 --- a/w32api/osex.c +++ b/w32api/osex.c @@ -1,5 +1,8 @@ -#define WIN32_LEAN_AND_MEAN +#include +#include #include +#include +#include #include #include #include @@ -7,15 +10,42 @@ extern char **environ; /* helper functions */ -static void *safe_alloc(lua_State *L, size_t n) +static void *safe_alloc(lua_State *L, void *p, size_t n) +#if 0 { - return lua_newuserdata(L, n); + void *q = realloc(p, n); + if (!q) { + realloc(p, 0); + lua_error(L, "memory allocation error"); + } + return q; +} +#else +{ + p = lua_newuserdata(L, n); + lua_pop(L, 1); + return p; } +#endif + static int windows_error(lua_State *L) { + DWORD error = GetLastError(); + char buffer[1024]; + size_t len = sprintf(buffer, "%lu (0x%lX): ", error, error); + size_t res = FormatMessage( + FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + 0, error, 0, buffer + len, sizeof buffer - len, 0); + if (res) { + len += res; + while (len > 0 && isspace(buffer[len - 1])) + len--; + } + else + len += sprintf(buffer + len, ""); lua_pushnil(L); - lua_pushstring(L, strerror(errno)); + lua_pushlstring(L, buffer, len); return 2; } @@ -32,20 +62,71 @@ static int osex_sleep(lua_State *L) #define PROCESS_HANDLE "process" struct process { - HANDLE pid; + HANDLE hProcess; int status; }; -static void get_redirect(lua_State *L, HANDLE *handle, const char *stream) +/* +extern long _get_osfhandle(int); +extern int _fileno(FILE *); +*/ + +static void get_redirect(lua_State *L, const char *stream, HANDLE *handle) { lua_getfield(L, 2, stream); if (!lua_isnil(L, -1)) { - FILE **pf = luaL_checkudata(L, LUA_FILEHANDLE); - *handle = _get_osfhandle(_filen(*pf)); + FILE **pf = luaL_checkudata(L, -1, LUA_FILEHANDLE); + *handle = (HANDLE)_get_osfhandle(_fileno(*pf)); } lua_pop(L, 1); } +int abs_index(lua_State *L, int idx) +{ + if (idx < 0) + return lua_gettop(L) + idx + 1; + return idx; +} + +static char *insert_args(lua_State *L, int index, char *cmd, size_t cmdlen) +{ + size_t alloc = cmdlen + 1; + size_t i, n = lua_objlen(L, index); + index = abs_index(L, index); + for (i = 1; i <= n; i++) { + size_t arglen; + const char *arg; + lua_rawgeti(L, -1, i); + arg = luaL_checklstring(L, -1, &arglen); + if (cmdlen + arglen + 1 >= alloc) + cmd = safe_alloc(L, cmd, alloc *= 2); + cmdlen += sprintf(cmd + cmdlen, " \"%s\"", arg); + lua_pop(L, 1); + } + return cmd; +} + +static char *insert_env(lua_State *L, int index) +{ + char *env; + size_t envlen, alloc; + index = abs_index(L, index); + envlen = 0; + env = safe_alloc(L, env, alloc = 256); + lua_pushnil(L); + while (lua_next(L, -2)) { + size_t namlen, vallen; + const char *nam = luaL_checklstring(L, -2, &namlen); + const char *val = luaL_checklstring(L, -2, &vallen); + if (namlen + 1 + vallen + 2 >= alloc) + env = safe_alloc(L, env, alloc *= 2); + envlen += sprintf(env + envlen, "%s=%s", nam, val); + env[envlen++] = '\0'; + } + env[envlen] = '\0'; + return env; +} + /* filename [options] -- true/nil,error */ static int osex_spawn(lua_State *L) { @@ -57,32 +138,32 @@ static int osex_spawn(lua_State *L) STARTUPINFO si; PROCESS_INFORMATION pi; filename = luaL_checklstring(L, 1, &len); - cmdline = safe_alloc(len + 3); + cmdline = safe_alloc(L, 0, len += 3); sprintf(cmdline, "\"%s\"", filename); environment = 0; si.cb = sizeof si; si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = GetStandardHandle(STD_INPUT_HANDLE); - si.hStdOutput = GetStandardHandle(STD_OUTPUT_HANDLE); - si.hStdError = GetStandardHandle(STD_ERROR_HANDLE); + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); if (lua_type(L, 2) == LUA_TTABLE) { lua_getfield(L, 2, "args"); if (!lua_isnil(L, -1)) { luaL_checktype(L, -1, LUA_TTABLE); - cmdline = insert_alli(L, -1); + cmdline = insert_args(L, -1, cmdline, len); } lua_pop(L, 1); lua_getfield(L, 2, "env"); if (!lua_isnil(L, -1)) { luaL_checktype(L, -1, LUA_TTABLE); - environment = insert_all(L, -1); + environment = insert_env(L, -1); } lua_pop(L, 1); - get_redirect(L, "stdin", &si.hStdInput ); + get_redirect(L, "stdin", &si.hStdInput); get_redirect(L, "stdout", &si.hStdOutput); - get_redirect(L, "stderr", &si.hStdError ); + get_redirect(L, "stderr", &si.hStdError); } p = lua_newuserdata(L, sizeof *p); luaL_getmetatable(L, PROCESS_HANDLE); @@ -90,7 +171,7 @@ static int osex_spawn(lua_State *L) p->status = -1; if (!CreateProcess(0, cmdline, 0, 0, 0, 0, environment, 0, &si, &pi)) return windows_error(L); - p->pid = pi.hProcess; + p->hProcess = pi.hProcess; return 1; } @@ -98,9 +179,10 @@ static int process_wait(lua_State *L) { struct process *p = luaL_checkudata(L, 1, PROCESS_HANDLE); if (p->status != -1) { - int status; - waitpid(p->pid, &status, 0); - p->status = WEXITSTATUS(status); + DWORD exitcode; + WaitForSingleObject(p->hProcess, INFINITE); + GetExitCodeProcess(p->hProcess, &exitcode); + p->status = exitcode; } lua_pushnumber(L, p->status); return 1; @@ -114,19 +196,19 @@ static const luaL_reg process_lib[] = { static int osex_newpipe(lua_State *L) { - int fd[2]; + HANDLE ph[2]; FILE **pf; - if (0 != pipe(fd)) - return posix_error(L); - luaL_getmetatable(L, LUA_FILEHANDLE); - pf = lua_newuserdata(L, sizeof *pf); - lua_pushvalue(L, -2); - lua_setmetatable(L, -2); - *pf = fdopen(fd[0], "r"); - pf = lua_newuserdata(L, sizeof *pf); - lua_pushvalue(L, -2); - lua_setmetatable(L, -2); - *pf = fdopen(fd[1], "w"); + if (0 == CreatePipe(ph+0, ph+1, 0, 0)) + return windows_error(L); + luaL_getmetatable(L, LUA_FILEHANDLE); /* M */ + pf = lua_newuserdata(L, sizeof *pf); /* M in */ + lua_pushvalue(L, -2); /* M in M */ + lua_setmetatable(L, -2); /* M in */ + *pf = _fdopen(_open_osfhandle((long)ph[0], _O_RDONLY), "r"); + pf = lua_newuserdata(L, sizeof *pf); /* M in out */ + lua_pushvalue(L, -3); /* M in out M */ + lua_setmetatable(L, -2); /* M in out */ + *pf = _fdopen(_open_osfhandle((long)ph[1], _O_WRONLY), "w"); return 2; }