Subversion Repositories WoWGM

Rev

Details | Last modification | View Log | RSS feed

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