Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/lua-5.1.3/src/lua.c @ 28

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