- initial import of revision 374 from cnc
[apt.git] / lua / lua / lua.c
1 /*
2 ** $Id: lua.c,v 1.122 2003/04/03 13:34:42 roberto Exp $
3 ** Lua stand-alone interpreter
4 ** See Copyright Notice in lua.h
5 */
6
7
8 #include <signal.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #define lua_c
14
15 #include "lua.h"
16
17 #include "lauxlib.h"
18 #include "lualib.h"
19
20
21 /*
22 ** generic extra include file
23 */
24 #ifdef LUA_USERCONFIG
25 #include LUA_USERCONFIG
26 #endif
27
28
29 /*
30 ** definition of `isatty'
31 */
32 #ifdef _POSIX_C_SOURCE
33 #include <unistd.h>
34 #define stdin_is_tty()  isatty(0)
35 #else
36 #define stdin_is_tty()  1  /* assume stdin is a tty */
37 #endif
38
39
40
41 #ifndef PROMPT
42 #define PROMPT          "> "
43 #endif
44
45
46 #ifndef PROMPT2
47 #define PROMPT2         ">> "
48 #endif
49
50 #ifndef PROGNAME
51 #define PROGNAME        "lua"
52 #endif
53
54 #ifndef lua_userinit
55 #define lua_userinit(L)         openstdlibs(L)
56 #endif
57
58
59 #ifndef LUA_EXTRALIBS
60 #define LUA_EXTRALIBS   /* empty */
61 #endif
62
63
64 static lua_State *L = NULL;
65
66 static const char *progname = PROGNAME;
67
68
69
70 static const luaL_reg lualibs[] = {
71   {"base", luaopen_base},
72   {"table", luaopen_table},
73   {"io", luaopen_io},
74   {"string", luaopen_string},
75   {"math", luaopen_math},
76   {"debug", luaopen_debug},
77   {"loadlib", luaopen_loadlib},
78   /* add your libraries here */
79   LUA_EXTRALIBS
80   {NULL, NULL}
81 };
82
83
84
85 static void lstop (lua_State *l, lua_Debug *ar) {
86   (void)ar;  /* unused arg. */
87   lua_sethook(l, NULL, 0, 0);
88   luaL_error(l, "interrupted!");
89 }
90
91
92 static void laction (int i) {
93   signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
94                               terminate process (default action) */
95   lua_sethook(L, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
96 }
97
98
99 static void print_usage (void) {
100   fprintf(stderr,
101   "usage: %s [options] [script [args]].\n"
102   "Available options are:\n"
103   "  -        execute stdin as a file\n"
104   "  -e stat  execute string `stat'\n"
105   "  -i       enter interactive mode after executing `script'\n"
106   "  -l name  load and run library `name'\n"
107   "  -v       show version information\n"
108   "  --       stop handling options\n" ,
109   progname);
110 }
111
112
113 static void l_message (const char *pname, const char *msg) {
114   if (pname) fprintf(stderr, "%s: ", pname);
115   fprintf(stderr, "%s\n", msg);
116 }
117
118
119 static int report (int status) {
120   const char *msg;
121   if (status) {
122     msg = lua_tostring(L, -1);
123     if (msg == NULL) msg = "(error with no message)";
124     l_message(progname, msg);
125     lua_pop(L, 1);
126   }
127   return status;
128 }
129
130
131 static int lcall (int narg, int clear) {
132   int status;
133   int base = lua_gettop(L) - narg;  /* function index */
134   lua_pushliteral(L, "_TRACEBACK");
135   lua_rawget(L, LUA_GLOBALSINDEX);  /* get traceback function */
136   lua_insert(L, base);  /* put it under chunk and args */
137   signal(SIGINT, laction);
138   status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
139   signal(SIGINT, SIG_DFL);
140   lua_remove(L, base);  /* remove traceback function */
141   return status;
142 }
143
144
145 static void print_version (void) {
146   l_message(NULL, LUA_VERSION "  " LUA_COPYRIGHT);
147 }
148
149
150 static void getargs (char *argv[], int n) {
151   int i;
152   lua_newtable(L);
153   for (i=0; argv[i]; i++) {
154     lua_pushnumber(L, i - n);
155     lua_pushstring(L, argv[i]);
156     lua_rawset(L, -3);
157   }
158   /* arg.n = maximum index in table `arg' */
159   lua_pushliteral(L, "n");
160   lua_pushnumber(L, i-n-1);
161   lua_rawset(L, -3);
162 }
163
164
165 static int docall (int status) {
166   if (status == 0) status = lcall(0, 1);
167   return report(status);
168 }
169
170
171 static int file_input (const char *name) {
172   return docall(luaL_loadfile(L, name));
173 }
174
175
176 static int dostring (const char *s, const char *name) {
177   return docall(luaL_loadbuffer(L, s, strlen(s), name));
178 }
179
180
181 static int load_file (const char *name) {
182   lua_pushliteral(L, "require");
183   lua_rawget(L, LUA_GLOBALSINDEX);
184   if (!lua_isfunction(L, -1)) {  /* no `require' defined? */
185     lua_pop(L, 1);
186     return file_input(name);
187   }
188   else {
189     lua_pushstring(L, name);
190     return report(lcall(1, 1));
191   }
192 }
193
194
195 /*
196 ** this macro can be used by some `history' system to save lines
197 ** read in manual input
198 */
199 #ifndef lua_saveline
200 #define lua_saveline(L,line)    /* empty */
201 #endif
202
203
204 /*
205 ** this macro defines a function to show the prompt and reads the
206 ** next line for manual input
207 */
208 #ifndef lua_readline
209 #define lua_readline(L,prompt)          readline(L,prompt)
210
211 /* maximum length of an input line */
212 #ifndef MAXINPUT
213 #define MAXINPUT        512
214 #endif
215
216
217 static int readline (lua_State *l, const char *prompt) {
218   static char buffer[MAXINPUT];
219   if (prompt) {
220     fputs(prompt, stdout);
221     fflush(stdout);
222   }
223   if (fgets(buffer, sizeof(buffer), stdin) == NULL)
224     return 0;  /* read fails */
225   else {
226     lua_pushstring(l, buffer);
227     return 1;
228   }
229 }
230
231 #endif
232
233
234 static const char *get_prompt (int firstline) {
235   const char *p = NULL;
236   lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2");
237   lua_rawget(L, LUA_GLOBALSINDEX);
238   p = lua_tostring(L, -1);
239   if (p == NULL) p = (firstline ? PROMPT : PROMPT2);
240   lua_pop(L, 1);  /* remove global */
241   return p;
242 }
243
244
245 static int incomplete (int status) {
246   if (status == LUA_ERRSYNTAX &&
247          strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) {
248     lua_pop(L, 1);
249     return 1;
250   }
251   else
252     return 0;
253 }
254
255
256 static int load_string (void) {
257   int status;
258   lua_settop(L, 0);
259   if (lua_readline(L, get_prompt(1)) == 0)  /* no input? */
260     return -1;
261   if (lua_tostring(L, -1)[0] == '=') {  /* line starts with `=' ? */
262     lua_pushfstring(L, "return %s", lua_tostring(L, -1)+1);/* `=' -> `return' */
263     lua_remove(L, -2);  /* remove original line */
264   }
265   for (;;) {  /* repeat until gets a complete line */
266     status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
267     if (!incomplete(status)) break;  /* cannot try to add lines? */
268     if (lua_readline(L, get_prompt(0)) == 0)  /* no more input? */
269       return -1;
270     lua_concat(L, lua_gettop(L));  /* join lines */
271   }
272   lua_saveline(L, lua_tostring(L, 1));
273   lua_remove(L, 1);  /* remove line */
274   return status;
275 }
276
277
278 static void manual_input (void) {
279   int status;
280   const char *oldprogname = progname;
281   progname = NULL;
282   while ((status = load_string()) != -1) {
283     if (status == 0) status = lcall(0, 0);
284     report(status);
285     if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */
286       lua_getglobal(L, "print");
287       lua_insert(L, 1);
288       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
289         l_message(progname, lua_pushfstring(L, "error calling `print' (%s)",
290                                                lua_tostring(L, -1)));
291     }
292   }
293   lua_settop(L, 0);  /* clear stack */
294   fputs("\n", stdout);
295   progname = oldprogname;
296 }
297
298
299 static int handle_argv (char *argv[], int *interactive) {
300   if (argv[1] == NULL) {  /* no more arguments? */
301     if (stdin_is_tty()) {
302       print_version();
303       manual_input();
304     }
305     else
306       file_input(NULL);  /* executes stdin as a file */
307   }
308   else {  /* other arguments; loop over them */
309     int i;
310     for (i = 1; argv[i] != NULL; i++) {
311       if (argv[i][0] != '-') break;  /* not an option? */
312       switch (argv[i][1]) {  /* option */
313         case '-': {  /* `--' */
314           if (argv[i][2] != '\0') {
315             print_usage();
316             return 1;
317           }
318           i++;  /* skip this argument */
319           goto endloop;  /* stop handling arguments */
320         }
321         case '\0': {
322           file_input(NULL);  /* executes stdin as a file */
323           break;
324         }
325         case 'i': {
326           *interactive = 1;
327           break;
328         }
329         case 'v': {
330           print_version();
331           break;
332         }
333         case 'e': {
334           const char *chunk = argv[i] + 2;
335           if (*chunk == '\0') chunk = argv[++i];
336           if (chunk == NULL) {
337             print_usage();
338             return 1;
339           }
340           if (dostring(chunk, "=<command line>") != 0)
341             return 1;
342           break;
343         }
344         case 'l': {
345           const char *filename = argv[i] + 2;
346           if (*filename == '\0') filename = argv[++i];
347           if (filename == NULL) {
348             print_usage();
349             return 1;
350           }
351           if (load_file(filename))
352             return 1;  /* stop if file fails */
353           break;
354         }
355         case 'c': {
356           l_message(progname, "option `-c' is deprecated");
357           break;
358         }
359         case 's': {
360           l_message(progname, "option `-s' is deprecated");
361           break;
362         }
363         default: {
364           print_usage();
365           return 1;
366         }
367       }
368     } endloop:
369     if (argv[i] != NULL) {
370       const char *filename = argv[i];
371       getargs(argv, i);  /* collect arguments */
372       lua_setglobal(L, "arg");
373       return file_input(filename);  /* stop scanning arguments */
374     }
375   }
376   return 0;
377 }
378
379
380 static void openstdlibs (lua_State *l) {
381   const luaL_reg *lib = lualibs;
382   for (; lib->func; lib++) {
383     lib->func(l);  /* open library */
384     lua_settop(l, 0);  /* discard any results */
385   }
386 }
387
388
389 static int handle_luainit (void) {
390   const char *init = getenv("LUA_INIT");
391   if (init == NULL) return 0;  /* status OK */
392   else if (init[0] == '@')
393     return file_input(init+1);
394   else
395     return dostring(init, "=LUA_INIT");
396 }
397
398
399 struct Smain {
400   int argc;
401   char **argv;
402   int status;
403 };
404
405
406 static int pmain (lua_State *l) {
407   struct Smain *s = (struct Smain *)lua_touserdata(l, 1);
408   int status;
409   int interactive = 0;
410   if (s->argv[0] && s->argv[0][0]) progname = s->argv[0];
411   L = l;
412   lua_userinit(l);  /* open libraries */
413   status = handle_luainit();
414   if (status == 0) {
415     status = handle_argv(s->argv, &interactive);
416     if (status == 0 && interactive) manual_input();
417   }
418   s->status = status;
419   return 0;
420 }
421
422
423 int main (int argc, char *argv[]) {
424   int status;
425   struct Smain s;
426   lua_State *l = lua_open();  /* create state */
427   if (l == NULL) {
428     l_message(argv[0], "cannot create state: not enough memory");
429     return EXIT_FAILURE;
430   }
431   s.argc = argc;
432   s.argv = argv;
433   status = lua_cpcall(l, &pmain, &s);
434   report(status);
435   lua_close(l);
436   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
437 }
438