?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

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