Closer to merging ...

master
mark 21 years ago
parent 2ace11ed4c
commit 95bd5a3efc

@ -5,6 +5,7 @@ INCLUDES = -I$(LUA)/include
LUA = /home/mark/src/lang/lua/lua-5.1-rc1 LUA = /home/mark/src/lang/lua/lua-5.1-rc1
mingw:; $(MAKE) "EX_LIB=ex.dll" mingw:; $(MAKE) -C w32api ex.dll
cygwin:; $(MAKE) "EX_LIB=ex.so" "DEFINES=-D_XOPEN_SOURCE=600" cygwin:; $(MAKE) -C posix ex.dll
#"EX_LIB=ex.so" "DEFINES=-D_XOPEN_SOURCE=600"

@ -38,10 +38,9 @@ static int ex_getenv(lua_State *L)
{ {
const char *nam = luaL_checkstring(L, 1); const char *nam = luaL_checkstring(L, 1);
char *val = getenv(nam); char *val = getenv(nam);
if (val) if (!val)
return push_error(L);
lua_pushstring(L, val); lua_pushstring(L, val);
else
lua_pushnil(L);
return 1; return 1;
} }
@ -189,22 +188,6 @@ static int ex_pipe(lua_State *L)
} }
/* ... argtab -- ... */
static const char **build_vector(lua_State *L)
{
size_t i, n = lua_objlen(L, -1);
const char **vec = lua_newuserdata(L, (n + 2) * sizeof *vec);
/* ... arr vec */
for (i = 0; i <= n; i++) {
lua_rawgeti(L, -2, i); /* ... arr vec elem */
vec[i] = lua_tostring(L, -1);
lua_pop(L, 1); /* ... arr vec */
}
vec[n + 1] = 0;
lua_replace(L, -2); /* ... vector */
return vec;
}
struct spawn_params { struct spawn_params {
lua_State *L; lua_State *L;
const char *command, **argv, **envp; const char *command, **argv, **envp;
@ -219,7 +202,7 @@ static void spawn_param_filename(struct spawn_params *p)
p->command = luaL_checkstring(p->L, 1); p->command = luaL_checkstring(p->L, 1);
} }
/* -- */
static void spawn_param_defaults(struct spawn_params *p) static void spawn_param_defaults(struct spawn_params *p)
{ {
p->argv = lua_newuserdata(p->L, 2 * sizeof *p->argv); p->argv = lua_newuserdata(p->L, 2 * sizeof *p->argv);
@ -229,10 +212,34 @@ static void spawn_param_defaults(struct spawn_params *p)
p->has_actions = 0; p->has_actions = 0;
} }
/* Converts a Lua array of strings to a null-terminated array of char pointers.
* Pops a (0-based) Lua array and replaces it with a userdatum which is the
* null-terminated C array of char pointers. The elements of this array point
* to the strings in the Lua array. These strings should be associated with
* this userdatum via a weak table for GC purposes, but they are not here.
* Therefore, any function which calls this must make sure that these strings
* remain available until the userdatum is thrown away.
*/
/* ... array -- ... vector */
static const char **make_vector(lua_State *L)
{
size_t i, n = lua_objlen(L, -1);
const char **vec = lua_newuserdata(L, (n + 2) * sizeof *vec);
/* ... arr vec */
for (i = 0; i <= n; i++) {
lua_rawgeti(L, -2, i); /* ... arr vec elem */
vec[i] = lua_tostring(L, -1);
lua_pop(L, 1); /* ... arr vec */
}
vec[n + 1] = 0;
lua_replace(L, -2); /* ... vector */
return vec;
}
/* ... argtab */ /* ... argtab */
static void spawn_param_args(struct spawn_params *p) static void spawn_param_args(struct spawn_params *p)
{ {
const char **argv = build_vector(p->L); const char **argv = make_vector(p->L);
if (!argv[0]) argv[0] = p->command; if (!argv[0]) argv[0] = p->command;
p->argv = argv; p->argv = argv;
} }
@ -261,19 +268,19 @@ static void spawn_param_env(struct spawn_params *p)
lua_rawseti(p->L, -3, i); /* ... envtab arr[n]=estr k */ lua_rawseti(p->L, -3, i); /* ... envtab arr[n]=estr k */
} /* ... envtab arr */ } /* ... envtab arr */
lua_replace(p->L, -2); /* ... arr */ lua_replace(p->L, -2); /* ... arr */
build_vector(p->L); /* ... arr */ make_vector(p->L); /* ... arr */
} }
/* _ opts ... */ /* _ opts ... */
static int get_redirect(lua_State *L, posix_spawn_file_actions_t *file_actions, static int get_redirect(struct spawn_params *p, const char *stdname, int descriptor)
const char *stdname, int descriptor)
{ {
int ret; int ret;
lua_getfield(L, 2, stdname); lua_getfield(p->L, 2, stdname);
if ((ret = !lua_isnil(L, -1))) if ((ret = !lua_isnil(p->L, -1)))
posix_spawn_file_actions_adddup2(file_actions, /* XXX luaL_checkuserdata is confusing here */
fileno(luaL_checkudata(L, -1, LUA_FILEHANDLE)), descriptor); posix_spawn_file_actions_adddup2(&p->file_actions,
lua_pop(L, 1); fileno(luaL_checkuserdata(p->L, -1, LUA_FILEHANDLE)), descriptor);
lua_pop(p->L, 1);
return ret; return ret;
} }
@ -282,9 +289,9 @@ static void spawn_param_redirects(struct spawn_params *p)
{ {
posix_spawn_file_actions_init(&p->file_actions); posix_spawn_file_actions_init(&p->file_actions);
p->has_actions = 1; p->has_actions = 1;
get_redirect(p->L, &p->file_actions, "stdin", STDIN_FILENO); get_redirect(p, "stdin", STDIN_FILENO);
get_redirect(p->L, &p->file_actions, "stdout", STDOUT_FILENO); get_redirect(p, "stdout", STDOUT_FILENO);
get_redirect(p->L, &p->file_actions, "stderr", STDERR_FILENO); get_redirect(p, "stderr", STDERR_FILENO);
} }
#define PROCESS_HANDLE "process" #define PROCESS_HANDLE "process"
@ -339,7 +346,7 @@ static int ex_spawn(lua_State *L)
switch (lua_type(L, 2)) { switch (lua_type(L, 2)) {
default: luaL_argerror(L, 2, "expected options table"); break; default: luaL_argerror(L, 2, "expected options table"); break;
case LUA_TNONE: case LUA_TNONE:
spawn_param_defaults(&params); spawn_param_defaults(&params); /* cmd opts ... */
break; break;
case LUA_TTABLE: case LUA_TTABLE:
lua_getfield(L, 2, "args"); /* cmd opts ... argtab */ lua_getfield(L, 2, "args"); /* cmd opts ... argtab */
@ -363,7 +370,8 @@ static int ex_spawn(lua_State *L)
spawn_param_env(&params); /* cmd opts ... */ spawn_param_env(&params); /* cmd opts ... */
break; break;
} }
spawn_param_redirects(&params); spawn_param_redirects(&params); /* cmd opts ... */
break;
} }
proc = lua_newuserdata(L, sizeof *proc); /* cmd opts ... proc */ proc = lua_newuserdata(L, sizeof *proc); /* cmd opts ... proc */
luaL_getmetatable(L, PROCESS_HANDLE); /* cmd opts ... proc M */ luaL_getmetatable(L, PROCESS_HANDLE); /* cmd opts ... proc M */
@ -376,7 +384,7 @@ static int ex_spawn(lua_State *L)
/* proc -- exitcode/nil error */ /* proc -- exitcode/nil error */
static int process_wait(lua_State *L) static int process_wait(lua_State *L)
{ {
struct process *p = luaL_checkudata(L, 1, PROCESS_HANDLE); struct process *p = luaL_checkuserdata(L, 1, PROCESS_HANDLE);
if (p->status == -1) { if (p->status == -1) {
int status; int status;
if (-1 == waitpid(p->pid, &status, 0)) if (-1 == waitpid(p->pid, &status, 0))
@ -448,4 +456,3 @@ int luaopen_ex(lua_State *L)
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 1; return 1;
} }

@ -5,7 +5,7 @@ INCLUDES = -I${LUA}/include
WARNINGS = -W -Wall -Wno-missing-braces 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 LUA = /home/mark/src/lang/lua/lua51
LUALIBS = -L$(LUA)/lib -llua51 LUALIBS = -L$(LUA)/bin/mingw -llua51
ex.dll: ex.o ex.dll: ex.o
$(CC) $(TARGET_ARCH) -shared -o $@ ex.o $(LUALIBS) /c/windows/system32/msvcrt.dll $(CC) $(TARGET_ARCH) -shared -o $@ ex.o $(LUALIBS) /c/windows/system32/msvcrt.dll

@ -31,11 +31,8 @@ static int push_error(lua_State *L)
size_t res = FormatMessage( size_t res = FormatMessage(
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
0, error, 0, buffer + len, sizeof buffer - len, 0); 0, error, 0, buffer + len, sizeof buffer - len, 0);
if (res) { if (res) /* trim spaces */
len += res; for (len += res; len > 0 && isspace(buffer[len - 1]); len--) ;
while (len > 0 && isspace(buffer[len - 1]))
len--;
}
else else
len += sprintf(buffer + len, "<error string not available>"); len += sprintf(buffer + len, "<error string not available>");
lua_pushnil(L); lua_pushnil(L);
@ -53,9 +50,10 @@ static int ex_getenv(lua_State *L)
len = GetEnvironmentVariable(nam, val, sizeof val); len = GetEnvironmentVariable(nam, val, sizeof val);
if (sizeof val < len) if (sizeof val < len)
return push_error(L); return push_error(L);
else if (len == 0) else if (len == 0) {
lua_pushnil(L); lua_pushnil(L);
else return 1;
}
lua_pushlstring(L, val, len); lua_pushlstring(L, val, len);
return 1; return 1;
} }
@ -85,9 +83,8 @@ static int ex_unsetenv(lua_State *L)
static int ex_environ(lua_State *L) static int ex_environ(lua_State *L)
{ {
const char *nam, *val, *end; const char *nam, *val, *end;
const char *envs; const char *envs = GetEnvironmentStrings();
if (!(envs = GetEnvironmentStrings())) if (!envs) return push_error(L);
return push_error(L);
lua_newtable(L); lua_newtable(L);
for (nam = envs; *nam; nam = end + 1) { for (nam = envs; *nam; nam = end + 1) {
end = strchr(val = strchr(nam, '=') + 1, '\0'); end = strchr(val = strchr(nam, '=') + 1, '\0');
@ -132,9 +129,8 @@ static int ex_mkdir(lua_State *L)
static int ex_currentdir(lua_State *L) static int ex_currentdir(lua_State *L)
{ {
char pathname[PATH_MAX + 1]; char pathname[PATH_MAX + 1];
size_t len; size_t len = GetCurrentDirectory(sizeof pathname, pathname);
if (!(len = GetCurrentDirectory(sizeof pathname, pathname))) if (len == 0) return push_error(L);
return push_error(L);
lua_pushlstring(L, pathname, len); lua_pushlstring(L, pathname, len);
return 1; return 1;
} }
@ -219,6 +215,7 @@ static int ex_pipe(lua_State *L)
_fdopen(_open_osfhandle((long)ph[1], _O_WRONLY), "w")); _fdopen(_open_osfhandle((long)ph[1], _O_WRONLY), "w"));
} }
struct spawn_params { struct spawn_params {
lua_State *L; lua_State *L;
const char *cmdline; const char *cmdline;
@ -242,23 +239,26 @@ static void spawn_param_filename(struct spawn_params *p)
lua_pushvalue(p->L, -2); /* cmd ... q cmd q */ lua_pushvalue(p->L, -2); /* cmd ... q cmd q */
lua_concat(p->L, 3); /* cmd ... "cmd" */ lua_concat(p->L, 3); /* cmd ... "cmd" */
lua_replace(p->L, 1); /* "cmd" ... */ lua_replace(p->L, 1); /* "cmd" ... */
p->cmdline = lua_tostring(p->L, 1);
} }
} }
/* -- */ /* -- */
static void spawn_param_default(struct spawn_params *p) static void spawn_param_defaults(struct spawn_params *p)
{ {
p->environment = 0; p->environment = 0;
memset(&p->si, 0, sizeof p->si); memset(&p->si, 0, sizeof p->si);
p->si.cb = sizeof p->si; p->si.cb = sizeof p->si;
} }
/* {arg1,arg 2} => " arg1 \"arg2\"" */ /* cmd opts ... argtab -- cmd opts ... cmdline */
static const char *concat_args(lua_State *L) static void spawn_param_args(struct spawn_params *p)
{ {
lua_State *L = p->L;
luaL_Buffer args; luaL_Buffer args;
luaL_buffinit(L, &args); luaL_buffinit(L, &args);
size_t i, n = lua_objlen(L, -1); size_t i, n = lua_objlen(L, -1);
/* concatenate the arg array to a string */
for (i = 1; i <= n; i++) { for (i = 1; i <= n; i++) {
int quote; int quote;
lua_rawgeti(L, -1, i); /* ... argtab arg */ lua_rawgeti(L, -1, i); /* ... argtab arg */
@ -270,25 +270,26 @@ static const char *concat_args(lua_State *L)
if (quote) luaL_putchar(&args, '"'); if (quote) luaL_putchar(&args, '"');
lua_pop(L, 1); /* ... argtab */ lua_pop(L, 1); /* ... argtab */
} }
lua_pop(L, 1); /* ... */ luaL_pushresult(&args); /* ... argtab argstr */
luaL_pushresult(&args); /* ... argstr */ lua_pushvalue(L, 1); /* cmd opts ... argtab argstr cmd */
return lua_tostring(L, -1); lua_replace(L, -2); /* cmd opts ... argtab cmd argstr */
} lua_concat(L, 2); /* cmd opts ... argtab cmdline */
lua_replace(L, -2); /* cmd opts ... cmdline */
/* cmd opts ... argtab */ p->cmdline = lua_tostring(L, -1);
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" */ /* ... envtab */
static const char *concat_env(lua_State *L) static void spawn_param_env(struct spawn_params *p)
{ {
lua_State *L = p->L;
luaL_Buffer env; luaL_Buffer env;
if (lua_isnil(L, -1)) {
p->environment = 0;
lua_pop(L, 1);
return;
}
/* convert env table to zstring list */
/* {nam1=val1,nam2=val2} => "nam1=val1\0nam2=val2\0\0" */
luaL_buffinit(L, &env); luaL_buffinit(L, &env);
lua_pushnil(L); /* ... envtab nil */ lua_pushnil(L); /* ... envtab nil */
while (lua_next(L, -2)) { /* ... envtab k v */ while (lua_next(L, -2)) { /* ... envtab k v */
@ -304,46 +305,34 @@ static const char *concat_env(lua_State *L)
lua_pop(L, 1); /* ... envtab k */ lua_pop(L, 1); /* ... envtab k */
} }
luaL_putchar(&env, '\0'); luaL_putchar(&env, '\0');
lua_pop(L, 1); /* ... */ luaL_pushresult(&env); /* ... envtab envstr */
luaL_pushresult(&env); /* ... envstr */ lua_replace(L, -2); /* ... envtab envstr */
return lua_tostring(L, -1); p->environment = lua_tostring(L, -1);
}
/* ... 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 ... */ /* _ opts ... */
static int get_redirect(lua_State *L, const char *stdname, HANDLE *ph) static int get_redirect(struct spawn_params *p, const char *stdname, HANDLE *ph)
{ {
int ret; int ret;
lua_getfield(L, 2, stdname); lua_getfield(p->L, 2, stdname);
if ((ret = !lua_isnil(L, -1))) { if ((ret = !lua_isnil(p->L, -1))) {
/* XXX checkuserdata is confusing here */ /* XXX checkuserdata is confusing here */
FILE **pf = luaL_checkuserdata(L, -1, LUA_FILEHANDLE); FILE **pf = luaL_checkuserdata(p->L, -1, LUA_FILEHANDLE);
*ph = get_handle(*pf); *ph = get_handle(*pf);
} }
lua_pop(L, 1); lua_pop(p->L, 1);
return ret; return ret;
} }
/* _ opts ... */ /* _ opts ... */
static void spawn_param_redirect(struct spawn_params *p) static void spawn_param_redirects(struct spawn_params *p)
{ {
p->si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); p->si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
p->si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); p->si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
p->si.hStdError = GetStdHandle(STD_ERROR_HANDLE); p->si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if (get_redirect(p->L, "stdin", &p->si.hStdInput) if (get_redirect(p, "stdin", &p->si.hStdInput)
| get_redirect(p->L, "stdout", &p->si.hStdOutput) | get_redirect(p, "stdout", &p->si.hStdOutput)
| get_redirect(p->L, "stderr", &p->si.hStdError)) | get_redirect(p, "stderr", &p->si.hStdError))
p->si.dwFlags = STARTF_USESTDHANDLES; p->si.dwFlags = STARTF_USESTDHANDLES;
} }
@ -396,14 +385,14 @@ static int ex_spawn(lua_State *L)
} }
} }
/* get command */ /* get filename to execute */
spawn_param_filename(&params); spawn_param_filename(&params);
/* get arguments, environment, and redirections */ /* get arguments, environment, and redirections */
switch (lua_type(L, 2)) { switch (lua_type(L, 2)) {
default: luaL_argerror(L, 2, "expected options table"); break; default: luaL_argerror(L, 2, "expected options table"); break;
case LUA_TNONE: case LUA_TNONE:
spawn_param_default(&params); spawn_param_defaults(&params); /* cmd opts ... */
break; break;
case LUA_TTABLE: case LUA_TTABLE:
lua_getfield(L, 2, "args"); /* cmd opts ... argtab */ lua_getfield(L, 2, "args"); /* cmd opts ... argtab */
@ -416,7 +405,7 @@ static int ex_spawn(lua_State *L)
case LUA_TTABLE: case LUA_TTABLE:
if (lua_objlen(L, 2) > 0) if (lua_objlen(L, 2) > 0)
luaL_error(L, "cannot specify both the args option and array values"); luaL_error(L, "cannot specify both the args option and array values");
spawn_param_args(&params); spawn_param_args(&params); /* cmd opts ... */
break; break;
} }
lua_getfield(L, 2, "env"); /* cmd opts ... envtab */ lua_getfield(L, 2, "env"); /* cmd opts ... envtab */
@ -424,10 +413,10 @@ static int ex_spawn(lua_State *L)
default: luaL_error(L, "env option must be a table"); break; default: luaL_error(L, "env option must be a table"); break;
case LUA_TNIL: case LUA_TNIL:
case LUA_TTABLE: case LUA_TTABLE:
spawn_param_env(&params); spawn_param_env(&params); /* cmd opts ... */
break; break;
} }
spawn_param_redirect(&params); spawn_param_redirects(&params); /* cmd opts ... */
break; break;
} }
proc = lua_newuserdata(L, sizeof *proc); /* cmd opts ... proc */ proc = lua_newuserdata(L, sizeof *proc); /* cmd opts ... proc */
@ -449,7 +438,7 @@ static int process_wait(lua_State *L)
p->status = exitcode; p->status = exitcode;
} }
lua_pushnumber(L, p->status); lua_pushnumber(L, p->status);
return 1; /* exitcode */ return 1;
} }

Loading…
Cancel
Save