diff --git a/lua.c b/lua.c index 0453cf74..01c29bfc 100644 --- a/lua.c +++ b/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ +** $Id: lua.c,v 1.74 2001/12/10 22:09:51 lhf Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -33,34 +33,26 @@ static int isatty (int x) { return x==0; } /* assume stdin is a tty */ #endif +#ifndef PROMPT2 +#define PROMPT2 ">> " +#endif + + #ifndef LUA_USERINIT #define LUA_USERINIT(L) openstdlibs(L) #endif - static lua_State *L = NULL; -typedef void (*handler)(int); /* type for signal actions */ - -static void laction (int i); - - static lua_Hook old_linehook = NULL; static lua_Hook old_callhook = NULL; - -static handler lreset (void) { - return signal(SIGINT, laction); -} - - static void lstop (void) { lua_setlinehook(L, old_linehook); lua_setcallhook(L, old_callhook); - lreset(); lua_error(L, "interrupted!"); } @@ -74,35 +66,36 @@ static void laction (int i) { } -static int ldo (int (*f)(lua_State *l, const char *), const char *name, - int clear) { - int res; - handler h = lreset(); - int top = lua_gettop(L); - res = f(L, name); /* dostring | dofile */ - signal(SIGINT, h); /* restore old action */ - if (clear) - lua_settop(L, top); /* remove eventual results */ - /* Lua gives no message in such cases, so lua.c provides one */ - if (res == LUA_ERRMEM) { +/* Lua gives no message in such cases, so we provide one */ +static void report (int result) { + if (result == LUA_ERRMEM) fprintf(stderr, LUA_PROGNAME "memory allocation error\n"); - } - else if (res == LUA_ERRERR) + else if (result == LUA_ERRERR) fprintf(stderr, LUA_PROGNAME "error in error message\n"); - return res; } -static void print_message (void) { +static int ldo (int (*f)(lua_State *l, const char *), const char *name, + int clear) { + int result; + int top = lua_gettop(L); + signal(SIGINT, laction); + result = f(L, name); /* dostring | dofile */ + signal(SIGINT, SIG_DFL); + if (clear) lua_settop(L, top); /* remove eventual results */ + report(result); + return result; +} + + +static void print_usage (void) { fprintf(stderr, "usage: lua [options]. Available options are:\n" " - execute stdin as a file\n" " -c close Lua when exiting\n" " -e stat execute string `stat'\n" " -f name execute file `name' with remaining arguments in table `arg'\n" - " -i enter interactive mode with prompt\n" - " -q enter interactive mode without prompt\n" - " -sNUM set stack size to NUM (must be the first option)\n" + " -i enter interactive mode\n" " -v print version information\n" " a=b set global `a' to string `b'\n" " name execute file `name'\n" @@ -130,11 +123,12 @@ static void getargs (char *argv[]) { /* arg[i] = argv[i] */ lua_pushnumber(L, i); lua_pushstring(L, argv[i]); - lua_settable(L, -3); + lua_rawset(L, -3); } /* arg.n = maximum index in table `arg' */ + lua_pushliteral(L, "n"); lua_pushnumber(L, i-1); - lua_setstr(L, -2, "n"); + lua_rawset(L, -3); } @@ -145,12 +139,12 @@ static int l_getargs (lua_State *l) { } -static int file_input (const char *argv) { - int result = ldo(lua_dofile, argv, 1); +static int file_input (const char *name) { + int result = ldo(lua_dofile, name, 1); if (result) { if (result == LUA_ERRFILE) { fprintf(stderr, LUA_PROGNAME "cannot execute file "); - perror(argv); + perror(name); } return EXIT_FAILURE; } @@ -159,73 +153,119 @@ static int file_input (const char *argv) { } +#ifdef USE_READLINE +#include +#include +#define save_line(b) if (strcspn(b, " \t\n") != 0) add_history(b) +#define push_line(b) if (incomplete) lua_pushstring(L, "\n"); lua_pushstring(L, b); free(b) +#else +#define save_line(b) +#define push_line(b) lua_pushstring(L, b) + /* maximum length of an input line */ #ifndef MAXINPUT #define MAXINPUT 512 #endif -static const char *get_prompt (int prompt) { - if (!prompt) - return ""; - else { - const char *s; - lua_getglobal(L, "_PROMPT"); - s = lua_tostring(L, -1); - if (!s) s = PROMPT; - lua_pop(L, 1); /* remove global */ - return s; +static char *readline (const char *prompt) { + static char buffer[MAXINPUT]; + if (prompt) { + fputs(prompt, stdout); + fflush(stdout); } + return fgets(buffer, sizeof(buffer), stdin); +} +#endif + + +static const char *get_prompt (int incomplete) { + const char *p = NULL; + lua_getglobal(L, incomplete ? "_PROMPT2" : "_PROMPT"); + p = lua_tostring(L, -1); + if (p == NULL) p = (incomplete ? PROMPT2 : PROMPT); + lua_pop(L, 1); /* remove global */ + return p; } -static void manual_input (int version, int prompt) { - if (version) print_version(); - for (;;) { - int firstline = 1; - int toprint = 0; - fputs(get_prompt(prompt), stdout); /* show prompt */ - for(;;) { - char buffer[MAXINPUT]; - size_t l; - if (fgets(buffer, sizeof(buffer), stdin) == NULL) { - printf("\n"); - return; - } - if (firstline && buffer[0] == '=') { - buffer[0] = ' '; - lua_pushstring(L, "return"); - toprint = 1; - } - l = strlen(buffer); - if (buffer[l-1] == '\n' && buffer[l-2] == '\\') { - buffer[l-2] = '\n'; - lua_pushlstring(L, buffer, l-1); - } - else { - lua_pushlstring(L, buffer, l); - break; - } - firstline = 0; +static int incomplete = 0; + +static int trap_eof (lua_State *l) { + const char *s = lua_tostring(l, 1); + if (strstr(s, "last token read: `'") != NULL) + incomplete = 1; + else + fprintf(stderr, "error: %s\n", s); + return 0; +} + + +static int load_string (int *toprint) { + lua_getglobal(L, LUA_ERRORMESSAGE); + lua_pushvalue(L, 1); + lua_setglobal(L, LUA_ERRORMESSAGE); + incomplete = 0; + for (;;) { /* repeat until gets a complete line */ + int result; + char *buffer = readline(get_prompt(incomplete)); + if (buffer == NULL) { /* input end? */ + lua_settop(L, 2); + lua_setglobal(L, LUA_ERRORMESSAGE); + return 0; } - lua_concat(L, lua_gettop(L)); - ldo(lua_dostring, lua_tostring(L, 1), 0); - lua_remove(L, 1); /* remove ran string */ - if (toprint && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); - lua_insert(L, 1); - lua_call(L, lua_gettop(L)-1, 0); + *toprint = !incomplete && buffer[0] == '='; + if (*toprint) { + buffer[0] = ' '; + lua_pushstring(L, "return"); + } + push_line(buffer); + lua_concat(L, lua_gettop(L)-2); + incomplete = 0; + result = lua_loadbuffer(L, lua_tostring(L, 3), lua_strlen(L, 3), "=stdin"); + if (incomplete) continue; /* repeat loop to get rest of `line' */ + save_line(lua_tostring(L, 3)); + lua_remove(L, 3); + if (result == 0) { + lua_insert(L, 2); /* swap compiled chunk with old _ERRORMESSAGE */ + lua_setglobal(L, LUA_ERRORMESSAGE); /* restore old _ERRORMESSAGE */ + return 1; } else - lua_settop(L, 0); /* remove eventual results */ + report(result); + } +} + + +static int lcall (lua_State *l, const char *name) { + (void)name; /* to avoid warnings */ + return lua_call(l, 0, LUA_MULTRET); +} + + +static void manual_input (int version) { + int toprint = 0; + if (version) print_version(); + lua_pushcfunction(L, trap_eof); /* set up handler for incomplete lines */ + while (load_string(&toprint)) { + ldo(lcall, NULL, 0); + if (toprint && lua_gettop(L) > 1) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 2); + lua_call(L, lua_gettop(L)-2, 0); + } + else + lua_settop(L, 1); /* remove eventual results */ } + printf("\n"); + lua_settop(L, 0); /* remove trap_eof */ } static int handle_argv (char *argv[], int *toclose) { if (*argv == NULL) { /* no more arguments? */ if (isatty(0)) { - manual_input(1, 1); + manual_input(1); } else ldo(lua_dofile, NULL, 1); /* executes stdin as a file */ @@ -241,16 +281,12 @@ static int handle_argv (char *argv[], int *toclose) { return EXIT_FAILURE; /* stop if file fails */ } else switch (argv[i][1]) { /* option */ - case 0: { + case '\0': { ldo(lua_dofile, NULL, 1); /* executes stdin as a file */ break; } case 'i': { - manual_input(0, 1); - break; - } - case 'q': { - manual_input(0, 0); + manual_input(0); break; } case 'c': { @@ -264,7 +300,7 @@ static int handle_argv (char *argv[], int *toclose) { case 'e': { i++; if (argv[i] == NULL) { - print_message(); + print_usage(); return EXIT_FAILURE; } if (ldo(lua_dostring, argv[i], 1) != 0) { @@ -277,7 +313,7 @@ static int handle_argv (char *argv[], int *toclose) { case 'f': { i++; if (argv[i] == NULL) { - print_message(); + print_usage(); return EXIT_FAILURE; } getargs(argv+i); /* collect remaining arguments */ @@ -285,13 +321,12 @@ static int handle_argv (char *argv[], int *toclose) { return file_input(argv[i]); /* stop scanning arguments */ } case 's': { - if (i == 0) break; /* option already handled */ - fprintf(stderr, - LUA_PROGNAME "stack size (`-s') must be the first option\n"); - return EXIT_FAILURE; + fprintf(stderr, LUA_PROGNAME + "option `-s' is deprecated (dynamic stack now)\n"); + break; } default: { - print_message(); + print_usage(); return EXIT_FAILURE; } } @@ -301,20 +336,6 @@ static int handle_argv (char *argv[], int *toclose) { } -static int getstacksize (int argc, char *argv[]) { - int stacksize = 0; - if (argc >= 2 && argv[1][0] == '-' && argv[1][1] == 's') { - stacksize = strtol(&argv[1][2], NULL, 10); - if (stacksize <= 0) { - fprintf(stderr, LUA_PROGNAME "invalid stack size ('%.20s')\n", - &argv[1][2]); - exit(EXIT_FAILURE); - } - } - return stacksize; -} - - static void register_getargs (char *argv[]) { lua_newuserdatabox(L, argv); lua_pushcclosure(L, l_getargs, 1); @@ -334,7 +355,8 @@ static void openstdlibs (lua_State *l) { int main (int argc, char *argv[]) { int status; int toclose = 0; - L = lua_open(getstacksize(argc, argv)); /* create state */ + (void)argc; /* unused parameter: avoid warnings */ + L = lua_open(0); /* create state */ LUA_USERINIT(L); /* open libraries */ register_getargs(argv); /* create `getargs' function */ status = handle_argv(argv+1, &toclose);