Home | History | Annotate | Download | only in src
      1 /*
      2 ** $Id: lua.c,v 1.206.1.1 2013/04/12 18:48:47 roberto Exp $
      3 ** Lua stand-alone interpreter
      4 ** See Copyright Notice in lua.h
      5 */
      6 
      7 
      8 #ifdef SYSLINUX
      9 #include <console.h>
     10 #define signal(x,y)
     11 #else
     12 #include <signal.h>
     13 #endif
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 
     18 #define lua_c
     19 
     20 #include "lua.h"
     21 
     22 #include "lauxlib.h"
     23 #include "lualib.h"
     24 
     25 
     26 #if !defined(LUA_PROMPT)
     27 #define LUA_PROMPT		"> "
     28 #define LUA_PROMPT2		">> "
     29 #endif
     30 
     31 #if !defined(LUA_PROGNAME)
     32 #define LUA_PROGNAME		"lua"
     33 #endif
     34 
     35 #if !defined(LUA_MAXINPUT)
     36 #define LUA_MAXINPUT		512
     37 #endif
     38 
     39 #if !defined(LUA_INIT)
     40 #define LUA_INIT		"LUA_INIT"
     41 #endif
     42 
     43 #define LUA_INITVERSION  \
     44 	LUA_INIT "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
     45 
     46 
     47 /*
     48 ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
     49 ** is, whether we're running lua interactively).
     50 */
     51 #if defined(LUA_USE_ISATTY)
     52 #include <unistd.h>
     53 #define lua_stdin_is_tty()	isatty(0)
     54 #elif defined(LUA_WIN)
     55 #include <io.h>
     56 #include <stdio.h>
     57 #define lua_stdin_is_tty()	_isatty(_fileno(stdin))
     58 #else
     59 #define lua_stdin_is_tty()	1  /* assume stdin is a tty */
     60 #endif
     61 
     62 
     63 /*
     64 ** lua_readline defines how to show a prompt and then read a line from
     65 ** the standard input.
     66 ** lua_saveline defines how to "save" a read line in a "history".
     67 ** lua_freeline defines how to free a line read by lua_readline.
     68 */
     69 #if defined(LUA_USE_READLINE)
     70 
     71 #include <stdio.h>
     72 #include <readline/readline.h>
     73 #include <readline/history.h>
     74 #define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)
     75 #define lua_saveline(L,idx) \
     76         if (lua_rawlen(L,idx) > 0)  /* non-empty line? */ \
     77           add_history(lua_tostring(L, idx));  /* add it to history */
     78 #define lua_freeline(L,b)	((void)L, free(b))
     79 
     80 #elif !defined(lua_readline)
     81 
     82 #define lua_readline(L,b,p) \
     83         ((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
     84         fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
     85 #define lua_saveline(L,idx)	{ (void)L; (void)idx; }
     86 #define lua_freeline(L,b)	{ (void)L; (void)b; }
     87 
     88 #endif
     89 
     90 
     91 
     92 
     93 static lua_State *globalL = NULL;
     94 
     95 static const char *progname = LUA_PROGNAME;
     96 
     97 
     98 
     99 #ifndef SYSLINUX
    100 static void lstop (lua_State *L, lua_Debug *ar) {
    101   (void)ar;  /* unused arg. */
    102   lua_sethook(L, NULL, 0, 0);
    103   luaL_error(L, "interrupted!");
    104 }
    105 
    106 
    107 static void laction (int i) {
    108   signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
    109                               terminate process (default action) */
    110   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
    111 }
    112 #endif
    113 
    114 
    115 static void print_usage (const char *badoption) {
    116   luai_writestringerror("%s: ", progname);
    117   if (badoption[1] == 'e' || badoption[1] == 'l')
    118     luai_writestringerror("'%s' needs argument\n", badoption);
    119   else
    120     luai_writestringerror("unrecognized option '%s'\n", badoption);
    121   luai_writestringerror(
    122   "usage: %s [options] [script [args]]\n"
    123   "Available options are:\n"
    124   "  -e stat  execute string " LUA_QL("stat") "\n"
    125   "  -i       enter interactive mode after executing " LUA_QL("script") "\n"
    126   "  -l name  require library " LUA_QL("name") "\n"
    127   "  -v       show version information\n"
    128   "  -E       ignore environment variables\n"
    129   "  --       stop handling options\n"
    130   "  -        stop handling options and execute stdin\n"
    131   ,
    132   progname);
    133 }
    134 
    135 
    136 static void l_message (const char *pname, const char *msg) {
    137   if (pname) luai_writestringerror("%s: ", pname);
    138   luai_writestringerror("%s\n", msg);
    139 }
    140 
    141 
    142 static int report (lua_State *L, int status) {
    143   if (status != LUA_OK && !lua_isnil(L, -1)) {
    144     const char *msg = lua_tostring(L, -1);
    145     if (msg == NULL) msg = "(error object is not a string)";
    146     l_message(progname, msg);
    147     lua_pop(L, 1);
    148     /* force a complete garbage collection in case of errors */
    149     lua_gc(L, LUA_GCCOLLECT, 0);
    150   }
    151   return status;
    152 }
    153 
    154 
    155 /* the next function is called unprotected, so it must avoid errors */
    156 static void finalreport (lua_State *L, int status) {
    157   if (status != LUA_OK) {
    158     const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1)
    159                                                        : NULL;
    160     if (msg == NULL) msg = "(error object is not a string)";
    161     l_message(progname, msg);
    162     lua_pop(L, 1);
    163   }
    164 }
    165 
    166 
    167 static int traceback (lua_State *L) {
    168   const char *msg = lua_tostring(L, 1);
    169   if (msg)
    170     luaL_traceback(L, L, msg, 1);
    171   else if (!lua_isnoneornil(L, 1)) {  /* is there an error object? */
    172     if (!luaL_callmeta(L, 1, "__tostring"))  /* try its 'tostring' metamethod */
    173       lua_pushliteral(L, "(no error message)");
    174   }
    175   return 1;
    176 }
    177 
    178 
    179 static int docall (lua_State *L, int narg, int nres) {
    180   int status;
    181   int base = lua_gettop(L) - narg;  /* function index */
    182   lua_pushcfunction(L, traceback);  /* push traceback function */
    183   lua_insert(L, base);  /* put it under chunk and args */
    184   globalL = L;  /* to be available to 'laction' */
    185   signal(SIGINT, laction);
    186   status = lua_pcall(L, narg, nres, base);
    187   signal(SIGINT, SIG_DFL);
    188   lua_remove(L, base);  /* remove traceback function */
    189   return status;
    190 }
    191 
    192 
    193 static void print_version (void) {
    194   luai_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
    195   luai_writeline();
    196 }
    197 
    198 
    199 static int getargs (lua_State *L, char **argv, int n) {
    200   int narg;
    201   int i;
    202   int argc = 0;
    203   while (argv[argc]) argc++;  /* count total number of arguments */
    204   narg = argc - (n + 1);  /* number of arguments to the script */
    205   luaL_checkstack(L, narg + 3, "too many arguments to script");
    206   for (i=n+1; i < argc; i++)
    207     lua_pushstring(L, argv[i]);
    208   lua_createtable(L, narg, n + 1);
    209   for (i=0; i < argc; i++) {
    210     lua_pushstring(L, argv[i]);
    211     lua_rawseti(L, -2, i - n);
    212   }
    213   return narg;
    214 }
    215 
    216 
    217 static int dofile (lua_State *L, const char *name) {
    218   int status = luaL_loadfile(L, name);
    219   if (status == LUA_OK) status = docall(L, 0, 0);
    220   return report(L, status);
    221 }
    222 
    223 
    224 static int dostring (lua_State *L, const char *s, const char *name) {
    225   int status = luaL_loadbuffer(L, s, strlen(s), name);
    226   if (status == LUA_OK) status = docall(L, 0, 0);
    227   return report(L, status);
    228 }
    229 
    230 
    231 static int dolibrary (lua_State *L, const char *name) {
    232   int status;
    233   lua_getglobal(L, "require");
    234   lua_pushstring(L, name);
    235   status = docall(L, 1, 1);  /* call 'require(name)' */
    236   if (status == LUA_OK)
    237     lua_setglobal(L, name);  /* global[name] = require return */
    238   return report(L, status);
    239 }
    240 
    241 
    242 static const char *get_prompt (lua_State *L, int firstline) {
    243   const char *p;
    244   lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
    245   p = lua_tostring(L, -1);
    246   if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
    247   return p;
    248 }
    249 
    250 /* mark in error messages for incomplete statements */
    251 #define EOFMARK		"<eof>"
    252 #define marklen		(sizeof(EOFMARK)/sizeof(char) - 1)
    253 
    254 static int incomplete (lua_State *L, int status) {
    255   if (status == LUA_ERRSYNTAX) {
    256     size_t lmsg;
    257     const char *msg = lua_tolstring(L, -1, &lmsg);
    258     if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
    259       lua_pop(L, 1);
    260       return 1;
    261     }
    262   }
    263   return 0;  /* else... */
    264 }
    265 
    266 
    267 static int pushline (lua_State *L, int firstline) {
    268   char buffer[LUA_MAXINPUT];
    269   char *b = buffer;
    270   size_t l;
    271   const char *prmt = get_prompt(L, firstline);
    272   int readstatus = lua_readline(L, b, prmt);
    273   lua_pop(L, 1);  /* remove result from 'get_prompt' */
    274   if (readstatus == 0)
    275     return 0;  /* no input */
    276   l = strlen(b);
    277   if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
    278     b[l-1] = '\0';  /* remove it */
    279   if (firstline && b[0] == '=')  /* first line starts with `=' ? */
    280     lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */
    281   else
    282     lua_pushstring(L, b);
    283   lua_freeline(L, b);
    284   return 1;
    285 }
    286 
    287 
    288 static int loadline (lua_State *L) {
    289   int status;
    290   lua_settop(L, 0);
    291   if (!pushline(L, 1))
    292     return -1;  /* no input */
    293   for (;;) {  /* repeat until gets a complete line */
    294     size_t l;
    295     const char *line = lua_tolstring(L, 1, &l);
    296     status = luaL_loadbuffer(L, line, l, "=stdin");
    297     if (!incomplete(L, status)) break;  /* cannot try to add lines? */
    298     if (!pushline(L, 0))  /* no more input? */
    299       return -1;
    300     lua_pushliteral(L, "\n");  /* add a new line... */
    301     lua_insert(L, -2);  /* ...between the two lines */
    302     lua_concat(L, 3);  /* join them */
    303   }
    304   lua_saveline(L, 1);
    305   lua_remove(L, 1);  /* remove line */
    306   return status;
    307 }
    308 
    309 
    310 static void dotty (lua_State *L) {
    311   int status;
    312   const char *oldprogname = progname;
    313   progname = NULL;
    314   while ((status = loadline(L)) != -1) {
    315     if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET);
    316     report(L, status);
    317     if (status == LUA_OK && lua_gettop(L) > 0) {  /* any result to print? */
    318       luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
    319       lua_getglobal(L, "print");
    320       lua_insert(L, 1);
    321       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK)
    322         l_message(progname, lua_pushfstring(L,
    323                                "error calling " LUA_QL("print") " (%s)",
    324                                lua_tostring(L, -1)));
    325     }
    326   }
    327   lua_settop(L, 0);  /* clear stack */
    328   luai_writeline();
    329   progname = oldprogname;
    330 }
    331 
    332 
    333 static int handle_script (lua_State *L, char **argv, int n) {
    334   int status;
    335   const char *fname;
    336   int narg = getargs(L, argv, n);  /* collect arguments */
    337   lua_setglobal(L, "arg");
    338   fname = argv[n];
    339   if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
    340     fname = NULL;  /* stdin */
    341   status = luaL_loadfile(L, fname);
    342   lua_insert(L, -(narg+1));
    343   if (status == LUA_OK)
    344     status = docall(L, narg, LUA_MULTRET);
    345   else
    346     lua_pop(L, narg);
    347   return report(L, status);
    348 }
    349 
    350 
    351 /* check that argument has no extra characters at the end */
    352 #define noextrachars(x)		{if ((x)[2] != '\0') return -1;}
    353 
    354 
    355 /* indices of various argument indicators in array args */
    356 #define has_i		0	/* -i */
    357 #define has_v		1	/* -v */
    358 #define has_e		2	/* -e */
    359 #define has_E		3	/* -E */
    360 
    361 #define num_has		4	/* number of 'has_*' */
    362 
    363 
    364 static int collectargs (char **argv, int *args) {
    365   int i;
    366   for (i = 1; argv[i] != NULL; i++) {
    367     if (argv[i][0] != '-')  /* not an option? */
    368         return i;
    369     switch (argv[i][1]) {  /* option */
    370       case '-':
    371         noextrachars(argv[i]);
    372         return (argv[i+1] != NULL ? i+1 : 0);
    373       case '\0':
    374         return i;
    375       case 'E':
    376         args[has_E] = 1;
    377         break;
    378       case 'i':
    379         noextrachars(argv[i]);
    380         args[has_i] = 1;  /* go through */
    381       case 'v':
    382         noextrachars(argv[i]);
    383         args[has_v] = 1;
    384         break;
    385       case 'e':
    386         args[has_e] = 1;  /* go through */
    387       case 'l':  /* both options need an argument */
    388         if (argv[i][2] == '\0') {  /* no concatenated argument? */
    389           i++;  /* try next 'argv' */
    390           if (argv[i] == NULL || argv[i][0] == '-')
    391             return -(i - 1);  /* no next argument or it is another option */
    392         }
    393         break;
    394       default:  /* invalid option; return its index... */
    395         return -i;  /* ...as a negative value */
    396     }
    397   }
    398   return 0;
    399 }
    400 
    401 
    402 static int runargs (lua_State *L, char **argv, int n) {
    403   int i;
    404   for (i = 1; i < n; i++) {
    405     lua_assert(argv[i][0] == '-');
    406     switch (argv[i][1]) {  /* option */
    407       case 'e': {
    408         const char *chunk = argv[i] + 2;
    409         if (*chunk == '\0') chunk = argv[++i];
    410         lua_assert(chunk != NULL);
    411         if (dostring(L, chunk, "=(command line)") != LUA_OK)
    412           return 0;
    413         break;
    414       }
    415       case 'l': {
    416         const char *filename = argv[i] + 2;
    417         if (*filename == '\0') filename = argv[++i];
    418         lua_assert(filename != NULL);
    419         if (dolibrary(L, filename) != LUA_OK)
    420           return 0;  /* stop if file fails */
    421         break;
    422       }
    423       default: break;
    424     }
    425   }
    426   return 1;
    427 }
    428 
    429 
    430 static int handle_luainit (lua_State *L) {
    431   const char *name = "=" LUA_INITVERSION;
    432   const char *init = getenv(name + 1);
    433   if (init == NULL) {
    434     name = "=" LUA_INIT;
    435     init = getenv(name + 1);  /* try alternative name */
    436   }
    437   if (init == NULL) return LUA_OK;
    438   else if (init[0] == '@')
    439     return dofile(L, init+1);
    440   else
    441     return dostring(L, init, name);
    442 }
    443 
    444 
    445 static int pmain (lua_State *L) {
    446   int argc = (int)lua_tointeger(L, 1);
    447   char **argv = (char **)lua_touserdata(L, 2);
    448   int script;
    449   int args[num_has];
    450   args[has_i] = args[has_v] = args[has_e] = args[has_E] = 0;
    451   if (argv[0] && argv[0][0]) progname = argv[0];
    452   script = collectargs(argv, args);
    453   if (script < 0) {  /* invalid arg? */
    454     print_usage(argv[-script]);
    455     return 0;
    456   }
    457   if (args[has_v]) print_version();
    458   if (args[has_E]) {  /* option '-E'? */
    459     lua_pushboolean(L, 1);  /* signal for libraries to ignore env. vars. */
    460     lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
    461   }
    462   /* open standard libraries */
    463   luaL_checkversion(L);
    464   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
    465   luaL_openlibs(L);  /* open libraries */
    466   lua_gc(L, LUA_GCRESTART, 0);
    467   if (!args[has_E] && handle_luainit(L) != LUA_OK)
    468     return 0;  /* error running LUA_INIT */
    469   /* execute arguments -e and -l */
    470   if (!runargs(L, argv, (script > 0) ? script : argc)) return 0;
    471   /* execute main script (if there is one) */
    472   if (script && handle_script(L, argv, script) != LUA_OK) return 0;
    473   if (args[has_i])  /* -i option? */
    474     dotty(L);
    475   else if (script == 0 && !args[has_e] && !args[has_v]) {  /* no arguments? */
    476     if (lua_stdin_is_tty()) {
    477       print_version();
    478       dotty(L);
    479     }
    480     else dofile(L, NULL);  /* executes stdin as a file */
    481   }
    482   lua_pushboolean(L, 1);  /* signal no errors */
    483   return 1;
    484 }
    485 
    486 
    487 int main (int argc, char **argv) {
    488   int status, result;
    489   lua_State *L = luaL_newstate();  /* create state */
    490   if (L == NULL) {
    491     l_message(argv[0], "cannot create state: not enough memory");
    492     return EXIT_FAILURE;
    493   }
    494 #ifdef SYSLINUX
    495   openconsole(&dev_stdcon_r, &dev_stdcon_w);
    496 #endif
    497   /* call 'pmain' in protected mode */
    498   lua_pushcfunction(L, &pmain);
    499   lua_pushinteger(L, argc);  /* 1st argument */
    500   lua_pushlightuserdata(L, argv); /* 2nd argument */
    501   status = lua_pcall(L, 2, 1, 0);
    502   result = lua_toboolean(L, -1);  /* get result */
    503   finalreport(L, status);
    504   lua_close(L);
    505   return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
    506 }
    507 
    508