Set arg table before evaluating LUA_INIT and -e chunks.

This commit is contained in:
Mike Pall 2016-07-17 16:23:49 +02:00
parent 7374046299
commit 92d9ff211a
2 changed files with 60 additions and 44 deletions

View File

@ -349,6 +349,7 @@ break the Lua/C API and ABI (e.g. <tt>_ENV</tt>).
LuaJIT supports some extensions from Lua&nbsp;5.3: LuaJIT supports some extensions from Lua&nbsp;5.3:
<ul> <ul>
<li>Unicode escape <tt>'\u{XX...}'</tt> embeds the UTF-8 encoding in string literals.</li> <li>Unicode escape <tt>'\u{XX...}'</tt> embeds the UTF-8 encoding in string literals.</li>
<li>The argument table <tt>arg</tt> can be read (and modified) by <tt>LUA_INIT</tt> and <tt>-e</tt> chunks.</li>
</ul> </ul>
<h2 id="exceptions">C++ Exception Interoperability</h2> <h2 id="exceptions">C++ Exception Interoperability</h2>

View File

@ -152,22 +152,15 @@ static void print_jit_status(lua_State *L)
putc('\n', stdout); putc('\n', stdout);
} }
static int getargs(lua_State *L, char **argv, int n) static void createargtable(lua_State *L, char **argv, int argc, int argf)
{ {
int narg;
int i; int i;
int argc = 0; lua_createtable(L, argc - argf, argf);
while (argv[argc]) argc++; /* count total number of arguments */
narg = argc - (n + 1); /* number of arguments to the script */
luaL_checkstack(L, narg + 3, "too many arguments to script");
for (i = n+1; i < argc; i++)
lua_pushstring(L, argv[i]);
lua_createtable(L, narg, n + 1);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
lua_pushstring(L, argv[i]); lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, i - n); lua_rawseti(L, -2, i - argf);
} }
return narg; lua_setglobal(L, "arg");
} }
static int dofile(lua_State *L, const char *name) static int dofile(lua_State *L, const char *name)
@ -273,21 +266,30 @@ static void dotty(lua_State *L)
progname = oldprogname; progname = oldprogname;
} }
static int handle_script(lua_State *L, char **argv, int n) static int handle_script(lua_State *L, char **argx)
{ {
int status; int status;
const char *fname; const char *fname = argx[0];
int narg = getargs(L, argv, n); /* collect arguments */ if (strcmp(fname, "-") == 0 && strcmp(argx[-1], "--") != 0)
lua_setglobal(L, "arg");
fname = argv[n];
if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
fname = NULL; /* stdin */ fname = NULL; /* stdin */
status = luaL_loadfile(L, fname); status = luaL_loadfile(L, fname);
lua_insert(L, -(narg+1)); if (status == 0) {
if (status == 0) /* Fetch args from arg table. LUA_INIT or -e might have changed them. */
int narg = 0;
lua_getglobal(L, "arg");
if (lua_istable(L, -1)) {
do {
narg++;
lua_rawgeti(L, -narg, narg);
} while (!lua_isnil(L, -1));
lua_pop(L, 1);
lua_remove(L, -narg);
narg--;
} else {
lua_pop(L, 1);
}
status = docall(L, narg, 0); status = docall(L, narg, 0);
else }
lua_pop(L, narg);
return report(L, status); return report(L, status);
} }
@ -384,7 +386,8 @@ static int dobytecode(lua_State *L, char **argv)
} }
for (argv++; *argv != NULL; narg++, argv++) for (argv++; *argv != NULL; narg++, argv++)
lua_pushstring(L, *argv); lua_pushstring(L, *argv);
return report(L, lua_pcall(L, narg, 0, 0)); report(L, lua_pcall(L, narg, 0, 0));
return 1;
} }
/* check that argument has no extra characters at the end */ /* check that argument has no extra characters at the end */
@ -405,7 +408,7 @@ static int collectargs(char **argv, int *flags)
switch (argv[i][1]) { /* Check option. */ switch (argv[i][1]) { /* Check option. */
case '-': case '-':
notail(argv[i]); notail(argv[i]);
return (argv[i+1] != NULL ? i+1 : 0); return i+1;
case '\0': case '\0':
return i; return i;
case 'i': case 'i':
@ -430,23 +433,23 @@ static int collectargs(char **argv, int *flags)
case 'b': /* LuaJIT extension */ case 'b': /* LuaJIT extension */
if (*flags) return -1; if (*flags) return -1;
*flags |= FLAGS_EXEC; *flags |= FLAGS_EXEC;
return 0; return i+1;
case 'E': case 'E':
*flags |= FLAGS_NOENV; *flags |= FLAGS_NOENV;
break; break;
default: return -1; /* invalid option */ default: return -1; /* invalid option */
} }
} }
return 0; return i;
} }
static int runargs(lua_State *L, char **argv, int n) static int runargs(lua_State *L, char **argv, int argn)
{ {
int i; int i;
for (i = 1; i < n; i++) { for (i = 1; i < argn; i++) {
if (argv[i] == NULL) continue; if (argv[i] == NULL) continue;
lua_assert(argv[i][0] == '-'); lua_assert(argv[i][0] == '-');
switch (argv[i][1]) { /* option */ switch (argv[i][1]) {
case 'e': { case 'e': {
const char *chunk = argv[i] + 2; const char *chunk = argv[i] + 2;
if (*chunk == '\0') chunk = argv[++i]; if (*chunk == '\0') chunk = argv[++i];
@ -460,10 +463,10 @@ static int runargs(lua_State *L, char **argv, int n)
if (*filename == '\0') filename = argv[++i]; if (*filename == '\0') filename = argv[++i];
lua_assert(filename != NULL); lua_assert(filename != NULL);
if (dolibrary(L, filename)) if (dolibrary(L, filename))
return 1; /* stop if file fails */ return 1;
break; break;
} }
case 'j': { /* LuaJIT extension */ case 'j': { /* LuaJIT extension. */
const char *cmd = argv[i] + 2; const char *cmd = argv[i] + 2;
if (*cmd == '\0') cmd = argv[++i]; if (*cmd == '\0') cmd = argv[++i];
lua_assert(cmd != NULL); lua_assert(cmd != NULL);
@ -471,11 +474,11 @@ static int runargs(lua_State *L, char **argv, int n)
return 1; return 1;
break; break;
} }
case 'O': /* LuaJIT extension */ case 'O': /* LuaJIT extension. */
if (dojitopt(L, argv[i] + 2)) if (dojitopt(L, argv[i] + 2))
return 1; return 1;
break; break;
case 'b': /* LuaJIT extension */ case 'b': /* LuaJIT extension. */
return dobytecode(L, argv+i); return dobytecode(L, argv+i);
default: break; default: break;
} }
@ -508,45 +511,57 @@ static int pmain(lua_State *L)
{ {
struct Smain *s = &smain; struct Smain *s = &smain;
char **argv = s->argv; char **argv = s->argv;
int script; int argn;
int flags = 0; int flags = 0;
globalL = L; globalL = L;
if (argv[0] && argv[0][0]) progname = argv[0]; if (argv[0] && argv[0][0]) progname = argv[0];
LUAJIT_VERSION_SYM(); /* linker-enforced version check */
script = collectargs(argv, &flags); LUAJIT_VERSION_SYM(); /* Linker-enforced version check. */
if (script < 0) { /* invalid args? */
argn = collectargs(argv, &flags);
if (argn < 0) { /* Invalid args? */
print_usage(); print_usage();
s->status = 1; s->status = 1;
return 0; return 0;
} }
if ((flags & FLAGS_NOENV)) { if ((flags & FLAGS_NOENV)) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
} }
lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
luaL_openlibs(L); /* open libraries */ /* Stop collector during library initialization. */
lua_gc(L, LUA_GCSTOP, 0);
luaL_openlibs(L);
lua_gc(L, LUA_GCRESTART, -1); lua_gc(L, LUA_GCRESTART, -1);
createargtable(L, argv, s->argc, argn);
if (!(flags & FLAGS_NOENV)) { if (!(flags & FLAGS_NOENV)) {
s->status = handle_luainit(L); s->status = handle_luainit(L);
if (s->status != 0) return 0; if (s->status != 0) return 0;
} }
if ((flags & FLAGS_VERSION)) print_version(); if ((flags & FLAGS_VERSION)) print_version();
s->status = runargs(L, argv, (script > 0) ? script : s->argc);
s->status = runargs(L, argv, argn);
if (s->status != 0) return 0; if (s->status != 0) return 0;
if (script) {
s->status = handle_script(L, argv, script); if (s->argc > argn) {
s->status = handle_script(L, argv + argn);
if (s->status != 0) return 0; if (s->status != 0) return 0;
} }
if ((flags & FLAGS_INTERACTIVE)) { if ((flags & FLAGS_INTERACTIVE)) {
print_jit_status(L); print_jit_status(L);
dotty(L); dotty(L);
} else if (script == 0 && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) { } else if (s->argc == argn && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) {
if (lua_stdin_is_tty()) { if (lua_stdin_is_tty()) {
print_version(); print_version();
print_jit_status(L); print_jit_status(L);
dotty(L); dotty(L);
} else { } else {
dofile(L, NULL); /* executes stdin as a file */ dofile(L, NULL); /* Executes stdin as a file. */
} }
} }
return 0; return 0;
@ -555,7 +570,7 @@ static int pmain(lua_State *L)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int status; int status;
lua_State *L = lua_open(); /* create state */ lua_State *L = lua_open();
if (L == NULL) { if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory"); l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE; return EXIT_FAILURE;