xref: /netbsd-src/external/mit/lua/dist/src/lua.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
1 /*	$NetBSD: lua.c,v 1.9 2018/08/04 17:30:01 alnsn Exp $	*/
2 
3 /*
4 ** Id: lua.c,v 1.230.1.1 2017/04/19 17:29:57 roberto Exp
5 ** Lua stand-alone interpreter
6 ** See Copyright Notice in lua.h
7 */
8 
9 #define lua_c
10 
11 #include "lprefix.h"
12 
13 
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include "lua.h"
20 
21 #include "lauxlib.h"
22 #include "lualib.h"
23 
24 
25 
26 #if !defined(LUA_PROMPT)
27 #define LUA_PROMPT		"> "
28 #define LUA_PROMPT2		">> "
29 #endif
30 
31 #if !defined(LUA_PROGNAME)
32 #define LUA_PROGNAME		"lua"
33 #endif
34 
35 #if !defined(LUA_MAXINPUT)
36 #define LUA_MAXINPUT		512
37 #endif
38 
39 #if !defined(LUA_INIT_VAR)
40 #define LUA_INIT_VAR		"LUA_INIT"
41 #endif
42 
43 #define LUA_INITVARVERSION	LUA_INIT_VAR LUA_VERSUFFIX
44 
45 
46 /*
47 ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
48 ** is, whether we're running lua interactively).
49 */
50 #if !defined(lua_stdin_is_tty)	/* { */
51 
52 #if defined(LUA_USE_POSIX)	/* { */
53 
54 #include <unistd.h>
55 #define lua_stdin_is_tty()	isatty(0)
56 
57 #elif defined(LUA_USE_WINDOWS)	/* }{ */
58 
59 #include <io.h>
60 #include <windows.h>
61 
62 #define lua_stdin_is_tty()	_isatty(_fileno(stdin))
63 
64 #else				/* }{ */
65 
66 /* ISO C definition */
67 #define lua_stdin_is_tty()	1  /* assume stdin is a tty */
68 
69 #endif				/* } */
70 
71 #endif				/* } */
72 
73 
74 /*
75 ** lua_readline defines how to show a prompt and then read a line from
76 ** the standard input.
77 ** lua_saveline defines how to "save" a read line in a "history".
78 ** lua_freeline defines how to free a line read by lua_readline.
79 */
80 #if !defined(lua_readline)	/* { */
81 
82 #if defined(LUA_USE_READLINE)	/* { */
83 
84 #include <readline/readline.h>
85 #include <readline/history.h>
86 #define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)
87 #define lua_saveline(L,line)	((void)L, add_history(line))
88 #define lua_freeline(L,b)	((void)L, free(b))
89 
90 #else				/* }{ */
91 
92 #define lua_readline(L,b,p) \
93         ((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
94         fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
95 #define lua_saveline(L,line)	{ (void)L; (void)line; }
96 #define lua_freeline(L,b)	{ (void)L; (void)b; }
97 
98 #endif				/* } */
99 
100 #endif				/* } */
101 
102 
103 
104 
105 static lua_State *globalL = NULL;
106 
107 static const char *progname = LUA_PROGNAME;
108 
109 
110 /*
111 ** Hook set by signal function to stop the interpreter.
112 */
113 static void lstop (lua_State *L, lua_Debug *ar) {
114   (void)ar;  /* unused arg. */
115   lua_sethook(L, NULL, 0, 0);  /* reset hook */
116   luaL_error(L, "interrupted!");
117 }
118 
119 
120 /*
121 ** Function to be called at a C signal. Because a C signal cannot
122 ** just change a Lua state (as there is no proper synchronization),
123 ** this function only sets a hook that, when called, will stop the
124 ** interpreter.
125 */
126 static void laction (int i) {
127   signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
128   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
129 }
130 
131 
132 static void print_usage (const char *badoption) {
133   lua_writestringerror("%s: ", progname);
134   if (badoption[1] == 'e' || badoption[1] == 'l')
135     lua_writestringerror("'%s' needs argument\n", badoption);
136   else
137     lua_writestringerror("unrecognized option '%s'\n", badoption);
138   lua_writestringerror(
139   "usage: %s [options] [script [args]]\n"
140   "Available options are:\n"
141   "  -e stat  execute string 'stat'\n"
142   "  -i       enter interactive mode after executing 'script'\n"
143   "  -l name  require library 'name' into global 'name'\n"
144   "  -v       show version information\n"
145   "  -E       ignore environment variables\n"
146   "  --       stop handling options\n"
147   "  -        stop handling options and execute stdin\n"
148   ,
149   progname);
150 }
151 
152 
153 /*
154 ** Prints an error message, adding the program name in front of it
155 ** (if present)
156 */
157 static void l_message (const char *pname, const char *msg) {
158   if (pname) lua_writestringerror("%s: ", pname);
159   lua_writestringerror("%s\n", msg);
160 }
161 
162 
163 /*
164 ** Check whether 'status' is not OK and, if so, prints the error
165 ** message on the top of the stack. It assumes that the error object
166 ** is a string, as it was either generated by Lua or by 'msghandler'.
167 */
168 static int report (lua_State *L, int status) {
169   if (status != LUA_OK) {
170     const char *msg = lua_tostring(L, -1);
171     l_message(progname, msg);
172     lua_pop(L, 1);  /* remove message */
173   }
174   return status;
175 }
176 
177 
178 /*
179 ** Message handler used to run all chunks
180 */
181 static int msghandler (lua_State *L) {
182   const char *msg = lua_tostring(L, 1);
183   if (msg == NULL) {  /* is error object not a string? */
184     if (luaL_callmeta(L, 1, "__tostring") &&  /* does it have a metamethod */
185         lua_type(L, -1) == LUA_TSTRING)  /* that produces a string? */
186       return 1;  /* that is the message */
187     else
188       msg = lua_pushfstring(L, "(error object is a %s value)",
189                                luaL_typename(L, 1));
190   }
191   luaL_traceback(L, L, msg, 1);  /* append a standard traceback */
192   return 1;  /* return the traceback */
193 }
194 
195 
196 /*
197 ** Interface to 'lua_pcall', which sets appropriate message function
198 ** and C-signal handler. Used to run all chunks.
199 */
200 static int docall (lua_State *L, int narg, int nres) {
201   int status;
202   int base = lua_gettop(L) - narg;  /* function index */
203   lua_pushcfunction(L, msghandler);  /* push message handler */
204   lua_insert(L, base);  /* put it under function and args */
205   globalL = L;  /* to be available to 'laction' */
206   signal(SIGINT, laction);  /* set C-signal handler */
207   status = lua_pcall(L, narg, nres, base);
208   signal(SIGINT, SIG_DFL); /* reset C-signal handler */
209   lua_remove(L, base);  /* remove message handler from the stack */
210   return status;
211 }
212 
213 
214 static void print_version (void) {
215   lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
216   lua_writeline();
217 }
218 
219 
220 /*
221 ** Create the 'arg' table, which stores all arguments from the
222 ** command line ('argv'). It should be aligned so that, at index 0,
223 ** it has 'argv[script]', which is the script name. The arguments
224 ** to the script (everything after 'script') go to positive indices;
225 ** other arguments (before the script name) go to negative indices.
226 ** If there is no script name, assume interpreter's name as base.
227 */
228 static void createargtable (lua_State *L, char **argv, int argc, int script) {
229   int i, narg;
230   if (script == argc) script = 0;  /* no script name? */
231   narg = argc - (script + 1);  /* number of positive indices */
232   lua_createtable(L, narg, script + 1);
233   for (i = 0; i < argc; i++) {
234     lua_pushstring(L, argv[i]);
235     lua_rawseti(L, -2, i - script);
236   }
237   lua_setglobal(L, "arg");
238 }
239 
240 
241 static int dochunk (lua_State *L, int status) {
242   if (status == LUA_OK) status = docall(L, 0, 0);
243   return report(L, status);
244 }
245 
246 
247 static int dofile (lua_State *L, const char *name) {
248   return dochunk(L, luaL_loadfile(L, name));
249 }
250 
251 
252 static int dostring (lua_State *L, const char *s, const char *name) {
253   return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
254 }
255 
256 
257 /*
258 ** Calls 'require(name)' and stores the result in a global variable
259 ** with the given name.
260 */
261 static int dolibrary (lua_State *L, const char *name) {
262   int status;
263   lua_getglobal(L, "require");
264   lua_pushstring(L, name);
265   status = docall(L, 1, 1);  /* call 'require(name)' */
266   if (status == LUA_OK)
267     lua_setglobal(L, name);  /* global[name] = require return */
268   return report(L, status);
269 }
270 
271 
272 /*
273 ** Returns the string to be used as a prompt by the interpreter.
274 */
275 static const char *get_prompt (lua_State *L, int firstline) {
276   const char *p;
277   lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
278   p = lua_tostring(L, -1);
279   if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
280   return p;
281 }
282 
283 /* mark in error messages for incomplete statements */
284 #define EOFMARK		"<eof>"
285 #define marklen		(sizeof(EOFMARK)/sizeof(char) - 1)
286 
287 
288 /*
289 ** Check whether 'status' signals a syntax error and the error
290 ** message at the top of the stack ends with the above mark for
291 ** incomplete statements.
292 */
293 static int incomplete (lua_State *L, int status) {
294   if (status == LUA_ERRSYNTAX) {
295     size_t lmsg;
296     const char *msg = lua_tolstring(L, -1, &lmsg);
297     if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
298       lua_pop(L, 1);
299       return 1;
300     }
301   }
302   return 0;  /* else... */
303 }
304 
305 
306 /*
307 ** Prompt the user, read a line, and push it into the Lua stack.
308 */
309 static int pushline (lua_State *L, int firstline) {
310   char buffer[LUA_MAXINPUT];
311   char *b = buffer;
312   size_t l;
313   const char *prmt = get_prompt(L, firstline);
314   int readstatus = lua_readline(L, b, prmt);
315   if (readstatus == 0)
316     return 0;  /* no input (prompt will be popped by caller) */
317   lua_pop(L, 1);  /* remove prompt */
318   l = strlen(b);
319   if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
320     b[--l] = '\0';  /* remove it */
321   if (firstline && b[0] == '=')  /* for compatibility with 5.2, ... */
322     lua_pushfstring(L, "return %s", b + 1);  /* change '=' to 'return' */
323   else
324     lua_pushlstring(L, b, l);
325   lua_freeline(L, b);
326   return 1;
327 }
328 
329 
330 /*
331 ** Try to compile line on the stack as 'return <line>;'; on return, stack
332 ** has either compiled chunk or original line (if compilation failed).
333 */
334 static int addreturn (lua_State *L) {
335   const char *line = lua_tostring(L, -1);  /* original line */
336   const char *retline = lua_pushfstring(L, "return %s;", line);
337   int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
338   if (status == LUA_OK) {
339     lua_remove(L, -2);  /* remove modified line */
340     if (line[0] != '\0')  /* non empty? */
341       lua_saveline(L, line);  /* keep history */
342   }
343   else
344     lua_pop(L, 2);  /* pop result from 'luaL_loadbuffer' and modified line */
345   return status;
346 }
347 
348 
349 /*
350 ** Read multiple lines until a complete Lua statement
351 */
352 static int multiline (lua_State *L) {
353   for (;;) {  /* repeat until gets a complete statement */
354     size_t len;
355     const char *line = lua_tolstring(L, 1, &len);  /* get what it has */
356     int status = luaL_loadbuffer(L, line, len, "=stdin");  /* try it */
357     if (!incomplete(L, status) || !pushline(L, 0)) {
358       lua_saveline(L, line);  /* keep history */
359       return status;  /* cannot or should not try to add continuation line */
360     }
361     lua_pushliteral(L, "\n");  /* add newline... */
362     lua_insert(L, -2);  /* ...between the two lines */
363     lua_concat(L, 3);  /* join them */
364   }
365 }
366 
367 
368 /*
369 ** Read a line and try to load (compile) it first as an expression (by
370 ** adding "return " in front of it) and second as a statement. Return
371 ** the final status of load/call with the resulting function (if any)
372 ** in the top of the stack.
373 */
374 static int loadline (lua_State *L) {
375   int status;
376   lua_settop(L, 0);
377   if (!pushline(L, 1))
378     return -1;  /* no input */
379   if ((status = addreturn(L)) != LUA_OK)  /* 'return ...' did not work? */
380     status = multiline(L);  /* try as command, maybe with continuation lines */
381   lua_remove(L, 1);  /* remove line from the stack */
382   lua_assert(lua_gettop(L) == 1);
383   return status;
384 }
385 
386 
387 /*
388 ** Prints (calling the Lua 'print' function) any values on the stack
389 */
390 static void l_print (lua_State *L) {
391   int n = lua_gettop(L);
392   if (n > 0) {  /* any result to be printed? */
393     luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
394     lua_getglobal(L, "print");
395     lua_insert(L, 1);
396     if (lua_pcall(L, n, 0, 0) != LUA_OK)
397       l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)",
398                                              lua_tostring(L, -1)));
399   }
400 }
401 
402 
403 /*
404 ** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and
405 ** print any results.
406 */
407 static void doREPL (lua_State *L) {
408   int status;
409   const char *oldprogname = progname;
410   progname = NULL;  /* no 'progname' on errors in interactive mode */
411   while ((status = loadline(L)) != -1) {
412     if (status == LUA_OK)
413       status = docall(L, 0, LUA_MULTRET);
414     if (status == LUA_OK) l_print(L);
415     else report(L, status);
416   }
417   lua_settop(L, 0);  /* clear stack */
418   lua_writeline();
419   progname = oldprogname;
420 }
421 
422 
423 /*
424 ** Push on the stack the contents of table 'arg' from 1 to #arg
425 */
426 static int pushargs (lua_State *L) {
427   int i, n;
428   if (lua_getglobal(L, "arg") != LUA_TTABLE)
429     luaL_error(L, "'arg' is not a table");
430   n = (int)luaL_len(L, -1);
431   luaL_checkstack(L, n + 3, "too many arguments to script");
432   for (i = 1; i <= n; i++)
433     lua_rawgeti(L, -i, i);
434   lua_remove(L, -i);  /* remove table from the stack */
435   return n;
436 }
437 
438 
439 static int handle_script (lua_State *L, char **argv) {
440   int status;
441   const char *fname = argv[0];
442   if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
443     fname = NULL;  /* stdin */
444   status = luaL_loadfile(L, fname);
445   if (status == LUA_OK) {
446     int n = pushargs(L);  /* push arguments to script */
447     status = docall(L, n, LUA_MULTRET);
448   }
449   return report(L, status);
450 }
451 
452 
453 
454 /* bits of various argument indicators in 'args' */
455 #define has_error	1	/* bad option */
456 #define has_i		2	/* -i */
457 #define has_v		4	/* -v */
458 #define has_e		8	/* -e */
459 #define has_E		16	/* -E */
460 
461 /*
462 ** Traverses all arguments from 'argv', returning a mask with those
463 ** needed before running any Lua code (or an error code if it finds
464 ** any invalid argument). 'first' returns the first not-handled argument
465 ** (either the script name or a bad argument in case of error).
466 */
467 static int collectargs (char **argv, int *first) {
468   int args = 0;
469   int i;
470   for (i = 1; argv[i] != NULL; i++) {
471     *first = i;
472     if (argv[i][0] != '-')  /* not an option? */
473         return args;  /* stop handling options */
474     switch (argv[i][1]) {  /* else check option */
475       case '-':  /* '--' */
476         if (argv[i][2] != '\0')  /* extra characters after '--'? */
477           return has_error;  /* invalid option */
478         *first = i + 1;
479         return args;
480       case '\0':  /* '-' */
481         return args;  /* script "name" is '-' */
482       case 'E':
483         if (argv[i][2] != '\0')  /* extra characters after 1st? */
484           return has_error;  /* invalid option */
485         args |= has_E;
486         break;
487       case 'i':
488         args |= has_i;  /* (-i implies -v) *//* FALLTHROUGH */
489       case 'v':
490         if (argv[i][2] != '\0')  /* extra characters after 1st? */
491           return has_error;  /* invalid option */
492         args |= has_v;
493         break;
494       case 'e':
495         args |= has_e;  /* FALLTHROUGH */
496       case 'l':  /* both options need an argument */
497         if (argv[i][2] == '\0') {  /* no concatenated argument? */
498           i++;  /* try next 'argv' */
499           if (argv[i] == NULL || argv[i][0] == '-')
500             return has_error;  /* no next argument or it is another option */
501         }
502         break;
503       default:  /* invalid option */
504         return has_error;
505     }
506   }
507   *first = i;  /* no script name */
508   return args;
509 }
510 
511 
512 /*
513 ** Processes options 'e' and 'l', which involve running Lua code.
514 ** Returns 0 if some code raises an error.
515 */
516 static int runargs (lua_State *L, char **argv, int n) {
517   int i;
518   for (i = 1; i < n; i++) {
519     int option = argv[i][1];
520     lua_assert(argv[i][0] == '-');  /* already checked */
521     if (option == 'e' || option == 'l') {
522       int status;
523       const char *extra = argv[i] + 2;  /* both options need an argument */
524       if (*extra == '\0') extra = argv[++i];
525       lua_assert(extra != NULL);
526       status = (option == 'e')
527                ? dostring(L, extra, "=(command line)")
528                : dolibrary(L, extra);
529       if (status != LUA_OK) return 0;
530     }
531   }
532   return 1;
533 }
534 
535 
536 
537 static int handle_luainit (lua_State *L) {
538   const char *name = "=" LUA_INITVARVERSION;
539   const char *init = getenv(name + 1);
540   if (init == NULL) {
541     name = "=" LUA_INIT_VAR;
542     init = getenv(name + 1);  /* try alternative name */
543   }
544   if (init == NULL) return LUA_OK;
545   else if (init[0] == '@')
546     return dofile(L, init+1);
547   else
548     return dostring(L, init, name);
549 }
550 
551 
552 /*
553 ** Main body of stand-alone interpreter (to be called in protected mode).
554 ** Reads the options and handles them all.
555 */
556 static int pmain (lua_State *L) {
557   int argc = (int)lua_tointeger(L, 1);
558   char **argv = (char **)lua_touserdata(L, 2);
559   int script;
560   int args = collectargs(argv, &script);
561   luaL_checkversion(L);  /* check that interpreter has correct version */
562   if (argv[0] && argv[0][0]) progname = argv[0];
563   if (args == has_error) {  /* bad arg? */
564     print_usage(argv[script]);  /* 'script' has index of bad arg. */
565     return 0;
566   }
567   if (args & has_v)  /* option '-v'? */
568     print_version();
569   if (args & has_E) {  /* option '-E'? */
570     lua_pushboolean(L, 1);  /* signal for libraries to ignore env. vars. */
571     lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
572   }
573   luaL_openlibs(L);  /* open standard libraries */
574   createargtable(L, argv, argc, script);  /* create table 'arg' */
575   if (!(args & has_E)) {  /* no option '-E'? */
576     if (handle_luainit(L) != LUA_OK)  /* run LUA_INIT */
577       return 0;  /* error running LUA_INIT */
578   }
579   if (!runargs(L, argv, script))  /* execute arguments -e and -l */
580     return 0;  /* something failed */
581   if (script < argc &&  /* execute main script (if there is one) */
582       handle_script(L, argv + script) != LUA_OK)
583     return 0;
584   if (args & has_i)  /* -i option? */
585     doREPL(L);  /* do read-eval-print loop */
586   else if (script == argc && !(args & (has_e | has_v))) {  /* no arguments? */
587     if (lua_stdin_is_tty()) {  /* running in interactive mode? */
588       print_version();
589       doREPL(L);  /* do read-eval-print loop */
590     }
591     else dofile(L, NULL);  /* executes stdin as a file */
592   }
593   lua_pushboolean(L, 1);  /* signal no errors */
594   return 1;
595 }
596 
597 
598 int main (int argc, char **argv) {
599   int status, result;
600   lua_State *L = luaL_newstate();  /* create state */
601   if (L == NULL) {
602     l_message(argv[0], "cannot create state: not enough memory");
603     return EXIT_FAILURE;
604   }
605   lua_pushcfunction(L, &pmain);  /* to call 'pmain' in protected mode */
606   lua_pushinteger(L, argc);  /* 1st argument */
607   lua_pushlightuserdata(L, argv); /* 2nd argument */
608   status = lua_pcall(L, 2, 1, 0);  /* do the call */
609   result = lua_toboolean(L, -1);  /* get result */
610   report(L, status);
611   lua_close(L);
612   return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
613 }
614 
615