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