A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

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

+1724 -18
+1 -1
utils/hwstub/tools/Makefile
··· 26 26 %.o: %.cpp 27 27 $(CXX) $(CXXFLAGS) -c -o $@ $< 28 28 29 - hwstub_shell: hwstub_shell.o $(LIBS) 29 + hwstub_shell: hwstub_shell.o prompt.o $(LIBS) 30 30 $(LD) -o $@ $^ $(LDFLAGS) 31 31 32 32 hwstub_load: hwstub_load.o $(LIBS)
+5 -15
utils/hwstub/tools/hwstub_shell.cpp
··· 29 29 #include <lua.hpp> 30 30 #include <unistd.h> 31 31 #include "soc_desc.hpp" 32 + extern "C" { 33 + #include "prompt.h" 34 + } 32 35 33 36 #if LUA_VERSION_NUM < 502 34 37 #warning You need at least lua 5.2 ··· 941 944 printf("error: %s\n", lua_tostring(g_lua, -1)); 942 945 } 943 946 944 - // use readline to provide some history and completion 945 - rl_bind_key('\t', rl_complete); 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 - } 947 + // start interactive shell 948 + luap_enter(g_lua, &g_exit); 959 949 960 950 Lerr: 961 951 // display log if handled
+4 -2
utils/hwstub/tools/lua/hwlib.lua
··· 22 22 io.close(f) 23 23 end 24 24 25 - function HWLIB.printf(s,...) 26 - return io.write(s:format(...)) 25 + function HWLIB.printf(...) 26 + local function wrapper(...) io.write(string.format(...)) end 27 + local status, result = pcall(wrapper, ...) 28 + if not status then error(result, 2) end 27 29 end
+1659
utils/hwstub/tools/prompt.c
··· 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 + 63 + static 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 + 104 + static lua_State *M; 105 + static int initialized = 0; 106 + static char *logfile, *chunkname, *prompts[2][2], *buffer = NULL; 107 + 108 + #ifdef SAVE_RESULTS 109 + static int results = LUA_REFNIL, results_n = 0; 110 + #endif 111 + 112 + static int colorize = 1; 113 + static 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 + 125 + static 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 134 + static 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 + 169 + static int look_up_metatable; 170 + 171 + static 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 384 + static 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 + 650 + static 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 + 752 + static 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 + 763 + static 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 + 831 + static 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 + 883 + static char *dump; 884 + static 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 + 896 + static 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 + 921 + static 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 + 931 + static 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 + 949 + static 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 + 969 + static 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 + 993 + static 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 + 1300 + char *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 1346 + static 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 + 1382 + int 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 + 1415 + void 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 + 1439 + void 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 + 1450 + void 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 + 1461 + void 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 + 1468 + void luap_getprompts(lua_State *L, const char **single, const char **multi) 1469 + { 1470 + *single = prompts[0][0]; 1471 + *multi = prompts[0][1]; 1472 + } 1473 + 1474 + void luap_gethistory(lua_State *L, const char **file) 1475 + { 1476 + *file = logfile; 1477 + } 1478 + 1479 + void luap_getcolor(lua_State *L, int *enabled) 1480 + { 1481 + *enabled = colorize; 1482 + } 1483 + 1484 + void luap_getname(lua_State *L, const char **name) 1485 + { 1486 + *name = chunkname + 1; 1487 + } 1488 + 1489 + void 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 + }
+55
utils/hwstub/tools/prompt.h
··· 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 + 41 + void luap_setprompts(lua_State *L, const char *single, const char *multi); 42 + void luap_sethistory(lua_State *L, const char *file); 43 + void luap_setname(lua_State *L, const char *name); 44 + void luap_setcolor(lua_State *L, int enable); 45 + 46 + void luap_getprompts(lua_State *L, const char **single, const char **multi); 47 + void luap_gethistory(lua_State *L, const char **file); 48 + void luap_getcolor(lua_State *L, int *enabled); 49 + void luap_getname(lua_State *L, const char **name); 50 + 51 + void luap_enter(lua_State *L, bool *terminate); 52 + char *luap_describe (lua_State *L, int index); 53 + int luap_call (lua_State *L, int n); 54 + 55 + #endif