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  << "Build: " << BuildString() << std::endl
139  << "Plug-Ins: " << PluginsString() << std::endl
140  << "Credits: This libFAUDES interpreter is based on the projects Lua and SWIG." << std::endl
141  << "Type 'faudes.Help()' for a list of faudes related types and functions." << std::endl
142  << "Enter Ctrl-C to exit the luafaudes interpreter" << std::endl;
143  l_message(NULL, sstr.str().c_str());
144 }
145 
146 
147 static int getargs (lua_State *L, char **argv, int n) {
148  int narg;
149  int i;
150  int argc = 0;
151  while (argv[argc]) argc++; /* count total number of arguments */
152  narg = argc - (n + 1); /* number of arguments to the script */
153  luaL_checkstack(L, narg + 3, "too many arguments to script");
154  for (i=n+1; i < argc; i++)
155  lua_pushstring(L, argv[i]);
156  lua_createtable(L, narg, n + 1);
157  for (i=0; i < argc; i++) {
158  lua_pushstring(L, argv[i]);
159  lua_rawseti(L, -2, i - n);
160  }
161  return narg;
162 }
163 
164 
165 static int dofile (lua_State *L, const char *name) {
166  int status = luaL_loadfile(L, name) || docall(L, 0, 1);
167  return report(L, status);
168 }
169 
170 
171 static int dostring (lua_State *L, const char *s, const char *name) {
172  int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
173  return report(L, status);
174 }
175 
176 
177 static int dolibrary (lua_State *L, const char *name) {
178  lua_getglobal(L, "require");
179  lua_pushstring(L, name);
180  return report(L, docall(L, 1, 1));
181 }
182 
183 
184 
185 /* ------------------------------------------------------------------------ */
186 
187 #ifdef LUA_USE_READLINE
188 /*
189 
190 ** luafaudes: here used to be advanced readline support patch by Mike Pall. However,
191 ** we required some variations for SWIG __index functions and we also wanted identifier-
192 ** completion in DESTool. Thus, we moved the original completer code to LuaState
193 ** (see lbp_function.cpp and lbp_completer.cpp) and provide a C interface via
194 ** luafaudes_complete() (see lbp_addons.cpp). The below code is reduced to the libreadline
195 ** interface. The original patch still ships with libFAUDES for reference and can be
196 ** inspected in lua.c in the Lua source tree. TMoor.
197 
198 ** Advanced readline support for the GNU readline and history libraries
199 ** or compatible replacements.
200 **
201 ** Copyright (C) 2004-2006 Mike Pall. Same license as Lua. See lua.h.
202 **
203 ** The (original) patch has been successfully tested with:
204 **
205 ** GNU readline 2.2.1 (1998-07-17)
206 ** GNU readline 4.0 (1999-02-18) [harmless compiler warning]
207 ** GNU readline 4.3 (2002-07-16)
208 ** GNU readline 5.0 (2004-07-27)
209 ** GNU readline 5.1 (2005-12-07)
210 ** NETBSD libedit 2.6.5 (2002-03-25)
211 ** NETBSD libedit 2.6.9 (2004-05-01)
212 */
213 
214 #include <ctype.h>
215 
216 static char *lua_rl_hist;
217 static int lua_rl_histsize;
218 
219 static lua_State *lua_rl_L; /* User data is not passed to rl callbacks. */
220 
221 /* luafaudes: pass on global state */
222 static char **faudes_complete_L(const char *text, int start, int end) {
223  return faudes_complete(lua_rl_L,text,start,end);
224 }
225 
226 /* Initialize readline library. */
227 static void lua_rl_init(lua_State *L)
228 {
229  char *s;
230 
231  lua_rl_L = L;
232 
233  /* This allows for $if lua ... $endif in ~/.inputrc. */
234  rl_readline_name = "lua";
235  /* Break words at every non-identifier character except '.' and ':'. */
236  rl_completer_word_break_characters = (char *)
237  "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~"; // luafaudes: pragmatic avoidance of compiler warning
238 
239  rl_completer_quote_characters = "\"'";
240  rl_completion_append_character = '\0';
241  rl_attempted_completion_function = faudes_complete_L; // luafaudes: use libFAUDES variant
242  rl_initialize();
243 
244  /* Start using history, optionally set history size and load history file. */
245  using_history();
246  if ((s = getenv("LUA_HISTSIZE")) &&
247  (lua_rl_histsize = atoi(s))) stifle_history(lua_rl_histsize);
248  if ((lua_rl_hist = getenv("LUA_HISTORY"))) read_history(lua_rl_hist);
249 }
250 
251 /* Finalize readline library. */
252 static void lua_rl_exit(lua_State *L)
253 {
254  /* Optionally save history file. */
255  if (lua_rl_hist) write_history(lua_rl_hist);
256 }
257 #else
258 #define lua_rl_init(L) ((void)L)
259 #define lua_rl_exit(L) ((void)L)
260 #endif
261 
262 /* ------------------------------------------------------------------------ */
263 
264 
265 static const char *get_prompt (lua_State *L, int firstline) {
266  const char *p;
267  lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
268  p = lua_tostring(L, -1);
269  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
270  lua_pop(L, 1); /* remove global */
271  return p;
272 }
273 
274 
275 static int incomplete (lua_State *L, int status) {
276  if (status == LUA_ERRSYNTAX) {
277  size_t lmsg;
278  const char *msg = lua_tolstring(L, -1, &lmsg);
279  const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
280  if (strstr(msg, LUA_QL("<eof>")) == tp) {
281  lua_pop(L, 1);
282  return 1;
283  }
284  }
285  return 0; /* else... */
286 }
287 
288 
289 static int pushline (lua_State *L, int firstline) {
290  char buffer[LUA_MAXINPUT];
291  char *b = buffer;
292  size_t l;
293  const char *prmt = get_prompt(L, firstline);
294  if (lua_readline(L, b, prmt) == 0)
295  return 0; /* no input */
296  l = strlen(b);
297  if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
298  b[l-1] = '\0'; /* remove it */
299  if (firstline && b[0] == '=') /* first line starts with `=' ? */
300  lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
301  else
302  lua_pushstring(L, b);
303  lua_freeline(L, b);
304  return 1;
305 }
306 
307 
308 static int loadline (lua_State *L) {
309  int status;
310  lua_settop(L, 0);
311  if (!pushline(L, 1))
312  return -1; /* no input */
313  for (;;) { /* repeat until gets a complete line */
314  status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
315  if (!incomplete(L, status)) break; /* cannot try to add lines? */
316  if (!pushline(L, 0)) /* no more input? */
317  return -1;
318  lua_pushliteral(L, "\n"); /* add a new line... */
319  lua_insert(L, -2); /* ...between the two lines */
320  lua_concat(L, 3); /* join them */
321  }
322  lua_saveline(L, 1);
323  lua_remove(L, 1); /* remove line */
324  return status;
325 }
326 
327 
328 static void dotty (lua_State *L) {
329  int status;
330  const char *oldprogname = progname;
331  progname = NULL;
332  lua_rl_init(L);
333  while ((status = loadline(L)) != -1) {
334  if (status == 0) status = docall(L, 0, 0);
335  report(L, status);
336  if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
337  lua_getglobal(L, "print");
338  lua_insert(L, 1);
339  if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
340  l_message(progname, lua_pushfstring(L,
341  "error calling " LUA_QL("print") " (%s)",
342  lua_tostring(L, -1)));
343  }
344  }
345  lua_settop(L, 0); /* clear stack */
346  fputs("\n", stdout);
347  fflush(stdout);
348  lua_rl_exit(L);
349  progname = oldprogname;
350 }
351 
352 static int handle_script (lua_State *L, char **argv, int n) {
353  int status;
354  const char *fname;
355  int narg = getargs(L, argv, n); /* collect arguments */
356  lua_setglobal(L, "arg");
357  fname = argv[n];
358  if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
359  fname = NULL; /* stdin */
360  status = luaL_loadfile(L, fname);
361  lua_insert(L, -(narg+1));
362  if (status == 0)
363  status = docall(L, narg, 0);
364  else
365  lua_pop(L, narg);
366  return report(L, status);
367 }
368 
369 
370 /* check that argument has no extra characters at the end */
371 #define notail(x) {if ((x)[2] != '\0') return -1;}
372 
373 
374 // luafaudes: have extra options -d and -x
375 static int collectargs (char **argv, int *pi, int *pv, int *pe, int *pd, int *px) {
376  int i;
377  for (i = 1; argv[i] != NULL; i++) {
378  if (argv[i][0] != '-') /* not an option? */
379  return i;
380  switch (argv[i][1]) { /* option */
381  case '-':
382  notail(argv[i]);
383  return (argv[i+1] != NULL ? i+1 : 0);
384  case '\0':
385  return i;
386  case 'i':
387  notail(argv[i]);
388  *pi = 1; /* go through */
389  case 'v':
390  notail(argv[i]);
391  *pv = 1;
392  break;
393  case 'e':
394  *pe = 1; /* go through */
395  case 'l':
396  if (argv[i][2] == '\0') {
397  i++;
398  if (argv[i] == NULL) return -1;
399  }
400  break;
401  case 'd': // luafaudes: d-option
402  notail(argv[i]);
403  *pd = 1;
404  break;
405  case 'x': // luafaudes: x-option
406  if (argv[i][2] == '\0') {
407  i++;
408  if (argv[i] == NULL) return -1;
409  }
410  *px = 1;
411  break;
412  default: return -1; /* invalid option */
413  }
414  }
415  return 0;
416 }
417 
418 
419 // luafaudes: have extra option -x
420 static int runargs (lua_State *L, char **argv, int n) {
421  int i;
422  for (i = 1; i < n; i++) {
423  if (argv[i] == NULL) continue;
424  lua_assert(argv[i][0] == '-');
425  switch (argv[i][1]) { /* option */
426  case 'e': {
427  const char *chunk = argv[i] + 2;
428  if (*chunk == '\0') chunk = argv[++i];
429  lua_assert(chunk != NULL);
430  if (dostring(L, chunk, "=(command line)") != 0)
431  return 1;
432  break;
433  }
434  case 'l': {
435  const char *filename = argv[i] + 2;
436  if (*filename == '\0') filename = argv[++i];
437  lua_assert(filename != NULL);
438  if (dolibrary(L, filename))
439  return 1; /* stop if file fails */
440  break;
441  }
442  case 'x': { // luafaudes option x
443  const char *filename = argv[i] + 2;
444  if (*filename == '\0') filename = argv[++i];
445  lua_assert(filename != NULL);
446  if (faudes_loadext(L, filename)) {
447  l_message("fatal error: failed to load extension", filename);
448  return 1; /* stop if file fails */
449  }
450  break;
451  }
452  default: break;
453  }
454  }
455  return 0;
456 }
457 
458 
459 static int handle_luainit (lua_State *L) {
460  const char *init = getenv(LUA_INIT);
461  if (init == NULL) return 0; /* status OK */
462  else if (init[0] == '@')
463  return dofile(L, init+1);
464  else
465  return dostring(L, init, "=" LUA_INIT);
466 }
467 
468 
469 struct Smain {
470  int argc;
471  char **argv;
472  int status;
473 };
474 
475 
476 static int pmain (lua_State *L) {
477  struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
478  char **argv = s->argv;
479  int script;
480  int has_i = 0, has_v = 0, has_e = 0, has_d=0, has_x=0; // luafaudes: -d and -x option
481  globalL = L;
482  if (argv[0] && argv[0][0]) progname = argv[0];
483  faudes_initialize(L); // luafaudes: all of the below plus my namespace
484  /*
485  // original lua
486  lua_gc(L, LUA_GCSTOP, 0);
487  luaL_openlibs(L);
488  lua_gc(L, LUA_GCRESTART, 0);
489  */
490  s->status = handle_luainit(L);
491  if (s->status != 0) return 0;
492  script = collectargs(argv, &has_i, &has_v, &has_e, &has_d, &has_x); // luafaudes: -d and -x option
493  if (script < 0) { /* invalid args? */
494  print_usage();
495  s->status = 1;
496  return 0;
497  }
498  if (has_v) print_version();
499  if (!has_d) faudes_mute(true); /* luafaudes: mute */
500  if (!has_x) faudes_loaddefext(L, argv[0]); /* luafaudes: default extension */
501  s->status = runargs(L, argv, (script > 0) ? script : s->argc);
502  if (s->status != 0) return 0;
503  if (script)
504  s->status = handle_script(L, argv, script);
505  if (s->status != 0) return 0;
506  if (has_i)
507  dotty(L);
508  else if (script == 0 && !has_e && !has_v) {
509  if (lua_stdin_is_tty()) {
510  print_version();
511  dotty(L);
512  }
513  else dofile(L, NULL); /* executes stdin as a file */
514  }
515  return 0;
516 }
517 
518 
519 int main (int argc, char **argv) {
520  int status;
521  struct Smain s;
522  lua_State *L = lua_open(); /* create state */
523  if (L == NULL) {
524  l_message(argv[0], "cannot create state: not enough memory");
525  return EXIT_FAILURE;
526  }
527  s.argc = argc;
528  s.argv = argv;
529  status = lua_cpcall(L, &pmain, &s);
530  report(L, status);
531  lua_close(L);
532  return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
533 }
534 
535 
536 // luafaudes: end skip doxygen
537 #endif
static int report(lua_State *L, int status)
Definition: luafaudes.cpp:86
static void print_usage(void)
Definition: luafaudes.cpp:61
static int getargs(lua_State *L, char **argv, int n)
Definition: luafaudes.cpp:147
#define lua_rl_exit(L)
Definition: luafaudes.cpp:259
static void print_version(void)
Definition: luafaudes.cpp:133
int main(int argc, char **argv)
Definition: luafaudes.cpp:519
static int docall(lua_State *L, int narg, int clear)
Definition: luafaudes.cpp:117
#define lua_rl_init(L)
Definition: luafaudes.cpp:258
static int handle_luainit(lua_State *L)
Definition: luafaudes.cpp:459
static void lstop(lua_State *L, lua_Debug *ar)
Definition: luafaudes.cpp:47
static int pushline(lua_State *L, int firstline)
Definition: luafaudes.cpp:289
static int traceback(lua_State *L)
Definition: luafaudes.cpp:97
static int runargs(lua_State *L, char **argv, int n)
Definition: luafaudes.cpp:420
static int dofile(lua_State *L, const char *name)
Definition: luafaudes.cpp:165
static int pmain(lua_State *L)
Definition: luafaudes.cpp:476
static int collectargs(char **argv, int *pi, int *pv, int *pe, int *pd, int *px)
Definition: luafaudes.cpp:375
static void laction(int i)
Definition: luafaudes.cpp:54
static void l_message(const char *pname, const char *msg)
Definition: luafaudes.cpp:79
static int dolibrary(lua_State *L, const char *name)
Definition: luafaudes.cpp:177
#define notail(x)
Definition: luafaudes.cpp:371
static const char * progname
Definition: luafaudes.cpp:44
static int loadline(lua_State *L)
Definition: luafaudes.cpp:308
static int dostring(lua_State *L, const char *s, const char *name)
Definition: luafaudes.cpp:171
static int handle_script(lua_State *L, char **argv, int n)
Definition: luafaudes.cpp:352
static void dotty(lua_State *L)
Definition: luafaudes.cpp:328
static lua_State * globalL
Definition: luafaudes.cpp:43
static const char * get_prompt(lua_State *L, int firstline)
Definition: luafaudes.cpp:265
static int incomplete(lua_State *L, int status)
Definition: luafaudes.cpp:275
std::string VersionString()
Definition: cfl_utils.cpp:131
FAUDES_API void faudes_mute(bool on)
std::string PluginsString()
Definition: cfl_utils.cpp:136
int faudes_loadext(lua_State *pL, const char *filename)
Definition: lbp_addons.cpp:133
std::string BuildString()
Definition: cfl_utils.cpp:147
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
char ** argv
Definition: luafaudes.cpp:471
int argc
Definition: luafaudes.cpp:470
int status
Definition: luafaudes.cpp:472

libFAUDES 2.33b --- 2025.05.07 --- c++ api documentaion by doxygen