luafaudes.cppGo to the documentation of this file.00001 /** @file luafaudes.cpp Simple Lua stand-alone interpreter for lua/faudes 00002 00003 This lua interpreter is almost a plain copy of the original lua.c 00004 provided with the lua 5.1.3 distribution and under an MIT license; 00005 see original lua.h or http://www.lua.org 00006 00007 The Advanced-Readline patch has been applied, also with lua license, 00008 copyright see below. SWIG based Lua bindings and minor adjustments 00009 (wellcome string, logging) have been added (and signed "luafaudes"). 00010 Thomas Moor, 2008. 00011 00012 00013 @ingroup Tutorials 00014 00015 00016 */ 00017 00018 00019 // luafaudes: skip doxygen 00020 #ifndef FAUDES_DOXYGEN 00021 00022 /* 00023 ** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $ 00024 ** Lua stand-alone interpreter 00025 ** See Copyright Notice in lua.h 00026 */ 00027 00028 00029 // luafaudes: include c libs since we dont use lua.h 00030 #include <csignal> 00031 #include <cstdio> 00032 #include <cstdlib> 00033 #include <cstring> 00034 00035 00036 // luafaudes: use my include file 00037 #include "libluafaudes.h" 00038 00039 // below this line: all from lua provided interpreter lua.cpp, except tagged "luafaudes" 00040 00041 static lua_State *globalL = NULL; 00042 static const char *progname = LUA_PROGNAME; 00043 00044 00045 static void lstop (lua_State *L, lua_Debug *ar) { 00046 (void)ar; /* unused arg. */ 00047 lua_sethook(L, NULL, 0, 0); 00048 luaL_error(L, "interrupted!"); 00049 } 00050 00051 00052 static void laction (int i) { 00053 signal(i, SIG_DFL); /* if another SIGINT happens before lstop, 00054 terminate process (default action) */ 00055 lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); 00056 } 00057 00058 00059 static void print_usage (void) { 00060 fprintf(stderr, 00061 "usage: %s [options] [script [args]].\n" 00062 "Available options are:\n" 00063 " -e stat execute string " LUA_QL("stat") "\n" 00064 " -l name require library " LUA_QL("name") "\n" 00065 " -i enter interactive mode after executing " LUA_QL("script") "\n" 00066 " -v show version information\n" 00067 " -d pass on libFAUDES messages to console\n" /* luafaudes: d-option */ 00068 " -x load libFAUDES extension\n" /* luafaudes: x-option */ 00069 " -- stop handling options\n" 00070 " - execute stdin and stop handling options\n" 00071 , 00072 progname); 00073 fflush(stderr); 00074 } 00075 00076 00077 static void l_message (const char *pname, const char *msg) { 00078 if (pname) fprintf(stderr, "%s: ", pname); 00079 fprintf(stderr, "%s\n", msg); 00080 fflush(stderr); 00081 } 00082 00083 00084 static int report (lua_State *L, int status) { 00085 if (status && !lua_isnil(L, -1)) { 00086 const char *msg = lua_tostring(L, -1); 00087 if (msg == NULL) msg = "(error object is not a string)"; 00088 l_message(progname, msg); 00089 lua_pop(L, 1); 00090 } 00091 return status; 00092 } 00093 00094 00095 static int traceback (lua_State *L) { 00096 if (!lua_isstring(L, 1)) /* 'message' not a string? */ 00097 return 1; /* keep it intact */ 00098 lua_getfield(L, LUA_GLOBALSINDEX, "debug"); 00099 if (!lua_istable(L, -1)) { 00100 lua_pop(L, 1); 00101 return 1; 00102 } 00103 lua_getfield(L, -1, "traceback"); 00104 if (!lua_isfunction(L, -1)) { 00105 lua_pop(L, 2); 00106 return 1; 00107 } 00108 lua_pushvalue(L, 1); /* pass error message */ 00109 lua_pushinteger(L, 2); /* skip this function and traceback */ 00110 lua_call(L, 2, 1); /* call debug.traceback */ 00111 return 1; 00112 } 00113 00114 00115 static int docall (lua_State *L, int narg, int clear) { 00116 int status; 00117 int base = lua_gettop(L) - narg; /* function index */ 00118 lua_pushcfunction(L, traceback); /* push traceback function */ 00119 lua_insert(L, base); /* put it under chunk and args */ 00120 signal(SIGINT, laction); 00121 status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); 00122 signal(SIGINT, SIG_DFL); 00123 lua_remove(L, base); /* remove traceback function */ 00124 /* force a complete garbage collection in case of errors */ 00125 if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); 00126 return status; 00127 } 00128 00129 00130 // luafaudes: my print version 00131 static void print_version (void) { 00132 std::stringstream sstr; 00133 sstr 00134 << "Welcome to luafaudes console." << std::endl 00135 << "Versions: " << faudes::VersionString() << " / " << LUA_VERSION << std::endl 00136 << "Plug-Ins: " << faudes::PluginsString() << std::endl 00137 << "Credits: This libFAUDES interpreter is based on the projects Lua and SWIG." << std::endl 00138 << "Type 'faudes.Help()' for a list of faudes related types and functions." << std::endl 00139 << "Enter Ctrl-C to exit the luafaudes interpreter" << std::endl; 00140 l_message(NULL, sstr.str().c_str()); 00141 } 00142 00143 00144 static int getargs (lua_State *L, char **argv, int n) { 00145 int narg; 00146 int i; 00147 int argc = 0; 00148 while (argv[argc]) argc++; /* count total number of arguments */ 00149 narg = argc - (n + 1); /* number of arguments to the script */ 00150 luaL_checkstack(L, narg + 3, "too many arguments to script"); 00151 for (i=n+1; i < argc; i++) 00152 lua_pushstring(L, argv[i]); 00153 lua_createtable(L, narg, n + 1); 00154 for (i=0; i < argc; i++) { 00155 lua_pushstring(L, argv[i]); 00156 lua_rawseti(L, -2, i - n); 00157 } 00158 return narg; 00159 } 00160 00161 00162 static int dofile (lua_State *L, const char *name) { 00163 int status = luaL_loadfile(L, name) || docall(L, 0, 1); 00164 return report(L, status); 00165 } 00166 00167 00168 static int dostring (lua_State *L, const char *s, const char *name) { 00169 int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); 00170 return report(L, status); 00171 } 00172 00173 00174 static int dolibrary (lua_State *L, const char *name) { 00175 lua_getglobal(L, "require"); 00176 lua_pushstring(L, name); 00177 return report(L, docall(L, 1, 1)); 00178 } 00179 00180 00181 00182 /* ------------------------------------------------------------------------ */ 00183 00184 #ifdef LUA_USE_READLINE 00185 /* 00186 00187 ** luafaudes: here used to be advanced readline support patch by Mike Pall. However, 00188 ** we required some variations for SWIG __index functions and we also wanted identifier- 00189 ** completion in DESTool. Thus, we moved the original completer code to LuaState 00190 ** (see lbp_function.cpp and lbp_completer.cpp) and provide a C interface via 00191 ** luafaudes_complete() (see common.i). The below code is reduced to the libreadline 00192 ** interface. The original patch still ships with libFAUDES for reference and can be 00193 ** inspected in lua.c in the Lua source tree. TMoor. 00194 00195 ** Advanced readline support for the GNU readline and history libraries 00196 ** or compatible replacements. 00197 ** 00198 ** Copyright (C) 2004-2006 Mike Pall. Same license as Lua. See lua.h. 00199 ** 00200 ** The (original) patch has been successfully tested with: 00201 ** 00202 ** GNU readline 2.2.1 (1998-07-17) 00203 ** GNU readline 4.0 (1999-02-18) [harmless compiler warning] 00204 ** GNU readline 4.3 (2002-07-16) 00205 ** GNU readline 5.0 (2004-07-27) 00206 ** GNU readline 5.1 (2005-12-07) 00207 ** NETBSD libedit 2.6.5 (2002-03-25) 00208 ** NETBSD libedit 2.6.9 (2004-05-01) 00209 */ 00210 00211 #include <ctype.h> 00212 00213 static char *lua_rl_hist; 00214 static int lua_rl_histsize; 00215 00216 static lua_State *lua_rl_L; /* User data is not passed to rl callbacks. */ 00217 00218 /* luafaudes: pass on global state */ 00219 static char **luafaudes_complete_L(const char *text, int start, int end) { 00220 return luafaudes_complete(lua_rl_L,text,start,end); 00221 } 00222 00223 /* Initialize readline library. */ 00224 static void lua_rl_init(lua_State *L) 00225 { 00226 char *s; 00227 00228 lua_rl_L = L; 00229 00230 /* This allows for $if lua ... $endif in ~/.inputrc. */ 00231 rl_readline_name = "lua"; 00232 /* Break words at every non-identifier character except '.' and ':'. */ 00233 rl_completer_word_break_characters = (char *) 00234 "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~"; // luafaudes: pragmatic avoidance of compiler warning 00235 00236 rl_completer_quote_characters = "\"'"; 00237 rl_completion_append_character = '\0'; 00238 rl_attempted_completion_function = luafaudes_complete_L; // luafaudes: use libFAUDES variant 00239 rl_initialize(); 00240 00241 /* Start using history, optionally set history size and load history file. */ 00242 using_history(); 00243 if ((s = getenv("LUA_HISTSIZE")) && 00244 (lua_rl_histsize = atoi(s))) stifle_history(lua_rl_histsize); 00245 if ((lua_rl_hist = getenv("LUA_HISTORY"))) read_history(lua_rl_hist); 00246 } 00247 00248 /* Finalize readline library. */ 00249 static void lua_rl_exit(lua_State *L) 00250 { 00251 /* Optionally save history file. */ 00252 if (lua_rl_hist) write_history(lua_rl_hist); 00253 } 00254 #else 00255 #define lua_rl_init(L) ((void)L) 00256 #define lua_rl_exit(L) ((void)L) 00257 #endif 00258 00259 /* ------------------------------------------------------------------------ */ 00260 00261 00262 static const char *get_prompt (lua_State *L, int firstline) { 00263 const char *p; 00264 lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); 00265 p = lua_tostring(L, -1); 00266 if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); 00267 lua_pop(L, 1); /* remove global */ 00268 return p; 00269 } 00270 00271 00272 static int incomplete (lua_State *L, int status) { 00273 if (status == LUA_ERRSYNTAX) { 00274 size_t lmsg; 00275 const char *msg = lua_tolstring(L, -1, &lmsg); 00276 const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); 00277 if (strstr(msg, LUA_QL("<eof>")) == tp) { 00278 lua_pop(L, 1); 00279 return 1; 00280 } 00281 } 00282 return 0; /* else... */ 00283 } 00284 00285 00286 static int pushline (lua_State *L, int firstline) { 00287 char buffer[LUA_MAXINPUT]; 00288 char *b = buffer; 00289 size_t l; 00290 const char *prmt = get_prompt(L, firstline); 00291 if (lua_readline(L, b, prmt) == 0) 00292 return 0; /* no input */ 00293 l = strlen(b); 00294 luafaudes_lastline=b; // luafaudes: logging 00295 if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ 00296 b[l-1] = '\0'; /* remove it */ 00297 if (firstline && b[0] == '=') /* first line starts with `=' ? */ 00298 lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ 00299 else 00300 lua_pushstring(L, b); 00301 lua_freeline(L, b); 00302 return 1; 00303 } 00304 00305 00306 static int loadline (lua_State *L) { 00307 int status; 00308 lua_settop(L, 0); 00309 if (!pushline(L, 1)) 00310 return -1; /* no input */ 00311 for (;;) { /* repeat until gets a complete line */ 00312 status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); 00313 if (!incomplete(L, status)) break; /* cannot try to add lines? */ 00314 if (!pushline(L, 0)) /* no more input? */ 00315 return -1; 00316 lua_pushliteral(L, "\n"); /* add a new line... */ 00317 lua_insert(L, -2); /* ...between the two lines */ 00318 lua_concat(L, 3); /* join them */ 00319 } 00320 lua_saveline(L, 1); 00321 lua_remove(L, 1); /* remove line */ 00322 return status; 00323 } 00324 00325 00326 static void dotty (lua_State *L) { 00327 int status; 00328 const char *oldprogname = progname; 00329 progname = NULL; 00330 lua_rl_init(L); 00331 while ((status = loadline(L)) != -1) { 00332 if (status == 0) status = docall(L, 0, 0); 00333 luafaudes_logwrite(luafaudes_lastline); // luafaudes: logging 00334 report(L, status); 00335 if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ 00336 lua_getglobal(L, "print"); 00337 lua_insert(L, 1); 00338 if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) 00339 l_message(progname, lua_pushfstring(L, 00340 "error calling " LUA_QL("print") " (%s)", 00341 lua_tostring(L, -1))); 00342 } 00343 } 00344 lua_settop(L, 0); /* clear stack */ 00345 fputs("\n", stdout); 00346 fflush(stdout); 00347 lua_rl_exit(L); 00348 progname = oldprogname; 00349 } 00350 00351 static int handle_script (lua_State *L, char **argv, int n) { 00352 int status; 00353 const char *fname; 00354 int narg = getargs(L, argv, n); /* collect arguments */ 00355 lua_setglobal(L, "arg"); 00356 fname = argv[n]; 00357 if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) 00358 fname = NULL; /* stdin */ 00359 status = luaL_loadfile(L, fname); 00360 lua_insert(L, -(narg+1)); 00361 if (status == 0) 00362 status = docall(L, narg, 0); 00363 else 00364 lua_pop(L, narg); 00365 return report(L, status); 00366 } 00367 00368 00369 /* check that argument has no extra characters at the end */ 00370 #define notail(x) {if ((x)[2] != '\0') return -1;} 00371 00372 00373 // luafaudes: have extra options -d and -x 00374 static int collectargs (char **argv, int *pi, int *pv, int *pe, int *pd, int *px) { 00375 int i; 00376 for (i = 1; argv[i] != NULL; i++) { 00377 if (argv[i][0] != '-') /* not an option? */ 00378 return i; 00379 switch (argv[i][1]) { /* option */ 00380 case '-': 00381 notail(argv[i]); 00382 return (argv[i+1] != NULL ? i+1 : 0); 00383 case '\0': 00384 return i; 00385 case 'i': 00386 notail(argv[i]); 00387 *pi = 1; /* go through */ 00388 case 'v': 00389 notail(argv[i]); 00390 *pv = 1; 00391 break; 00392 case 'e': 00393 *pe = 1; /* go through */ 00394 case 'l': 00395 if (argv[i][2] == '\0') { 00396 i++; 00397 if (argv[i] == NULL) return -1; 00398 } 00399 break; 00400 case 'd': // luafaudes: d-option 00401 notail(argv[i]); 00402 *pd = 1; 00403 break; 00404 case 'x': // luafaudes: x-option 00405 if (argv[i][2] == '\0') { 00406 i++; 00407 if (argv[i] == NULL) return -1; 00408 } 00409 *px = 1; 00410 break; 00411 default: return -1; /* invalid option */ 00412 } 00413 } 00414 return 0; 00415 } 00416 00417 00418 // luafaudes: have extra option -x 00419 static int runargs (lua_State *L, char **argv, int n) { 00420 int i; 00421 for (i = 1; i < n; i++) { 00422 if (argv[i] == NULL) continue; 00423 lua_assert(argv[i][0] == '-'); 00424 switch (argv[i][1]) { /* option */ 00425 case 'e': { 00426 const char *chunk = argv[i] + 2; 00427 if (*chunk == '\0') chunk = argv[++i]; 00428 lua_assert(chunk != NULL); 00429 if (dostring(L, chunk, "=(command line)") != 0) 00430 return 1; 00431 break; 00432 } 00433 case 'l': { 00434 const char *filename = argv[i] + 2; 00435 if (*filename == '\0') filename = argv[++i]; 00436 lua_assert(filename != NULL); 00437 if (dolibrary(L, filename)) 00438 return 1; /* stop if file fails */ 00439 break; 00440 } 00441 case 'x': { // luafaudes option x 00442 const char *filename = argv[i] + 2; 00443 if (*filename == '\0') filename = argv[++i]; 00444 lua_assert(filename != NULL); 00445 if (luafaudes_loadext(L, filename)) { 00446 l_message("fatal error: failed to load extension", filename); 00447 return 1; /* stop if file fails */ 00448 } 00449 break; 00450 } 00451 default: break; 00452 } 00453 } 00454 return 0; 00455 } 00456 00457 00458 static int handle_luainit (lua_State *L) { 00459 const char *init = getenv(LUA_INIT); 00460 if (init == NULL) return 0; /* status OK */ 00461 else if (init[0] == '@') 00462 return dofile(L, init+1); 00463 else 00464 return dostring(L, init, "=" LUA_INIT); 00465 } 00466 00467 00468 struct Smain { 00469 int argc; 00470 char **argv; 00471 int status; 00472 }; 00473 00474 00475 static int pmain (lua_State *L) { 00476 struct Smain *s = (struct Smain *)lua_touserdata(L, 1); 00477 char **argv = s->argv; 00478 int script; 00479 int has_i = 0, has_v = 0, has_e = 0, has_d=0, has_x=0; // luafaudes: -d and -x option 00480 globalL = L; 00481 if (argv[0] && argv[0][0]) progname = argv[0]; 00482 luafaudes_initialize(L); // luafaudes: all of the below plus my namespace 00483 /* 00484 // original lua 00485 lua_gc(L, LUA_GCSTOP, 0); 00486 luaL_openlibs(L); 00487 lua_gc(L, LUA_GCRESTART, 0); 00488 */ 00489 s->status = handle_luainit(L); 00490 if (s->status != 0) return 0; 00491 script = collectargs(argv, &has_i, &has_v, &has_e, &has_d, &has_x); // luafaudes: -d and -x option 00492 if (script < 0) { /* invalid args? */ 00493 print_usage(); 00494 s->status = 1; 00495 return 0; 00496 } 00497 if (has_v) print_version(); 00498 if (!has_d) luafaudes_mute(true); /* luafaudes: mute */ 00499 if (!has_x) luafaudes_loaddefext(L, argv[0]); /* luafaudes: default extension */ 00500 s->status = runargs(L, argv, (script > 0) ? script : s->argc); 00501 if (s->status != 0) return 0; 00502 if (script) 00503 s->status = handle_script(L, argv, script); 00504 if (s->status != 0) return 0; 00505 if (has_i) 00506 dotty(L); 00507 else if (script == 0 && !has_e && !has_v) { 00508 if (lua_stdin_is_tty()) { 00509 print_version(); 00510 dotty(L); 00511 } 00512 else dofile(L, NULL); /* executes stdin as a file */ 00513 } 00514 return 0; 00515 } 00516 00517 00518 int main (int argc, char **argv) { 00519 int status; 00520 struct Smain s; 00521 lua_State *L = lua_open(); /* create state */ 00522 if (L == NULL) { 00523 l_message(argv[0], "cannot create state: not enough memory"); 00524 return EXIT_FAILURE; 00525 } 00526 s.argc = argc; 00527 s.argv = argv; 00528 status = lua_cpcall(L, &pmain, &s); 00529 report(L, status); 00530 lua_close(L); 00531 return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; 00532 } 00533 00534 00535 // luafaudes: end skip doxygen 00536 #endif libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |