luafaudes.cpp
Go to the documentation of this file.
1 /** @file luafaudes.cpp Simple Lua stand-alone interpreter for lua/faudes
2 
3  This lua interpreter is almost a plain copy of the original lua.c
4  provided with the lua 5.1.3 distribution and under an MIT license;
5  see original lua.h or http://www.lua.org
6 
7  The Advanced-Readline patch has been applied, also with lua license,
8  copyright see below. SWIG based Lua bindings and minor adjustments
9  (wellcome string, logging) have been added (and signed "luafaudes").
10  Thomas Moor, 2008.
11 
12 
13 @ingroup Tutorials
14 
15 
16 */
17 
18 
19 // luafaudes: skip doxygen
20 #ifndef FAUDES_DOXYGEN
21 
22 /*
23 ** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
24 ** Lua stand-alone interpreter
25 ** See Copyright Notice in lua.h
26 */
27 
28 
29 // luafaudes: include c libs since we dont use lua.h
30 #include <csignal>
31 #include <cstdio>
32 #include <cstdlib>
33 #include <cstring>
34 
35 
36 // luafaudes: use my include file
37 #include "libluafaudes.h"
38 
39 // below this line: all from lua provided interpreter lua.cpp, except tagged "luafaudes"
40 
41 static lua_State *globalL = NULL;
42 static const char *progname = LUA_PROGNAME;
43 
44 
45 static void lstop (lua_State *L, lua_Debug *ar) {
46  (void)ar; /* unused arg. */
47  lua_sethook(L, NULL, 0, 0);
48  luaL_error(L, "interrupted!");
49 }
50 
51 
52 static void laction (int i) {
53  signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
54  terminate process (default action) */
55  lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
56 }
57 
58 
59 static void print_usage (void) {
60  fprintf(stderr,
61  "usage: %s [options] [script [args]].\n"
62  "Available options are:\n"
63  " -e stat execute string " LUA_QL("stat") "\n"
64  " -l name require library " LUA_QL("name") "\n"
65  " -i enter interactive mode after executing " LUA_QL("script") "\n"
66  " -v show version information\n"
67  " -d pass on libFAUDES messages to console\n" /* luafaudes: d-option */
68  " -x load libFAUDES extension\n" /* luafaudes: x-option */
69  " -- stop handling options\n"
70  " - execute stdin and stop handling options\n"
71  ,
72  progname);
73  fflush(stderr);
74 }
75 
76 
77 static void l_message (const char *pname, const char *msg) {
78  if (pname) fprintf(stderr, "%s: ", pname);
79  fprintf(stderr, "%s\n", msg);
80  fflush(stderr);
81 }
82 
83 
84 static int report (lua_State *L, int status) {
85  if (status && !lua_isnil(L, -1)) {
86  const char *msg = lua_tostring(L, -1);
87  if (msg == NULL) msg = "(error object is not a string)";
88  l_message(progname, msg);
89  lua_pop(L, 1);
90  }
91  return status;
92 }
93 
94 
95 static int traceback (lua_State *L) {
96  if (!lua_isstring(L, 1)) /* 'message' not a string? */
97  return 1; /* keep it intact */
98  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
99  if (!lua_istable(L, -1)) {
100  lua_pop(L, 1);
101  return 1;
102  }
103  lua_getfield(L, -1, "traceback");
104  if (!lua_isfunction(L, -1)) {
105  lua_pop(L, 2);
106  return 1;
107  }
108  lua_pushvalue(L, 1); /* pass error message */
109  lua_pushinteger(L, 2); /* skip this function and traceback */
110  lua_call(L, 2, 1); /* call debug.traceback */
111  return 1;
112 }
113 
114 
115 static int docall (lua_State *L, int narg, int clear) {
116  int status;
117  int base = lua_gettop(L) - narg; /* function index */
118  lua_pushcfunction(L, traceback); /* push traceback function */
119  lua_insert(L, base); /* put it under chunk and args */
120  signal(SIGINT, laction);
121  status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
122  signal(SIGINT, SIG_DFL);
123  lua_remove(L, base); /* remove traceback function */
124  /* force a complete garbage collection in case of errors */
125  if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
126  return status;
127 }
128 
129 
130 // luafaudes: my print version
131 static void print_version (void) {
132  std::stringstream sstr;
133  sstr
134  << "Welcome to luafaudes console." << std::endl
135  << "Versions: " << faudes::VersionString() << " / " << LUA_VERSION << std::endl
136  << "Plug-Ins: " << faudes::PluginsString() << std::endl
137  << "Credits: This libFAUDES interpreter is based on the projects Lua and SWIG." << std::endl
138  << "Type 'faudes.Help()' for a list of faudes related types and functions." << std::endl
139  << "Enter Ctrl-C to exit the luafaudes interpreter" << std::endl;
140  l_message(NULL, sstr.str().c_str());
141 }
142 
143 
144 static int getargs (lua_State *L, char **argv, int n) {
145  int narg;
146  int i;
147  int argc = 0;
148  while (argv[argc]) argc++; /* count total number of arguments */
149  narg = argc - (n + 1); /* number of arguments to the script */
150  luaL_checkstack(L, narg + 3, "too many arguments to script");
151  for (i=n+1; i < argc; i++)
152  lua_pushstring(L, argv[i]);
153  lua_createtable(L, narg, n + 1);
154  for (i=0; i < argc; i++) {
155  lua_pushstring(L, argv[i]);
156  lua_rawseti(L, -2, i - n);
157  }
158  return narg;
159 }
160 
161 
162 static int dofile (lua_State *L, const char *name) {
163  int status = luaL_loadfile(L, name) || docall(L, 0, 1);
164  return report(L, status);
165 }
166 
167 
168 static int dostring (lua_State *L, const char *s, const char *name) {
169  int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
170  return report(L, status);
171 }
172 
173 
174 static int dolibrary (lua_State *L, const char *name) {
175  lua_getglobal(L, "require");
176  lua_pushstring(L, name);
177  return report(L, docall(L, 1, 1));
178 }
179 
180 
181 
182 /* ------------------------------------------------------------------------ */
183 
184 #ifdef LUA_USE_READLINE
185 /*
186 
187 ** luafaudes: here used to be advanced readline support patch by Mike Pall. However,
188 ** we required some variations for SWIG __index functions and we also wanted identifier-
189 ** completion in DESTool. Thus, we moved the original completer code to LuaState
190 ** (see lbp_function.cpp and lbp_completer.cpp) and provide a C interface via
191 ** luafaudes_complete() (see common.i). The below code is reduced to the libreadline
192 ** interface. The original patch still ships with libFAUDES for reference and can be
193 ** inspected in lua.c in the Lua source tree. TMoor.
194 
195 ** Advanced readline support for the GNU readline and history libraries
196 ** or compatible replacements.
197 **
198 ** Copyright (C) 2004-2006 Mike Pall. Same license as Lua. See lua.h.
199 **
200 ** The (original) patch has been successfully tested with:
201 **
202 ** GNU readline 2.2.1 (1998-07-17)
203 ** GNU readline 4.0 (1999-02-18) [harmless compiler warning]
204 ** GNU readline 4.3 (2002-07-16)
205 ** GNU readline 5.0 (2004-07-27)
206 ** GNU readline 5.1 (2005-12-07)
207 ** NETBSD libedit 2.6.5 (2002-03-25)
208 ** NETBSD libedit 2.6.9 (2004-05-01)
209 */
210 
211 #include <ctype.h>
212 
213 static char *lua_rl_hist;
214 static int lua_rl_histsize;
215 
216 static lua_State *lua_rl_L; /* User data is not passed to rl callbacks. */
217 
218 /* luafaudes: pass on global state */
219 static char **luafaudes_complete_L(const char *text, int start, int end) {
220  return luafaudes_complete(lua_rl_L,text,start,end);
221 }
222 
223 /* Initialize readline library. */
224 static void lua_rl_init(lua_State *L)
225 {
226  char *s;
227 
228  lua_rl_L = L;
229 
230  /* This allows for $if lua ... $endif in ~/.inputrc. */
231  rl_readline_name = "lua";
232  /* Break words at every non-identifier character except '.' and ':'. */
233  rl_completer_word_break_characters = (char *)
234  "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~"; // luafaudes: pragmatic avoidance of compiler warning
235 
236  rl_completer_quote_characters = "\"'";
237  rl_completion_append_character = '\0';
238  rl_attempted_completion_function = luafaudes_complete_L; // luafaudes: use libFAUDES variant
239  rl_initialize();
240 
241  /* Start using history, optionally set history size and load history file. */
242  using_history();
243  if ((s = getenv("LUA_HISTSIZE")) &&
244  (lua_rl_histsize = atoi(s))) stifle_history(lua_rl_histsize);
245  if ((lua_rl_hist = getenv("LUA_HISTORY"))) read_history(lua_rl_hist);
246 }
247 
248 /* Finalize readline library. */
249 static void lua_rl_exit(lua_State *L)
250 {
251  /* Optionally save history file. */
252  if (lua_rl_hist) write_history(lua_rl_hist);
253 }
254 #else
255 #define lua_rl_init(L) ((void)L)
256 #define lua_rl_exit(L) ((void)L)
257 #endif
258 
259 /* ------------------------------------------------------------------------ */
260 
261 
262 static const char *get_prompt (lua_State *L, int firstline) {
263  const char *p;
264  lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
265  p = lua_tostring(L, -1);
266  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
267  lua_pop(L, 1); /* remove global */
268  return p;
269 }
270 
271 
272 static int incomplete (lua_State *L, int status) {
273  if (status == LUA_ERRSYNTAX) {
274  size_t lmsg;
275  const char *msg = lua_tolstring(L, -1, &lmsg);
276  const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
277  if (strstr(msg, LUA_QL("<eof>")) == tp) {
278  lua_pop(L, 1);
279  return 1;
280  }
281  }
282  return 0; /* else... */
283 }
284 
285 
286 static int pushline (lua_State *L, int firstline) {
287  char buffer[LUA_MAXINPUT];
288  char *b = buffer;
289  size_t l;
290  const char *prmt = get_prompt(L, firstline);
291  if (lua_readline(L, b, prmt) == 0)
292  return 0; /* no input */
293  l = strlen(b);
294  luafaudes_lastline=b; // luafaudes: logging
295  if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
296  b[l-1] = '\0'; /* remove it */
297  if (firstline && b[0] == '=') /* first line starts with `=' ? */
298  lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
299  else
300  lua_pushstring(L, b);
301  lua_freeline(L, b);
302  return 1;
303 }
304 
305 
306 static int loadline (lua_State *L) {
307  int status;
308  lua_settop(L, 0);
309  if (!pushline(L, 1))
310  return -1; /* no input */
311  for (;;) { /* repeat until gets a complete line */
312  status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
313  if (!incomplete(L, status)) break; /* cannot try to add lines? */
314  if (!pushline(L, 0)) /* no more input? */
315  return -1;
316  lua_pushliteral(L, "\n"); /* add a new line... */
317  lua_insert(L, -2); /* ...between the two lines */
318  lua_concat(L, 3); /* join them */
319  }
320  lua_saveline(L, 1);
321  lua_remove(L, 1); /* remove line */
322  return status;
323 }
324 
325 
326 static void dotty (lua_State *L) {
327  int status;
328  const char *oldprogname = progname;
329  progname = NULL;
330  lua_rl_init(L);
331  while ((status = loadline(L)) != -1) {
332  if (status == 0) status = docall(L, 0, 0);
333  luafaudes_logwrite(luafaudes_lastline); // luafaudes: logging
334  report(L, status);
335  if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
336  lua_getglobal(L, "print");
337  lua_insert(L, 1);
338  if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
339  l_message(progname, lua_pushfstring(L,
340  "error calling " LUA_QL("print") " (%s)",
341  lua_tostring(L, -1)));
342  }
343  }
344  lua_settop(L, 0); /* clear stack */
345  fputs("\n", stdout);
346  fflush(stdout);
347  lua_rl_exit(L);
348  progname = oldprogname;
349 }
350 
351 static int handle_script (lua_State *L, char **argv, int n) {
352  int status;
353  const char *fname;
354  int narg = getargs(L, argv, n); /* collect arguments */
355  lua_setglobal(L, "arg");
356  fname = argv[n];
357  if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
358  fname = NULL; /* stdin */
359  status = luaL_loadfile(L, fname);
360  lua_insert(L, -(narg+1));
361  if (status == 0)
362  status = docall(L, narg, 0);
363  else
364  lua_pop(L, narg);
365  return report(L, status);
366 }
367 
368 
369 /* check that argument has no extra characters at the end */
370 #define notail(x) {if ((x)[2] != '\0') return -1;}
371 
372 
373 // luafaudes: have extra options -d and -x
374 static int collectargs (char **argv, int *pi, int *pv, int *pe, int *pd, int *px) {
375  int i;
376  for (i = 1; argv[i] != NULL; i++) {
377  if (argv[i][0] != '-') /* not an option? */
378  return i;
379  switch (argv[i][1]) { /* option */
380  case '-':
381  notail(argv[i]);
382  return (argv[i+1] != NULL ? i+1 : 0);
383  case '\0':
384  return i;
385  case 'i':
386  notail(argv[i]);
387  *pi = 1; /* go through */
388  case 'v':
389  notail(argv[i]);
390  *pv = 1;
391  break;
392  case 'e':
393  *pe = 1; /* go through */
394  case 'l':
395  if (argv[i][2] == '\0') {
396  i++;
397  if (argv[i] == NULL) return -1;
398  }
399  break;
400  case 'd': // luafaudes: d-option
401  notail(argv[i]);
402  *pd = 1;
403  break;
404  case 'x': // luafaudes: x-option
405  if (argv[i][2] == '\0') {
406  i++;
407  if (argv[i] == NULL) return -1;
408  }
409  *px = 1;
410  break;
411  default: return -1; /* invalid option */
412  }
413  }
414  return 0;
415 }
416 
417 
418 // luafaudes: have extra option -x
419 static int runargs (lua_State *L, char **argv, int n) {
420  int i;
421  for (i = 1; i < n; i++) {
422  if (argv[i] == NULL) continue;
423  lua_assert(argv[i][0] == '-');
424  switch (argv[i][1]) { /* option */
425  case 'e': {
426  const char *chunk = argv[i] + 2;
427  if (*chunk == '\0') chunk = argv[++i];
428  lua_assert(chunk != NULL);
429  if (dostring(L, chunk, "=(command line)") != 0)
430  return 1;
431  break;
432  }
433  case 'l': {
434  const char *filename = argv[i] + 2;
435  if (*filename == '\0') filename = argv[++i];
436  lua_assert(filename != NULL);
437  if (dolibrary(L, filename))
438  return 1; /* stop if file fails */
439  break;
440  }
441  case 'x': { // luafaudes option x
442  const char *filename = argv[i] + 2;
443  if (*filename == '\0') filename = argv[++i];
444  lua_assert(filename != NULL);
445  if (luafaudes_loadext(L, filename)) {
446  l_message("fatal error: failed to load extension", filename);
447  return 1; /* stop if file fails */
448  }
449  break;
450  }
451  default: break;
452  }
453  }
454  return 0;
455 }
456 
457 
458 static int handle_luainit (lua_State *L) {
459  const char *init = getenv(LUA_INIT);
460  if (init == NULL) return 0; /* status OK */
461  else if (init[0] == '@')
462  return dofile(L, init+1);
463  else
464  return dostring(L, init, "=" LUA_INIT);
465 }
466 
467 
468 struct Smain {
469  int argc;
470  char **argv;
471  int status;
472 };
473 
474 
475 static int pmain (lua_State *L) {
476  struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
477  char **argv = s->argv;
478  int script;
479  int has_i = 0, has_v = 0, has_e = 0, has_d=0, has_x=0; // luafaudes: -d and -x option
480  globalL = L;
481  if (argv[0] && argv[0][0]) progname = argv[0];
482  luafaudes_initialize(L); // luafaudes: all of the below plus my namespace
483  /*
484  // original lua
485  lua_gc(L, LUA_GCSTOP, 0);
486  luaL_openlibs(L);
487  lua_gc(L, LUA_GCRESTART, 0);
488  */
489  s->status = handle_luainit(L);
490  if (s->status != 0) return 0;
491  script = collectargs(argv, &has_i, &has_v, &has_e, &has_d, &has_x); // luafaudes: -d and -x option
492  if (script < 0) { /* invalid args? */
493  print_usage();
494  s->status = 1;
495  return 0;
496  }
497  if (has_v) print_version();
498  if (!has_d) luafaudes_mute(true); /* luafaudes: mute */
499  if (!has_x) luafaudes_loaddefext(L, argv[0]); /* luafaudes: default extension */
500  s->status = runargs(L, argv, (script > 0) ? script : s->argc);
501  if (s->status != 0) return 0;
502  if (script)
503  s->status = handle_script(L, argv, script);
504  if (s->status != 0) return 0;
505  if (has_i)
506  dotty(L);
507  else if (script == 0 && !has_e && !has_v) {
508  if (lua_stdin_is_tty()) {
509  print_version();
510  dotty(L);
511  }
512  else dofile(L, NULL); /* executes stdin as a file */
513  }
514  return 0;
515 }
516 
517 
518 int main (int argc, char **argv) {
519  int status;
520  struct Smain s;
521  lua_State *L = lua_open(); /* create state */
522  if (L == NULL) {
523  l_message(argv[0], "cannot create state: not enough memory");
524  return EXIT_FAILURE;
525  }
526  s.argc = argc;
527  s.argv = argv;
528  status = lua_cpcall(L, &pmain, &s);
529  report(L, status);
530  lua_close(L);
531  return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
532 }
533 
534 
535 // luafaudes: end skip doxygen
536 #endif

libFAUDES 2.24g --- 2014.09.15 --- c++ api documentaion by doxygen