ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

luajit.c (23190B)


      1 /*
      2 ** LuaJIT frontend. Runs commands, scripts, read-eval-print (REPL) etc.
      3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
      4 **
      5 ** Advanced readline support for the GNU readline and history
      6 ** libraries or compatible replacements taken from Mike's Lua patch.
      7 **
      8 ** Major portions taken verbatim or adapted from the Lua interpreter.
      9 ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
     10 */
     11 
     12 
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 
     17 #define luajit_c
     18 
     19 #include "lua.h"
     20 #include "lauxlib.h"
     21 #include "lualib.h"
     22 #include "luajit.h"
     23 
     24 #include "lj_arch.h"
     25 #include "lj_char.h"
     26 
     27 #include <unistd.h>
     28 
     29 #if !defined(lua_readline)
     30 #if defined(LUA_USE_READLINE)
     31 #include <readline/readline.h>
     32 #include <readline/history.h>
     33 #include <ctype.h>
     34 #define lua_readline(L,b,p)     ((void)L, ((b)=readline(p)) != NULL)
     35 #define lua_saveline(L,idx) \
     36           if (lua_rawlen(L,idx) > 0)  /* non-empty line? */ \
     37           add_history(lua_tostring(L, idx));  /* add it to history */
     38 #define lua_freeline(L,b)       ((void)L, free(b))
     39 
     40 static char *lua_rl_hist;
     41 static int lua_rl_histsize;
     42 static lua_State *lua_rl_L;  /* User data is not passed to rl callbacks. */
     43 
     44 /* Reserved keywords. */
     45 static const char *const lua_rl_keywords[] = {
     46   "and", "break", "do", "else", "elseif", "end", "false",
     47   "for", "function", "goto", "if", "in", "local", "nil", "not", "or",
     48   "repeat", "return", "then", "true", "until", "while", NULL
     49 };
     50 
     51 static int valididentifier(const char *s)
     52 {
     53   if (!(isalpha((int)*s) || *s == '_')) return 0;
     54   for (s++; *s; s++) if (!(isalpha((int)*s) || isdigit((int)*s) || *s == '_')) return 0;
     55   return 1;
     56 }
     57 
     58 /* Dynamically resizable match list. */
     59 typedef struct {
     60   char **list;
     61   size_t idx, allocated, matchlen;
     62 } dmlist;
     63 
     64 /* Add prefix + string + suffix to list and compute common prefix. */
     65 static int lua_rl_dmadd(dmlist *ml, const char *p, size_t pn, const char *s,
     66 			int suf)
     67 {
     68   char *t = NULL;
     69 
     70   if (ml->idx+1 >= ml->allocated &&
     71       !(ml->list = realloc(ml->list, sizeof(char *)*(ml->allocated += 32))))
     72     return -1;
     73 
     74   if (s) {
     75     size_t n = strlen(s);
     76     if (!(t = (char *)malloc(sizeof(char)*(pn+n+(suf?2:1))))) return 1;
     77     memcpy(t, p, pn);
     78     memcpy(t+pn, s, n);
     79     n += pn;
     80     t[n] = suf;
     81     if (suf) t[++n] = '\0';
     82 
     83     if (ml->idx == 0) {
     84       ml->matchlen = n;
     85     } else {
     86       size_t i;
     87       for (i = 0; i < ml->matchlen && i < n && ml->list[1][i] == t[i]; i++) ;
     88       ml->matchlen = i;  /* Set matchlen to common prefix. */
     89     }
     90   }
     91 
     92   ml->list[++ml->idx] = t;
     93   return 0;
     94 }
     95 
     96 /* Get __index field of metatable of object on top of stack. */
     97 static int lua_rl_getmetaindex(lua_State *L)
     98 {
     99   if (!lua_getmetatable(L, -1)) { lua_pop(L, 1); return 0; }
    100   lua_pushstring(L, "__index");
    101   lua_rawget(L, -2);
    102   lua_replace(L, -2);
    103   if (lua_isnil(L, -1) || lua_rawequal(L, -1, -2)) { lua_pop(L, 2); return 0; }
    104   lua_replace(L, -2);
    105   return 1;
    106 }  /* 1: obj -- val, 0: obj -- */
    107 
    108 /* Get field from object on top of stack. Avoid calling metamethods. */
    109 static int lua_rl_getfield(lua_State *L, const char *s, size_t n)
    110 {
    111   int i = 20;  /* Avoid infinite metatable loops. */
    112   do {
    113     if (lua_istable(L, -1)) {
    114       lua_pushlstring(L, s, n);
    115       lua_rawget(L, -2);
    116       if (!lua_isnil(L, -1)) { lua_replace(L, -2); return 1; }
    117       lua_pop(L, 1);
    118     }
    119   } while (--i > 0 && lua_rl_getmetaindex(L));
    120   lua_pop(L, 1);
    121   return 0;
    122 }  /* 1: obj -- val, 0: obj -- */
    123 
    124 /* Completion callback. */
    125 static char **lua_rl_complete(const char *text, int start, int end)
    126 {
    127   lua_State *L = lua_rl_L;
    128   dmlist ml;
    129   const char *s;
    130   size_t i, n, dot, loop;
    131   int savetop;
    132 
    133   if (!(text[0] == '\0' || isalpha((int)text[0]) || text[0] == '_')) return NULL;
    134 
    135   ml.list = NULL;
    136   ml.idx = ml.allocated = ml.matchlen = 0;
    137 
    138   savetop = lua_gettop(L);
    139   lua_pushglobaltable(L);
    140   for (n = (size_t)(end-start), i = dot = 0; i < n; i++)
    141     if (text[i] == '.' || text[i] == ':') {
    142       if (!lua_rl_getfield(L, text+dot, i-dot))
    143 	goto error;  /* Invalid prefix. */
    144       dot = i+1;  /* Points to first char after dot/colon. */
    145     }
    146 
    147   /* Add all matches against keywords if there is no dot/colon. */
    148   if (dot == 0)
    149     for (i = 0; (s = lua_rl_keywords[i]) != NULL; i++)
    150       if (!strncmp(s, text, n) && lua_rl_dmadd(&ml, NULL, 0, s, ' '))
    151 	goto error;
    152 
    153   /* Add all valid matches from all tables/metatables. */
    154   loop = 0;  /* Avoid infinite metatable loops. */
    155   lua_pushglobaltable(L);
    156   lua_insert(L, -2);
    157   do {
    158     if (lua_istable(L, -1) &&
    159 	(loop == 0 || !lua_rawequal(L, -1, -2)))
    160       for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1))
    161 	if (lua_type(L, -2) == LUA_TSTRING) {
    162 	  s = lua_tostring(L, -2);
    163 	  /* Only match names starting with '_' if explicitly requested. */
    164 	  if (!strncmp(s, text+dot, n-dot) && valididentifier(s) &&
    165 	      (*s != '_' || text[dot] == '_')) {
    166 	    int suf = ' ';  /* Default suffix is a space. */
    167 	    switch (lua_type(L, -1)) {
    168 	    case LUA_TTABLE:	suf = '.'; break;  /* No way to guess ':'. */
    169 	    case LUA_TFUNCTION:	suf = '('; break;
    170 	    case LUA_TUSERDATA:
    171 	      if (lua_getmetatable(L, -1)) { lua_pop(L, 1); suf = ':'; }
    172 	      break;
    173 	    }
    174 	    if (lua_rl_dmadd(&ml, text, dot, s, suf)) goto error;
    175 	  }
    176 	}
    177   } while (++loop < 20 && lua_rl_getmetaindex(L));
    178   lua_pop(L, 1);
    179 
    180   if (ml.idx == 0) {
    181 error:
    182     lua_settop(L, savetop);
    183     return NULL;
    184   } else {
    185     /* list[0] holds the common prefix of all matches (may be ""). */
    186     /* If there is only one match, list[0] and list[1] will be the same. */
    187     if (!(ml.list[0] = (char *)malloc(sizeof(char)*(ml.matchlen+1))))
    188       goto error;
    189     memcpy(ml.list[0], ml.list[1], ml.matchlen);
    190     ml.list[0][ml.matchlen] = '\0';
    191     /* Add the NULL list terminator. */
    192     if (lua_rl_dmadd(&ml, NULL, 0, NULL, 0)) goto error;
    193   }
    194 
    195   lua_settop(L, savetop);
    196 #if RL_READLINE_VERSION >= 0x0600
    197   rl_completion_suppress_append = 1;
    198 #endif
    199   return ml.list;
    200 }
    201 
    202 /* Initialize readline library. */
    203 static void lua_rl_init(lua_State *L)
    204 {
    205   char *s;
    206 
    207   lua_rl_L = L;
    208 
    209   /* This allows for $if lua ... $endif in ~/.inputrc. */
    210   rl_readline_name = "lua";
    211   /* Break words at every non-identifier character except '.' and ':'. */
    212   rl_completer_word_break_characters = 
    213     "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~";
    214   rl_completer_quote_characters = "\"'";
    215 #if RL_READLINE_VERSION < 0x0600
    216   rl_completion_append_character = '\0';
    217 #endif
    218   rl_attempted_completion_function = lua_rl_complete;
    219   rl_initialize();
    220 
    221   /* Start using history, optionally set history size and load history file. */
    222   using_history();
    223   if ((s = getenv("LUA_HISTSIZE")) &&
    224       (lua_rl_histsize = atoi(s))) stifle_history(lua_rl_histsize);
    225   if ((lua_rl_hist = getenv("LUA_HISTORY"))) read_history(lua_rl_hist);
    226 }
    227 
    228 /* Finalize readline library. */
    229 static void lua_rl_exit(lua_State *L)
    230 {
    231   (void)L; /* Avoid 'unused parameter' warning. */
    232   /* Optionally save history file. */
    233   if (lua_rl_hist) write_history(lua_rl_hist);
    234 }
    235 #else
    236 /* ------------------------------------------------------------------------ */
    237 #define lua_rl_init(L)		((void)L)
    238 #define lua_rl_exit(L)		((void)L)
    239 
    240 #define lua_readline(L,b,p) \
    241           ((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
    242                    fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
    243 #define lua_saveline(L,idx)     { (void)L; (void)idx; }
    244 #define lua_freeline(L,b)       { (void)L; (void)b; }
    245 #endif
    246 #endif
    247 
    248 #if LJ_TARGET_POSIX
    249 #define lua_stdin_is_tty()	isatty(0)
    250 #elif LJ_TARGET_WINDOWS
    251 #include <io.h>
    252 #ifdef __BORLANDC__
    253 #define lua_stdin_is_tty()	isatty(_fileno(stdin))
    254 #else
    255 #define lua_stdin_is_tty()	_isatty(_fileno(stdin))
    256 #endif
    257 #else
    258 #define lua_stdin_is_tty()	1
    259 #endif
    260 
    261 #if !LJ_TARGET_CONSOLE
    262 #include <signal.h>
    263 #endif
    264 
    265 static lua_State *globalL = NULL;
    266 static const char *progname = LUA_PROGNAME;
    267 
    268 #if !LJ_TARGET_CONSOLE
    269 static void lstop(lua_State *L, lua_Debug *ar)
    270 {
    271   (void)ar;  /* unused arg. */
    272   lua_sethook(L, NULL, 0, 0);
    273   /* Avoid luaL_error -- a C hook doesn't add an extra frame. */
    274   luaL_where(L, 0);
    275   lua_pushfstring(L, "%sinterrupted!", lua_tostring(L, -1));
    276   lua_error(L);
    277 }
    278 
    279 static void laction(int i)
    280 {
    281   signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
    282 			 terminate process (default action) */
    283   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
    284 }
    285 #endif
    286 
    287 static void print_usage(void)
    288 {
    289   fputs("usage: ", stderr);
    290   fputs(progname, stderr);
    291   fputs(" [options]... [script [args]...].\n"
    292   "Available options are:\n"
    293   "  -e chunk  Execute string " LUA_QL("chunk") ".\n"
    294   "  -l name   Require library " LUA_QL("name") ".\n"
    295   "  -b ...    Save or list bytecode.\n"
    296   "  -j cmd    Perform LuaJIT control command.\n"
    297   "  -O[opt]   Control LuaJIT optimizations.\n"
    298   "  -i        Enter interactive mode after executing " LUA_QL("script") ".\n"
    299   "  -v        Show version information.\n"
    300   "  -E        Ignore environment variables.\n"
    301   "  --        Stop handling options.\n"
    302   "  -         Execute stdin and stop handling options.\n", stderr);
    303   fflush(stderr);
    304 }
    305 
    306 static void l_message(const char *pname, const char *msg)
    307 {
    308   if (pname) { fputs(pname, stderr); fputc(':', stderr); fputc(' ', stderr); }
    309   fputs(msg, stderr); fputc('\n', stderr);
    310   fflush(stderr);
    311 }
    312 
    313 static int report(lua_State *L, int status)
    314 {
    315   if (status && !lua_isnil(L, -1)) {
    316     const char *msg = lua_tostring(L, -1);
    317     if (msg == NULL) msg = "(error object is not a string)";
    318     l_message(progname, msg);
    319     lua_pop(L, 1);
    320   }
    321   return status;
    322 }
    323 
    324 static int traceback (lua_State *L) {
    325   const char *msg = lua_tostring(L, 1);
    326   if (msg)
    327     luaL_traceback(L, L, msg, 1);
    328   else if (!lua_isnoneornil(L, 1)) {  /* is there an error object? */
    329     if (!luaL_callmeta(L, 1, "__tostring"))  /* try its 'tostring' metamethod */
    330       lua_pushliteral(L, "(no error message)");
    331   }
    332   return 1;
    333 }
    334 
    335 static int docall(lua_State *L, int narg, int nres)
    336 {
    337   int status;
    338   int base = lua_gettop(L) - narg;  /* function index */
    339   lua_pushcfunction(L, traceback);  /* push traceback function */
    340   lua_insert(L, base);  /* put it under chunk and args */
    341 #if !LJ_TARGET_CONSOLE
    342   signal(SIGINT, laction);
    343 #endif
    344   status = lua_pcall(L, narg, nres, base);
    345 #if !LJ_TARGET_CONSOLE
    346   signal(SIGINT, SIG_DFL);
    347 #endif
    348   lua_remove(L, base);  /* remove traceback function */
    349   /* force a complete garbage collection in case of errors */
    350   if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
    351   return status;
    352 }
    353 
    354 static void print_jit_status(lua_State *L)
    355 {
    356   int n;
    357   const char *s;
    358   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
    359   lua_getfield(L, -1, "jit");  /* Get jit.* module table. */
    360   lua_remove(L, -2);
    361   lua_getfield(L, -1, "status");
    362   lua_remove(L, -2);
    363   n = lua_gettop(L);
    364   lua_call(L, 0, LUA_MULTRET);
    365   fputs(lua_toboolean(L, n) ? "JIT: ON" : "JIT: OFF", stdout);
    366   for (n++; (s = lua_tostring(L, n)); n++) {
    367     putc(' ', stdout);
    368     fputs(s, stdout);
    369   }
    370   putc('\n', stdout);
    371 }
    372 
    373 static void print_version(lua_State *L, int jit)
    374 {
    375 #ifndef LUAJIT_PRETEND_RIO
    376   fputs(LJX_VERSION
    377       ", type _COPYRIGHTS, _CREDITS, _VERSION for more info.\n", stdout);
    378   fputs(LUA_VERSION ", ABI: " LUA_ABIVER_STRING
    379         " on " LJ_OS_NAME "/" LJ_ARCH_NAME
    380 #if LJ_4GB
    381 	"/4GB heap"
    382 #elif LJ_GC64
    383 	"/GC64"
    384 #endif
    385 	, stdout);
    386 #ifdef __DATE__
    387   fputs(", built " __DATE__, stdout);
    388 #endif
    389 #ifdef __VERSION__
    390   fputs(" using GCC " __VERSION__ "\n", stdout);
    391 #else
    392   fputs("\n", stdout);
    393 #endif
    394   if (jit) print_jit_status(L);
    395 #else
    396   fputs(LUA_RELEASE "  " LUA_COPYRIGHT"\n", stdout);
    397 #endif
    398   /* These are defined only in interactive session. */
    399   lua_pushliteral(L, LUA_COPYRIGHTS);
    400   lua_setglobal(L, "_COPYRIGHTS");
    401   lua_pushliteral(L, LUA_CREDITS);
    402   lua_setglobal(L, "_CREDITS");
    403 }
    404 
    405 static int getargs(lua_State *L, char **argv, int n)
    406 {
    407   int narg;
    408   int i;
    409   int argc = 0;
    410   while (argv[argc]) argc++;  /* count total number of arguments */
    411   narg = argc - (n + 1);  /* number of arguments to the script */
    412   luaL_checkstack(L, narg + 3, "too many arguments to script");
    413   for (i = n+1; i < argc; i++)
    414     lua_pushstring(L, argv[i]);
    415   lua_createtable(L, narg, n + 1);
    416   for (i = 0; i < argc; i++) {
    417     lua_pushstring(L, argv[i]);
    418     lua_rawseti(L, -2, i - n);
    419   }
    420   return narg;
    421 }
    422 
    423 static int dofile(lua_State *L, const char *name)
    424 {
    425   int status = luaL_loadfile(L, name) || docall(L, 0, 0);
    426   return report(L, status);
    427 }
    428 
    429 static int dostring(lua_State *L, const char *s, const char *name)
    430 {
    431   int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 0);
    432   return report(L, status);
    433 }
    434 
    435 static int dolibrary(lua_State *L, const char *name)
    436 {
    437   int status;
    438   lua_getglobal(L, "require");
    439   lua_pushstring(L, name);
    440   status = docall(L, 1, 1);  /* call 'require(name)' */
    441   if (status == LUA_OK)
    442     lua_setglobal(L, name);  /* global[name] = require return */
    443   return report(L, status);
    444 }
    445 
    446 static const char *get_prompt(lua_State *L, int firstline)
    447 {
    448   const char *p;
    449   lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
    450   p = lua_tostring(L, -1);
    451   if (p == NULL) p = firstline ? LUA_PROMPT : LUA_PROMPT2;
    452   return p;
    453 }
    454 
    455 static int incomplete(lua_State *L, int status)
    456 {
    457   if (status == LUA_ERRSYNTAX) {
    458     size_t lmsg;
    459     const char *msg = lua_tolstring(L, -1, &lmsg);
    460     const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
    461     if (strstr(msg, LUA_QL("<eof>")) == tp) {
    462       lua_pop(L, 1);
    463       return 1;
    464     }
    465   }
    466   return 0;  /* else... */
    467 }
    468 
    469 static int pushline(lua_State *L, int firstline)
    470 {
    471   char buffer[LUA_MAXINPUT];
    472   char *buf = buffer;
    473   size_t len;
    474   const char *prmt = get_prompt(L, firstline);
    475   if (lua_readline(L, buf, prmt)) {
    476     lua_pop(L, 1); /* prompt */
    477     len = strlen(buf);
    478     if (len > 0 && buf[len-1] == '\n')
    479       buf[len-1] = '\0';
    480     if (firstline && buf[0] == '=')
    481       lua_pushfstring(L, "return %s", buf+1);
    482     else
    483       lua_pushstring(L, buf);
    484     return 1;
    485   }
    486   return 0;
    487 }
    488 
    489 static int addreturn (lua_State *L) {
    490   int status;
    491   size_t len; const char *line;
    492   lua_pushliteral(L, "return ");
    493   lua_pushvalue(L, -2);  /* duplicate line */
    494   lua_concat(L, 2);  /* new line is "return ..." */
    495   line = lua_tolstring(L, -1, &len);
    496   if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK)
    497     lua_remove(L, -3);  /* remove original line */
    498   else
    499     lua_pop(L, 2);  /* remove result from 'luaL_loadbuffer' and new line */
    500   return status;
    501 }
    502 
    503 static int loadline(lua_State *L)
    504 {
    505   int status;
    506   lua_settop(L, 0);
    507   if (!pushline(L, 1))
    508     return -1;  /* no input */
    509   if ((status = addreturn(L)) != LUA_OK) for (;;) {  /* repeat until gets a complete line */
    510     status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
    511     if (!incomplete(L, status)) break;  /* cannot try to add lines? */
    512     if (!pushline(L, 0))  /* no more input? */
    513       return -1;
    514     lua_pushliteral(L, "\n");  /* add a new line... */
    515     lua_insert(L, -2);  /* ...between the two lines */
    516     lua_concat(L, 3);  /* join them */
    517   }
    518   lua_saveline(L, 1);
    519   lua_remove(L, 1);  /* remove line */
    520   return status;
    521 }
    522 
    523 static void dotty(lua_State *L)
    524 {
    525   int status;
    526   const char *oldprogname = progname;
    527   progname = NULL;
    528   lua_rl_init(L);
    529   while ((status = loadline(L)) != -1) {
    530     if (status == 0) status = docall(L, 0, LUA_MULTRET);
    531     report(L, status);
    532     if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */
    533       lua_getglobal(L, "print");
    534       lua_insert(L, 1);
    535       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
    536 	l_message(progname,
    537 	  lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)",
    538 			      lua_tostring(L, -1)));
    539     }
    540   }
    541   lua_settop(L, 0);  /* clear stack */
    542   fputs("\n", stdout);
    543   fflush(stdout);
    544   lua_rl_exit(L);
    545   progname = oldprogname;
    546 }
    547 
    548 static int handle_script(lua_State *L, char **argv, int n)
    549 {
    550   int status;
    551   const char *fname;
    552   int narg = getargs(L, argv, n);  /* collect arguments */
    553   lua_setglobal(L, "arg");
    554   fname = argv[n];
    555   if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
    556     fname = NULL;  /* stdin */
    557   status = luaL_loadfile(L, fname);
    558   lua_insert(L, -(narg+1));
    559   if (status == 0)
    560     status = docall(L, narg, LUA_MULTRET);
    561   else
    562     lua_pop(L, narg);
    563   return report(L, status);
    564 }
    565 
    566 /* Load add-on module. */
    567 static int loadjitmodule(lua_State *L)
    568 {
    569   lua_getglobal(L, "require");
    570   lua_pushliteral(L, "jit.");
    571   lua_pushvalue(L, -3);
    572   lua_concat(L, 2);
    573   if (lua_pcall(L, 1, 1, 0)) {
    574     const char *msg = lua_tostring(L, -1);
    575     if (msg && !strncmp(msg, "module ", 7))
    576       goto nomodule;
    577     return report(L, 1);
    578   }
    579   lua_getfield(L, -1, "start");
    580   if (lua_isnil(L, -1)) {
    581   nomodule:
    582     l_message(progname,
    583 	      "unknown luaJIT command or jit.* modules not installed");
    584     return 1;
    585   }
    586   lua_remove(L, -2);  /* Drop module table. */
    587   return 0;
    588 }
    589 
    590 /* Run command with options. */
    591 static int runcmdopt(lua_State *L, const char *opt)
    592 {
    593   int narg = 0;
    594   if (opt && *opt) {
    595     for (;;) {  /* Split arguments. */
    596       const char *p = strchr(opt, ',');
    597       narg++;
    598       if (!p) break;
    599       if (p == opt)
    600 	lua_pushnil(L);
    601       else
    602 	lua_pushlstring(L, opt, (size_t)(p - opt));
    603       opt = p + 1;
    604     }
    605     if (*opt)
    606       lua_pushstring(L, opt);
    607     else
    608       lua_pushnil(L);
    609   }
    610   return report(L, lua_pcall(L, narg, 0, 0));
    611 }
    612 
    613 /* JIT engine control command: try jit library first or load add-on module. */
    614 static int dojitcmd(lua_State *L, const char *cmd)
    615 {
    616   const char *opt = strchr(cmd, '=');
    617   lua_pushlstring(L, cmd, opt ? (size_t)(opt - cmd) : strlen(cmd));
    618   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
    619   lua_getfield(L, -1, "jit");  /* Get jit.* module table. */
    620   lua_remove(L, -2);
    621   lua_pushvalue(L, -2);
    622   lua_gettable(L, -2);  /* Lookup library function. */
    623   if (!lua_isfunction(L, -1)) {
    624     lua_pop(L, 2);  /* Drop non-function and jit.* table, keep module name. */
    625     if (loadjitmodule(L))
    626       return 1;
    627   } else {
    628     lua_remove(L, -2);  /* Drop jit.* table. */
    629   }
    630   lua_remove(L, -2);  /* Drop module name. */
    631   return runcmdopt(L, opt ? opt+1 : opt);
    632 }
    633 
    634 /* Optimization flags. */
    635 static int dojitopt(lua_State *L, const char *opt)
    636 {
    637   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
    638   lua_getfield(L, -1, "jit.opt");  /* Get jit.opt.* module table. */
    639   lua_remove(L, -2);
    640   lua_getfield(L, -1, "start");
    641   lua_remove(L, -2);
    642   return runcmdopt(L, opt);
    643 }
    644 
    645 /* Save or list bytecode. */
    646 static int dobytecode(lua_State *L, char **argv)
    647 {
    648   int narg = 0;
    649   lua_pushliteral(L, "bcsave");
    650   if (loadjitmodule(L))
    651     return 1;
    652   if (argv[0][2]) {
    653     narg++;
    654     argv[0][1] = '-';
    655     lua_pushstring(L, argv[0]+1);
    656   }
    657   for (argv++; *argv != NULL; narg++, argv++)
    658     lua_pushstring(L, *argv);
    659   return report(L, lua_pcall(L, narg, 0, 0));
    660 }
    661 
    662 /* check that argument has no extra characters at the end */
    663 #define notail(x)	{if ((x)[2] != '\0') return -1;}
    664 
    665 #define FLAGS_INTERACTIVE	1
    666 #define FLAGS_VERSION		2
    667 #define FLAGS_EXEC		4
    668 #define FLAGS_OPTION		8
    669 #define FLAGS_NOENV		16
    670 
    671 static int collectargs(char **argv, int *flags)
    672 {
    673   int i;
    674   for (i = 1; argv[i] != NULL; i++) {
    675     if (argv[i][0] != '-')  /* Not an option? */
    676       return i;
    677     switch (argv[i][1]) {  /* Check option. */
    678     case '-':
    679       notail(argv[i]);
    680       return (argv[i+1] != NULL ? i+1 : 0);
    681     case '\0':
    682       return i;
    683     case 'i':
    684       notail(argv[i]);
    685       *flags |= FLAGS_INTERACTIVE;
    686       /* fallthrough */
    687     case 'v':
    688       notail(argv[i]);
    689       *flags |= FLAGS_VERSION;
    690       break;
    691     case 'e':
    692       *flags |= FLAGS_EXEC;
    693     case 'j':  /* LuaJIT extension */
    694     case 'l':
    695       *flags |= FLAGS_OPTION;
    696       if (argv[i][2] == '\0') {
    697 	i++;
    698 	if (argv[i] == NULL) return -1;
    699       }
    700       break;
    701     case 'O': break;  /* LuaJIT extension */
    702     case 'b':  /* LuaJIT extension */
    703       if (*flags) return -1;
    704       *flags |= FLAGS_EXEC;
    705       return 0;
    706     case 'E':
    707       *flags |= FLAGS_NOENV;
    708       break;
    709     default: return -1;  /* invalid option */
    710     }
    711   }
    712   return 0;
    713 }
    714 
    715 static int runargs(lua_State *L, char **argv, int n)
    716 {
    717   int i;
    718   for (i = 1; i < n; i++) {
    719     if (argv[i] == NULL) continue;
    720     lua_assert(argv[i][0] == '-');
    721     switch (argv[i][1]) {  /* option */
    722     case 'e': {
    723       const char *chunk = argv[i] + 2;
    724       if (*chunk == '\0') chunk = argv[++i];
    725       lua_assert(chunk != NULL);
    726       if (dostring(L, chunk, "=(command line)") != 0)
    727 	return 1;
    728       break;
    729       }
    730     case 'l': {
    731       const char *filename = argv[i] + 2;
    732       if (*filename == '\0') filename = argv[++i];
    733       lua_assert(filename != NULL);
    734       if (dolibrary(L, filename))
    735 	return 1;  /* stop if file fails */
    736       break;
    737       }
    738     case 'j': {  /* LuaJIT extension */
    739       const char *cmd = argv[i] + 2;
    740       if (*cmd == '\0') cmd = argv[++i];
    741       lua_assert(cmd != NULL);
    742       if (dojitcmd(L, cmd))
    743 	return 1;
    744       break;
    745       }
    746     case 'O':  /* LuaJIT extension */
    747       if (dojitopt(L, argv[i] + 2))
    748 	return 1;
    749       break;
    750     case 'b':  /* LuaJIT extension */
    751       return dobytecode(L, argv+i);
    752     default: break;
    753     }
    754   }
    755   return 0;
    756 }
    757 
    758 static int handle_luainit(lua_State *L)
    759 {
    760 #if LJ_TARGET_CONSOLE
    761   const char *init = NULL;
    762 #else
    763   const char *init = getenv(LUA_INIT_5_2);
    764   if (!init)
    765     init = getenv(LUA_INIT);
    766 #endif
    767   if (init == NULL)
    768     return 0;  /* status OK */
    769   else if (init[0] == '@')
    770     return dofile(L, init+1);
    771   else
    772     return dostring(L, init, "=" LUA_INIT);
    773 }
    774 
    775 static struct Smain {
    776   char **argv;
    777   int argc;
    778   int status;
    779 } smain;
    780 
    781 static int pmain(lua_State *L)
    782 {
    783   struct Smain *s = &smain;
    784   char **argv = s->argv;
    785   int script;
    786   int flags = 0;
    787   globalL = L;
    788   if (argv[0] && argv[0][0]) progname = argv[0];
    789   LUAJIT_VERSION_SYM();  /* linker-enforced version check */
    790   script = collectargs(argv, &flags);
    791   if (script < 0) {  /* invalid args? */
    792     print_usage();
    793     s->status = 1;
    794     return 0;
    795   }
    796   if ((flags & FLAGS_NOENV)) {
    797     lua_pushboolean(L, 1);
    798     lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
    799   }
    800   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
    801   luaL_openlibs(L);  /* open libraries */
    802   lua_gc(L, LUA_GCRESTART, -1);
    803   if (!(flags & FLAGS_NOENV)) {
    804     s->status = handle_luainit(L);
    805     if (s->status != 0) return 0;
    806   }
    807   if ((flags & FLAGS_VERSION)) fputs(LUA_COPYRIGHTS, stdout);
    808   s->status = runargs(L, argv, (script > 0) ? script : s->argc);
    809   if (s->status != 0) return 0;
    810   if (script) {
    811     s->status = handle_script(L, argv, script);
    812     if (s->status != 0) return 0;
    813   }
    814   if ((flags & FLAGS_INTERACTIVE)) {
    815     print_jit_status(L);
    816     dotty(L);
    817   } else if (script == 0 && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) {
    818     if (lua_stdin_is_tty()) {
    819       print_version(L, 1);
    820       dotty(L);
    821     } else {
    822       dofile(L, NULL);  /* executes stdin as a file */
    823     }
    824   }
    825   return 0;
    826 }
    827 
    828 int main(int argc, char **argv)
    829 {
    830   int status;
    831   lua_State *L = lua_open();  /* create state */
    832   if (L == NULL) {
    833     l_message(argv[0], "cannot create state: not enough memory");
    834     return EXIT_FAILURE;
    835   }
    836   smain.argc = argc;
    837   smain.argv = argv;
    838   status = lua_cpcall(L, pmain, NULL);
    839   report(L, status);
    840   lua_close(L);
    841   return (status || smain.status) ? EXIT_FAILURE : EXIT_SUCCESS;
    842 }
    843