diff options
| author | Lua Team <team@lua.org> | 2003-04-11 12:00:00 +0000 |
|---|---|---|
| committer | repogen <> | 2003-04-11 12:00:00 +0000 |
| commit | f0e4e22f5c119865eb5a8d3844a40df2d5980b3b (patch) | |
| tree | c4df063a747e9c99f8aba1678588a030993780a9 /src/lua | |
| parent | 1981b7c90eb09e956e969cda5c473be4560af573 (diff) | |
| download | lua-github-5.0.tar.gz | |
Lua 5.05.0
Diffstat (limited to 'src/lua')
| -rw-r--r-- | src/lua/Makefile | 9 | ||||
| -rw-r--r-- | src/lua/README | 50 | ||||
| -rw-r--r-- | src/lua/lua.c | 548 |
3 files changed, 357 insertions, 250 deletions
diff --git a/src/lua/Makefile b/src/lua/Makefile index 5b47161f..aa52832f 100644 --- a/src/lua/Makefile +++ b/src/lua/Makefile @@ -4,17 +4,16 @@ LUA= ../.. include $(LUA)/config -EXTRA_DEFS= $(POSIX) - +EXTRA_DEFS= $(USERCONF) OBJS= lua.o SRCS= lua.c T= $(BIN)/lua -all: $T +all: $T -$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) +$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a + $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) $(LIB)/liblua.a: cd ..; $(MAKE) diff --git a/src/lua/README b/src/lua/README index 832fb5bf..febd229a 100644 --- a/src/lua/README +++ b/src/lua/README @@ -2,39 +2,31 @@ This is lua, a sample Lua interpreter. It can be used as a batch interpreter and also interactively. There are man pages for it in both nroff and html in ../../doc. -Here are the options that it understands: +Usage: ./lua [options] [script [args]]. Available options are: - execute stdin as a file - -c close Lua when exiting -e stat execute string `stat' - -f name execute file `name' with remaining arguments in table `arg' - -i enter interactive mode with prompt - -q enter interactive mode without prompt - -sNUM set stack size to NUM (must be the first option) - -v print version information - a=b set global `a' to string `b' - name execute file `name' + -i enter interactive mode after executing `script' + -l name load and run library `name' + -v show version information + -- stop handling options -If no options are given, then it reads lines from stdin and executes them -as they are read -- so, each line must contain a complete statement. -To span a statement across several lines, end each line with a backslash '\'. +This interpreter is suitable for using Lua as a standalone language; it loads +all standard libraries. For a minimal interpreter, see ../../etc/min.c. -To change the prompt, set the global variable _PROMPT to whatever you want. -You can do this after calling the interpreter or on the command line with - lua _PROMPT="lua: " -i -for example. Note that you need "-i" in this case. +If your application simply exports new functions to Lua (which is common), +then you can use this interpreter (almost) unmodified, as follows: -You must be careful when using quotes on the command line because they are -usually handled by the shell. +* First, define a function + void myinit (lua_State *L) + in your own code. In this function, you should do whatever initializations + are needed by your application, typically exporting your functions to Lua. + (Of course, you can use any name instead of "myinit".) -This interpreter is good for using Lua as a standalone language. -For a minimal interpreter, see ../../etc/min.c. +* Then, #define lua_userinit(L) to be "openstdlibs(L)+myinit(L)". + Here, openstdlibs is a function in lua.c that opens all standard libraries. + If you don't need them, just don't call openstdlibs and open any standard + libraries that you do need in myinit. -If your application simply exports new functions to Lua (which is common), -then you can use this interpreter (almost) unmodified, as follows: -First, define a function - void myinit (lua_State *L) -in your own code. In this function, you should do whatever initializations -are needed by your application, typically exporting your functions to Lua. -Then, add a call "myinit(L)" in lua.c after the place marked - "add your libraries here" -Of course, you can use any name instead of "myinit". +* Finally, remember to link your C code when building lua. + +For other customizations, see ../../etc/config.c. diff --git a/src/lua/lua.c b/src/lua/lua.c index 2da857e1..28c84cb6 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.55 2000/10/20 16:36:32 roberto Exp $ +** $Id: lua.c,v 1.122 2003/04/03 13:34:42 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -10,313 +10,429 @@ #include <stdlib.h> #include <string.h> +#define lua_c + #include "lua.h" -#include "luadebug.h" +#include "lauxlib.h" #include "lualib.h" -static lua_State *L = NULL; +/* +** generic extra include file +*/ +#ifdef LUA_USERCONFIG +#include LUA_USERCONFIG +#endif + + +/* +** definition of `isatty' +*/ +#ifdef _POSIX_C_SOURCE +#include <unistd.h> +#define stdin_is_tty() isatty(0) +#else +#define stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + #ifndef PROMPT #define PROMPT "> " #endif -#ifdef _POSIX_SOURCE -#include <unistd.h> -#else -static int isatty (int x) { return x==0; } /* assume stdin is a tty */ + +#ifndef PROMPT2 +#define PROMPT2 ">> " #endif +#ifndef PROGNAME +#define PROGNAME "lua" +#endif -/* -** global options -*/ -struct Options { - int toclose; - int stacksize; -}; +#ifndef lua_userinit +#define lua_userinit(L) openstdlibs(L) +#endif -typedef void (*handler)(int); /* type for signal actions */ +#ifndef LUA_EXTRALIBS +#define LUA_EXTRALIBS /* empty */ +#endif -static void laction (int i); +static lua_State *L = NULL; -static lua_Hook old_linehook = NULL; -static lua_Hook old_callhook = NULL; +static const char *progname = PROGNAME; -static void userinit (void) { - lua_baselibopen(L); - lua_iolibopen(L); - lua_strlibopen(L); - lua_mathlibopen(L); - lua_dblibopen(L); + +static const luaL_reg lualibs[] = { + {"base", luaopen_base}, + {"table", luaopen_table}, + {"io", luaopen_io}, + {"string", luaopen_string}, + {"math", luaopen_math}, + {"debug", luaopen_debug}, + {"loadlib", luaopen_loadlib}, /* add your libraries here */ -} + LUA_EXTRALIBS + {NULL, 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!"); +static void lstop (lua_State *l, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(l, NULL, 0, 0); + luaL_error(l, "interrupted!"); } static void laction (int i) { - (void)i; /* to avoid warnings */ - signal(SIGINT, SIG_DFL); /* if another SIGINT happens before lstop, + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ - old_linehook = lua_setlinehook(L, (lua_Hook)lstop); - old_callhook = lua_setcallhook(L, (lua_Hook)lstop); -} - - -static int ldo (int (*f)(lua_State *l, const char *), const char *name) { - int res; - handler h = lreset(); - int top = lua_gettop(L); - res = f(L, name); /* dostring | dofile */ - lua_settop(L, top); /* remove eventual results */ - signal(SIGINT, h); /* restore old action */ - /* Lua gives no message in such cases, so lua.c provides one */ - if (res == LUA_ERRMEM) { - fprintf(stderr, "lua: memory allocation error\n"); - } - else if (res == LUA_ERRERR) - fprintf(stderr, "lua: error in error message\n"); - return res; + lua_sethook(L, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } -static void print_message (void) { +static void print_usage (void) { fprintf(stderr, - "usage: lua [options]. Available options are:\n" + "usage: %s [options] [script [args]].\n" + "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" - " -v print version information\n" - " a=b set global `a' to string `b'\n" - " name execute file `name'\n" -); + " -i enter interactive mode after executing `script'\n" + " -l name load and run library `name'\n" + " -v show version information\n" + " -- stop handling options\n" , + progname); } -static void print_version (void) { - printf("%.80s %.80s\n", LUA_VERSION, LUA_COPYRIGHT); +static void l_message (const char *pname, const char *msg) { + if (pname) fprintf(stderr, "%s: ", pname); + fprintf(stderr, "%s\n", msg); } -static void assign (char *arg) { - char *eq = strchr(arg, '='); - *eq = '\0'; /* spilt `arg' in two strings (name & value) */ - lua_pushstring(L, eq+1); - lua_setglobal(L, arg); +static int report (int status) { + const char *msg; + if (status) { + msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error with no message)"; + l_message(progname, msg); + lua_pop(L, 1); + } + return status; } -static void getargs (char *argv[]) { +static int lcall (int narg, int clear) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushliteral(L, "_TRACEBACK"); + lua_rawget(L, LUA_GLOBALSINDEX); /* get traceback function */ + lua_insert(L, base); /* put it under chunk and args */ + signal(SIGINT, laction); + status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); + signal(SIGINT, SIG_DFL); + lua_remove(L, base); /* remove traceback function */ + return status; +} + + +static void print_version (void) { + l_message(NULL, LUA_VERSION " " LUA_COPYRIGHT); +} + + +static void getargs (char *argv[], int n) { int i; lua_newtable(L); for (i=0; argv[i]; i++) { - /* arg[i] = argv[i] */ - lua_pushnumber(L, i); + lua_pushnumber(L, i - n); lua_pushstring(L, argv[i]); - lua_settable(L, -3); + lua_rawset(L, -3); } /* arg.n = maximum index in table `arg' */ - lua_pushstring(L, "n"); - lua_pushnumber(L, i-1); - lua_settable(L, -3); + lua_pushliteral(L, "n"); + lua_pushnumber(L, i-n-1); + lua_rawset(L, -3); } -static int l_getargs (lua_State *l) { - char **argv = (char **)lua_touserdata(l, -1); - getargs(argv); - return 1; +static int docall (int status) { + if (status == 0) status = lcall(0, 1); + return report(status); } -static int file_input (const char *argv) { - int result = ldo(lua_dofile, argv); - if (result) { - if (result == LUA_ERRFILE) { - fprintf(stderr, "lua: cannot execute file "); - perror(argv); - } - return EXIT_FAILURE; +static int file_input (const char *name) { + return docall(luaL_loadfile(L, name)); +} + + +static int dostring (const char *s, const char *name) { + return docall(luaL_loadbuffer(L, s, strlen(s), name)); +} + + +static int load_file (const char *name) { + lua_pushliteral(L, "require"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (!lua_isfunction(L, -1)) { /* no `require' defined? */ + lua_pop(L, 1); + return file_input(name); + } + else { + lua_pushstring(L, name); + return report(lcall(1, 1)); } - else - return EXIT_SUCCESS; } -/* maximum length of an input string */ +/* +** this macro can be used by some `history' system to save lines +** read in manual input +*/ +#ifndef lua_saveline +#define lua_saveline(L,line) /* empty */ +#endif + + +/* +** this macro defines a function to show the prompt and reads the +** next line for manual input +*/ +#ifndef lua_readline +#define lua_readline(L,prompt) readline(L,prompt) + +/* maximum length of an input line */ #ifndef MAXINPUT -#define MAXINPUT BUFSIZ +#define MAXINPUT 512 #endif -static void manual_input (int version, int prompt) { - int cont = 1; - if (version) print_version(); - while (cont) { - char buffer[MAXINPUT]; - int i = 0; - if (prompt) { - const char *s; - lua_getglobal(L, "_PROMPT"); - s = lua_tostring(L, -1); - if (!s) s = PROMPT; - fputs(s, stdout); - lua_pop(L, 1); /* remove global */ - } - for(;;) { - int c = getchar(); - if (c == EOF) { - cont = 0; - break; - } - else if (c == '\n') { - if (i>0 && buffer[i-1] == '\\') - buffer[i-1] = '\n'; - else break; - } - else if (i >= MAXINPUT-1) { - fprintf(stderr, "lua: input line too long\n"); - break; - } - else buffer[i++] = (char)c; + +static int readline (lua_State *l, const char *prompt) { + static char buffer[MAXINPUT]; + if (prompt) { + fputs(prompt, stdout); + fflush(stdout); + } + if (fgets(buffer, sizeof(buffer), stdin) == NULL) + return 0; /* read fails */ + else { + lua_pushstring(l, buffer); + return 1; + } +} + +#endif + + +static const char *get_prompt (int firstline) { + const char *p = NULL; + lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2"); + lua_rawget(L, LUA_GLOBALSINDEX); + p = lua_tostring(L, -1); + if (p == NULL) p = (firstline ? PROMPT : PROMPT2); + lua_pop(L, 1); /* remove global */ + return p; +} + + +static int incomplete (int status) { + if (status == LUA_ERRSYNTAX && + strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) { + lua_pop(L, 1); + return 1; + } + else + return 0; +} + + +static int load_string (void) { + int status; + lua_settop(L, 0); + if (lua_readline(L, get_prompt(1)) == 0) /* no input? */ + return -1; + if (lua_tostring(L, -1)[0] == '=') { /* line starts with `=' ? */ + lua_pushfstring(L, "return %s", lua_tostring(L, -1)+1);/* `=' -> `return' */ + lua_remove(L, -2); /* remove original line */ + } + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(status)) break; /* cannot try to add lines? */ + if (lua_readline(L, get_prompt(0)) == 0) /* no more input? */ + return -1; + lua_concat(L, lua_gettop(L)); /* join lines */ + } + lua_saveline(L, lua_tostring(L, 1)); + lua_remove(L, 1); /* remove line */ + return status; +} + + +static void manual_input (void) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = load_string()) != -1) { + if (status == 0) status = lcall(0, 0); + report(status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, "error calling `print' (%s)", + lua_tostring(L, -1))); } - buffer[i] = '\0'; - ldo(lua_dostring, buffer); - lua_settop(L, 0); /* remove eventual results */ } - printf("\n"); + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + progname = oldprogname; } -static int handle_argv (char *argv[], struct Options *opt) { - if (opt->stacksize > 0) argv++; /* skip option `-s' (if present) */ - if (*argv == NULL) { /* no more arguments? */ - if (isatty(0)) { - manual_input(1, 1); +static int handle_argv (char *argv[], int *interactive) { + if (argv[1] == NULL) { /* no more arguments? */ + if (stdin_is_tty()) { + print_version(); + manual_input(); } else - ldo(lua_dofile, NULL); /* executes stdin as a file */ + file_input(NULL); /* executes stdin as a file */ } else { /* other arguments; loop over them */ int i; - for (i = 0; argv[i] != NULL; i++) { - if (argv[i][0] != '-') { /* not an option? */ - if (strchr(argv[i], '=')) - assign(argv[i]); - else - if (file_input(argv[i]) != EXIT_SUCCESS) - return EXIT_FAILURE; /* stop if file fails */ - } - else switch (argv[i][1]) { /* option */ - case 0: { - ldo(lua_dofile, NULL); /* executes stdin as a file */ - break; - } - case 'i': { - manual_input(0, 1); - break; - } - case 'q': { - manual_input(0, 0); - break; - } - case 'c': { - opt->toclose = 1; - break; + for (i = 1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') break; /* not an option? */ + switch (argv[i][1]) { /* option */ + case '-': { /* `--' */ + if (argv[i][2] != '\0') { + print_usage(); + return 1; } - case 'v': { - print_version(); - break; - } - case 'e': { - i++; - if (argv[i] == NULL) { - print_message(); - return EXIT_FAILURE; - } - if (ldo(lua_dostring, argv[i]) != 0) { - fprintf(stderr, "lua: error running argument `%.99s'\n", argv[i]); - return EXIT_FAILURE; - } - break; - } - case 'f': { - i++; - if (argv[i] == NULL) { - print_message(); - return EXIT_FAILURE; - } - getargs(argv+i); /* collect remaining arguments */ - lua_setglobal(L, "arg"); - return file_input(argv[i]); /* stop scanning arguments */ - } - case 's': { - fprintf(stderr, "lua: stack size (`-s') must be the first option\n"); - return EXIT_FAILURE; + i++; /* skip this argument */ + goto endloop; /* stop handling arguments */ + } + case '\0': { + file_input(NULL); /* executes stdin as a file */ + break; + } + case 'i': { + *interactive = 1; + break; + } + case 'v': { + print_version(); + break; + } + case 'e': { + const char *chunk = argv[i] + 2; + if (*chunk == '\0') chunk = argv[++i]; + if (chunk == NULL) { + print_usage(); + return 1; } - default: { - print_message(); - return EXIT_FAILURE; + if (dostring(chunk, "=<command line>") != 0) + return 1; + break; + } + case 'l': { + const char *filename = argv[i] + 2; + if (*filename == '\0') filename = argv[++i]; + if (filename == NULL) { + print_usage(); + return 1; } + if (load_file(filename)) + return 1; /* stop if file fails */ + break; + } + case 'c': { + l_message(progname, "option `-c' is deprecated"); + break; + } + case 's': { + l_message(progname, "option `-s' is deprecated"); + break; + } + default: { + print_usage(); + return 1; } + } + } endloop: + if (argv[i] != NULL) { + const char *filename = argv[i]; + getargs(argv, i); /* collect arguments */ + lua_setglobal(L, "arg"); + return file_input(filename); /* stop scanning arguments */ } } - return EXIT_SUCCESS; + return 0; } -static void getstacksize (int argc, char *argv[], struct Options *opt) { - if (argc >= 2 && argv[1][0] == '-' && argv[1][1] == 's') { - int stacksize = atoi(&argv[1][2]); - if (stacksize <= 0) { - fprintf(stderr, "lua: invalid stack size ('%.20s')\n", &argv[1][2]); - exit(EXIT_FAILURE); - } - opt->stacksize = stacksize; +static void openstdlibs (lua_State *l) { + const luaL_reg *lib = lualibs; + for (; lib->func; lib++) { + lib->func(l); /* open library */ + lua_settop(l, 0); /* discard any results */ } +} + + +static int handle_luainit (void) { + const char *init = getenv("LUA_INIT"); + if (init == NULL) return 0; /* status OK */ + else if (init[0] == '@') + return file_input(init+1); else - opt->stacksize = 0; /* no stack size */ + return dostring(init, "=LUA_INIT"); } -static void register_getargs (char *argv[]) { - lua_pushuserdata(L, argv); - lua_pushcclosure(L, l_getargs, 1); - lua_setglobal(L, "getargs"); +struct Smain { + int argc; + char **argv; + int status; +}; + + +static int pmain (lua_State *l) { + struct Smain *s = (struct Smain *)lua_touserdata(l, 1); + int status; + int interactive = 0; + if (s->argv[0] && s->argv[0][0]) progname = s->argv[0]; + L = l; + lua_userinit(l); /* open libraries */ + status = handle_luainit(); + if (status == 0) { + status = handle_argv(s->argv, &interactive); + if (status == 0 && interactive) manual_input(); + } + s->status = status; + return 0; } int main (int argc, char *argv[]) { - struct Options opt; int status; - opt.toclose = 0; - getstacksize(argc, argv, &opt); /* handle option `-s' */ - L = lua_open(opt.stacksize); /* create state */ - userinit(); /* open libraries */ - register_getargs(argv); /* create `getargs' function */ - status = handle_argv(argv+1, &opt); - if (opt.toclose) - lua_close(L); - return status; + struct Smain s; + lua_State *l = lua_open(); /* create state */ + if (l == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + s.argc = argc; + s.argv = argv; + status = lua_cpcall(l, &pmain, &s); + report(status); + lua_close(l); + return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; } |
