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
28using 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
59static lua_State *globalL = NULL;
60
61static const char *progname = LUA_PROGNAME;
62
63
64#if defined(LUA_USE_POSIX) /* { */
65
66/*
67** Use 'sigaction' when available.
68*/
69static 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*/
87static 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*/
100static 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
109static 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*/
159static 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*/
169static 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*/
184static 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*/
205static 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.
220static 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*/
245static 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
257static 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
263static int dofile (lua_State *L, const char *name) {
264 return dochunk(L, luaL_loadfile(L, name));
265}
266
267
268static 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*/
278static 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*/
305static 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
332static 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*/
363static 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*/
438static 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
477static 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
564static char *lua_rl_hist;
565static int lua_rl_histsize;
566
567static lua_State *lua_rl_L; /* User data is not passed to rl callbacks. */
568
569/* luafaudes: pass on global state */
570static 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. */
575static 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. */
598static 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*/
629static 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*/
661static 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*/
675static 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*/
700static 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*/
718static 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*/
741static 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*/
757static 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*/
774static void doREPL (lua_State *L) {
775 int status;
776 const char *oldprogname = progname;
777 progname = NULL; /* no 'progname' on errors in interactive mode */
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
799static 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'? */
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? */
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
865int 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
int main()
static const char * get_prompt(lua_State *L, int firstline)
static int report(lua_State *L, int status)
#define LUA_MAXINPUT
#define has_e
#define EOFMARK
#define lua_initreadline(L)
static int pushargs(lua_State *L)
static int collectargs(char **argv, int *first)
#define lua_exitreadline(L)
#define LUA_INITVARVERSION
Definition luafaudes.cpp:56
#define setsignal
Definition luafaudes.cpp:79
static void print_version(void)
static int docall(lua_State *L, int narg, int nres)
#define lua_freeline(L, b)
static int handle_script(lua_State *L, char **argv)
static int handle_luainit(lua_State *L)
static void lstop(lua_State *L, lua_Debug *ar)
Definition luafaudes.cpp:87
#define has_v
#define has_error
static int pushline(lua_State *L, int firstline)
static int dochunk(lua_State *L, int status)
#define has_E
static void print_usage(const char *badoption)
static void doREPL(lua_State *L)
static int runargs(lua_State *L, char **argv, int n)
static int dofile(lua_State *L, const char *name)
static int pmain(lua_State *L)
#define LUA_PROMPT
#define LUA_INIT_VAR
Definition luafaudes.cpp:53
static void l_print(lua_State *L)
#define has_d
static int msghandler(lua_State *L)
#define lua_saveline(L, line)
#define has_i
static int addreturn(lua_State *L)
#define LUA_PROMPT2
#define faudes_stdin_is_tty()
Definition luafaudes.cpp:35
static int dolibrary(lua_State *L, char *globname)
static void laction(int i)
static void l_message(const char *pname, const char *msg)
static const char * progname
Definition luafaudes.cpp:61
static int loadline(lua_State *L)
#define has_x
static int dostring(lua_State *L, const char *s, const char *name)
static void createargtable(lua_State *L, char **argv, int argc, int script)
static lua_State * globalL
Definition luafaudes.cpp:59
#define LUA_PROGNAME
Definition luafaudes.cpp:48
#define marklen
static int incomplete(lua_State *L, int status)
#define lua_readline(L, b, p)
static int multiline(lua_State *L)
std::string VersionString()
int Verbosity(void)
std::string PluginsString()
int faudes_loadext(lua_State *pL, const char *filename)
std::string BuildString()
char ** faudes_complete(lua_State *pL, const char *text, int start, int end)
int faudes_loaddefext(lua_State *pL, const char *arg0)

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