summaryrefslogtreecommitdiff
path: root/utils/hwstub/tools
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2015-06-28 17:51:43 +0200
committerMarcin Bukat <marcin.bukat@gmail.com>2015-06-28 17:55:17 +0200
commite70ea5d21ff1aca5b8c534da8f3a1ccadd330a2e (patch)
tree611750d6bd70f20585801cfd7e8c441180798bee /utils/hwstub/tools
parent465eb727a30fd1f4470ff6c172f7b41856775167 (diff)
downloadrockbox-e70ea5d21ff1aca5b8c534da8f3a1ccadd330a2e.tar.gz
rockbox-e70ea5d21ff1aca5b8c534da8f3a1ccadd330a2e.zip
hwstub: Add completion and some pretty printing to the shell
This uses slightly hacked luaprompt to provide all the goodis. See https://github.com/dpapavas/luaprompt for original. Change-Id: Iedddb79abae5809299322bc215722dd928c35cca
Diffstat (limited to 'utils/hwstub/tools')
-rw-r--r--utils/hwstub/tools/Makefile2
-rw-r--r--utils/hwstub/tools/hwstub_shell.cpp20
-rw-r--r--utils/hwstub/tools/lua/hwlib.lua6
-rw-r--r--utils/hwstub/tools/prompt.c1659
-rw-r--r--utils/hwstub/tools/prompt.h55
5 files changed, 1724 insertions, 18 deletions
diff --git a/utils/hwstub/tools/Makefile b/utils/hwstub/tools/Makefile
index 6db0c709b1..f718300623 100644
--- a/utils/hwstub/tools/Makefile
+++ b/utils/hwstub/tools/Makefile
@@ -26,7 +26,7 @@ $(REGTOOLS_LIB_DIR)/libsocdesc.a:
26%.o: %.cpp 26%.o: %.cpp
27 $(CXX) $(CXXFLAGS) -c -o $@ $< 27 $(CXX) $(CXXFLAGS) -c -o $@ $<
28 28
29hwstub_shell: hwstub_shell.o $(LIBS) 29hwstub_shell: hwstub_shell.o prompt.o $(LIBS)
30 $(LD) -o $@ $^ $(LDFLAGS) 30 $(LD) -o $@ $^ $(LDFLAGS)
31 31
32hwstub_load: hwstub_load.o $(LIBS) 32hwstub_load: hwstub_load.o $(LIBS)
diff --git a/utils/hwstub/tools/hwstub_shell.cpp b/utils/hwstub/tools/hwstub_shell.cpp
index 8b7a8b9e80..f59ca8b82a 100644
--- a/utils/hwstub/tools/hwstub_shell.cpp
+++ b/utils/hwstub/tools/hwstub_shell.cpp
@@ -29,6 +29,9 @@
29#include <lua.hpp> 29#include <lua.hpp>
30#include <unistd.h> 30#include <unistd.h>
31#include "soc_desc.hpp" 31#include "soc_desc.hpp"
32extern "C" {
33#include "prompt.h"
34}
32 35
33#if LUA_VERSION_NUM < 502 36#if LUA_VERSION_NUM < 502
34#warning You need at least lua 5.2 37#warning You need at least lua 5.2
@@ -941,21 +944,8 @@ int main(int argc, char **argv)
941 printf("error: %s\n", lua_tostring(g_lua, -1)); 944 printf("error: %s\n", lua_tostring(g_lua, -1));
942 } 945 }
943 946
944 // use readline to provide some history and completion 947 // start interactive shell
945 rl_bind_key('\t', rl_complete); 948 luap_enter(g_lua, &g_exit);
946 while(!g_exit)
947 {
948 char *input = readline("> ");
949 if(!input)
950 break;
951 add_history(input);
952 // evaluate string
953 if(luaL_dostring(g_lua, input))
954 printf("error: %s\n", lua_tostring(g_lua, -1));
955 // pop everything to start from a clean stack
956 lua_pop(g_lua, lua_gettop(g_lua));
957 free(input);
958 }
959 949
960 Lerr: 950 Lerr:
961 // display log if handled 951 // display log if handled
diff --git a/utils/hwstub/tools/lua/hwlib.lua b/utils/hwstub/tools/lua/hwlib.lua
index 5bbd1e2668..02ab9718d4 100644
--- a/utils/hwstub/tools/lua/hwlib.lua
+++ b/utils/hwstub/tools/lua/hwlib.lua
@@ -22,6 +22,8 @@ function HWLIB.load_blob(filename, address)
22 io.close(f) 22 io.close(f)
23end 23end
24 24
25function HWLIB.printf(s,...) 25function HWLIB.printf(...)
26 return io.write(s:format(...)) 26 local function wrapper(...) io.write(string.format(...)) end
27 local status, result = pcall(wrapper, ...)
28 if not status then error(result, 2) end
27end 29end
diff --git a/utils/hwstub/tools/prompt.c b/utils/hwstub/tools/prompt.c
new file mode 100644
index 0000000000..4674158df6
--- /dev/null
+++ b/utils/hwstub/tools/prompt.c
@@ -0,0 +1,1659 @@
1/* Copyright (C) 2012-2015 Papavasileiou Dimitris
2 *
3 * Permission is hereby granted, free of charge, to any person
4 * obtaining a copy of this software and associated documentation
5 * files (the "Software"), to deal in the Software without
6 * restriction, including without limitation the rights to use, copy,
7 * modify, merge, publish, distribute, sublicense, and/or sell copies
8 * of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#define _GNU_SOURCE
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <ctype.h>
33#include <stdbool.h>
34#include <sys/stat.h>
35#include <unistd.h>
36#include "prompt.h"
37
38#ifdef HAVE_IOCTL
39#include <sys/ioctl.h>
40#endif
41
42#include <glob.h>
43
44#include <lualib.h>
45#include <lauxlib.h>
46
47
48#if LUA_VERSION_NUM == 501
49#define lua_pushglobaltable(L) lua_pushvalue (L, LUA_GLOBALSINDEX)
50#define LUA_OK 0
51#define lua_rawlen lua_objlen
52#endif
53
54#ifdef HAVE_LIBREADLINE
55#include <readline/readline.h>
56#else
57
58/* This is a simple readline-like function in case readline is not
59 * available. */
60
61#define MAXINPUT 1024
62
63static char *readline(char *prompt)
64{
65 char *line = NULL;
66 int k;
67
68 line = malloc (MAXINPUT);
69
70 fputs(prompt, stdout);
71 fflush(stdout);
72
73 if (!fgets(line, MAXINPUT, stdin)) {
74 return NULL;
75 }
76
77 k = strlen (line);
78
79 if (line[k - 1] == '\n') {
80 line[k - 1] = '\0';
81 }
82
83 return line;
84}
85
86#endif /* HAVE_LIBREADLINE */
87
88#ifdef HAVE_READLINE_HISTORY
89#include <readline/history.h>
90#endif /* HAVE_READLINE_HISTORY */
91
92#if LUA_VERSION_NUM == 501
93#define EOF_MARKER "'<eof>'"
94#else
95#define EOF_MARKER "<eof>"
96#endif
97
98#define print_output(...) fprintf (stdout, __VA_ARGS__), fflush(stdout)
99#define print_error(...) fprintf (stderr, __VA_ARGS__), fflush(stderr)
100#define absolute(L, i) (i < 0 ? lua_gettop (L) + i + 1 : i)
101
102#define COLOR(i) (colorize ? colors[i] : "")
103
104static lua_State *M;
105static int initialized = 0;
106static char *logfile, *chunkname, *prompts[2][2], *buffer = NULL;
107
108#ifdef SAVE_RESULTS
109static int results = LUA_REFNIL, results_n = 0;
110#endif
111
112static int colorize = 1;
113static const char *colors[] = {"\033[0m",
114 "\033[0;31m",
115 "\033[1;31m",
116 "\033[0;32m",
117 "\033[1;32m",
118 "\033[0;33m",
119 "\033[1;33m",
120 "\033[1m",
121 "\033[22m"};
122
123#ifdef HAVE_LIBREADLINE
124
125static void display_matches (char **matches, int num_matches, int max_length)
126{
127 print_output ("%s", COLOR(7));
128 rl_display_match_list (matches, num_matches, max_length);
129 print_output ("%s", COLOR(0));
130 rl_on_new_line ();
131}
132
133#ifdef COMPLETE_KEYWORDS
134static char *keyword_completions (const char *text, int state)
135{
136 static const char **c, *keywords[] = {
137#if LUA_VERSION_NUM == 502
138 "goto",
139#endif
140 "and", "break", "do", "else", "elseif", "end", "false", "for",
141 "function", "if", "in", "local", "nil", "not", "or",
142 "repeat", "return", "then", "true", "until", "while", NULL
143 };
144
145 int s, t;
146
147 if (state == 0) {
148 c = keywords - 1;
149 }
150
151 /* Loop through the list of keywords and return the ones that
152 * match. */
153
154 for (c += 1 ; *c ; c += 1) {
155 s = strlen (*c);
156 t = strlen(text);
157
158 if (s >= t && !strncmp (*c, text, t)) {
159 return strdup (*c);
160 }
161 }
162
163 return NULL;
164}
165#endif
166
167#ifdef COMPLETE_TABLE_KEYS
168
169static int look_up_metatable;
170
171static char *table_key_completions (const char *text, int state)
172{
173 static const char *c, *token;
174 static char oper;
175 static int h;
176
177 if (state == 0) {
178 h = lua_gettop(M);
179
180 /* Scan to the beginning of the to-be-completed token. */
181
182 for (c = text + strlen (text) - 1;
183 c >= text && *c != '.' && *c != ':' && *c != '[';
184 c -= 1);
185
186 if (c > text) {
187 oper = *c;
188 token = c + 1;
189
190 /* Get the iterable value, the keys of which we wish to
191 * complete. */
192
193 lua_pushliteral (M, "return ");
194 lua_pushlstring (M, text, token - text - 1);
195 lua_concat (M, 2);
196
197 if (luaL_loadstring (M, lua_tostring (M, -1)) ||
198 lua_pcall (M, 0, 1, 0) ||
199 (lua_type (M, -1) != LUA_TUSERDATA &&
200 lua_type (M, -1) != LUA_TTABLE)) {
201
202 lua_settop(M, h);
203 return NULL;
204 }
205 } else {
206 oper = 0;
207 token = text;
208
209 lua_pushglobaltable(M);
210 }
211
212 if (look_up_metatable) {
213 /* Replace the to-be-iterated value with it's metatable
214 * and set up a call to next. */
215
216 if (!luaL_getmetafield(M, -1, "__index") ||
217 (lua_type (M, -1) != LUA_TUSERDATA &&
218 lua_type (M, -1) != LUA_TTABLE)) {
219 lua_settop(M, h);
220 return NULL;
221 }
222
223 lua_getglobal(M, "next");
224 lua_replace(M, -3);
225 lua_pushnil(M);
226 } else {
227 /* Call the standard pairs function. */
228
229 lua_getglobal (M, "pairs");
230 lua_insert (M, -2);
231
232 if(lua_type (M, -2) != LUA_TFUNCTION ||
233 lua_pcall (M, 1, 3, 0)) {
234
235 lua_settop(M, h);
236 return NULL;
237 }
238 }
239 }
240
241 /* Iterate the table/userdata and generate matches. */
242
243 while (lua_pushvalue(M, -3), lua_insert (M, -3),
244 lua_pushvalue(M, -2), lua_insert (M, -4),
245 lua_pcall (M, 2, 2, 0) == 0) {
246 char *candidate;
247 size_t l, m;
248 int suppress, type, keytype;
249
250 if (lua_isnil(M, -2)) {
251 lua_settop(M, h);
252 return NULL;
253 }
254
255 /* Make some notes about the value we're completing. We'll
256 * make use of them later on. */
257
258 type = lua_type (M, -1);
259 suppress = (type == LUA_TTABLE || type == LUA_TUSERDATA ||
260 type == LUA_TFUNCTION);
261
262 keytype = LUA_TNIL;
263 if (type == LUA_TTABLE) {
264 lua_pushnil(M);
265 if (lua_next(M, -2)) {
266 keytype = lua_type (M, -2);
267 lua_pop (M, 2);
268 } else {
269 /* There are no keys in the table so we won't want to
270 * index it. Add a space. */
271
272 suppress = 0;
273 }
274 }
275
276 /* Pop the value, keep the key. */
277
278 lua_pop (M, 1);
279
280 /* We're mainly interested in strings at this point but if
281 * we're completing for the table[key] syntax we consider
282 * numeric keys too. */
283
284 if (lua_type (M, -1) == LUA_TSTRING ||
285 (oper == '[' && lua_type (M, -1) == LUA_TNUMBER)) {
286 if (oper == '[') {
287 if (lua_type (M, -1) == LUA_TNUMBER) {
288 lua_Number n;
289 int i;
290
291 n = lua_tonumber (M, -1);
292 i = lua_tointeger (M, -1);
293
294 /* If this isn't an integer key, we may as well
295 * forget about it. */
296
297 if ((lua_Number)i == n) {
298 l = asprintf (&candidate, "%d]", i);
299 } else {
300 continue;
301 }
302 } else {
303 char q;
304
305 q = token[0];
306 if (q != '"' && q != '\'') {
307 q = '"';
308 }
309
310 l = asprintf (&candidate, "%c%s%c]",
311 q, lua_tostring (M, -1), q);
312 }
313 } else {
314 candidate = strdup((char *)lua_tolstring (M, -1, &l));
315 }
316
317 m = strlen(token);
318
319 if (l >= m && !strncmp (token, candidate, m) &&
320 (oper != ':' || type == LUA_TFUNCTION)
321#ifdef HIDDEN_KEY_PREFIX
322 && strncmp(candidate, HIDDEN_KEY_PREFIX,
323 sizeof(HIDDEN_KEY_PREFIX) - 1)
324#endif
325 ) {
326 char *match;
327
328 /* If the candidate has been fully typed (or
329 * previously completed) consider adding certain
330 * helpful suffixes. */
331#ifndef ALWAYS_APPEND_SUFFIXES
332 if (l == m) {
333#endif
334 if (type == LUA_TFUNCTION) {
335 rl_completion_append_character = '('; suppress = 0;
336 } else if (type == LUA_TTABLE) {
337 if (keytype == LUA_TSTRING) {
338 rl_completion_append_character = '.'; suppress = 0;
339 } else if (keytype != LUA_TNIL) {
340 rl_completion_append_character = '['; suppress = 0;
341 }
342 }
343#ifndef ALWAYS_APPEND_SUFFIXES
344 };
345#endif
346
347 if (token > text) {
348 /* Were not completing a global variable. Put the
349 * completed string together out of the table and
350 * the key. */
351
352 match = (char *)malloc ((token - text) + l + 1);
353 strncpy (match, text, token - text);
354 strcpy (match + (token - text), candidate);
355
356 free(candidate);
357 } else {
358 /* Return the whole candidate as is, to be freed
359 * by Readline. */
360
361 match = candidate;
362 }
363
364 /* Suppress the newline when completing a table
365 * or other potentially complex value. */
366
367 if (suppress) {
368 rl_completion_suppress_append = 1;
369 }
370
371 return match;
372 } else {
373 free(candidate);
374 }
375 }
376 }
377
378 lua_settop(M, h);
379 return NULL;
380}
381#endif
382
383#ifdef COMPLETE_MODULES
384static char *module_completions (const char *text, int state)
385{
386 char *match = NULL;
387 static int h;
388
389 if (state == 0) {
390 glob_t vector;
391 const char *b, *d, *q, *s, *t, *strings[3];
392 int i, n = 0, ondot, hasdot, quoted;
393
394 hasdot = strchr(text, '.') != NULL;
395 ondot = text[0] != '\0' && text[strlen(text) - 1] == '.';
396 quoted = text[0] == '\'' || text[0] == '"';
397
398#ifdef NO_MODULE_LOAD
399 if(!quoted) {
400 return NULL;
401 }
402#endif
403
404 lua_newtable(M);
405 h = lua_gettop(M);
406
407 /* Try to load the input as a module. */
408
409 lua_getglobal(M, "require");
410
411 if (!lua_isfunction (M, -1)) {
412 lua_settop(M, h - 1);
413 return NULL;
414 }
415
416 lua_pushliteral(M, "package");
417
418 if(lua_pcall(M, 1, 1, 0) != LUA_OK) {
419 lua_settop(M, h - 1);
420 return NULL;
421 }
422
423 if (!ondot && !quoted && text[0] != '\0') {
424 lua_getfield(M, -1, "loaded");
425 lua_pushstring(M, text);
426 lua_gettable(M, -2);
427
428 /* If it's not an already loaded module, check whether the
429 * input is an available module by searching for it and/or
430 * trying to load it. */
431
432 if (!lua_toboolean(M, -1)) {
433 int load = 1;
434
435 lua_pop(M, 2);
436
437#ifdef CONFIRM_MODULE_LOAD
438 /* Look for the module as require would and ask the
439 * user whether it should be loaded or not. */
440
441#if LUA_VERSION_NUM == 501
442 lua_getfield(M, -1, "loaders");
443#else
444 lua_getfield(M, -1, "searchers");
445#endif
446 lua_pushnil(M);
447
448 while((load = lua_next(M, -2))) {
449 lua_pushstring(M, text);
450 lua_call(M, 1, 1);
451
452 if (lua_isfunction(M, -1)) {
453 char c;
454
455 print_output ("\nLoad module '%s' (y or n)", text);
456
457 while ((c = tolower(rl_read_key())) != 'y' && c != 'n');
458
459 if (c == 'y') {
460 lua_pop(M, 3);
461 break;
462 } else {
463 print_output ("\n");
464 rl_on_new_line ();
465
466 /* If it was found but not loaded, return
467 * the module name as a match to avoid
468 * asking the user againg if the tab key
469 * is pressed repeatedly. */
470
471 lua_settop(M, h);
472 return strdup(text);
473 }
474 }
475
476 lua_pop(M, 1);
477 }
478#endif
479
480 /* Load the model if needed. */
481
482 if (load) {
483 lua_pushfstring (M, "%s=require(\"%s\")", text, text);
484
485 if (luaL_loadstring (M, lua_tostring (M, -1)) == LUA_OK &&
486 lua_pcall (M, 0, 0, 0) == LUA_OK) {
487#ifdef CONFIRM_MODULE_LOAD
488 print_output (" ...loaded\n");
489#else
490 print_output ("\nLoaded module '%s'.\n", text);
491#endif
492
493 rl_on_new_line ();
494
495 lua_settop(M, h - 1);
496 return NULL;
497 }
498 }
499 } else {
500 lua_settop(M, h - 1);
501 return NULL;
502 }
503
504 /* Clean up but leave the package.table on the stack. */
505
506 lua_settop(M, h + 1);
507 }
508
509 /* Look for matches in package.preload. */
510
511 lua_getfield(M, -1, "preload");
512
513 lua_pushnil(M);
514 while(lua_next(M, -2)) {
515 lua_pop(M, 1);
516
517 if (lua_type(M, -1) == LUA_TSTRING &&
518 !strncmp(text + quoted, lua_tostring(M, -1),
519 strlen(text + quoted))) {
520
521 lua_pushstring(M, text);
522 lua_rawseti (M, h, (n += 1));
523 }
524 }
525
526 lua_pop(M, 1);
527
528 /* Get the configuration (directory, path separators, module
529 * name wildcard). */
530
531 lua_getfield(M, -1, "config");
532 for (s = (char *)lua_tostring(M, -1), i = 0;
533 i < 3;
534 s = t + 1, i += 1) {
535
536 t = strchr(s, '\n');
537 lua_pushlstring(M, s, t - s);
538 strings[i] = lua_tostring(M, -1);
539 }
540
541 lua_remove(M, -4);
542
543 /* Get the path and cpath */
544
545 lua_getfield(M, -4, "path");
546 lua_pushstring(M, strings[1]);
547 lua_getfield(M, -6, "cpath");
548 lua_pushstring(M, strings[1]);
549 lua_concat(M, 4);
550
551 /* Synthesize the pattern. */
552
553 if (hasdot) {
554 luaL_gsub(M, text + quoted, ".", strings[0]);
555 } else {
556 lua_pushstring(M, text + quoted);
557 }
558
559 lua_pushliteral(M, "*");
560 lua_concat(M, 2);
561
562 for (b = d = lua_tostring(M, -2) ; d ; b = d + 1) {
563 size_t i;
564
565 d = strstr(b, strings[1]);
566 q = strstr(b, strings[2]);
567
568 if (!q || q > d) {
569 continue;
570 }
571
572 lua_pushlstring(M, b, d - b);
573 luaL_gsub(M, lua_tostring(M, -1), strings[2],
574 lua_tostring(M, -2));
575
576 glob(lua_tostring(M, -1), 0, NULL, &vector);
577
578 lua_pop(M, 2);
579
580 for (i = 0 ; i < vector.gl_pathc ; i += 1) {
581 char *p = vector.gl_pathv[i];
582
583 if (quoted) {
584 lua_pushlstring(M, text, 1);
585 }
586
587 lua_pushlstring(M, p + (q - b), strlen(p) - (d - b) + 1);
588
589 if (hasdot) {
590 luaL_gsub(M, lua_tostring(M, -1), strings[0], ".");
591 lua_replace(M, -2);
592 }
593
594 {
595 const char *s;
596 size_t l;
597
598 s = lua_tolstring(M, -1, &l);
599
600 /* Suppress submodules named init. */
601
602 if (l < sizeof("init") - 1 ||
603 strcmp(s + l - sizeof("init") + 1, "init")) {
604
605 if (quoted) {
606 lua_pushlstring(M, text, 1);
607
608 lua_concat(M, 3);
609 }
610
611 lua_rawseti(M, h, (n += 1));
612 } else {
613 lua_pop(M, 1 + quoted);
614 }
615 }
616 }
617
618 globfree(&vector);
619 }
620
621 lua_pop(M, 6);
622 }
623
624 /* Return the next match from the table of matches. */
625
626 lua_pushnil(M);
627 if (lua_next(M, -2)) {
628 match = strdup(lua_tostring(M, -1));
629
630 rl_completion_suppress_append = !(match[0] == '"' || match[0] == '\'');
631
632 /* Pop the match. */
633
634 lua_pushnil(M);
635 lua_rawseti(M, -4, lua_tointeger(M, -3));
636
637 /* Pop key/value. */
638
639 lua_pop(M, 2);
640 } else {
641 /* Pop the empty table. */
642
643 lua_pop(M, 1);
644 }
645
646 return match;
647}
648#endif
649
650static char *generator (const char *text, int state)
651{
652 static int which;
653 char *match = NULL;
654
655 if (state == 0) {
656 which = 0;
657 }
658
659 /* Try to complete a keyword. */
660
661 if (which == 0) {
662#ifdef COMPLETE_KEYWORDS
663 if ((match = keyword_completions (text, state))) {
664 return match;
665 }
666#endif
667 which += 1;
668 state = 0;
669 }
670
671 /* Try to complete a module name. */
672
673 if (which == 1) {
674#ifdef COMPLETE_MODULES
675 if ((match = module_completions (text, state))) {
676 return match;
677 }
678#endif
679 which += 1;
680 state = 0;
681 }
682
683 /* Try to complete a table access. */
684
685 if (which == 2) {
686#ifdef COMPLETE_TABLE_KEYS
687 look_up_metatable = 0;
688 if ((match = table_key_completions (text, state))) {
689 return match;
690 }
691#endif
692 which += 1;
693 state = 0;
694 }
695
696 /* Try to complete a metatable access. */
697
698 if (which == 3) {
699#ifdef COMPLETE_METATABLE_KEYS
700 look_up_metatable = 1;
701 if ((match = table_key_completions (text, state))) {
702 return match;
703 }
704#endif
705 which += 1;
706 state = 0;
707 }
708
709#ifdef COMPLETE_FILE_NAMES
710 /* Try to complete a file name. */
711
712 if (which == 4) {
713 if (text[0] == '\'' || text[0] == '"') {
714 match = rl_filename_completion_function (text + 1, state);
715
716 if (match) {
717 struct stat s;
718 int n;
719
720 n = strlen (match);
721 stat(match, &s);
722
723 /* If a match was produced, add the quote
724 * characters. */
725
726 match = (char *)realloc (match, n + 3);
727 memmove (match + 1, match, n);
728 match[0] = text[0];
729
730 /* If the file's a directory, add a trailing backslash
731 * and suppress the space, otherwise add the closing
732 * quote. */
733
734 if (S_ISDIR(s.st_mode)) {
735 match[n + 1] = '/';
736
737 rl_completion_suppress_append = 1;
738 } else {
739 match[n + 1] = text[0];
740 }
741
742 match[n + 2] = '\0';
743 }
744 }
745 }
746#endif
747
748 return match;
749}
750#endif
751
752static void finish ()
753{
754#ifdef HAVE_READLINE_HISTORY
755 /* Save the command history on exit. */
756
757 if (logfile) {
758 write_history (logfile);
759 }
760#endif
761}
762
763static int traceback(lua_State *L)
764{
765 lua_Debug ar;
766 int i;
767
768 if (lua_isnoneornil (L, 1) ||
769 (!lua_isstring (L, 1) &&
770 !luaL_callmeta(L, 1, "__tostring"))) {
771 lua_pushliteral(L, "(no error message)");
772 }
773
774 if (lua_gettop (L) > 1) {
775 lua_replace (L, 1);
776 lua_settop (L, 1);
777 }
778
779 /* Print the Lua stack. */
780
781 lua_pushstring(L, "\n\nStack trace:\n");
782
783 for (i = 0 ; lua_getstack (L, i, &ar) ; i += 1) {
784#if LUA_VERSION_NUM == 501
785 lua_getinfo(M, "Snl", &ar);
786#else
787 lua_getinfo(M, "Snlt", &ar);
788
789 if (ar.istailcall) {
790 lua_pushfstring(L, "\t... tail calls\n");
791 }
792#endif
793
794 if (!strcmp (ar.what, "C")) {
795 lua_pushfstring(L, "\t#%d %s[C]:%s in function ",
796 i, COLOR(7), COLOR(8));
797
798 if (ar.name) {
799 lua_pushfstring(L, "'%s%s%s'\n",
800 COLOR(7), ar.name, COLOR(8));
801 } else {
802 lua_pushfstring(L, "%s?%s\n", COLOR(7), COLOR(8));
803 }
804 } else if (!strcmp (ar.what, "main")) {
805 lua_pushfstring(L, "\t#%d %s%s:%d:%s in the main chunk\n",
806 i, COLOR(7), ar.short_src, ar.currentline,
807 COLOR(8));
808 } else if (!strcmp (ar.what, "Lua")) {
809 lua_pushfstring(L, "\t#%d %s%s:%d:%s in function ",
810 i, COLOR(7), ar.short_src, ar.currentline,
811 COLOR(8));
812
813 if (ar.name) {
814 lua_pushfstring(L, "'%s%s%s'\n",
815 COLOR(7), ar.name, COLOR(8));
816 } else {
817 lua_pushfstring(L, "%s?%s\n", COLOR(7), COLOR(8));
818 }
819 }
820 }
821
822 if (i == 0) {
823 lua_pushstring (L, "No activation records.\n");
824 }
825
826 lua_concat (L, lua_gettop(L));
827
828 return 1;
829}
830
831static int execute ()
832{
833 int i, h_0, h, status;
834
835#ifdef SAVE_RESULTS
836 /* Get the results table, and stash it behind the to-be-executed
837 * chunk. */
838
839 lua_rawgeti(M, LUA_REGISTRYINDEX, results);
840 lua_insert(M, -2);
841#endif
842
843 h_0 = lua_gettop(M);
844 status = luap_call (M, 0);
845 h = lua_gettop (M) - h_0 + 1;
846
847 for (i = h ; i > 0 ; i -= 1) {
848 const char *result;
849
850 result = luap_describe (M, -i);
851
852#ifdef SAVE_RESULTS
853 lua_pushvalue (M, -i);
854 lua_rawseti(M, h_0 - 1, (results_n += 1));
855
856 print_output ("%s%s[%d]%s = %s%s\n",
857 COLOR(4), RESULTS_TABLE_NAME, results_n,
858 COLOR(3), result, COLOR(0));
859#else
860 if (h == 1) {
861 print_output ("%s%s%s\n", COLOR(3), result, COLOR(0));
862 } else {
863 print_output ("%s%d%s: %s%s\n", COLOR(4), h - i + 1,
864 COLOR(3), result, COLOR(0));
865 }
866#endif
867 }
868
869 /* Clean up. We need to remove the results table as well if we
870 * track results. */
871
872#ifdef SAVE_RESULTS
873 lua_settop (M, h_0 - 2);
874#else
875 lua_settop (M, h_0 - 1);
876#endif
877
878 return status;
879}
880
881/* This is the pretty-printing related stuff. */
882
883static char *dump;
884static int length, offset, indent, column, linewidth, ancestors;
885
886#define dump_literal(s) (check_fit(sizeof(s) - 1), \
887 strcpy (dump + offset, s), \
888 offset += sizeof(s) - 1, \
889 column += width(s))
890
891#define dump_character(c) (check_fit(1), \
892 dump[offset] = c, \
893 offset += 1, \
894 column += 1)
895
896static int width (const char *s)
897{
898 const char *c;
899 int n, discard = 0;
900
901 /* Calculate the printed width of the chunk s ignoring escape
902 * sequences. */
903
904 for (c = s, n = 0 ; *c ; c += 1) {
905 if (!discard && *c == '\033') {
906 discard = 1;
907 }
908
909 if (!discard) {
910 n+= 1;
911 }
912
913 if (discard && *c == 'm') {
914 discard = 0;
915 }
916 }
917
918 return n;
919}
920
921static void check_fit (int size)
922{
923 /* Check if a chunk fits in the buffer and expand as necessary. */
924
925 if (offset + size + 1 > length) {
926 length = offset + size + 1;
927 dump = (char *)realloc (dump, length * sizeof (char));
928 }
929}
930
931static int is_identifier (const char *s, int n)
932{
933 int i;
934
935 /* Check whether a string can be used as a key without quotes and
936 * braces. */
937
938 for (i = 0 ; i < n ; i += 1) {
939 if (!isalpha(s[i]) &&
940 (i == 0 || !isalnum(s[i])) &&
941 s[i] != '_') {
942 return 0;
943 }
944 }
945
946 return 1;
947}
948
949static void break_line ()
950{
951 int i;
952
953 check_fit (indent + 1);
954
955 /* Add a line break. */
956
957 dump[offset] = '\n';
958
959 /* And indent to the current level. */
960
961 for (i = 1 ; i <= indent ; i += 1) {
962 dump[offset + i] = ' ';
963 }
964
965 offset += indent + 1;
966 column = indent;
967}
968
969static void dump_string (const char *s, int n)
970{
971 int l;
972
973 /* Break the line if the current chunk doesn't fit but it would
974 * fit if we started on a fresh line at the current indent. */
975
976 l = width(s);
977
978 if (column + l > linewidth && indent + l <= linewidth) {
979 break_line();
980 }
981
982 check_fit (n);
983
984 /* Copy the string to the buffer. */
985
986 memcpy (dump + offset, s, n);
987 dump[offset + n] = '\0';
988
989 offset += n;
990 column += l;
991}
992
993static void describe (lua_State *L, int index)
994{
995 char *s;
996 size_t n;
997 int type;
998
999 index = absolute (L, index);
1000 type = lua_type (L, index);
1001
1002 if (luaL_getmetafield (L, index, "__tostring")) {
1003 lua_pushvalue (L, index);
1004 lua_pcall (L, 1, 1, 0);
1005 s = (char *)lua_tolstring (L, -1, &n);
1006 lua_pop (L, 1);
1007
1008 dump_string (s, n);
1009 } else if (type == LUA_TNUMBER) {
1010 /* Copy the value to avoid mutating it. */
1011
1012 lua_pushvalue (L, index);
1013 s = (char *)lua_tolstring (L, -1, &n);
1014 lua_pop (L, 1);
1015
1016 dump_string (s, n);
1017 } else if (type == LUA_TSTRING) {
1018 int i, started, score, level, uselevel = 0;
1019
1020 s = (char *)lua_tolstring (L, index, &n);
1021
1022 /* Scan the string to decide how to print it. */
1023
1024 for (i = 0, score = n, started = 0 ; i < (int)n ; i += 1) {
1025 if (s[i] == '\n' || s[i] == '\t' ||
1026 s[i] == '\v' || s[i] == '\r') {
1027 /* These characters show up better in a long sting so
1028 * bias towards that. */
1029
1030 score += linewidth / 2;
1031 } else if (s[i] == '\a' || s[i] == '\b' ||
1032 s[i] == '\f' || !isprint(s[i])) {
1033 /* These however go better with an escaped short
1034 * string (unless you like the bell or weird
1035 * characters). */
1036
1037 score -= linewidth / 4;
1038 }
1039
1040 /* Check what long string delimeter level to use so that
1041 * the string won't be closed prematurely. */
1042
1043 if (!started) {
1044 if (s[i] == ']') {
1045 started = 1;
1046 level = 0;
1047 }
1048 } else {
1049 if (s[i] == '=') {
1050 level += 1;
1051 } else if (s[i] == ']') {
1052 if (level >= uselevel) {
1053 uselevel = level + 1;
1054 }
1055 } else {
1056 started = 0;
1057 }
1058 }
1059 }
1060
1061 if (score > linewidth) {
1062 /* Dump the string as a long string. */
1063
1064 dump_character ('[');
1065 for (i = 0 ; i < uselevel ; i += 1) {
1066 dump_character ('=');
1067 }
1068 dump_literal ("[\n");
1069
1070 dump_string (s, n);
1071
1072 dump_character (']');
1073 for (i = 0 ; i < uselevel ; i += 1) {
1074 dump_character ('=');
1075 }
1076 dump_literal ("]");
1077 } else {
1078 /* Escape the string as needed and print it as a normal
1079 * string. */
1080
1081 dump_literal ("\"");
1082
1083 for (i = 0 ; i < (int)n ; i += 1) {
1084 if (s[i] == '"' || s[i] == '\\') {
1085 dump_literal ("\\");
1086 dump_character (s[i]);
1087 } else if (s[i] == '\a') {
1088 dump_literal ("\\a");
1089 } else if (s[i] == '\b') {
1090 dump_literal ("\\b");
1091 } else if (s[i] == '\f') {
1092 dump_literal ("\\f");
1093 } else if (s[i] == '\n') {
1094 dump_literal ("\\n");
1095 } else if (s[i] == '\r') {
1096 dump_literal ("\\r");
1097 } else if (s[i] == '\t') {
1098 dump_literal ("\\t");
1099 } else if (s[i] == '\v') {
1100 dump_literal ("\\v");
1101 } else if (isprint(s[i])) {
1102 dump_character (s[i]);
1103 } else {
1104 char t[5];
1105 size_t n;
1106
1107 n = sprintf (t, "\\%03u", ((unsigned char *)s)[i]);
1108 dump_string (t, n);
1109 }
1110 }
1111
1112 dump_literal ("\"");
1113 }
1114 } else if (type == LUA_TNIL) {
1115 n = asprintf (&s, "%snil%s", COLOR(7), COLOR(8));
1116 dump_string (s, n);
1117 free(s);
1118 } else if (type == LUA_TBOOLEAN) {
1119 n = asprintf (&s, "%s%s%s",
1120 COLOR(7),
1121 lua_toboolean (L, index) ? "true" : "false",
1122 COLOR(8));
1123 dump_string (s, n);
1124 free(s);
1125 } else if (type == LUA_TFUNCTION) {
1126 n = asprintf (&s, "<%sfunction:%s %p>",
1127 COLOR(7), COLOR(8), lua_topointer (L, index));
1128 dump_string (s, n);
1129 free(s);
1130 } else if (type == LUA_TUSERDATA) {
1131 n = asprintf (&s, "<%suserdata:%s %p>",
1132 COLOR(7), COLOR(8), lua_topointer (L, index));
1133
1134 dump_string (s, n);
1135 free(s);
1136 } else if (type == LUA_TTHREAD) {
1137 n = asprintf (&s, "<%sthread:%s %p>",
1138 COLOR(7), COLOR(8), lua_topointer (L, index));
1139 dump_string (s, n);
1140 free(s);
1141 } else if (type == LUA_TTABLE) {
1142 int i, l, n, oldindent, multiline, nobreak;
1143
1144 /* Check if table is too deeply nested. */
1145
1146 if (indent > 8 * linewidth / 10) {
1147 char *s;
1148 size_t n;
1149
1150 n = asprintf (&s, "{ %s...%s }", COLOR(7), COLOR(8));
1151 dump_string (s, n);
1152 free(s);
1153
1154 return;
1155 }
1156
1157 /* Check if the table introduces a cycle by checking whether
1158 * it is a back-edge (that is equal to an ancestor table. */
1159
1160 lua_rawgeti (L, LUA_REGISTRYINDEX, ancestors);
1161 n = lua_rawlen(L, -1);
1162
1163 for (i = 0 ; i < n ; i += 1) {
1164 lua_rawgeti (L, -1, n - i);
1165#if LUA_VERSION_NUM == 501
1166 if(lua_equal (L, -1, -3)) {
1167#else
1168 if(lua_compare (L, -1, -3, LUA_OPEQ)) {
1169#endif
1170 char *s;
1171 size_t n;
1172
1173 n = asprintf (&s, "{ %s[%d]...%s }",
1174 COLOR(7), -(i + 1), COLOR(8));
1175 dump_string (s, n);
1176 free(s);
1177 lua_pop (L, 2);
1178
1179 return;
1180 }
1181
1182 lua_pop (L, 1);
1183 }
1184
1185 /* Add the table to the ancestor list and pop the ancestor
1186 * list table. */
1187
1188 lua_pushvalue (L, index);
1189 lua_rawseti (L, -2, n + 1);
1190 lua_pop (L, 1);
1191
1192 /* Open the table and update the indentation level to the
1193 * current column. */
1194
1195 dump_literal ("{ ");
1196 oldindent = indent;
1197 indent = column;
1198 multiline = 0;
1199 nobreak = 0;
1200
1201 l = lua_rawlen (L, index);
1202
1203 /* Traverse the array part first. */
1204
1205 for (i = 0 ; i < l ; i += 1) {
1206 lua_pushinteger (L, i + 1);
1207 lua_gettable (L, index);
1208
1209 /* Start a fresh line when dumping tables to make sure
1210 * there's plenty of room. */
1211
1212 if (lua_istable (L, -1)) {
1213 if (!nobreak) {
1214 break_line();
1215 }
1216
1217 multiline = 1;
1218 }
1219
1220 nobreak = 0;
1221
1222 /* Dump the value and separating comma. */
1223
1224 describe (L, -1);
1225 dump_literal (", ");
1226
1227 if (lua_istable (L, -1) && i != l - 1) {
1228 break_line();
1229 nobreak = 1;
1230 }
1231
1232 lua_pop (L, 1);
1233 }
1234
1235 /* Now for the hash part. */
1236
1237 lua_pushnil (L);
1238 while (lua_next (L, index) != 0) {
1239 if (lua_type (L, -2) != LUA_TNUMBER ||
1240 lua_tonumber (L, -2) != lua_tointeger (L, -2) ||
1241 lua_tointeger (L, -2) < 1 ||
1242 lua_tointeger (L, -2) > l) {
1243
1244 /* Keep each key-value pair on a separate line. */
1245
1246 break_line ();
1247 multiline = 1;
1248
1249 /* Dump the key and value. */
1250
1251 if (lua_type (L, -2) == LUA_TSTRING) {
1252 char *s;
1253 size_t n;
1254
1255 s = (char *)lua_tolstring (L, -2, &n);
1256
1257 if(is_identifier (s, n)) {
1258 dump_string (COLOR(7), strlen(COLOR(7)));
1259 dump_string (s, n);
1260 dump_string (COLOR(8), strlen(COLOR(8)));
1261 } else {
1262 dump_literal ("[");
1263 describe (L, -2);
1264 dump_literal ("]");
1265 }
1266 } else {
1267 dump_literal ("[");
1268 describe (L, -2);
1269 dump_literal ("]");
1270 }
1271
1272 dump_literal (" = ");
1273 describe (L, -1);
1274 dump_literal (",");
1275 }
1276
1277 lua_pop (L, 1);
1278 }
1279
1280 /* Remove the table from the ancestor list. */
1281
1282 lua_rawgeti (L, LUA_REGISTRYINDEX, ancestors);
1283 lua_pushnil (L);
1284 lua_rawseti (L, -2, n + 1);
1285 lua_pop (L, 1);
1286
1287 /* Pop the indentation level. */
1288
1289 indent = oldindent;
1290
1291 if (multiline) {
1292 break_line();
1293 dump_literal ("}");
1294 } else {
1295 dump_literal (" }");
1296 }
1297 }
1298}
1299
1300char *luap_describe (lua_State *L, int index)
1301{
1302 int oldcolorize;
1303
1304#ifdef HAVE_IOCTL
1305 struct winsize w;
1306
1307 /* Initialize the state. */
1308
1309 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0) {
1310 linewidth = 80;
1311 } else {
1312 linewidth = w.ws_col;
1313 }
1314#else
1315 linewidth = 80;
1316#endif
1317
1318 index = absolute (L, index);
1319 offset = 0;
1320 indent = 0;
1321 column = 0;
1322
1323 /* Suppress colorization, to avoid escape sequences in the
1324 * returned strings. */
1325
1326 oldcolorize = colorize;
1327 colorize = 0;
1328
1329 /* Create a table to hold the ancestors for checking for cycles
1330 * when printing table hierarchies. */
1331
1332 lua_newtable (L);
1333 ancestors = luaL_ref (L, LUA_REGISTRYINDEX);
1334
1335 describe (L, index);
1336
1337 luaL_unref (L, LUA_REGISTRYINDEX, ancestors);
1338 colorize = oldcolorize;
1339
1340 return dump;
1341}
1342
1343/* These are custom commands. */
1344
1345#ifdef HAVE_LIBREADLINE
1346static int describe_stack (int count, int key)
1347{
1348 int i, h;
1349
1350 print_output ("%s", COLOR(7));
1351
1352 h = lua_gettop (M);
1353
1354 if (count < 0) {
1355 i = h + count + 1;
1356
1357 if (i > 0 && i <= h) {
1358 print_output ("\nValue at stack index %d(%d):\n%s%s",
1359 i, -h + i - 1, COLOR(3), luap_describe (M, i));
1360 } else {
1361 print_error ("Invalid stack index.\n");
1362 }
1363 } else {
1364 if (h > 0) {
1365 print_output ("\nThe stack contains %d values.\n", h);
1366 for (i = 1 ; i <= h ; i += 1) {
1367 print_output ("\n%d(%d):\t%s", i, -h + i - 1, lua_typename(M, lua_type(M, i)));
1368 }
1369 } else {
1370 print_output ("\nThe stack is empty.");
1371 }
1372 }
1373
1374 print_output ("%s\n", COLOR(0));
1375
1376 rl_on_new_line ();
1377
1378 return 0;
1379}
1380#endif
1381
1382int luap_call (lua_State *L, int n) {
1383 int h, status;
1384
1385 /* We can wind up here before reaching luap_enter, so this is
1386 * needed. */
1387
1388 M = L;
1389
1390 /* Push the error handler onto the stack. */
1391
1392 h = lua_gettop(L) - n;
1393 lua_pushcfunction (L, traceback);
1394 lua_insert (L, h);
1395
1396 /* Try to execute the supplied chunk and keep note of any return
1397 * values. */
1398
1399 status = lua_pcall(L, n, LUA_MULTRET, h);
1400
1401 /* Print any errors. */
1402
1403 if (status != LUA_OK) {
1404 print_error ("%s%s%s\n", COLOR(1), lua_tostring (L, -1), COLOR(0));
1405 lua_pop (L, 1);
1406 }
1407
1408 /* Remove the error handler. */
1409
1410 lua_remove (L, h);
1411
1412 return status;
1413}
1414
1415void luap_setprompts(lua_State *L, const char *single, const char *multi)
1416{
1417 /* Plain, uncolored prompts. */
1418
1419 prompts[0][0] = (char *)realloc (prompts[0][0], strlen (single) + 1);
1420 prompts[0][1] = (char *)realloc (prompts[0][1], strlen (multi) + 1);
1421 strcpy(prompts[0][0], single);
1422 strcpy(prompts[0][1], multi);
1423
1424 /* Colored prompts. */
1425
1426 prompts[1][0] = (char *)realloc (prompts[1][0], strlen (single) + 16);
1427 prompts[1][1] = (char *)realloc (prompts[1][1], strlen (multi) + 16);
1428#ifdef HAVE_LIBREADLINE
1429 sprintf (prompts[1][0], "\001%s\002%s\001%s\002",
1430 COLOR(6), single, COLOR(0));
1431 sprintf (prompts[1][1], "\001%s\002%s\001%s\002",
1432 COLOR(6), multi, COLOR(0));
1433#else
1434 sprintf (prompts[1][0], "%s%s%s", COLOR(6), single, COLOR(0));
1435 sprintf (prompts[1][1], "%s%s%s", COLOR(6), multi, COLOR(0));
1436#endif
1437}
1438
1439void luap_sethistory(lua_State *L, const char *file)
1440{
1441 if (file) {
1442 logfile = realloc (logfile, strlen(file) + 1);
1443 strcpy (logfile, file);
1444 } else if (logfile) {
1445 free(logfile);
1446 logfile = NULL;
1447 }
1448}
1449
1450void luap_setcolor(lua_State *L, int enable)
1451{
1452 /* Don't allow color if we're not writing to a terminal. */
1453
1454 if (!isatty (STDOUT_FILENO) || !isatty (STDERR_FILENO)) {
1455 colorize = 0;
1456 } else {
1457 colorize = enable;
1458 }
1459}
1460
1461void luap_setname(lua_State *L, const char *name)
1462{
1463 chunkname = (char *)realloc (chunkname, strlen(name) + 2);
1464 chunkname[0] = '=';
1465 strcpy (chunkname + 1, name);
1466}
1467
1468void luap_getprompts(lua_State *L, const char **single, const char **multi)
1469{
1470 *single = prompts[0][0];
1471 *multi = prompts[0][1];
1472}
1473
1474void luap_gethistory(lua_State *L, const char **file)
1475{
1476 *file = logfile;
1477}
1478
1479void luap_getcolor(lua_State *L, int *enabled)
1480{
1481 *enabled = colorize;
1482}
1483
1484void luap_getname(lua_State *L, const char **name)
1485{
1486 *name = chunkname + 1;
1487}
1488
1489void luap_enter(lua_State *L, bool *terminate)
1490{
1491 int incomplete = 0, s = 0, t = 0, l;
1492 char *line, *prepended;
1493#ifdef SAVE_RESULTS
1494 int cleanup = 0;
1495#endif
1496
1497 /* Save the state since it needs to be passed to some readline
1498 * callbacks. */
1499
1500 M = L;
1501
1502 if (!initialized) {
1503#ifdef HAVE_LIBREADLINE
1504 rl_basic_word_break_characters = " \t\n`@$><=;|&{(";
1505 rl_completion_entry_function = generator;
1506 rl_completion_display_matches_hook = display_matches;
1507
1508 rl_add_defun ("lua-describe-stack", describe_stack, META('s'));
1509#endif
1510
1511#ifdef HAVE_READLINE_HISTORY
1512 /* Load the command history if there is one. */
1513
1514 if (logfile) {
1515 read_history (logfile);
1516 }
1517#endif
1518 if (!chunkname) {
1519 luap_setname (L, "lua");
1520 }
1521
1522 if (!prompts[0][0]) {
1523 luap_setprompts (L, "> ", ">> ");
1524 }
1525
1526 atexit (finish);
1527
1528 initialized = 1;
1529 }
1530
1531#ifdef SAVE_RESULTS
1532 if (results == LUA_REFNIL) {
1533 lua_newtable(L);
1534
1535#ifdef WEAK_RESULTS
1536 lua_newtable(L);
1537 lua_pushliteral(L, "v");
1538 lua_setfield(L, -2, "__mode");
1539 lua_setmetatable(L, -2);
1540#endif
1541
1542 results = luaL_ref(L, LUA_REGISTRYINDEX);
1543 }
1544
1545 lua_getglobal(L, RESULTS_TABLE_NAME);
1546 if (lua_isnil(L, -1)) {
1547 lua_rawgeti(L, LUA_REGISTRYINDEX, results);
1548 lua_setglobal(L, RESULTS_TABLE_NAME);
1549
1550 cleanup = 1;
1551 }
1552 lua_pop(L, 1);
1553#endif
1554
1555 while (!(*terminate) &&
1556 (line = readline (incomplete ?
1557 prompts[colorize][1] : prompts[colorize][0]))) {
1558 int status;
1559
1560 if (*line == '\0') {
1561 free(line);
1562 continue;
1563 }
1564
1565 /* Add/copy the line to the buffer. */
1566
1567 if (incomplete) {
1568 s += strlen (line) + 1;
1569
1570 if (s > t) {
1571 buffer = (char *)realloc (buffer, s + 1);
1572 t = s;
1573 }
1574
1575 strcat (buffer, "\n");
1576 strcat (buffer, line);
1577 } else {
1578 s = strlen (line);
1579
1580 if (s > t) {
1581 buffer = (char *)realloc (buffer, s + 1);
1582 t = s;
1583 }
1584
1585 strcpy (buffer, line);
1586 }
1587
1588 /* Try to execute the line with a return prepended first. If
1589 * this works we can show returned values. */
1590
1591 l = asprintf (&prepended, "return %s", buffer);
1592
1593 if (luaL_loadbuffer(L, prepended, l, chunkname) == LUA_OK) {
1594 execute();
1595
1596 incomplete = 0;
1597 } else {
1598 lua_pop (L, 1);
1599
1600 /* Try to execute the line as-is. */
1601
1602 status = luaL_loadbuffer(L, buffer, s, chunkname);
1603
1604 incomplete = 0;
1605
1606 if (status == LUA_ERRSYNTAX) {
1607 const char *message;
1608 const int k = sizeof(EOF_MARKER) / sizeof(char) - 1;
1609 size_t n;
1610
1611 message = lua_tolstring (L, -1, &n);
1612
1613 /* If the error message mentions an unexpected eof
1614 * then consider this a multi-line statement and wait
1615 * for more input. If not then just print the error
1616 * message.*/
1617
1618 if ((int)n > k &&
1619 !strncmp (message + n - k, EOF_MARKER, k)) {
1620 incomplete = 1;
1621 } else {
1622 print_error ("%s%s%s\n", COLOR(1), lua_tostring (L, -1),
1623 COLOR(0));
1624 }
1625
1626 lua_pop (L, 1);
1627 } else if (status == LUA_ERRMEM) {
1628 print_error ("%s%s%s\n", COLOR(1), lua_tostring (L, -1),
1629 COLOR(0));
1630 lua_pop (L, 1);
1631 } else {
1632 /* Try to execute the loaded chunk. */
1633
1634 execute ();
1635 incomplete = 0;
1636 }
1637 }
1638
1639#ifdef HAVE_READLINE_HISTORY
1640 /* Add the line to the history if non-empty. */
1641
1642 if (!incomplete) {
1643 add_history (buffer);
1644 }
1645#endif
1646
1647 free (prepended);
1648 free (line);
1649 }
1650
1651#ifdef SAVE_RESULTS
1652 if (cleanup) {
1653 lua_pushnil(L);
1654 lua_setglobal(L, RESULTS_TABLE_NAME);
1655 }
1656#endif
1657
1658 print_output ("\n");
1659}
diff --git a/utils/hwstub/tools/prompt.h b/utils/hwstub/tools/prompt.h
new file mode 100644
index 0000000000..0ad044b934
--- /dev/null
+++ b/utils/hwstub/tools/prompt.h
@@ -0,0 +1,55 @@
1/* Copyright (C) 2012-2015 Papavasileiou Dimitris
2 *
3 * Permission is hereby granted, free of charge, to any person
4 * obtaining a copy of this software and associated documentation
5 * files (the "Software"), to deal in the Software without
6 * restriction, including without limitation the rights to use, copy,
7 * modify, merge, publish, distribute, sublicense, and/or sell copies
8 * of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#ifndef _PROMPT_H_
25#define _PROMPT_H_
26
27#include <lualib.h>
28#include <lauxlib.h>
29
30#define HAVE_LIBREADLINE
31#define HAVE_READLINE_HISTORY
32#define HAVE_IOCTL
33#define COMPLETE_KEYWORDS
34#define COMPLETE_MODULES
35#define COMPLETE_TABLE_KEYS
36#define COMPLETE_METATABLE_KEYS
37#define COMPLETE_FILE_NAMES
38
39#define LUAP_VERSION "0.6"
40
41void luap_setprompts(lua_State *L, const char *single, const char *multi);
42void luap_sethistory(lua_State *L, const char *file);
43void luap_setname(lua_State *L, const char *name);
44void luap_setcolor(lua_State *L, int enable);
45
46void luap_getprompts(lua_State *L, const char **single, const char **multi);
47void luap_gethistory(lua_State *L, const char **file);
48void luap_getcolor(lua_State *L, int *enabled);
49void luap_getname(lua_State *L, const char **name);
50
51void luap_enter(lua_State *L, bool *terminate);
52char *luap_describe (lua_State *L, int index);
53int luap_call (lua_State *L, int n);
54
55#endif