- Main Page
- Data Structures
- Files

- File List

# E:/DevIL/include/IL/luadevil.c

    00001 /*
    00002 ** $Id: luadevil.c,v 1.1 2007-02-12 21:03:04 darkyojimbo 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   printf("DevIL embedded lua interpreter\n");
    00380 //@TODO: Where the heck is this defined?
    00381   //Devil_Init(L);
    00382   if (L == NULL) {
    00383     l_message(argv[0], "cannot create state: not enough memory");
    00384     return EXIT_FAILURE;
    00385   }
    00386   s.argc = argc;
    00387   s.argv = argv;
    00388   status = lua_cpcall(L, &pmain, &s);
    00389   report(L, status);
    00390   lua_close(L);
    00391   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
    00392 }
    00393