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) 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 (incl. lpb_include.h)
37 #include "libfaudes.h"
38 
39 // import all
40 using namespace faudes;
41 
42 // below this line: all from lua provided interpreter lua.cpp, except tagged "luafaudes"
43 static lua_State *globalL = NULL;
44 static const char *progname = LUA_PROGNAME;
45 
46 
47 static void lstop (lua_State *L, lua_Debug *ar) {
48  (void)ar; /* unused arg. */
49  lua_sethook(L, NULL, 0, 0);
50  luaL_error(L, "interrupted!");
51 }
52 
53 
54 static void laction (int i) {
55  signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
56  terminate process (default action) */
57  lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
58 }
59 
60 
61 static void print_usage (void) {
62  fprintf(stderr,
63  "usage: %s [options] [script [args]].\n"
64  "Available options are:\n"
65  " -e stat execute string " LUA_QL("stat") "\n"
66  " -l name require library " LUA_QL("name") "\n"
67  " -i enter interactive mode after executing " LUA_QL("script") "\n"
68  " -v show version information\n"
69  " -d pass on libFAUDES messages to console\n" /* luafaudes: d-option */
70  " -x load libFAUDES extension\n" /* luafaudes: x-option */
71  " -- stop handling options\n"
72  " - execute stdin and stop handling options\n"
73  ,
74  progname);
75  fflush(stderr);
76 }
77 
78 
79 static void l_message (const char *pname, const char *msg) {
80  if (pname) fprintf(stderr, "%s: ", pname);
81  fprintf(stderr, "%s\n", msg);
82  fflush(stderr);
83 }
84 
85 
86 static int report (lua_State *L, int status) {
87  if (status && !lua_isnil(L, -1)) {
88  const char *msg = lua_tostring(L, -1);
89  if (msg == NULL) msg = "(error object is not a string)";
90  l_message(progname, msg);
91  lua_pop(L, 1);
92  }
93  return status;
94 }
95 
96 
97 static int traceback (lua_State *L) {
98  if (!lua_isstring(L, 1)) /* 'message' not a string? */
99  return 1; /* keep it intact */
100  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
101  if (!lua_istable(L, -1)) {
102  lua_pop(L, 1);
103  return 1;
104  }
105  lua_getfield(L, -1, "traceback");
106  if (!lua_isfunction(L, -1)) {
107  lua_pop(L, 2);
108  return 1;
109  }
110  lua_pushvalue(L, 1); /* pass error message */
111  lua_pushinteger(L, 2); /* skip this function and traceback */
112  lua_call(L, 2, 1); /* call debug.traceback */
113  return 1;
114 }
115 
116 
117 static int docall (lua_State *L, int narg, int clear) {
118  int status;
119  int base = lua_gettop(L) - narg; /* function index */
120  lua_pushcfunction(L, traceback); /* push traceback function */
121  lua_insert(L, base); /* put it under chunk and args */
122  signal(SIGINT, laction);
123  status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
124  signal(SIGINT, SIG_DFL);
125  lua_remove(L, base); /* remove traceback function */
126  /* force a complete garbage collection in case of errors */
127  if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
128  return status;
129 }
130 
131 
132 // luafaudes: my print version
133 static void print_version (void) {
134  std::stringstream sstr;
135  sstr
136  << "Welcome to luafaudes console." << std::endl
137  << "Versions: " << VersionString() << " / " << LUA_VERSION << std::endl
138  << "Plug-Ins: " << PluginsString() << std::endl
139  << "Credits: This libFAUDES interpreter is based on the projects Lua and SWIG." << std::endl
140  << "Type 'faudes.Help()' for a list of faudes related types and functions." << std::endl
141  << "Enter Ctrl-C to exit the luafaudes interpreter" << std::endl;
142  l_message(NULL, sstr.str().c_str());
143 }
144 
145 
146 static int getargs (lua_State *L, char **argv, int n) {
147  int narg;
148  int i;
149  int argc = 0;
150  while (argv[argc]) argc++; /* count total number of arguments */
151  narg = argc - (n + 1); /* number of arguments to the script */
152  luaL_checkstack(L, narg + 3, "too many arguments to script");
153  for (i=n+1; i < argc; i++)
154  lua_pushstring(L, argv[i]);
155  lua_createtable(L, narg, n + 1);
156  for (i=0; i < argc; i++) {
157  lua_pushstring(L, argv[i]);
158  lua_rawseti(L, -2, i - n);
159  }
160  return narg;
161 }
162 
163 
164 static int dofile (lua_State *L, const char *name) {
165  int status = luaL_loadfile(L, name) || docall(L, 0, 1);
166  return report(L, status);
167 }
168 
169 
170 static int dostring (lua_State *L, const char *s, const char *name) {
171  int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
172  return report(L, status);
173 }
174 
175 
176 static int dolibrary (lua_State *L, const char *name) {
177  lua_getglobal(L, "require");
178  lua_pushstring(L, name);
179  return report(L, docall(L, 1, 1));
180 }
181 
182 
183 
184 /* ------------------------------------------------------------------------ */
185 
186 #ifdef LUA_USE_READLINE
187 /*
188 
189 ** luafaudes: here used to be advanced readline support patch by Mike Pall. However,
190 ** we required some variations for SWIG __index functions and we also wanted identifier-
191 ** completion in DESTool. Thus, we moved the original completer code to LuaState
192 ** (see lbp_function.cpp and lbp_completer.cpp) and provide a C interface via
193 ** luafaudes_complete() (see lbp_addons.cpp). The below code is reduced to the libreadline
194 ** interface. The original patch still ships with libFAUDES for reference and can be
195 ** inspected in lua.c in the Lua source tree. TMoor.
196 
197 ** Advanced readline support for the GNU readline and history libraries
198 ** or compatible replacements.
199 **
200 ** Copyright (C) 2004-2006 Mike Pall. Same license as Lua. See lua.h.
201 **
202 ** The (original) patch has been successfully tested with:
203 **
204 ** GNU readline 2.2.1 (1998-07-17)
205 ** GNU readline 4.0 (1999-02-18) [harmless compiler warning]
206 ** GNU readline 4.3 (2002-07-16)
207 ** GNU readline 5.0 (2004-07-27)
208 ** GNU readline 5.1 (2005-12-07)
209 ** NETBSD libedit 2.6.5 (2002-03-25)
210 ** NETBSD libedit 2.6.9 (2004-05-01)
211 */
212 
213 #include <ctype.h>
214 
215 static char *lua_rl_hist;
216 static int lua_rl_histsize;
217 
218 static lua_State *lua_rl_L; /* User data is not passed to rl callbacks. */
219 
220 /* luafaudes: pass on global state */
221 static char **faudes_complete_L(const char *text, int start, int end) {
222  return faudes_complete(lua_rl_L,text,start,end);
223 }
224 
225 /* Initialize readline library. */
226 static void lua_rl_init(lua_State *L)
227 {
228  char *s;
229 
230  lua_rl_L = L;
231 
232  /* This allows for $if lua ... $endif in ~/.inputrc. */
233  rl_readline_name = "lua";
234  /* Break words at every non-identifier character except '.' and ':'. */
235  rl_completer_word_break_characters = (char *)
236  "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~"; // luafaudes: pragmatic avoidance of compiler warning
237 
238  rl_completer_quote_characters = "\"'";
239  rl_completion_append_character = '\0';
240  rl_attempted_completion_function = faudes_complete_L; // luafaudes: use libFAUDES variant
241  rl_initialize();
242 
243  /* Start using history, optionally set history size and load history file. */
244  using_history();
245  if ((s = getenv("LUA_HISTSIZE")) &&
246  (lua_rl_histsize = atoi(s))) stifle_history(lua_rl_histsize);
247  if ((lua_rl_hist = getenv("LUA_HISTORY"))) read_history(lua_rl_hist);
248 }
249 
250 /* Finalize readline library. */
251 static void lua_rl_exit(lua_State *L)
252 {
253  /* Optionally save history file. */
254  if (lua_rl_hist) write_history(lua_rl_hist);
255 }
256 #else
257 #define lua_rl_init(L) ((void)L)
258 #define lua_rl_exit(L) ((void)L)
259 #endif
260 
261 /* ------------------------------------------------------------------------ */
262 
263 
264 static const char *get_prompt (lua_State *L, int firstline) {
265  const char *p;
266  lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
267  p = lua_tostring(L, -1);
268  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
269  lua_pop(L, 1); /* remove global */
270  return p;
271 }
272 
273 
274 static int incomplete (lua_State *L, int status) {
275  if (status == LUA_ERRSYNTAX) {
276  size_t lmsg;
277  const char *msg = lua_tolstring(L, -1, &lmsg);
278  const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
279  if (strstr(msg, LUA_QL("<eof>")) == tp) {
280  lua_pop(L, 1);
281  return 1;
282  }
283  }
284  return 0; /* else... */
285 }
286 
287 
288 static int pushline (lua_State *L, int firstline) {
289  char buffer[LUA_MAXINPUT];
290  char *b = buffer;
291  size_t l;
292  const char *prmt = get_prompt(L, firstline);
293  if (lua_readline(L, b, prmt) == 0)
294  return 0; /* no input */
295  l = strlen(b);
296  if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
297  b[l-1] = '\0'; /* remove it */
298  if (firstline && b[0] == '=') /* first line starts with `=' ? */
299  lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
300  else
301  lua_pushstring(L, b);
302  lua_freeline(L, b);
303  return 1;
304 }
305 
306 
307 static int loadline (lua_State *L) {
308  int status;
309  lua_settop(L, 0);
310  if (!pushline(L, 1))
311  return -1; /* no input */
312  for (;;) { /* repeat until gets a complete line */
313  status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
314  if (!incomplete(L, status)) break; /* cannot try to add lines? */
315  if (!pushline(L, 0)) /* no more input? */
316  return -1;
317  lua_pushliteral(L, "\n"); /* add a new line... */
318  lua_insert(L, -2); /* ...between the two lines */
319  lua_concat(L, 3); /* join them */
320  }
321  lua_saveline(L, 1);
322  lua_remove(L, 1); /* remove line */
323  return status;
324 }
325 
326 
327 static void dotty (lua_State *L) {
328  int status;
329  const char *oldprogname = progname;
330  progname = NULL;
331  lua_rl_init(L);
332  while ((status = loadline(L)) != -1) {
333  if (status == 0) status = docall(L, 0, 0);
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 (faudes_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  faudes_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) faudes_mute(true); /* luafaudes: mute */
499  if (!has_x) faudes_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
int main(int argc, char *argv[])
Includes all libFAUDES headers, incl plugings
libFAUDES resides within the namespace faudes.
std::string VersionString()
Return FAUDES_VERSION as std::string.
Definition: cfl_helper.cpp:131
FAUDES_API void faudes_mute(bool on)
std::string PluginsString()
Return FAUDES_PLUGINS as std::string.
Definition: cfl_helper.cpp:136
int faudes_loadext(lua_State *pL, const char *filename)
Definition: lbp_addons.cpp:133
void faudes_initialize(lua_State *pL)
Definition: lbp_addons.cpp:128
char ** faudes_complete(lua_State *pL, const char *text, int start, int end)
Definition: lbp_addons.cpp:156
int faudes_loaddefext(lua_State *pL, const char *arg0)
Definition: lbp_addons.cpp:144

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen