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