1 /*
2 ** $Id: lua.c,v 1.206.1.1 2013/04/12 18:48:47 roberto Exp $
3 ** Lua stand-alone interpreter
4 ** See Copyright Notice in lua.h
5 */
6 
7 
8 #ifdef SYSLINUX
9 #include <console.h>
10 #define signal(x,y)
11 #else
12 #include <signal.h>
13 #endif
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #define lua_c
19 
20 #include "lua.h"
21 
22 #include "lauxlib.h"
23 #include "lualib.h"
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)
40 #define LUA_INIT		"LUA_INIT"
41 #endif
42 
43 #define LUA_INITVERSION  \
44 	LUA_INIT "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
45 
46 
47 /*
48 ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
49 ** is, whether we're running lua interactively).
50 */
51 #if defined(LUA_USE_ISATTY)
52 #include <unistd.h>
53 #define lua_stdin_is_tty()	isatty(0)
54 #elif defined(LUA_WIN)
55 #include <io.h>
56 #include <stdio.h>
57 #define lua_stdin_is_tty()	_isatty(_fileno(stdin))
58 #else
59 #define lua_stdin_is_tty()	1  /* assume stdin is a tty */
60 #endif
61 
62 
63 /*
64 ** lua_readline defines how to show a prompt and then read a line from
65 ** the standard input.
66 ** lua_saveline defines how to "save" a read line in a "history".
67 ** lua_freeline defines how to free a line read by lua_readline.
68 */
69 #if defined(LUA_USE_READLINE)
70 
71 #include <stdio.h>
72 #include <readline/readline.h>
73 #include <readline/history.h>
74 #define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)
75 #define lua_saveline(L,idx) \
76         if (lua_rawlen(L,idx) > 0)  /* non-empty line? */ \
77           add_history(lua_tostring(L, idx));  /* add it to history */
78 #define lua_freeline(L,b)	((void)L, free(b))
79 
80 #elif !defined(lua_readline)
81 
82 #define lua_readline(L,b,p) \
83         ((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
84         fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
85 #define lua_saveline(L,idx)	{ (void)L; (void)idx; }
86 #define lua_freeline(L,b)	{ (void)L; (void)b; }
87 
88 #endif
89 
90 
91 
92 
93 static lua_State *globalL = NULL;
94 
95 static const char *progname = LUA_PROGNAME;
96 
97 
98 
99 #ifndef SYSLINUX
lstop(lua_State * L,lua_Debug * ar)100 static void lstop (lua_State *L, lua_Debug *ar) {
101   (void)ar;  /* unused arg. */
102   lua_sethook(L, NULL, 0, 0);
103   luaL_error(L, "interrupted!");
104 }
105 
106 
laction(int i)107 static void laction (int i) {
108   signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
109                               terminate process (default action) */
110   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
111 }
112 #endif
113 
114 
print_usage(const char * badoption)115 static void print_usage (const char *badoption) {
116   luai_writestringerror("%s: ", progname);
117   if (badoption[1] == 'e' || badoption[1] == 'l')
118     luai_writestringerror("'%s' needs argument\n", badoption);
119   else
120     luai_writestringerror("unrecognized option '%s'\n", badoption);
121   luai_writestringerror(
122   "usage: %s [options] [script [args]]\n"
123   "Available options are:\n"
124   "  -e stat  execute string " LUA_QL("stat") "\n"
125   "  -i       enter interactive mode after executing " LUA_QL("script") "\n"
126   "  -l name  require library " LUA_QL("name") "\n"
127   "  -v       show version information\n"
128   "  -E       ignore environment variables\n"
129   "  --       stop handling options\n"
130   "  -        stop handling options and execute stdin\n"
131   ,
132   progname);
133 }
134 
135 
l_message(const char * pname,const char * msg)136 static void l_message (const char *pname, const char *msg) {
137   if (pname) luai_writestringerror("%s: ", pname);
138   luai_writestringerror("%s\n", msg);
139 }
140 
141 
report(lua_State * L,int status)142 static int report (lua_State *L, int status) {
143   if (status != LUA_OK && !lua_isnil(L, -1)) {
144     const char *msg = lua_tostring(L, -1);
145     if (msg == NULL) msg = "(error object is not a string)";
146     l_message(progname, msg);
147     lua_pop(L, 1);
148     /* force a complete garbage collection in case of errors */
149     lua_gc(L, LUA_GCCOLLECT, 0);
150   }
151   return status;
152 }
153 
154 
155 /* the next function is called unprotected, so it must avoid errors */
finalreport(lua_State * L,int status)156 static void finalreport (lua_State *L, int status) {
157   if (status != LUA_OK) {
158     const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1)
159                                                        : NULL;
160     if (msg == NULL) msg = "(error object is not a string)";
161     l_message(progname, msg);
162     lua_pop(L, 1);
163   }
164 }
165 
166 
traceback(lua_State * L)167 static int traceback (lua_State *L) {
168   const char *msg = lua_tostring(L, 1);
169   if (msg)
170     luaL_traceback(L, L, msg, 1);
171   else if (!lua_isnoneornil(L, 1)) {  /* is there an error object? */
172     if (!luaL_callmeta(L, 1, "__tostring"))  /* try its 'tostring' metamethod */
173       lua_pushliteral(L, "(no error message)");
174   }
175   return 1;
176 }
177 
178 
docall(lua_State * L,int narg,int nres)179 static int docall (lua_State *L, int narg, int nres) {
180   int status;
181   int base = lua_gettop(L) - narg;  /* function index */
182   lua_pushcfunction(L, traceback);  /* push traceback function */
183   lua_insert(L, base);  /* put it under chunk and args */
184   globalL = L;  /* to be available to 'laction' */
185   signal(SIGINT, laction);
186   status = lua_pcall(L, narg, nres, base);
187   signal(SIGINT, SIG_DFL);
188   lua_remove(L, base);  /* remove traceback function */
189   return status;
190 }
191 
192 
print_version(void)193 static void print_version (void) {
194   luai_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT));
195   luai_writeline();
196 }
197 
198 
getargs(lua_State * L,char ** argv,int n)199 static int getargs (lua_State *L, char **argv, int n) {
200   int narg;
201   int i;
202   int argc = 0;
203   while (argv[argc]) argc++;  /* count total number of arguments */
204   narg = argc - (n + 1);  /* number of arguments to the script */
205   luaL_checkstack(L, narg + 3, "too many arguments to script");
206   for (i=n+1; i < argc; i++)
207     lua_pushstring(L, argv[i]);
208   lua_createtable(L, narg, n + 1);
209   for (i=0; i < argc; i++) {
210     lua_pushstring(L, argv[i]);
211     lua_rawseti(L, -2, i - n);
212   }
213   return narg;
214 }
215 
216 
dofile(lua_State * L,const char * name)217 static int dofile (lua_State *L, const char *name) {
218   int status = luaL_loadfile(L, name);
219   if (status == LUA_OK) status = docall(L, 0, 0);
220   return report(L, status);
221 }
222 
223 
dostring(lua_State * L,const char * s,const char * name)224 static int dostring (lua_State *L, const char *s, const char *name) {
225   int status = luaL_loadbuffer(L, s, strlen(s), name);
226   if (status == LUA_OK) status = docall(L, 0, 0);
227   return report(L, status);
228 }
229 
230 
dolibrary(lua_State * L,const char * name)231 static int dolibrary (lua_State *L, const char *name) {
232   int status;
233   lua_getglobal(L, "require");
234   lua_pushstring(L, name);
235   status = docall(L, 1, 1);  /* call 'require(name)' */
236   if (status == LUA_OK)
237     lua_setglobal(L, name);  /* global[name] = require return */
238   return report(L, status);
239 }
240 
241 
get_prompt(lua_State * L,int firstline)242 static const char *get_prompt (lua_State *L, int firstline) {
243   const char *p;
244   lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
245   p = lua_tostring(L, -1);
246   if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
247   return p;
248 }
249 
250 /* mark in error messages for incomplete statements */
251 #define EOFMARK		"<eof>"
252 #define marklen		(sizeof(EOFMARK)/sizeof(char) - 1)
253 
incomplete(lua_State * L,int status)254 static int incomplete (lua_State *L, int status) {
255   if (status == LUA_ERRSYNTAX) {
256     size_t lmsg;
257     const char *msg = lua_tolstring(L, -1, &lmsg);
258     if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
259       lua_pop(L, 1);
260       return 1;
261     }
262   }
263   return 0;  /* else... */
264 }
265 
266 
pushline(lua_State * L,int firstline)267 static int pushline (lua_State *L, int firstline) {
268   char buffer[LUA_MAXINPUT];
269   char *b = buffer;
270   size_t l;
271   const char *prmt = get_prompt(L, firstline);
272   int readstatus = lua_readline(L, b, prmt);
273   lua_pop(L, 1);  /* remove result from 'get_prompt' */
274   if (readstatus == 0)
275     return 0;  /* no input */
276   l = strlen(b);
277   if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
278     b[l-1] = '\0';  /* remove it */
279   if (firstline && b[0] == '=')  /* first line starts with `=' ? */
280     lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */
281   else
282     lua_pushstring(L, b);
283   lua_freeline(L, b);
284   return 1;
285 }
286 
287 
loadline(lua_State * L)288 static int loadline (lua_State *L) {
289   int status;
290   lua_settop(L, 0);
291   if (!pushline(L, 1))
292     return -1;  /* no input */
293   for (;;) {  /* repeat until gets a complete line */
294     size_t l;
295     const char *line = lua_tolstring(L, 1, &l);
296     status = luaL_loadbuffer(L, line, l, "=stdin");
297     if (!incomplete(L, status)) break;  /* cannot try to add lines? */
298     if (!pushline(L, 0))  /* no more input? */
299       return -1;
300     lua_pushliteral(L, "\n");  /* add a new line... */
301     lua_insert(L, -2);  /* ...between the two lines */
302     lua_concat(L, 3);  /* join them */
303   }
304   lua_saveline(L, 1);
305   lua_remove(L, 1);  /* remove line */
306   return status;
307 }
308 
309 
dotty(lua_State * L)310 static void dotty (lua_State *L) {
311   int status;
312   const char *oldprogname = progname;
313   progname = NULL;
314   while ((status = loadline(L)) != -1) {
315     if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET);
316     report(L, status);
317     if (status == LUA_OK && lua_gettop(L) > 0) {  /* any result to print? */
318       luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
319       lua_getglobal(L, "print");
320       lua_insert(L, 1);
321       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK)
322         l_message(progname, lua_pushfstring(L,
323                                "error calling " LUA_QL("print") " (%s)",
324                                lua_tostring(L, -1)));
325     }
326   }
327   lua_settop(L, 0);  /* clear stack */
328   luai_writeline();
329   progname = oldprogname;
330 }
331 
332 
handle_script(lua_State * L,char ** argv,int n)333 static int handle_script (lua_State *L, char **argv, int n) {
334   int status;
335   const char *fname;
336   int narg = getargs(L, argv, n);  /* collect arguments */
337   lua_setglobal(L, "arg");
338   fname = argv[n];
339   if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
340     fname = NULL;  /* stdin */
341   status = luaL_loadfile(L, fname);
342   lua_insert(L, -(narg+1));
343   if (status == LUA_OK)
344     status = docall(L, narg, LUA_MULTRET);
345   else
346     lua_pop(L, narg);
347   return report(L, status);
348 }
349 
350 
351 /* check that argument has no extra characters at the end */
352 #define noextrachars(x)		{if ((x)[2] != '\0') return -1;}
353 
354 
355 /* indices of various argument indicators in array args */
356 #define has_i		0	/* -i */
357 #define has_v		1	/* -v */
358 #define has_e		2	/* -e */
359 #define has_E		3	/* -E */
360 
361 #define num_has		4	/* number of 'has_*' */
362 
363 
collectargs(char ** argv,int * args)364 static int collectargs (char **argv, int *args) {
365   int i;
366   for (i = 1; argv[i] != NULL; i++) {
367     if (argv[i][0] != '-')  /* not an option? */
368         return i;
369     switch (argv[i][1]) {  /* option */
370       case '-':
371         noextrachars(argv[i]);
372         return (argv[i+1] != NULL ? i+1 : 0);
373       case '\0':
374         return i;
375       case 'E':
376         args[has_E] = 1;
377         break;
378       case 'i':
379         noextrachars(argv[i]);
380         args[has_i] = 1;  /* go through */
381       case 'v':
382         noextrachars(argv[i]);
383         args[has_v] = 1;
384         break;
385       case 'e':
386         args[has_e] = 1;  /* go through */
387       case 'l':  /* both options need an argument */
388         if (argv[i][2] == '\0') {  /* no concatenated argument? */
389           i++;  /* try next 'argv' */
390           if (argv[i] == NULL || argv[i][0] == '-')
391             return -(i - 1);  /* no next argument or it is another option */
392         }
393         break;
394       default:  /* invalid option; return its index... */
395         return -i;  /* ...as a negative value */
396     }
397   }
398   return 0;
399 }
400 
401 
runargs(lua_State * L,char ** argv,int n)402 static int runargs (lua_State *L, char **argv, int n) {
403   int i;
404   for (i = 1; i < n; i++) {
405     lua_assert(argv[i][0] == '-');
406     switch (argv[i][1]) {  /* option */
407       case 'e': {
408         const char *chunk = argv[i] + 2;
409         if (*chunk == '\0') chunk = argv[++i];
410         lua_assert(chunk != NULL);
411         if (dostring(L, chunk, "=(command line)") != LUA_OK)
412           return 0;
413         break;
414       }
415       case 'l': {
416         const char *filename = argv[i] + 2;
417         if (*filename == '\0') filename = argv[++i];
418         lua_assert(filename != NULL);
419         if (dolibrary(L, filename) != LUA_OK)
420           return 0;  /* stop if file fails */
421         break;
422       }
423       default: break;
424     }
425   }
426   return 1;
427 }
428 
429 
handle_luainit(lua_State * L)430 static int handle_luainit (lua_State *L) {
431   const char *name = "=" LUA_INITVERSION;
432   const char *init = getenv(name + 1);
433   if (init == NULL) {
434     name = "=" LUA_INIT;
435     init = getenv(name + 1);  /* try alternative name */
436   }
437   if (init == NULL) return LUA_OK;
438   else if (init[0] == '@')
439     return dofile(L, init+1);
440   else
441     return dostring(L, init, name);
442 }
443 
444 
pmain(lua_State * L)445 static int pmain (lua_State *L) {
446   int argc = (int)lua_tointeger(L, 1);
447   char **argv = (char **)lua_touserdata(L, 2);
448   int script;
449   int args[num_has];
450   args[has_i] = args[has_v] = args[has_e] = args[has_E] = 0;
451   if (argv[0] && argv[0][0]) progname = argv[0];
452   script = collectargs(argv, args);
453   if (script < 0) {  /* invalid arg? */
454     print_usage(argv[-script]);
455     return 0;
456   }
457   if (args[has_v]) print_version();
458   if (args[has_E]) {  /* option '-E'? */
459     lua_pushboolean(L, 1);  /* signal for libraries to ignore env. vars. */
460     lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
461   }
462   /* open standard libraries */
463   luaL_checkversion(L);
464   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
465   luaL_openlibs(L);  /* open libraries */
466   lua_gc(L, LUA_GCRESTART, 0);
467   if (!args[has_E] && handle_luainit(L) != LUA_OK)
468     return 0;  /* error running LUA_INIT */
469   /* execute arguments -e and -l */
470   if (!runargs(L, argv, (script > 0) ? script : argc)) return 0;
471   /* execute main script (if there is one) */
472   if (script && handle_script(L, argv, script) != LUA_OK) return 0;
473   if (args[has_i])  /* -i option? */
474     dotty(L);
475   else if (script == 0 && !args[has_e] && !args[has_v]) {  /* no arguments? */
476     if (lua_stdin_is_tty()) {
477       print_version();
478       dotty(L);
479     }
480     else dofile(L, NULL);  /* executes stdin as a file */
481   }
482   lua_pushboolean(L, 1);  /* signal no errors */
483   return 1;
484 }
485 
486 
main(int argc,char ** argv)487 int main (int argc, char **argv) {
488   int status, result;
489   lua_State *L = luaL_newstate();  /* create state */
490   if (L == NULL) {
491     l_message(argv[0], "cannot create state: not enough memory");
492     return EXIT_FAILURE;
493   }
494 #ifdef SYSLINUX
495   openconsole(&dev_stdcon_r, &dev_stdcon_w);
496 #endif
497   /* call 'pmain' in protected mode */
498   lua_pushcfunction(L, &pmain);
499   lua_pushinteger(L, argc);  /* 1st argument */
500   lua_pushlightuserdata(L, argv); /* 2nd argument */
501   status = lua_pcall(L, 2, 1, 0);
502   result = lua_toboolean(L, -1);  /* get result */
503   finalreport(L, status);
504   lua_close(L);
505   return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
506 }
507 
508