Line data Source code
1 : /*
2 : ** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 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 : static lua_State *globalL = NULL;
23 :
24 : static const char *progname = LUA_PROGNAME;
25 :
26 :
27 :
28 0 : static void lstop (lua_State *L, lua_Debug *ar) {
29 : (void)ar; /* unused arg. */
30 0 : lua_sethook(L, NULL, 0, 0);
31 0 : luaL_error(L, "interrupted!");
32 0 : }
33 :
34 :
35 0 : static void laction (int i) {
36 0 : signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
37 : terminate process (default action) */
38 0 : lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
39 0 : }
40 :
41 :
42 0 : static void print_usage (void) {
43 0 : fprintf(stderr,
44 : "usage: %s [options] [script [args]].\n"
45 : "Available options are:\n"
46 : " -e stat execute string " LUA_QL("stat") "\n"
47 : " -l name require library " LUA_QL("name") "\n"
48 : " -i enter interactive mode after executing " LUA_QL("script") "\n"
49 : " -v show version information\n"
50 : " -- stop handling options\n"
51 : " - execute stdin and stop handling options\n"
52 : ,
53 : progname);
54 0 : fflush(stderr);
55 0 : }
56 :
57 :
58 8 : static void l_message (const char *pname, const char *msg) {
59 8 : if (pname) fprintf(stderr, "%s: ", pname);
60 8 : fprintf(stderr, "%s\n", msg);
61 8 : fflush(stderr);
62 8 : }
63 :
64 :
65 284 : static int report (lua_State *L, int status) {
66 284 : if (status && !lua_isnil(L, -1)) {
67 5 : const char *msg = lua_tostring(L, -1);
68 5 : if (msg == NULL) msg = "(error object is not a string)";
69 5 : l_message(progname, msg);
70 5 : lua_pop(L, 1);
71 : }
72 284 : return status;
73 : }
74 :
75 :
76 4 : static int traceback (lua_State *L) {
77 4 : if (!lua_isstring(L, 1)) /* 'message' not a string? */
78 2 : return 1; /* keep it intact */
79 2 : lua_getfield(L, LUA_GLOBALSINDEX, "debug");
80 2 : if (!lua_istable(L, -1)) {
81 0 : lua_pop(L, 1);
82 0 : return 1;
83 : }
84 2 : lua_getfield(L, -1, "traceback");
85 2 : if (!lua_isfunction(L, -1)) {
86 0 : lua_pop(L, 2);
87 0 : return 1;
88 : }
89 2 : lua_pushvalue(L, 1); /* pass error message */
90 2 : lua_pushinteger(L, 2); /* skip this function and traceback */
91 2 : lua_call(L, 2, 1); /* call debug.traceback */
92 2 : return 1;
93 : }
94 :
95 :
96 217 : static int docall (lua_State *L, int narg, int clear) {
97 : int status;
98 217 : int base = lua_gettop(L) - narg; /* function index */
99 217 : lua_pushcfunction(L, traceback); /* push traceback function */
100 217 : lua_insert(L, base); /* put it under chunk and args */
101 217 : signal(SIGINT, laction);
102 217 : status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
103 208 : signal(SIGINT, SIG_DFL);
104 208 : lua_remove(L, base); /* remove traceback function */
105 : /* force a complete garbage collection in case of errors */
106 208 : if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
107 208 : return status;
108 : }
109 :
110 :
111 3 : static void print_version (void) {
112 3 : l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT);
113 3 : }
114 :
115 :
116 58 : static int getargs (lua_State *L, char **argv, int n) {
117 : int narg;
118 : int i;
119 58 : int argc = 0;
120 279 : while (argv[argc]) argc++; /* count total number of arguments */
121 58 : narg = argc - (n + 1); /* number of arguments to the script */
122 58 : luaL_checkstack(L, narg + 3, "too many arguments to script");
123 58 : for (i=n+1; i < argc; i++)
124 0 : lua_pushstring(L, argv[i]);
125 58 : lua_createtable(L, narg, n + 1);
126 279 : for (i=0; i < argc; i++) {
127 221 : lua_pushstring(L, argv[i]);
128 221 : lua_rawseti(L, -2, i - n);
129 : }
130 58 : return narg;
131 : }
132 :
133 :
134 1 : static int dofile (lua_State *L, const char *name) {
135 1 : int status = luaL_loadfile(L, name) || docall(L, 0, 1);
136 1 : return report(L, status);
137 : }
138 :
139 :
140 108 : static int dostring (lua_State *L, const char *s, const char *name) {
141 108 : int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
142 105 : return report(L, status);
143 : }
144 :
145 :
146 52 : static int dolibrary (lua_State *L, const char *name) {
147 52 : lua_getglobal(L, "require");
148 52 : lua_pushstring(L, name);
149 52 : return report(L, docall(L, 1, 1));
150 : }
151 :
152 :
153 0 : static const char *get_prompt (lua_State *L, int firstline) {
154 : const char *p;
155 0 : lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
156 0 : p = lua_tostring(L, -1);
157 0 : if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
158 0 : lua_pop(L, 1); /* remove global */
159 0 : return p;
160 : }
161 :
162 :
163 0 : static int incomplete (lua_State *L, int status) {
164 0 : if (status == LUA_ERRSYNTAX) {
165 : size_t lmsg;
166 0 : const char *msg = lua_tolstring(L, -1, &lmsg);
167 0 : const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
168 0 : if (strstr(msg, LUA_QL("<eof>")) == tp) {
169 0 : lua_pop(L, 1);
170 0 : return 1;
171 : }
172 : }
173 0 : return 0; /* else... */
174 : }
175 :
176 :
177 0 : static int pushline (lua_State *L, int firstline) {
178 : char buffer[LUA_MAXINPUT];
179 0 : char *b = buffer;
180 : size_t l;
181 0 : const char *prmt = get_prompt(L, firstline);
182 0 : if (lua_readline(L, b, prmt) == 0)
183 0 : return 0; /* no input */
184 0 : l = strlen(b);
185 0 : if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
186 0 : b[l-1] = '\0'; /* remove it */
187 0 : if (firstline && b[0] == '=') /* first line starts with `=' ? */
188 0 : lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
189 : else
190 0 : lua_pushstring(L, b);
191 0 : lua_freeline(L, b);
192 0 : return 1;
193 : }
194 :
195 :
196 0 : static int loadline (lua_State *L) {
197 : int status;
198 0 : lua_settop(L, 0);
199 0 : if (!pushline(L, 1))
200 0 : return -1; /* no input */
201 : for (;;) { /* repeat until gets a complete line */
202 0 : status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
203 0 : if (!incomplete(L, status)) break; /* cannot try to add lines? */
204 0 : if (!pushline(L, 0)) /* no more input? */
205 0 : return -1;
206 0 : lua_pushliteral(L, "\n"); /* add a new line... */
207 0 : lua_insert(L, -2); /* ...between the two lines */
208 0 : lua_concat(L, 3); /* join them */
209 : }
210 0 : lua_saveline(L, 1);
211 0 : lua_remove(L, 1); /* remove line */
212 0 : return status;
213 : }
214 :
215 :
216 0 : static void dotty (lua_State *L) {
217 : int status;
218 0 : const char *oldprogname = progname;
219 0 : progname = NULL;
220 0 : while ((status = loadline(L)) != -1) {
221 0 : if (status == 0) status = docall(L, 0, 0);
222 0 : report(L, status);
223 0 : if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
224 0 : lua_getglobal(L, "print");
225 0 : lua_insert(L, 1);
226 0 : if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
227 0 : l_message(progname, lua_pushfstring(L,
228 : "error calling " LUA_QL("print") " (%s)",
229 : lua_tostring(L, -1)));
230 : }
231 : }
232 0 : lua_settop(L, 0); /* clear stack */
233 0 : fputs("\n", stdout);
234 0 : fflush(stdout);
235 0 : progname = oldprogname;
236 0 : }
237 :
238 :
239 58 : static int handle_script (lua_State *L, char **argv, int n) {
240 : int status;
241 : const char *fname;
242 58 : int narg = getargs(L, argv, n); /* collect arguments */
243 58 : lua_setglobal(L, "arg");
244 58 : fname = argv[n];
245 58 : if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
246 1 : fname = NULL; /* stdin */
247 58 : status = luaL_loadfile(L, fname);
248 58 : lua_insert(L, -(narg+1));
249 58 : if (status == 0)
250 57 : status = docall(L, narg, 0);
251 : else
252 1 : lua_pop(L, narg);
253 52 : return report(L, status);
254 : }
255 :
256 :
257 : /* check that argument has no extra characters at the end */
258 : #define notail(x) {if ((x)[2] != '\0') return -1;}
259 :
260 :
261 83 : static int collectargs (char **argv, int *pi, int *pv, int *pe) {
262 : int i;
263 163 : for (i = 1; argv[i] != NULL; i++) {
264 139 : if (argv[i][0] != '-') /* not an option? */
265 56 : return i;
266 83 : switch (argv[i][1]) { /* option */
267 2 : case '-':
268 2 : notail(argv[i]);
269 2 : return (argv[i+1] != NULL ? i+1 : 0);
270 1 : case '\0':
271 1 : return i;
272 0 : case 'i':
273 0 : notail(argv[i]);
274 0 : *pi = 1; /* go through */
275 3 : case 'v':
276 3 : notail(argv[i]);
277 3 : *pv = 1;
278 3 : break;
279 25 : case 'e':
280 25 : *pe = 1; /* go through */
281 77 : case 'l':
282 77 : if (argv[i][2] == '\0') {
283 74 : i++;
284 74 : if (argv[i] == NULL) return -1;
285 : }
286 77 : break;
287 0 : default: return -1; /* invalid option */
288 : }
289 : }
290 24 : return 0;
291 : }
292 :
293 :
294 83 : static int runargs (lua_State *L, char **argv, int n) {
295 : int i;
296 158 : for (i = 1; i < n; i++) {
297 82 : if (argv[i] == NULL) continue;
298 : lua_assert(argv[i][0] == '-');
299 82 : switch (argv[i][1]) { /* option */
300 25 : case 'e': {
301 25 : const char *chunk = argv[i] + 2;
302 25 : if (*chunk == '\0') chunk = argv[++i];
303 : lua_assert(chunk != NULL);
304 25 : if (dostring(L, chunk, "=(command line)") != 0)
305 4 : return 1;
306 18 : break;
307 : }
308 52 : case 'l': {
309 52 : const char *filename = argv[i] + 2;
310 52 : if (*filename == '\0') filename = argv[++i];
311 : lua_assert(filename != NULL);
312 52 : if (dolibrary(L, filename))
313 0 : return 1; /* stop if file fails */
314 52 : break;
315 : }
316 5 : default: break;
317 : }
318 : }
319 76 : return 0;
320 : }
321 :
322 :
323 83 : static int handle_luainit (lua_State *L) {
324 83 : const char *init = getenv(LUA_INIT);
325 83 : if (init == NULL) return 0; /* status OK */
326 83 : else if (init[0] == '@')
327 0 : return dofile(L, init+1);
328 : else
329 83 : return dostring(L, init, "=" LUA_INIT);
330 : }
331 :
332 :
333 : struct Smain {
334 : int argc;
335 : char **argv;
336 : int status;
337 : };
338 :
339 :
340 83 : static int pmain (lua_State *L) {
341 83 : struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
342 83 : char **argv = s->argv;
343 : int script;
344 83 : int has_i = 0, has_v = 0, has_e = 0;
345 83 : globalL = L;
346 83 : if (argv[0] && argv[0][0]) progname = argv[0];
347 83 : lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
348 83 : luaL_openlibs(L); /* open libraries */
349 83 : lua_gc(L, LUA_GCRESTART, 0);
350 83 : s->status = handle_luainit(L);
351 83 : if (s->status != 0) return 0;
352 83 : script = collectargs(argv, &has_i, &has_v, &has_e);
353 83 : if (script < 0) { /* invalid args? */
354 0 : print_usage();
355 0 : s->status = 1;
356 0 : return 0;
357 : }
358 83 : if (has_v) print_version();
359 83 : s->status = runargs(L, argv, (script > 0) ? script : s->argc);
360 80 : if (s->status != 0) return 0;
361 76 : if (script)
362 58 : s->status = handle_script(L, argv, script);
363 70 : if (s->status != 0) return 0;
364 69 : if (has_i)
365 0 : dotty(L);
366 69 : else if (script == 0 && !has_e && !has_v) {
367 1 : if (lua_stdin_is_tty()) {
368 0 : print_version();
369 0 : dotty(L);
370 : }
371 1 : else dofile(L, NULL); /* executes stdin as a file */
372 : }
373 69 : return 0;
374 : }
375 :
376 :
377 83 : int main (int argc, char **argv) {
378 : int status;
379 : struct Smain s;
380 83 : lua_State *L = lua_open(); /* create state */
381 83 : if (L == NULL) {
382 0 : l_message(argv[0], "cannot create state: not enough memory");
383 0 : return EXIT_FAILURE;
384 : }
385 83 : s.argc = argc;
386 83 : s.argv = argv;
387 83 : status = lua_cpcall(L, &pmain, &s);
388 74 : report(L, status);
389 74 : lua_close(L);
390 74 : return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
391 : }
392 :
|