lua.cpp

Go to the documentation of this file.
00001 /*
00002 ** $Id: lua.c,v 1.160 2006/06/02 15:34:00 roberto Exp $
00003 ** Lua stand-alone interpreter
00004 ** See Copyright Notice in lua.h
00005 */
00006 
00007 
00008 #include <signal.h>
00009 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 
00013 #define lua_c
00014 
00015 #include "lua.h"
00016 
00017 #include "lauxlib.h"
00018 #include "lualib.h"
00019 
00020 
00021 
00022 static lua_State *globalL = NULL;
00023 
00024 static const char *progname = LUA_PROGNAME;
00025 
00026 
00027 
00028 static void lstop (lua_State *L, lua_Debug *ar) {
00029   (void)ar;  /* unused arg. */
00030   lua_sethook(L, NULL, 0, 0);
00031   luaL_error(L, "interrupted!");
00032 }
00033 
00034 
00035 static void laction (int i) {
00036   signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
00037                               terminate process (default action) */
00038   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
00039 }
00040 
00041 
00042 static void print_usage (void) {
00043   fprintf(stderr,
00044   "usage: %s [options] [script [args]].\n"
00045   "Available options are:\n"
00046   "  -e stat  execute string " LUA_QL("stat") "\n"
00047   "  -l name  require library " LUA_QL("name") "\n"
00048   "  -i       enter interactive mode after executing " LUA_QL("script") "\n"
00049   "  -v       show version information\n"
00050   "  --       stop handling options\n"
00051   "  -        execute stdin and stop handling options\n"
00052   ,
00053   progname);
00054   fflush(stderr);
00055 }
00056 
00057 
00058 static void l_message (const char *pname, const char *msg) {
00059   if (pname) fprintf(stderr, "%s: ", pname);
00060   fprintf(stderr, "%s\n", msg);
00061   fflush(stderr);
00062 }
00063 
00064 
00065 static int report (lua_State *L, int status) {
00066   if (status && !lua_isnil(L, -1)) {
00067     const char *msg = lua_tostring(L, -1);
00068     if (msg == NULL) msg = "(error object is not a string)";
00069     l_message(progname, msg);
00070     lua_pop(L, 1);
00071   }
00072   return status;
00073 }
00074 
00075 
00076 static int traceback (lua_State *L) {
00077   lua_getfield(L, LUA_GLOBALSINDEX, "debug");
00078   if (!lua_istable(L, -1)) {
00079     lua_pop(L, 1);
00080     return 1;
00081   }
00082   lua_getfield(L, -1, "traceback");
00083   if (!lua_isfunction(L, -1)) {
00084     lua_pop(L, 2);
00085     return 1;
00086   }
00087   lua_pushvalue(L, 1);  /* pass error message */
00088   lua_pushinteger(L, 2);  /* skip this function and traceback */
00089   lua_call(L, 2, 1);  /* call debug.traceback */
00090   return 1;
00091 }
00092 
00093 
00094 static int docall (lua_State *L, int narg, int clear) {
00095   int status;
00096   int base = lua_gettop(L) - narg;  /* function index */
00097   lua_pushcfunction(L, traceback);  /* push traceback function */
00098   lua_insert(L, base);  /* put it under chunk and args */
00099   signal(SIGINT, laction);
00100   status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
00101   signal(SIGINT, SIG_DFL);
00102   lua_remove(L, base);  /* remove traceback function */
00103   /* force a complete garbage collection in case of errors */
00104   if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
00105   return status;
00106 }
00107 
00108 
00109 static void print_version (void) {
00110   l_message(NULL, LUA_RELEASE "  " LUA_COPYRIGHT);
00111 }
00112 
00113 
00114 static int getargs (lua_State *L, char **argv, int n) {
00115   int narg;
00116   int i;
00117   int argc = 0;
00118   while (argv[argc]) argc++;  /* count total number of arguments */
00119   narg = argc - (n + 1);  /* number of arguments to the script */
00120   luaL_checkstack(L, narg + 3, "too many arguments to script");
00121   for (i=n+1; i < argc; i++)
00122     lua_pushstring(L, argv[i]);
00123   lua_createtable(L, narg, n + 1);
00124   for (i=0; i < argc; i++) {
00125     lua_pushstring(L, argv[i]);
00126     lua_rawseti(L, -2, i - n);
00127   }
00128   return narg;
00129 }
00130 
00131 
00132 static int dofile (lua_State *L, const char *name) {
00133   int status = luaL_loadfile(L, name) || docall(L, 0, 1);
00134   return report(L, status);
00135 }
00136 
00137 
00138 static int dostring (lua_State *L, const char *s, const char *name) {
00139   int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
00140   return report(L, status);
00141 }
00142 
00143 
00144 static int dolibrary (lua_State *L, const char *name) {
00145   lua_getglobal(L, "require");
00146   lua_pushstring(L, name);
00147   return report(L, lua_pcall(L, 1, 0, 0));
00148 }
00149 
00150 
00151 static const char *get_prompt (lua_State *L, int firstline) {
00152   const char *p;
00153   lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
00154   p = lua_tostring(L, -1);
00155   if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
00156   lua_pop(L, 1);  /* remove global */
00157   return p;
00158 }
00159 
00160 
00161 static int incomplete (lua_State *L, int status) {
00162   if (status == LUA_ERRSYNTAX) {
00163     size_t lmsg;
00164     const char *msg = lua_tolstring(L, -1, &lmsg);
00165     const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
00166     if (strstr(msg, LUA_QL("<eof>")) == tp) {
00167       lua_pop(L, 1);
00168       return 1;
00169     }
00170   }
00171   return 0;  /* else... */
00172 }
00173 
00174 
00175 static int pushline (lua_State *L, int firstline) {
00176   char buffer[LUA_MAXINPUT];
00177   char *b = buffer;
00178   size_t l;
00179   const char *prmt = get_prompt(L, firstline);
00180   if (lua_readline(L, b, prmt) == 0)
00181     return 0;  /* no input */
00182   l = strlen(b);
00183   if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
00184     b[l-1] = '\0';  /* remove it */
00185   if (firstline && b[0] == '=')  /* first line starts with `=' ? */
00186     lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */
00187   else
00188     lua_pushstring(L, b);
00189   lua_freeline(L, b);
00190   return 1;
00191 }
00192 
00193 
00194 static int loadline (lua_State *L) {
00195   int status;
00196   lua_settop(L, 0);
00197   if (!pushline(L, 1))
00198     return -1;  /* no input */
00199   for (;;) {  /* repeat until gets a complete line */
00200     status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
00201     if (!incomplete(L, status)) break;  /* cannot try to add lines? */
00202     if (!pushline(L, 0))  /* no more input? */
00203       return -1;
00204     lua_pushliteral(L, "\n");  /* add a new line... */
00205     lua_insert(L, -2);  /* ...between the two lines */
00206     lua_concat(L, 3);  /* join them */
00207   }
00208   lua_saveline(L, 1);
00209   lua_remove(L, 1);  /* remove line */
00210   return status;
00211 }
00212 
00213 
00214 static void dotty (lua_State *L) {
00215   int status;
00216   const char *oldprogname = progname;
00217   progname = NULL;
00218   while ((status = loadline(L)) != -1) {
00219     if (status == 0) status = docall(L, 0, 0);
00220     report(L, status);
00221     if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */
00222       lua_getglobal(L, "print");
00223       lua_insert(L, 1);
00224       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
00225         l_message(progname, lua_pushfstring(L,
00226                                "error calling " LUA_QL("print") " (%s)",
00227                                lua_tostring(L, -1)));
00228     }
00229   }
00230   lua_settop(L, 0);  /* clear stack */
00231   fputs("\n", stdout);
00232   fflush(stdout);
00233   progname = oldprogname;
00234 }
00235 
00236 
00237 static int handle_script (lua_State *L, char **argv, int n) {
00238   int status;
00239   const char *fname;
00240   int narg = getargs(L, argv, n);  /* collect arguments */
00241   lua_setglobal(L, "arg");
00242   fname = argv[n];
00243   if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) 
00244     fname = NULL;  /* stdin */
00245   status = luaL_loadfile(L, fname);
00246   lua_insert(L, -(narg+1));
00247   if (status == 0)
00248     status = docall(L, narg, 0);
00249   else
00250     lua_pop(L, narg);      
00251   return report(L, status);
00252 }
00253 
00254 
00255 /* check that argument has no extra characters at the end */
00256 #define notail(x)       {if ((x)[2] != '\0') return -1;}
00257 
00258 
00259 static int collectargs (char **argv, int *pi, int *pv, int *pe) {
00260   int i;
00261   for (i = 1; argv[i] != NULL; i++) {
00262     if (argv[i][0] != '-')  /* not an option? */
00263         return i;
00264     switch (argv[i][1]) {  /* option */
00265       case '-':
00266         notail(argv[i]);
00267         return (argv[i+1] != NULL ? i+1 : 0);
00268       case '\0':
00269         return i;
00270       case 'i':
00271         notail(argv[i]);
00272         *pi = 1;  /* go through */
00273       case 'v':
00274         notail(argv[i]);
00275         *pv = 1;
00276         break;
00277       case 'e':
00278         *pe = 1;  /* go through */
00279       case 'l':
00280         if (argv[i][2] == '\0') {
00281           i++;
00282           if (argv[i] == NULL) return -1;
00283         }
00284         break;
00285       default: return -1;  /* invalid option */
00286     }
00287   }
00288   return 0;
00289 }
00290 
00291 
00292 static int runargs (lua_State *L, char **argv, int n) {
00293   int i;
00294   for (i = 1; i < n; i++) {
00295     if (argv[i] == NULL) continue;
00296     lua_assert(argv[i][0] == '-');
00297     switch (argv[i][1]) {  /* option */
00298       case 'e': {
00299         const char *chunk = argv[i] + 2;
00300         if (*chunk == '\0') chunk = argv[++i];
00301         lua_assert(chunk != NULL);
00302         if (dostring(L, chunk, "=(command line)") != 0)
00303           return 1;
00304         break;
00305       }
00306       case 'l': {
00307         const char *filename = argv[i] + 2;
00308         if (*filename == '\0') filename = argv[++i];
00309         lua_assert(filename != NULL);
00310         if (dolibrary(L, filename))
00311           return 1;  /* stop if file fails */
00312         break;
00313       }
00314       default: break;
00315     }
00316   }
00317   return 0;
00318 }
00319 
00320 
00321 static int handle_luainit (lua_State *L) {
00322   const char *init = getenv(LUA_INIT);
00323   if (init == NULL) return 0;  /* status OK */
00324   else if (init[0] == '@')
00325     return dofile(L, init+1);
00326   else
00327     return dostring(L, init, "=" LUA_INIT);
00328 }
00329 
00330 
00331 struct Smain {
00332   int argc;
00333   char **argv;
00334   int status;
00335 };
00336 
00337 
00338 static int pmain (lua_State *L) {
00339   struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
00340   char **argv = s->argv;
00341   int script;
00342   int has_i = 0, has_v = 0, has_e = 0;
00343   globalL = L;
00344   if (argv[0] && argv[0][0]) progname = argv[0];
00345   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
00346   luaL_openlibs(L);  /* open libraries */
00347   lua_gc(L, LUA_GCRESTART, 0);
00348   s->status = handle_luainit(L);
00349   if (s->status != 0) return 0;
00350   script = collectargs(argv, &has_i, &has_v, &has_e);
00351   if (script < 0) {  /* invalid args? */
00352     print_usage();
00353     s->status = 1;
00354     return 0;
00355   }
00356   if (has_v) print_version();
00357   s->status = runargs(L, argv, (script > 0) ? script : s->argc);
00358   if (s->status != 0) return 0;
00359   if (script)
00360     s->status = handle_script(L, argv, script);
00361   if (s->status != 0) return 0;
00362   if (has_i)
00363     dotty(L);
00364   else if (script == 0 && !has_e && !has_v) {
00365     if (lua_stdin_is_tty()) {
00366       print_version();
00367       dotty(L);
00368     }
00369     else dofile(L, NULL);  /* executes stdin as a file */
00370   }
00371   return 0;
00372 }
00373 
00374 
00375 int main (int argc, char **argv) {
00376   int status;
00377   struct Smain s;
00378   lua_State *L = lua_open();  /* create state */
00379   if (L == NULL) {
00380     l_message(argv[0], "cannot create state: not enough memory");
00381     return EXIT_FAILURE;
00382   }
00383   s.argc = argc;
00384   s.argv = argv;
00385   status = lua_cpcall(L, &pmain, &s);
00386   report(L, status);
00387   lua_close(L);
00388   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
00389 }
00390 

Generated on Mon Feb 16 15:14:51 2009 for Scorched3D by  doxygen 1.5.3