LCOV - code coverage report
Current view: top level - src - lua.c Coverage Total Hit
Test: Lua 5.1.5 Lines: 62.4 % 234 146
Test Date: 2024-04-28 10:23:09
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              : ** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
       3              : ** Lua stand-alone interpreter
       4              : ** See Copyright Notice in lua.h
       5              : */
       6              : 
       7              : 
       8              : #include <signal.h>
       9              : #include <stdio.h>
      10              : #include <stdlib.h>
      11              : #include <string.h>
      12              : 
      13              : #define lua_c
      14              : 
      15              : #include "lua.h"
      16              : 
      17              : #include "lauxlib.h"
      18              : #include "lualib.h"
      19              : 
      20              : 
      21              : 
      22              : static lua_State *globalL = NULL;
      23              : 
      24              : static const char *progname = LUA_PROGNAME;
      25              : 
      26              : 
      27              : 
      28            0 : static void lstop (lua_State *L, lua_Debug *ar) {
      29              :   (void)ar;  /* unused arg. */
      30            0 :   lua_sethook(L, NULL, 0, 0);
      31            0 :   luaL_error(L, "interrupted!");
      32            0 : }
      33              : 
      34              : 
      35            0 : static void laction (int i) {
      36            0 :   signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
      37              :                               terminate process (default action) */
      38            0 :   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
      39            0 : }
      40              : 
      41              : 
      42            0 : static void print_usage (void) {
      43            0 :   fprintf(stderr,
      44              :   "usage: %s [options] [script [args]].\n"
      45              :   "Available options are:\n"
      46              :   "  -e stat  execute string " LUA_QL("stat") "\n"
      47              :   "  -l name  require library " LUA_QL("name") "\n"
      48              :   "  -i       enter interactive mode after executing " LUA_QL("script") "\n"
      49              :   "  -v       show version information\n"
      50              :   "  --       stop handling options\n"
      51              :   "  -        execute stdin and stop handling options\n"
      52              :   ,
      53              :   progname);
      54            0 :   fflush(stderr);
      55            0 : }
      56              : 
      57              : 
      58            8 : static void l_message (const char *pname, const char *msg) {
      59            8 :   if (pname) fprintf(stderr, "%s: ", pname);
      60            8 :   fprintf(stderr, "%s\n", msg);
      61            8 :   fflush(stderr);
      62            8 : }
      63              : 
      64              : 
      65          284 : static int report (lua_State *L, int status) {
      66          284 :   if (status && !lua_isnil(L, -1)) {
      67            5 :     const char *msg = lua_tostring(L, -1);
      68            5 :     if (msg == NULL) msg = "(error object is not a string)";
      69            5 :     l_message(progname, msg);
      70            5 :     lua_pop(L, 1);
      71              :   }
      72          284 :   return status;
      73              : }
      74              : 
      75              : 
      76            4 : static int traceback (lua_State *L) {
      77            4 :   if (!lua_isstring(L, 1))  /* 'message' not a string? */
      78            2 :     return 1;  /* keep it intact */
      79            2 :   lua_getfield(L, LUA_GLOBALSINDEX, "debug");
      80            2 :   if (!lua_istable(L, -1)) {
      81            0 :     lua_pop(L, 1);
      82            0 :     return 1;
      83              :   }
      84            2 :   lua_getfield(L, -1, "traceback");
      85            2 :   if (!lua_isfunction(L, -1)) {
      86            0 :     lua_pop(L, 2);
      87            0 :     return 1;
      88              :   }
      89            2 :   lua_pushvalue(L, 1);  /* pass error message */
      90            2 :   lua_pushinteger(L, 2);  /* skip this function and traceback */
      91            2 :   lua_call(L, 2, 1);  /* call debug.traceback */
      92            2 :   return 1;
      93              : }
      94              : 
      95              : 
      96          217 : static int docall (lua_State *L, int narg, int clear) {
      97              :   int status;
      98          217 :   int base = lua_gettop(L) - narg;  /* function index */
      99          217 :   lua_pushcfunction(L, traceback);  /* push traceback function */
     100          217 :   lua_insert(L, base);  /* put it under chunk and args */
     101          217 :   signal(SIGINT, laction);
     102          217 :   status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
     103          208 :   signal(SIGINT, SIG_DFL);
     104          208 :   lua_remove(L, base);  /* remove traceback function */
     105              :   /* force a complete garbage collection in case of errors */
     106          208 :   if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
     107          208 :   return status;
     108              : }
     109              : 
     110              : 
     111            3 : static void print_version (void) {
     112            3 :   l_message(NULL, LUA_RELEASE "  " LUA_COPYRIGHT);
     113            3 : }
     114              : 
     115              : 
     116           58 : static int getargs (lua_State *L, char **argv, int n) {
     117              :   int narg;
     118              :   int i;
     119           58 :   int argc = 0;
     120          279 :   while (argv[argc]) argc++;  /* count total number of arguments */
     121           58 :   narg = argc - (n + 1);  /* number of arguments to the script */
     122           58 :   luaL_checkstack(L, narg + 3, "too many arguments to script");
     123           58 :   for (i=n+1; i < argc; i++)
     124            0 :     lua_pushstring(L, argv[i]);
     125           58 :   lua_createtable(L, narg, n + 1);
     126          279 :   for (i=0; i < argc; i++) {
     127          221 :     lua_pushstring(L, argv[i]);
     128          221 :     lua_rawseti(L, -2, i - n);
     129              :   }
     130           58 :   return narg;
     131              : }
     132              : 
     133              : 
     134            1 : static int dofile (lua_State *L, const char *name) {
     135            1 :   int status = luaL_loadfile(L, name) || docall(L, 0, 1);
     136            1 :   return report(L, status);
     137              : }
     138              : 
     139              : 
     140          108 : static int dostring (lua_State *L, const char *s, const char *name) {
     141          108 :   int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
     142          105 :   return report(L, status);
     143              : }
     144              : 
     145              : 
     146           52 : static int dolibrary (lua_State *L, const char *name) {
     147           52 :   lua_getglobal(L, "require");
     148           52 :   lua_pushstring(L, name);
     149           52 :   return report(L, docall(L, 1, 1));
     150              : }
     151              : 
     152              : 
     153            0 : static const char *get_prompt (lua_State *L, int firstline) {
     154              :   const char *p;
     155            0 :   lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
     156            0 :   p = lua_tostring(L, -1);
     157            0 :   if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
     158            0 :   lua_pop(L, 1);  /* remove global */
     159            0 :   return p;
     160              : }
     161              : 
     162              : 
     163            0 : static int incomplete (lua_State *L, int status) {
     164            0 :   if (status == LUA_ERRSYNTAX) {
     165              :     size_t lmsg;
     166            0 :     const char *msg = lua_tolstring(L, -1, &lmsg);
     167            0 :     const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
     168            0 :     if (strstr(msg, LUA_QL("<eof>")) == tp) {
     169            0 :       lua_pop(L, 1);
     170            0 :       return 1;
     171              :     }
     172              :   }
     173            0 :   return 0;  /* else... */
     174              : }
     175              : 
     176              : 
     177            0 : static int pushline (lua_State *L, int firstline) {
     178              :   char buffer[LUA_MAXINPUT];
     179            0 :   char *b = buffer;
     180              :   size_t l;
     181            0 :   const char *prmt = get_prompt(L, firstline);
     182            0 :   if (lua_readline(L, b, prmt) == 0)
     183            0 :     return 0;  /* no input */
     184            0 :   l = strlen(b);
     185            0 :   if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
     186            0 :     b[l-1] = '\0';  /* remove it */
     187            0 :   if (firstline && b[0] == '=')  /* first line starts with `=' ? */
     188            0 :     lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */
     189              :   else
     190            0 :     lua_pushstring(L, b);
     191            0 :   lua_freeline(L, b);
     192            0 :   return 1;
     193              : }
     194              : 
     195              : 
     196            0 : static int loadline (lua_State *L) {
     197              :   int status;
     198            0 :   lua_settop(L, 0);
     199            0 :   if (!pushline(L, 1))
     200            0 :     return -1;  /* no input */
     201              :   for (;;) {  /* repeat until gets a complete line */
     202            0 :     status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
     203            0 :     if (!incomplete(L, status)) break;  /* cannot try to add lines? */
     204            0 :     if (!pushline(L, 0))  /* no more input? */
     205            0 :       return -1;
     206            0 :     lua_pushliteral(L, "\n");  /* add a new line... */
     207            0 :     lua_insert(L, -2);  /* ...between the two lines */
     208            0 :     lua_concat(L, 3);  /* join them */
     209              :   }
     210            0 :   lua_saveline(L, 1);
     211            0 :   lua_remove(L, 1);  /* remove line */
     212            0 :   return status;
     213              : }
     214              : 
     215              : 
     216            0 : static void dotty (lua_State *L) {
     217              :   int status;
     218            0 :   const char *oldprogname = progname;
     219            0 :   progname = NULL;
     220            0 :   while ((status = loadline(L)) != -1) {
     221            0 :     if (status == 0) status = docall(L, 0, 0);
     222            0 :     report(L, status);
     223            0 :     if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */
     224            0 :       lua_getglobal(L, "print");
     225            0 :       lua_insert(L, 1);
     226            0 :       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
     227            0 :         l_message(progname, lua_pushfstring(L,
     228              :                                "error calling " LUA_QL("print") " (%s)",
     229              :                                lua_tostring(L, -1)));
     230              :     }
     231              :   }
     232            0 :   lua_settop(L, 0);  /* clear stack */
     233            0 :   fputs("\n", stdout);
     234            0 :   fflush(stdout);
     235            0 :   progname = oldprogname;
     236            0 : }
     237              : 
     238              : 
     239           58 : static int handle_script (lua_State *L, char **argv, int n) {
     240              :   int status;
     241              :   const char *fname;
     242           58 :   int narg = getargs(L, argv, n);  /* collect arguments */
     243           58 :   lua_setglobal(L, "arg");
     244           58 :   fname = argv[n];
     245           58 :   if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) 
     246            1 :     fname = NULL;  /* stdin */
     247           58 :   status = luaL_loadfile(L, fname);
     248           58 :   lua_insert(L, -(narg+1));
     249           58 :   if (status == 0)
     250           57 :     status = docall(L, narg, 0);
     251              :   else
     252            1 :     lua_pop(L, narg);      
     253           52 :   return report(L, status);
     254              : }
     255              : 
     256              : 
     257              : /* check that argument has no extra characters at the end */
     258              : #define notail(x)       {if ((x)[2] != '\0') return -1;}
     259              : 
     260              : 
     261           83 : static int collectargs (char **argv, int *pi, int *pv, int *pe) {
     262              :   int i;
     263          163 :   for (i = 1; argv[i] != NULL; i++) {
     264          139 :     if (argv[i][0] != '-')  /* not an option? */
     265           56 :         return i;
     266           83 :     switch (argv[i][1]) {  /* option */
     267            2 :       case '-':
     268            2 :         notail(argv[i]);
     269            2 :         return (argv[i+1] != NULL ? i+1 : 0);
     270            1 :       case '\0':
     271            1 :         return i;
     272            0 :       case 'i':
     273            0 :         notail(argv[i]);
     274            0 :         *pi = 1;  /* go through */
     275            3 :       case 'v':
     276            3 :         notail(argv[i]);
     277            3 :         *pv = 1;
     278            3 :         break;
     279           25 :       case 'e':
     280           25 :         *pe = 1;  /* go through */
     281           77 :       case 'l':
     282           77 :         if (argv[i][2] == '\0') {
     283           74 :           i++;
     284           74 :           if (argv[i] == NULL) return -1;
     285              :         }
     286           77 :         break;
     287            0 :       default: return -1;  /* invalid option */
     288              :     }
     289              :   }
     290           24 :   return 0;
     291              : }
     292              : 
     293              : 
     294           83 : static int runargs (lua_State *L, char **argv, int n) {
     295              :   int i;
     296          158 :   for (i = 1; i < n; i++) {
     297           82 :     if (argv[i] == NULL) continue;
     298              :     lua_assert(argv[i][0] == '-');
     299           82 :     switch (argv[i][1]) {  /* option */
     300           25 :       case 'e': {
     301           25 :         const char *chunk = argv[i] + 2;
     302           25 :         if (*chunk == '\0') chunk = argv[++i];
     303              :         lua_assert(chunk != NULL);
     304           25 :         if (dostring(L, chunk, "=(command line)") != 0)
     305            4 :           return 1;
     306           18 :         break;
     307              :       }
     308           52 :       case 'l': {
     309           52 :         const char *filename = argv[i] + 2;
     310           52 :         if (*filename == '\0') filename = argv[++i];
     311              :         lua_assert(filename != NULL);
     312           52 :         if (dolibrary(L, filename))
     313            0 :           return 1;  /* stop if file fails */
     314           52 :         break;
     315              :       }
     316            5 :       default: break;
     317              :     }
     318              :   }
     319           76 :   return 0;
     320              : }
     321              : 
     322              : 
     323           83 : static int handle_luainit (lua_State *L) {
     324           83 :   const char *init = getenv(LUA_INIT);
     325           83 :   if (init == NULL) return 0;  /* status OK */
     326           83 :   else if (init[0] == '@')
     327            0 :     return dofile(L, init+1);
     328              :   else
     329           83 :     return dostring(L, init, "=" LUA_INIT);
     330              : }
     331              : 
     332              : 
     333              : struct Smain {
     334              :   int argc;
     335              :   char **argv;
     336              :   int status;
     337              : };
     338              : 
     339              : 
     340           83 : static int pmain (lua_State *L) {
     341           83 :   struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
     342           83 :   char **argv = s->argv;
     343              :   int script;
     344           83 :   int has_i = 0, has_v = 0, has_e = 0;
     345           83 :   globalL = L;
     346           83 :   if (argv[0] && argv[0][0]) progname = argv[0];
     347           83 :   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
     348           83 :   luaL_openlibs(L);  /* open libraries */
     349           83 :   lua_gc(L, LUA_GCRESTART, 0);
     350           83 :   s->status = handle_luainit(L);
     351           83 :   if (s->status != 0) return 0;
     352           83 :   script = collectargs(argv, &has_i, &has_v, &has_e);
     353           83 :   if (script < 0) {  /* invalid args? */
     354            0 :     print_usage();
     355            0 :     s->status = 1;
     356            0 :     return 0;
     357              :   }
     358           83 :   if (has_v) print_version();
     359           83 :   s->status = runargs(L, argv, (script > 0) ? script : s->argc);
     360           80 :   if (s->status != 0) return 0;
     361           76 :   if (script)
     362           58 :     s->status = handle_script(L, argv, script);
     363           70 :   if (s->status != 0) return 0;
     364           69 :   if (has_i)
     365            0 :     dotty(L);
     366           69 :   else if (script == 0 && !has_e && !has_v) {
     367            1 :     if (lua_stdin_is_tty()) {
     368            0 :       print_version();
     369            0 :       dotty(L);
     370              :     }
     371            1 :     else dofile(L, NULL);  /* executes stdin as a file */
     372              :   }
     373           69 :   return 0;
     374              : }
     375              : 
     376              : 
     377           83 : int main (int argc, char **argv) {
     378              :   int status;
     379              :   struct Smain s;
     380           83 :   lua_State *L = lua_open();  /* create state */
     381           83 :   if (L == NULL) {
     382            0 :     l_message(argv[0], "cannot create state: not enough memory");
     383            0 :     return EXIT_FAILURE;
     384              :   }
     385           83 :   s.argc = argc;
     386           83 :   s.argv = argv;
     387           83 :   status = lua_cpcall(L, &pmain, &s);
     388           74 :   report(L, status);
     389           74 :   lua_close(L);
     390           74 :   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
     391              : }
     392              : 
        

Generated by: LCOV version 2.0-1