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 based on a plain copy of the original lua.c
4  provided with the lua 5.4.8 distribution under an MIT license; see
5  lua.h or http://www.lua.org
6 
7  Changes to the original code are signed "//FAUDES". They include
8  (a) loading of libFAUDES bindings;
9  (b) libFAUDES specific additional options '-d' and '-x'
10  (c) Mike Palls "Advanced-Readline patch" has been applied (and adapted)
11  (d) be version agniostic to go with Lua 5.1.3 if need be
12 
13  Thomas Moor, 2008, 2025.
14 
15 
16 @ingroup Tutorials
17 
18 
19 */
20 
21 //FAUDES: skip doxygen
22 #ifndef FAUDES_DOXYGEN
23 
24 //FAUDES: use my C++ include file (incl. lpb_include.h and, hence, lua.h & friends)
25 #include "libfaudes.h"
26 
27 //FAUDES: import all libFAUDES
28 using namespace faudes;
29 
30 //FAUDES: dislike isatty on MSYS (disable via Makefile)
31 #if defined(LUA_USE_ISATTY)
32 #include <unistd.h>
33 #define faudes_stdin_is_tty() isatty(0)
34 #else
35 #define faudes_stdin_is_tty() 1
36 #endif
37 
38 //FAUDES: version agnostic: 5.1.3 used to def this and we want to override
39 #ifdef lua_readline
40 #undef lua_readline
41 #endif
42 #ifdef lua_saveline
43 #undef lua_saveline
44 #endif
45 
46 //FAUDES: changed name form 'lua' to 'luafaudes'
47 #if !defined(LUA_PROGNAME)
48 #define LUA_PROGNAME "luafaudes"
49 #endif
50 
51 
52 #if !defined(LUA_INIT_VAR)
53 #define LUA_INIT_VAR "LUA_INIT"
54 #endif
55 
56 #define LUA_INITVARVERSION LUA_INIT_VAR // LUA_VERSUFFIX
57 
58 
59 static lua_State *globalL = NULL;
60 
61 static const char *progname = LUA_PROGNAME;
62 
63 
64 #if defined(LUA_USE_POSIX) /* { */
65 
66 /*
67 ** Use 'sigaction' when available.
68 */
69 static void setsignal (int sig, void (*handler)(int)) {
70  struct sigaction sa;
71  sa.sa_handler = handler;
72  sa.sa_flags = 0;
73  sigemptyset(&sa.sa_mask); /* do not mask any signal */
74  sigaction(sig, &sa, NULL);
75 }
76 
77 #else /* }{ */
78 
79 #define setsignal signal
80 
81 #endif /* } */
82 
83 
84 /*
85 ** Hook set by signal function to stop the interpreter.
86 */
87 static void lstop (lua_State *L, lua_Debug *ar) {
88  (void)ar; /* unused arg. */
89  lua_sethook(L, NULL, 0, 0); /* reset hook */
90  luaL_error(L, "interrupted!");
91 }
92 
93 
94 /*
95 ** Function to be called at a C signal. Because a C signal cannot
96 ** just change a Lua state (as there is no proper synchronization),
97 ** this function only sets a hook that, when called, will stop the
98 ** interpreter.
99 */
100 static void laction (int i) {
101  int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT;
102  setsignal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
103  lua_sethook(globalL, lstop, flag, 1);
104 }
105 
106 
107 
108 
109 static void print_usage (const char *badoption) {
110  lua_writestringerror("%s: ", progname);
111  if (badoption[1] == 'e' || badoption[1] == 'l')
112  lua_writestringerror("'%s' needs argument\n", badoption);
113  else
114  lua_writestringerror("unrecognized option '%s'\n", badoption);
115 #if LUA_VERSION_NUM >= 504
116  /* //FAUDES: original 5.4.8 code */
117  lua_writestringerror(
118  "usage: %s [options] [script [args]]\n"
119  "available options are:\n"
120  " -e stat execute string 'stat'\n"
121  " -i enter interactive mode after executing 'script'\n"
122  " -l mod require library 'mod' into global 'mod'\n"
123  " -l g=mod require library 'mod' into global 'g'\n"
124  " -v show version information\n"
125  " -E ignore environment variables\n"
126  " -W turn warnings on\n"
127  " -d pass on libFAUDES messages to console\n" /* //FAUDES */
128  " -x flx load libFAUDES extension 'flx'\n" /* //FAUDES */
129  " -- stop handling options\n"
130  " - stop handling options and execute stdin\n"
131  ,
132  progname);
133  /* //FAUDES: end */
134 #else
135  /* //FAUDES: all of the above except -E and -W [MS CL wont digest preprocessing within concateneted strings]*/
136  lua_writestringerror(
137  "usage: %s [options] [script [args]]\n"
138  "available options are:\n"
139  " -e stat execute string 'stat'\n"
140  " -i enter interactive mode after executing 'script'\n"
141  " -l mod require library 'mod' into global 'mod'\n"
142  " -l g=mod require library 'mod' into global 'g'\n"
143  " -v show version information\n"
144  " -d pass on libFAUDES messages to console\n" /* //FAUDES */
145  " -x flx load libFAUDES extension 'flx'\n" /* //FAUDES */
146  " -- stop handling options\n"
147  " - stop handling options and execute stdin\n"
148  ,
149  progname);
150  /* //FAUDES: end */
151 #endif
152 }
153 
154 
155 /*
156 ** Prints an error message, adding the program name in front of it
157 ** (if present)
158 */
159 static void l_message (const char *pname, const char *msg) {
160  if (pname) lua_writestringerror("%s: ", pname);
161  lua_writestringerror("%s\n", msg);
162 }
163 
164 
165 /*
166 ** Check whether 'status' is not OK and, if so, prints the error
167 ** message on the top of the stack.
168 */
169 static int report (lua_State *L, int status) {
170  if (status != LUA_OK) {
171  const char *msg = lua_tostring(L, -1);
172  if (msg == NULL)
173  msg = "(error message not a string)";
174  l_message(progname, msg);
175  lua_pop(L, 1); /* remove message */
176  }
177  return status;
178 }
179 
180 
181 /*
182 ** Message handler used to run all chunks
183 */
184 static int msghandler (lua_State *L) {
185  const char *msg = lua_tostring(L, 1);
186  if (msg == NULL) { /* is error object not a string? */
187  if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */
188  lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */
189  return 1; /* that is the message */
190  else
191  msg = lua_pushfstring(L, "(error object is a %s value)",
192  luaL_typename(L, 1));
193  }
194 #if LUA_VERSION_NUM >= 504 /* //FAUDES: try to be version agnostic */
195  luaL_traceback(L, L, msg, 1); /* append a standard traceback */
196 #endif
197  return 1; /* return the traceback */
198 }
199 
200 
201 /*
202 ** Interface to 'lua_pcall', which sets appropriate message function
203 ** and C-signal handler. Used to run all chunks.
204 */
205 static int docall (lua_State *L, int narg, int nres) {
206  int status;
207  int base = lua_gettop(L) - narg; /* function index */
208  lua_pushcfunction(L, msghandler); /* push message handler */
209  lua_insert(L, base); /* put it under function and args */
210  globalL = L; /* to be available to 'laction' */
211  setsignal(SIGINT, laction); /* set C-signal handler */
212  status = lua_pcall(L, narg, nres, base);
213  setsignal(SIGINT, SIG_DFL); /* reset C-signal handler */
214  lua_remove(L, base); /* remove message handler from the stack */
215  return status;
216 }
217 
218 
219 //FAUDES: libFAUDES specific version/greeting.
220 static void print_version (void) {
221  std::stringstream sstr;
222  sstr
223  << "welcome to the libFAUDES-Lua console" << std::endl
224  << "version: " << VersionString() << " / " << LUA_RELEASE << std::endl
225  << "build: " << BuildString() << std::endl
226  << "plug-ins: " << PluginsString() << std::endl
227  << "credits: this libFAUDES interpreter is based on the projects Lua and SWIG" << std::endl
228  << "enter 'faudes.Help()' for a list of faudes related types and functions" << std::endl
229  << "press ctrl-c to exit the interpreter";
230  lua_writestring(sstr.str().c_str(),sstr.str().length());
231  lua_writeline();
232 }
233 
234 
235 /*
236 ** Create the 'arg' table, which stores all arguments from the
237 ** command line ('argv'). It should be aligned so that, at index 0,
238 ** it has 'argv[script]', which is the script name. The arguments
239 ** to the script (everything after 'script') go to positive indices;
240 ** other arguments (before the script name) go to negative indices.
241 ** If there is no script name, assume interpreter's name as base.
242 ** (If there is no interpreter's name either, 'script' is -1, so
243 ** table sizes are zero.)
244 */
245 static void createargtable (lua_State *L, char **argv, int argc, int script) {
246  int i, narg;
247  narg = argc - (script + 1); /* number of positive indices */
248  lua_createtable(L, narg, script + 1);
249  for (i = 0; i < argc; i++) {
250  lua_pushstring(L, argv[i]);
251  lua_rawseti(L, -2, i - script);
252  }
253  lua_setglobal(L, "arg");
254 }
255 
256 
257 static int dochunk (lua_State *L, int status) {
258  if (status == LUA_OK) status = docall(L, 0, 0);
259  return report(L, status);
260 }
261 
262 
263 static int dofile (lua_State *L, const char *name) {
264  return dochunk(L, luaL_loadfile(L, name));
265 }
266 
267 
268 static int dostring (lua_State *L, const char *s, const char *name) {
269  return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
270 }
271 
272 
273 /*
274 ** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
275 ** If there is no explicit modname and globname contains a '-', cut
276 ** the suffix after '-' (the "version") to make the global name.
277 */
278 static int dolibrary (lua_State *L, char *globname) {
279  int status;
280  char *suffix = NULL;
281  char *modname = strchr(globname, '=');
282  if (modname == NULL) { /* no explicit name? */
283  modname = globname; /* module name is equal to global name */
284  suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */
285  }
286  else {
287  *modname = '\0'; /* global name ends here */
288  modname++; /* module name starts after the '=' */
289  }
290  lua_getglobal(L, "require");
291  lua_pushstring(L, modname);
292  status = docall(L, 1, 1); /* call 'require(modname)' */
293  if (status == LUA_OK) {
294  if (suffix != NULL) /* is there a suffix mark? */
295  *suffix = '\0'; /* remove suffix from global name */
296  lua_setglobal(L, globname); /* globname = require(modname) */
297  }
298  return report(L, status);
299 }
300 
301 
302 /*
303 ** Push on the stack the contents of table 'arg' from 1 to #arg
304 */
305 static int pushargs (lua_State *L) {
306  int i, n;
307  /* //FAUDES: original 5.4.8 */
308  //if (lua_getglobal(L, "arg") != LUA_TTABLE)
309  // luaL_error(L, "'arg' is not a table");
310  /* //FAUDES: version agnostic variant */
311  lua_getglobal(L, "arg");
312  if(lua_type(L, -1) != LUA_TTABLE)
313  luaL_error(L, "'arg' is not a table");
314  /* //FAUDES: end */
315 #if LUA_VERSION_NUM >= 504
316  /* //FAUDES: original 5.4.8 */
317  n = (int)luaL_len(L, -1);
318 #else
319  /* //FAUDES: original 5.1.3 */.
320  n = 0;
321  if(!luaL_callmeta(L, -1, "__len"))
322  n= (int) lua_objlen(L,-1);
323 #endif
324  luaL_checkstack(L, n + 3, "too many arguments to script");
325  for (i = 1; i <= n; i++)
326  lua_rawgeti(L, -i, i);
327  lua_remove(L, -i); /* remove table from the stack */
328  return n;
329 }
330 
331 
332 static int handle_script (lua_State *L, char **argv) {
333  int status;
334  const char *fname = argv[0];
335  if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
336  fname = NULL; /* stdin */
337  status = luaL_loadfile(L, fname);
338  if (status == LUA_OK) {
339  int n = pushargs(L); /* push arguments to script */
340  status = docall(L, n, LUA_MULTRET);
341  }
342  return report(L, status);
343 }
344 
345 
346 /* bits of various argument indicators in 'args' */
347 #define has_error 1 /* bad option */
348 #define has_i 2 /* -i */
349 #define has_v 4 /* -v */
350 #define has_e 8 /* -e */
351 #define has_E 16 /* -E */
352 #define has_x 32 /* //FAUDES: -x */
353 #define has_d 64 /* //FAUDES: -d */
354 
355 
356 /*
357 ** Traverses all arguments from 'argv', returning a mask with those
358 ** needed before running any Lua code or an error code if it finds any
359 ** invalid argument. In case of error, 'first' is the index of the bad
360 ** argument. Otherwise, 'first' is -1 if there is no program name,
361 ** 0 if there is no script name, or the index of the script name.
362 */
363 static int collectargs (char **argv, int *first) {
364  int args = 0;
365  int i;
366  if (argv[0] != NULL) { /* is there a program name? */
367  if (argv[0][0]) /* not empty? */
368  progname = argv[0]; /* save it */
369  }
370  else { /* no program name */
371  *first = -1;
372  return 0;
373  }
374  for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
375  *first = i;
376  if (argv[i][0] != '-') /* not an option? */
377  return args; /* stop handling options */
378  switch (argv[i][1]) { /* else check option */
379  case '-': /* '--' */
380  if (argv[i][2] != '\0') /* extra characters after '--'? */
381  return has_error; /* invalid option */
382  *first = i + 1;
383  return args;
384  case '\0': /* '-' */
385  return args; /* script "name" is '-' */
386  case 'E':
387  if (argv[i][2] != '\0') /* extra characters? */
388  return has_error; /* invalid option */
389  args |= has_E;
390  break;
391  case 'W':
392  if (argv[i][2] != '\0') /* extra characters? */
393  return has_error; /* invalid option */
394  break;
395  case 'i':
396  args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
397  case 'v':
398  if (argv[i][2] != '\0') /* extra characters? */
399  return has_error; /* invalid option */
400  args |= has_v;
401  break;
402  case 'e':
403  args |= has_e; /* FALLTHROUGH */
404  case 'l': /* both options need an argument */
405  if (argv[i][2] == '\0') { /* no concatenated argument? */
406  i++; /* try next 'argv' */
407  if (argv[i] == NULL || argv[i][0] == '-')
408  return has_error; /* no next argument or it is another option */
409  }
410  break;
411  case 'd': /* //FAUDES: d-option */
412  if (argv[i][2] != '\0') /* extra characters? */
413  return has_error; /* invalid option */
414  args |= has_d;
415  break;
416  case 'x': /* //FAUDES: -x: needs an argument and sets the flag */
417  if (argv[i][2] == '\0') { /* no concatenated argument? */
418  i++; /* try next 'argv' */
419  if (argv[i] == NULL || argv[i][0] == '-')
420  return has_error; /* no next argument or it is another option */
421  }
422  args |= has_x;
423  break;
424  default: /* invalid option */
425  return has_error;
426  }
427  }
428  *first = 0; /* no script name */
429  return args;
430 }
431 
432 
433 /*
434 ** Processes options 'e' and 'l', which involve running Lua code, and
435 ** 'W', which also affects the state.
436 ** Returns 0 if some code raises an error.
437 */
438 static int runargs (lua_State *L, char **argv, int n) {
439  int i;
440  for (i = 1; i < n; i++) {
441  int option = argv[i][1];
442  lua_assert(argv[i][0] == '-'); /* already checked */
443  switch (option) {
444  case 'e': case 'l': {
445  int status;
446  char *extra = argv[i] + 2; /* both options need an argument */
447  if (*extra == '\0') extra = argv[++i];
448  lua_assert(extra != NULL);
449  status = (option == 'e')
450  ? dostring(L, extra, "=(command line)")
451  : dolibrary(L, extra);
452  if (status != LUA_OK) return 0;
453  break;
454  }
455 #if LUA_VERSION_NUM >= 504
456  /* //FAUDES: original 5.4.8 code (warnings not available in 5.1.3) */
457  case 'W':
458  lua_warning(L, "@on", 0); /* warnings on */
459  break;
460 #endif
461  case 'x': { /* //FAUDES: load faudes extension */
462  const char *filename = argv[i] + 2;
463  if (*filename == '\0') filename = argv[++i];
464  lua_assert(filename != NULL);
465  if (faudes_loadext(L, filename)) {
466  l_message("fatal error: failed to load extension", filename);
467  return 1; /* stop if file fails */
468  }
469  break;
470  }
471  }
472  }
473  return 1;
474 }
475 
476 
477 static int handle_luainit (lua_State *L) {
478  const char *name = "=" LUA_INITVARVERSION;
479  const char *init = getenv(name + 1);
480  if (init == NULL) {
481  name = "=" LUA_INIT_VAR;
482  init = getenv(name + 1); /* try alternative name */
483  }
484  if (init == NULL) return LUA_OK;
485  else if (init[0] == '@')
486  return dofile(L, init+1);
487  else
488  return dostring(L, init, name);
489 }
490 
491 
492 /*
493 ** {==================================================================
494 ** Read-Eval-Print Loop (REPL)
495 ** ===================================================================
496 */
497 
498 #if !defined(LUA_PROMPT)
499 #define LUA_PROMPT "> "
500 #define LUA_PROMPT2 ">> "
501 #endif
502 
503 #if !defined(LUA_MAXINPUT)
504 #define LUA_MAXINPUT 512
505 #endif
506 
507 
508 /*
509 ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that
510 ** is, whether we're running lua interactively).
511 */
512 #if !defined(lua_stdin_is_tty) /* { */
513 
514 #if defined(LUA_USE_POSIX) /* { */
515 
516 #include <unistd.h>
517 #define lua_stdin_is_tty() isatty(0)
518 
519 #elif defined(LUA_USE_WINDOWS) /* }{ */
520 
521 #include <io.h>
522 #include <windows.h>
523 
524 #define lua_stdin_is_tty() _isatty(_fileno(stdin))
525 
526 #else /* }{ */
527 
528 /* ISO C definition */
529 #define lua_stdin_is_tty() 1 /* assume stdin is a tty */
530 
531 #endif /* } */
532 
533 #endif /* } */
534 
535 
536 /*
537 ** lua_readline defines how to show a prompt and then read a line from
538 ** the standard input.
539 ** lua_saveline defines how to "save" a read line in a "history".
540 ** lua_freeline defines how to free a line read by lua_readline.
541 */
542 #if !defined(lua_readline) /* { */
543 
544 #if defined(LUA_USE_READLINE) /* { */
545 
546 /*
547 ** //FAUDES: here we to be advanced readline support patch by Mike Pall. However,
548 ** we required some variations for SWIG __index functions and we also wanted identifier-
549 ** completion in DESTool. Thus, we moved the original completer code to LuaState
550 ** (see lbp_function.cpp and lbp_completer.cpp) and provide a C interface via
551 ** luafaudes_complete() (see lbp_addons.cpp). The below code is reduced to the libreadline
552 ** interface. The original patch still ships with libFAUDES for reference and can be
553 ** inspected in plugins/luabindings/lib
554 **
555 ** Original License/Copyright
556 **
557 ** Copyright (C) 2004-2006 Mike Pall. Same license as Lua. See lua.h.
558 **
559 */
560 
561 #include <readline/readline.h>
562 #include <readline/history.h>
563 
564 static char *lua_rl_hist;
565 static int lua_rl_histsize;
566 
567 static lua_State *lua_rl_L; /* User data is not passed to rl callbacks. */
568 
569 /* luafaudes: pass on global state */
570 static char **faudes_complete_L(const char *text, int start, int end) {
571  return faudes_complete(lua_rl_L,text,start,end);
572 }
573 
574 /* Initialize readline library. */
575 static void lua_initreadline(lua_State *L) {
576  char *s;
577  lua_rl_L = L;
578 
579  /* This allows for $if lua ... $endif in ~/.inputrc. */
580  rl_readline_name = "lua";
581  /* Break words at every non-identifier character except '.' and ':'. */
582  rl_completer_word_break_characters = (char *)
583  "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~"; //FAUDES: pragmatic avoidance of compiler warning
584 
585  rl_completer_quote_characters = "\"'";
586  rl_completion_append_character = '\0';
587  rl_attempted_completion_function = faudes_complete_L; //FAUDES: use libFAUDES variant
588  rl_initialize();
589 
590  /* Start using history, optionally set history size and load history file. */
591  using_history();
592  if ((s = getenv("LUA_HISTSIZE")) &&
593  (lua_rl_histsize = atoi(s))) stifle_history(lua_rl_histsize);
594  if ((lua_rl_hist = getenv("LUA_HISTORY"))) read_history(lua_rl_hist);
595 }
596 
597 /* Finalize readline library. */
598 static void lua_exitreadline(lua_State *L) {
599  (void) L;
600  /* Optionally save history file. */
601  if (lua_rl_hist) write_history(lua_rl_hist);
602 }
603 
604 #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
605 #define lua_saveline(L,line) ((void)L, add_history(line))
606 #define lua_freeline(L,b) ((void)L, free(b))
607 
608 
609 #else /* }{ */
610 
611 #define lua_initreadline(L) ((void)L)
612 #define lua_readline(L,b,p) \
613  ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
614  fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
615 #define lua_saveline(L,line) { (void)L; (void)line; }
616 #define lua_freeline(L,b) { (void)L; (void)b; }
617 #define lua_exitreadline(L) { (void)L; }
618 
619 #endif /* } */
620 
621 #endif /* } */
622 
623 
624 /*
625 ** Return the string to be used as a prompt by the interpreter. Leave
626 ** the string (or nil, if using the default value) on the stack, to keep
627 ** it anchored.
628 */
629 static const char *get_prompt (lua_State *L, int firstline) {
630  const char* p;
631 #if LUA_VERSION_NUM >= 504
632  /* //FAUDES: original Lua 5.4.8 */
633  if (lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2") == LUA_TNIL)
634  return (firstline ? LUA_PROMPT : LUA_PROMPT2); /* use the default */
635  else { /* apply 'tostring' over the value */
636  const char *p = luaL_tolstring(L, -1, NULL);
637  lua_remove(L, -2); /* remove original value */
638  return p;
639  }
640  /* //FAUDES: end */
641 #else
642  /* //FAUDES: (sort of) original Lua 5.1.3 */
643  lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
644  p = lua_tostring(L, -1);
645  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
646  return p;
647  /* //FAUDES: end */
648 #endif
649 }
650 
651 /* mark in error messages for incomplete statements */
652 #define EOFMARK "<eof>"
653 #define marklen (sizeof(EOFMARK)/sizeof(char) - 1)
654 
655 
656 /*
657 ** Check whether 'status' signals a syntax error and the error
658 ** message at the top of the stack ends with the above mark for
659 ** incomplete statements.
660 */
661 static int incomplete (lua_State *L, int status) {
662  if (status == LUA_ERRSYNTAX) {
663  size_t lmsg;
664  const char *msg = lua_tolstring(L, -1, &lmsg);
665  if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0)
666  return 1;
667  }
668  return 0; /* else... */
669 }
670 
671 
672 /*
673 ** Prompt the user, read a line, and push it into the Lua stack.
674 */
675 static int pushline (lua_State *L, int firstline) {
676  char buffer[LUA_MAXINPUT];
677  char *b = buffer;
678  size_t l;
679  const char *prmt = get_prompt(L, firstline);
680  int readstatus = lua_readline(L, b, prmt);
681  lua_pop(L, 1); /* remove prompt */
682  if (readstatus == 0)
683  return 0; /* no input */
684  l = strlen(b);
685  if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
686  b[--l] = '\0'; /* remove it */
687  if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
688  lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
689  else
690  lua_pushlstring(L, b, l);
691  lua_freeline(L, b);
692  return 1;
693 }
694 
695 
696 /*
697 ** Try to compile line on the stack as 'return <line>;'; on return, stack
698 ** has either compiled chunk or original line (if compilation failed).
699 */
700 static int addreturn (lua_State *L) {
701  const char *line = lua_tostring(L, -1); /* original line */
702  const char *retline = lua_pushfstring(L, "return %s;", line);
703  int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
704  if (status == LUA_OK) {
705  lua_remove(L, -2); /* remove modified line */
706  if (line[0] != '\0') /* non empty? */
707  lua_saveline(L, line); /* keep history */
708  }
709  else
710  lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
711  return status;
712 }
713 
714 
715 /*
716 ** Read multiple lines until a complete Lua statement
717 */
718 static int multiline (lua_State *L) {
719  for (;;) { /* repeat until gets a complete statement */
720  size_t len;
721  const char *line = lua_tolstring(L, 1, &len); /* get what it has */
722  int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
723  if (!incomplete(L, status) || !pushline(L, 0)) {
724  lua_saveline(L, line); /* keep history */
725  return status; /* should not or cannot try to add continuation line */
726  }
727  lua_remove(L, -2); /* remove error message (from incomplete line) */
728  lua_pushliteral(L, "\n"); /* add newline... */
729  lua_insert(L, -2); /* ...between the two lines */
730  lua_concat(L, 3); /* join them */
731  }
732 }
733 
734 
735 /*
736 ** Read a line and try to load (compile) it first as an expression (by
737 ** adding "return " in front of it) and second as a statement. Return
738 ** the final status of load/call with the resulting function (if any)
739 ** in the top of the stack.
740 */
741 static int loadline (lua_State *L) {
742  int status;
743  lua_settop(L, 0);
744  if (!pushline(L, 1))
745  return -1; /* no input */
746  if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
747  status = multiline(L); /* try as command, maybe with continuation lines */
748  lua_remove(L, 1); /* remove line from the stack */
749  lua_assert(lua_gettop(L) == 1);
750  return status;
751 }
752 
753 
754 /*
755 ** Prints (calling the Lua 'print' function) any values on the stack
756 */
757 static void l_print (lua_State *L) {
758  int n = lua_gettop(L);
759  if (n > 0) { /* any result to be printed? */
760  luaL_checkstack(L, LUA_MINSTACK, "too many results to print");
761  lua_getglobal(L, "print");
762  lua_insert(L, 1);
763  if (lua_pcall(L, n, 0, 0) != LUA_OK)
764  l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)",
765  lua_tostring(L, -1)));
766  }
767 }
768 
769 
770 /*
771 ** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and
772 ** print any results.
773 */
774 static void doREPL (lua_State *L) {
775  int status;
776  const char *oldprogname = progname;
777  progname = NULL; /* no 'progname' on errors in interactive mode */
778  lua_initreadline(L);
779  while ((status = loadline(L)) != -1) {
780  if (status == LUA_OK)
781  status = docall(L, 0, LUA_MULTRET);
782  if (status == LUA_OK) l_print(L);
783  else report(L, status);
784  }
785  lua_settop(L, 0); /* clear stack */
786  lua_writeline();
787  lua_exitreadline(L); /* //FAUDES */
788  progname = oldprogname;
789 }
790 
791 /* }================================================================== */
792 
793 
794 /*
795 ** Main body of stand-alone interpreter (to be called in protected mode).
796 ** Reads the options and handles them all.
797 */
798 
799 static int pmain (lua_State *L) {
800  int argc = (int)lua_tointeger(L, 1);
801  char **argv = (char **)lua_touserdata(L, 2);
802  int script;
803  int args = collectargs(argv, &script);
804  int optlim = (script > 0) ? script : argc; /* first argv not an option */
805 
806  /* //FAUDES: version agnostic (not available in 5.1.3) */
807 #if LUA_VERSION_NUM >= 504
808  luaL_checkversion(L); /* check that interpreter has correct version */
809 #endif
810  /* //FAUDES: end */
811  if (args == has_error) { /* bad arg? */
812  print_usage(argv[script]); /* 'script' has index of bad arg. */
813  return 0;
814  }
815  if (args & has_v) /* option '-v'? */
816  print_version();
817  if (args & has_d) /* //FAUDES: option '-d'? */
818  Verbosity(999);
819  else
820  Verbosity(0);
821 #if LUA_VERSION_NUM >= 504
822  /* //FAUDES: original 5.4.8 (not available in 5.1.3) */
823  if (args & has_E) { /* option '-E'? */
824  lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
825  lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
826  }
827 #endif
828  luaL_openlibs(L); /* open standard libraries */
829  luaopen_faudes_allplugins(L); /* //FAUDES: load all faudes bindings */
830  createargtable(L, argv, argc, script); /* create table 'arg' */
831 #if LUA_VERSION_NUM >= 504
832  /* //FAUDES: original 5.4.8 */
833  lua_gc(L, LUA_GCRESTART); /* start GC... */
834  lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
835 #else
836  /* //FAUDES: 5.1.3 stype */
837  lua_gc(L, LUA_GCRESTART,0); /* start GC... */
838 #endif
839  if (!(args & has_E)) { /* no option '-E'? */
840  if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
841  return 0; /* error running LUA_INIT */
842  }
843  if (!runargs(L, argv, optlim)) /* execute arguments -e, -l //FAUDES and -x */
844  return 0; /* something failed */
845  if (!(args & has_x))
846  faudes_loaddefext(L, argv[0]); /* //FAUDES: load default extension */
847  if (script > 0) { /* execute main script (if there is one) */
848  if (handle_script(L, argv + script) != LUA_OK)
849  return 0; /* interrupt in case of error */
850  }
851  if (args & has_i) /* -i option? */
852  doREPL(L); /* do read-eval-print loop */
853  else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
854  if (faudes_stdin_is_tty()) { /* running in interactive mode? */
855  print_version();
856  doREPL(L); /* do read-eval-print loop */
857  }
858  else dofile(L, NULL); /* executes stdin as a file */
859  }
860  lua_pushboolean(L, 1); /* signal no errors */
861  return 1;
862 }
863 
864 
865 int main (int argc, char **argv) {
866  int status, result;
867  lua_State *L = luaL_newstate(); /* create state */
868  if (L == NULL) {
869  l_message(argv[0], "cannot create state: not enough memory");
870  return EXIT_FAILURE;
871  }
872 #if LUA_VERSION_NUM >= 504
873  /* //FAUDES: original 5.4.8 */
874  lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
875 #else
876  /* //FAUDES: 5.1.3 style */
877  lua_gc(L, LUA_GCSTOP,0); /* stop GC while building state */
878 #endif
879  lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
880  lua_pushinteger(L, argc); /* 1st argument */
881  lua_pushlightuserdata(L, argv); /* 2nd argument */
882  status = lua_pcall(L, 2, 1, 0); /* do the call */
883  result = lua_toboolean(L, -1); /* get result */
884  report(L, status);
885  lua_close(L);
886  return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
887 }
888 
889 
890 /* //FAUDES: end skip doxygen */
891 #endif
static int report(lua_State *L, int status)
Definition: luafaudes.cpp:169
#define LUA_MAXINPUT
Definition: luafaudes.cpp:504
#define has_e
Definition: luafaudes.cpp:350
#define EOFMARK
Definition: luafaudes.cpp:652
#define lua_initreadline(L)
Definition: luafaudes.cpp:611
static int pushargs(lua_State *L)
Definition: luafaudes.cpp:305
static int collectargs(char **argv, int *first)
Definition: luafaudes.cpp:363
#define lua_exitreadline(L)
Definition: luafaudes.cpp:617
#define LUA_INITVARVERSION
Definition: luafaudes.cpp:56
#define setsignal
Definition: luafaudes.cpp:79
static void print_version(void)
Definition: luafaudes.cpp:220
int main(int argc, char **argv)
Definition: luafaudes.cpp:865
static int docall(lua_State *L, int narg, int nres)
Definition: luafaudes.cpp:205
#define lua_freeline(L, b)
Definition: luafaudes.cpp:616
static int handle_script(lua_State *L, char **argv)
Definition: luafaudes.cpp:332
static int handle_luainit(lua_State *L)
Definition: luafaudes.cpp:477
static void lstop(lua_State *L, lua_Debug *ar)
Definition: luafaudes.cpp:87
#define has_v
Definition: luafaudes.cpp:349
#define has_error
Definition: luafaudes.cpp:347
static int pushline(lua_State *L, int firstline)
Definition: luafaudes.cpp:675
static int dochunk(lua_State *L, int status)
Definition: luafaudes.cpp:257
#define has_E
Definition: luafaudes.cpp:351
static void print_usage(const char *badoption)
Definition: luafaudes.cpp:109
static void doREPL(lua_State *L)
Definition: luafaudes.cpp:774
static int runargs(lua_State *L, char **argv, int n)
Definition: luafaudes.cpp:438
static int dofile(lua_State *L, const char *name)
Definition: luafaudes.cpp:263
static int pmain(lua_State *L)
Definition: luafaudes.cpp:799
#define LUA_PROMPT
Definition: luafaudes.cpp:499
#define LUA_INIT_VAR
Definition: luafaudes.cpp:53
static void l_print(lua_State *L)
Definition: luafaudes.cpp:757
#define has_d
Definition: luafaudes.cpp:353
static int msghandler(lua_State *L)
Definition: luafaudes.cpp:184
#define lua_saveline(L, line)
Definition: luafaudes.cpp:615
#define has_i
Definition: luafaudes.cpp:348
static int addreturn(lua_State *L)
Definition: luafaudes.cpp:700
#define LUA_PROMPT2
Definition: luafaudes.cpp:500
#define faudes_stdin_is_tty()
Definition: luafaudes.cpp:35
static int dolibrary(lua_State *L, char *globname)
Definition: luafaudes.cpp:278
static void laction(int i)
Definition: luafaudes.cpp:100
static void l_message(const char *pname, const char *msg)
Definition: luafaudes.cpp:159
static const char * progname
Definition: luafaudes.cpp:61
static int loadline(lua_State *L)
Definition: luafaudes.cpp:741
#define has_x
Definition: luafaudes.cpp:352
static int dostring(lua_State *L, const char *s, const char *name)
Definition: luafaudes.cpp:268
static void createargtable(lua_State *L, char **argv, int argc, int script)
Definition: luafaudes.cpp:245
static lua_State * globalL
Definition: luafaudes.cpp:59
static const char * get_prompt(lua_State *L, int firstline)
Definition: luafaudes.cpp:629
#define LUA_PROGNAME
Definition: luafaudes.cpp:48
#define marklen
Definition: luafaudes.cpp:653
static int incomplete(lua_State *L, int status)
Definition: luafaudes.cpp:661
#define lua_readline(L, b, p)
Definition: luafaudes.cpp:612
static int multiline(lua_State *L)
Definition: luafaudes.cpp:718
std::string VersionString()
Definition: cfl_utils.cpp:141
std::string PluginsString()
Definition: cfl_utils.cpp:146
int faudes_loadext(lua_State *pL, const char *filename)
Definition: lbp_addons.cpp:146
std::string BuildString()
Definition: cfl_utils.cpp:160
char ** faudes_complete(lua_State *pL, const char *text, int start, int end)
Definition: lbp_addons.cpp:169
int faudes_loaddefext(lua_State *pL, const char *arg0)
Definition: lbp_addons.cpp:157
void Verbosity(int v)
Definition: cfl_utils.cpp:504

libFAUDES 2.33l --- 2025.09.16 --- c++ api documentaion by doxygen