lua.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /*
  2. ** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
  3. ** Lua stand-alone interpreter
  4. ** See Copyright Notice in lua.h
  5. */
  6. // #include <signal.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "flash_fs.h"
  11. #include "user_version.h"
  12. #include "driver/readline.h"
  13. #include "driver/uart.h"
  14. #include "esp_system.h"
  15. #define lua_c
  16. #include "lua.h"
  17. #include "lauxlib.h"
  18. #include "lualib.h"
  19. #include "legc.h"
  20. #include "os_type.h"
  21. lua_State *globalL = NULL;
  22. lua_Load gLoad;
  23. static const char *progname = LUA_PROGNAME;
  24. #if 0
  25. static void lstop (lua_State *L, lua_Debug *ar) {
  26. (void)ar; /* unused arg. */
  27. lua_sethook(L, NULL, 0, 0);
  28. luaL_error(L, "interrupted!");
  29. }
  30. static void laction (int i) {
  31. // signal(i, SIG_DFL);
  32. /* if another SIGINT happens before lstop,
  33. terminate process (default action) */
  34. lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
  35. }
  36. static void print_usage (void) {
  37. #if defined(LUA_USE_STDIO)
  38. c_fprintf(c_stderr,
  39. #else
  40. luai_writestringerror(
  41. #endif
  42. "usage: %s [options] [script [args]].\n"
  43. "Available options are:\n"
  44. " -e stat execute string " LUA_QL("stat") "\n"
  45. " -l name require library " LUA_QL("name") "\n"
  46. " -m limit set memory limit. (units are in Kbytes)\n"
  47. " -i enter interactive mode after executing " LUA_QL("script") "\n"
  48. " -v show version information\n"
  49. " -- stop handling options\n"
  50. " - execute stdin and stop handling options\n"
  51. ,
  52. progname);
  53. #if defined(LUA_USE_STDIO)
  54. c_fflush(c_stderr);
  55. #endif
  56. }
  57. #endif
  58. static void l_message (const char *pname, const char *msg) {
  59. #if defined(LUA_USE_STDIO)
  60. if (pname) c_fprintf(c_stderr, "%s: ", pname);
  61. c_fprintf(c_stderr, "%s\n", msg);
  62. c_fflush(c_stderr);
  63. #else
  64. if (pname) luai_writestringerror("%s: ", pname);
  65. luai_writestringerror("%s\n", msg);
  66. #endif
  67. }
  68. static int report (lua_State *L, int status) {
  69. if (status && !lua_isnil(L, -1)) {
  70. const char *msg = lua_tostring(L, -1);
  71. if (msg == NULL) msg = "(error object is not a string)";
  72. l_message(progname, msg);
  73. lua_pop(L, 1);
  74. }
  75. return status;
  76. }
  77. static int traceback (lua_State *L) {
  78. if (!lua_isstring(L, 1)) /* 'message' not a string? */
  79. return 1; /* keep it intact */
  80. lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  81. if (!lua_istable(L, -1) && !lua_isrotable(L, -1)) {
  82. lua_pop(L, 1);
  83. return 1;
  84. }
  85. lua_getfield(L, -1, "traceback");
  86. if (!lua_isfunction(L, -1) && !lua_islightfunction(L, -1)) {
  87. lua_pop(L, 2);
  88. return 1;
  89. }
  90. lua_pushvalue(L, 1); /* pass error message */
  91. lua_pushinteger(L, 2); /* skip this function and traceback */
  92. lua_call(L, 2, 1); /* call debug.traceback */
  93. return 1;
  94. }
  95. static int docall (lua_State *L, int narg, int clear) {
  96. int status;
  97. int base = lua_gettop(L) - narg; /* function index */
  98. lua_pushcfunction(L, traceback); /* push traceback function */
  99. lua_insert(L, base); /* put it under chunk and args */
  100. // signal(SIGINT, laction);
  101. status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
  102. // signal(SIGINT, SIG_DFL);
  103. lua_remove(L, base); /* remove traceback function */
  104. /* force a complete garbage collection in case of errors */
  105. if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
  106. return status;
  107. }
  108. static void print_version (lua_State *L) {
  109. lua_pushliteral (L, "\n" NODE_VERSION " build " BUILD_DATE " powered by " LUA_RELEASE " on RTOS-SDK ");
  110. lua_pushstring (L, system_get_sdk_version ());
  111. lua_concat (L, 2);
  112. const char *msg = lua_tostring (L, -1);
  113. l_message (NULL, msg);
  114. lua_pop (L, 1);
  115. }
  116. static int getargs (lua_State *L, char **argv, int n) {
  117. int narg;
  118. int i;
  119. int argc = 0;
  120. while (argv[argc]) argc++; /* count total number of arguments */
  121. narg = argc - (n + 1); /* number of arguments to the script */
  122. luaL_checkstack(L, narg + 3, "too many arguments to script");
  123. for (i=n+1; i < argc; i++)
  124. lua_pushstring(L, argv[i]);
  125. lua_createtable(L, narg, n + 1);
  126. for (i=0; i < argc; i++) {
  127. lua_pushstring(L, argv[i]);
  128. lua_rawseti(L, -2, i - n);
  129. }
  130. return narg;
  131. }
  132. #if 0
  133. static int dofile (lua_State *L, const char *name) {
  134. int status = luaL_loadfile(L, name) || docall(L, 0, 1);
  135. return report(L, status);
  136. }
  137. #else
  138. static int dofsfile (lua_State *L, const char *name) {
  139. int status = luaL_loadfsfile(L, name) || docall(L, 0, 1);
  140. return report(L, status);
  141. }
  142. #endif
  143. static int dostring (lua_State *L, const char *s, const char *name) {
  144. int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
  145. return report(L, status);
  146. }
  147. static int dolibrary (lua_State *L, const char *name) {
  148. lua_getglobal(L, "require");
  149. lua_pushstring(L, name);
  150. return report(L, docall(L, 1, 1));
  151. }
  152. static const char *get_prompt (lua_State *L, int firstline) {
  153. const char *p;
  154. lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
  155. p = lua_tostring(L, -1);
  156. if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
  157. lua_pop(L, 1); /* remove global */
  158. return p;
  159. }
  160. static int incomplete (lua_State *L, int status) {
  161. if (status == LUA_ERRSYNTAX) {
  162. size_t lmsg;
  163. const char *msg = lua_tolstring(L, -1, &lmsg);
  164. const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
  165. if (strstr(msg, LUA_QL("<eof>")) == tp) {
  166. lua_pop(L, 1);
  167. return 1;
  168. }
  169. }
  170. return 0; /* else... */
  171. }
  172. #if 0
  173. static int pushline (lua_State *L, int firstline) {
  174. char buffer[LUA_MAXINPUT];
  175. char *b = buffer;
  176. size_t l;
  177. const char *prmt = get_prompt(L, firstline);
  178. if (lua_readline(L, b, prmt) == 0)
  179. return 0; /* no input */
  180. l = strlen(b);
  181. if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
  182. b[l-1] = '\0'; /* remove it */
  183. if (firstline && b[0] == '=') /* first line starts with `=' ? */
  184. lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
  185. else
  186. lua_pushstring(L, b);
  187. lua_freeline(L, b);
  188. return 1;
  189. }
  190. static int loadline (lua_State *L) {
  191. int status;
  192. lua_settop(L, 0);
  193. if (!pushline(L, 1))
  194. return -1; /* no input */
  195. for (;;) { /* repeat until gets a complete line */
  196. status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
  197. if (!incomplete(L, status)) break; /* cannot try to add lines? */
  198. if (!pushline(L, 0)) /* no more input? */
  199. return -1;
  200. lua_pushliteral(L, "\n"); /* add a new line... */
  201. lua_insert(L, -2); /* ...between the two lines */
  202. lua_concat(L, 3); /* join them */
  203. }
  204. lua_saveline(L, 1);
  205. lua_remove(L, 1); /* remove line */
  206. return status;
  207. }
  208. static void dotty (lua_State *L) {
  209. int status;
  210. const char *oldprogname = progname;
  211. progname = NULL;
  212. while ((status = loadline(L)) != -1) {
  213. if (status == 0) status = docall(L, 0, 0);
  214. report(L, status);
  215. if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
  216. lua_getglobal(L, "print");
  217. lua_insert(L, 1);
  218. if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
  219. l_message(progname, lua_pushfstring(L,
  220. "error calling " LUA_QL("print") " (%s)",
  221. lua_tostring(L, -1)));
  222. }
  223. }
  224. lua_settop(L, 0); /* clear stack */
  225. #if defined(LUA_USE_STDIO)
  226. c_fputs("\n", c_stdout);
  227. c_fflush(c_stdout);
  228. #else
  229. luai_writeline();
  230. #endif
  231. progname = oldprogname;
  232. }
  233. static int handle_script (lua_State *L, char **argv, int n) {
  234. int status;
  235. const char *fname;
  236. int narg = getargs(L, argv, n); /* collect arguments */
  237. lua_setglobal(L, "arg");
  238. fname = argv[n];
  239. if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
  240. fname = NULL; /* stdin */
  241. status = luaL_loadfile(L, fname);
  242. lua_insert(L, -(narg+1));
  243. if (status == 0)
  244. status = docall(L, narg, 0);
  245. else
  246. lua_pop(L, narg);
  247. return report(L, status);
  248. }
  249. #endif
  250. /* check that argument has no extra characters at the end */
  251. #define notail(x) {if ((x)[2] != '\0') return -1;}
  252. static int collectargs (char **argv, int *pi, int *pv, int *pe) {
  253. int i;
  254. for (i = 1; argv[i] != NULL; i++) {
  255. if (argv[i][0] != '-') /* not an option? */
  256. return i;
  257. switch (argv[i][1]) { /* option */
  258. case '-':
  259. notail(argv[i]);
  260. return (argv[i+1] != NULL ? i+1 : 0);
  261. case '\0':
  262. return i;
  263. case 'i':
  264. notail(argv[i]);
  265. *pi = 1; /* go through */
  266. case 'v':
  267. notail(argv[i]);
  268. *pv = 1;
  269. break;
  270. case 'e':
  271. *pe = 1; /* go through */
  272. case 'm': /* go through */
  273. case 'l':
  274. if (argv[i][2] == '\0') {
  275. i++;
  276. if (argv[i] == NULL) return -1;
  277. }
  278. break;
  279. default: return -1; /* invalid option */
  280. }
  281. }
  282. return 0;
  283. }
  284. static int runargs (lua_State *L, char **argv, int n) {
  285. int i;
  286. for (i = 1; i < n; i++) {
  287. if (argv[i] == NULL) continue;
  288. lua_assert(argv[i][0] == '-');
  289. switch (argv[i][1]) { /* option */
  290. case 'e': {
  291. const char *chunk = argv[i] + 2;
  292. if (*chunk == '\0') chunk = argv[++i];
  293. lua_assert(chunk != NULL);
  294. if (dostring(L, chunk, "=(command line)") != 0)
  295. return 1;
  296. break;
  297. }
  298. case 'm': {
  299. const char *limit = argv[i] + 2;
  300. int memlimit=0;
  301. if (*limit == '\0') limit = argv[++i];
  302. lua_assert(limit != NULL);
  303. memlimit = atoi(limit);
  304. lua_gc(L, LUA_GCSETMEMLIMIT, memlimit);
  305. break;
  306. }
  307. case 'l': {
  308. const char *filename = argv[i] + 2;
  309. if (*filename == '\0') filename = argv[++i];
  310. lua_assert(filename != NULL);
  311. if (dolibrary(L, filename))
  312. return 1; /* stop if file fails */
  313. break;
  314. }
  315. default: break;
  316. }
  317. }
  318. return 0;
  319. }
  320. static int handle_luainit (lua_State *L) {
  321. const char *init = c_getenv(LUA_INIT);
  322. if (init == NULL) return 0; /* status OK */
  323. else if (init[0] == '@')
  324. #if 0
  325. return dofile(L, init+1);
  326. #else
  327. return dofsfile(L, init+1);
  328. #endif
  329. else
  330. return dostring(L, init, "=" LUA_INIT);
  331. }
  332. struct Smain {
  333. int argc;
  334. char **argv;
  335. int status;
  336. };
  337. static int pmain (lua_State *L) {
  338. struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
  339. char **argv = s->argv;
  340. int script;
  341. int has_i = 0, has_v = 0, has_e = 0;
  342. globalL = L;
  343. if (argv[0] && argv[0][0]) progname = argv[0];
  344. lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
  345. luaL_openlibs(L); /* open libraries */
  346. lua_gc(L, LUA_GCRESTART, 0);
  347. print_version(L);
  348. s->status = handle_luainit(L);
  349. #if 0
  350. if (s->status != 0) return 0;
  351. #endif
  352. script = collectargs(argv, &has_i, &has_v, &has_e);
  353. if (script < 0) { /* invalid args? */
  354. #if 0
  355. print_usage();
  356. #endif
  357. s->status = 1;
  358. return 0;
  359. }
  360. // if (has_v) print_version();
  361. s->status = runargs(L, argv, (script > 0) ? script : s->argc);
  362. if (s->status != 0) return 0;
  363. #if 0
  364. if (script)
  365. s->status = handle_script(L, argv, script);
  366. if (s->status != 0) return 0;
  367. if (has_i)
  368. dotty(L);
  369. else if (script == 0 && !has_e && !has_v) {
  370. if (lua_stdin_is_tty()) {
  371. print_version();
  372. dotty(L);
  373. }
  374. else dofile(L, NULL); /* executes stdin as a file */
  375. }
  376. #endif
  377. return 0;
  378. }
  379. static void dojob(lua_Load *load);
  380. static bool readline(lua_Load *load);
  381. char line_buffer[LUA_MAXINPUT];
  382. #ifdef LUA_RPC
  383. int main (int argc, char **argv) {
  384. #else
  385. int lua_main (int argc, char **argv) {
  386. #endif
  387. int status;
  388. struct Smain s;
  389. lua_State *L = lua_open(); /* create state */
  390. if (L == NULL) {
  391. l_message(argv[0], "cannot create state: not enough memory");
  392. return EXIT_FAILURE;
  393. }
  394. s.argc = argc;
  395. s.argv = argv;
  396. status = lua_cpcall(L, &pmain, &s);
  397. report(L, status);
  398. gLoad.L = L;
  399. gLoad.firstline = 1;
  400. gLoad.done = 0;
  401. gLoad.line = line_buffer;
  402. gLoad.len = LUA_MAXINPUT;
  403. gLoad.line_position = 0;
  404. gLoad.prmt = get_prompt(L, 1);
  405. dojob(&gLoad);
  406. NODE_DBG("Heap size::%d.\n",system_get_free_heap_size());
  407. legc_set_mode( L, EGC_ALWAYS, 4096 );
  408. // legc_set_mode( L, EGC_ON_MEM_LIMIT, 4096 );
  409. // lua_close(L);
  410. return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
  411. }
  412. void lua_handle_input (bool force)
  413. {
  414. if (gLoad.L && (force || readline (&gLoad)))
  415. dojob (&gLoad);
  416. }
  417. void donejob(lua_Load *load){
  418. lua_close(load->L);
  419. }
  420. static void dojob(lua_Load *load){
  421. size_t l, rs;
  422. int status;
  423. char *b = load->line;
  424. lua_State *L = load->L;
  425. const char *oldprogname = progname;
  426. progname = NULL;
  427. do{
  428. if(load->done == 1){
  429. l = strlen(b);
  430. if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
  431. b[l-1] = '\0'; /* remove it */
  432. if (load->firstline && b[0] == '=') /* first line starts with `=' ? */
  433. lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
  434. else
  435. lua_pushstring(L, b);
  436. if(load->firstline != 1){
  437. lua_pushliteral(L, "\n"); /* add a new line... */
  438. lua_insert(L, -2); /* ...between the two lines */
  439. lua_concat(L, 3); /* join them */
  440. }
  441. status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
  442. if (!incomplete(L, status)) { /* cannot try to add lines? */
  443. lua_remove(L, 1); /* remove line */
  444. if (status == 0) {
  445. status = docall(L, 0, 0);
  446. }
  447. report(L, status);
  448. if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
  449. lua_getglobal(L, "print");
  450. lua_insert(L, 1);
  451. if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
  452. l_message(progname, lua_pushfstring(L,
  453. "error calling " LUA_QL("print") " (%s)",
  454. lua_tostring(L, -1)));
  455. }
  456. load->firstline = 1;
  457. load->prmt = get_prompt(L, 1);
  458. lua_settop(L, 0);
  459. /* force a complete garbage collection in case of errors */
  460. if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
  461. } else {
  462. load->firstline = 0;
  463. load->prmt = get_prompt(L, 0);
  464. }
  465. }
  466. }while(0);
  467. progname = oldprogname;
  468. load->done = 0;
  469. load->line_position = 0;
  470. memset(load->line, 0, load->len);
  471. printf(load->prmt);
  472. }
  473. #ifndef uart_putc
  474. #define uart_putc uart0_putc
  475. #endif
  476. extern bool uart_on_data_cb(const char *buf, size_t len);
  477. extern bool uart0_echo;
  478. extern bool run_input;
  479. extern uint16_t need_len;
  480. extern int16_t end_char;
  481. static char last_nl_char = '\0';
  482. static bool readline(lua_Load *load){
  483. // NODE_DBG("readline() is called.\n");
  484. bool need_dojob = false;
  485. char ch;
  486. while (uart0_getc(&ch))
  487. {
  488. if(run_input)
  489. {
  490. char tmp_last_nl_char = last_nl_char;
  491. // reset marker, will be finally set below when newline is processed
  492. last_nl_char = '\0';
  493. /* handle CR & LF characters
  494. filters second char of LF&CR (\n\r) or CR&LF (\r\n) sequences */
  495. if ((ch == '\r' && tmp_last_nl_char == '\n') || // \n\r sequence -> skip \r
  496. (ch == '\n' && tmp_last_nl_char == '\r')) // \r\n sequence -> skip \n
  497. {
  498. continue;
  499. }
  500. /* backspace key */
  501. else if (ch == 0x7f || ch == 0x08)
  502. {
  503. if (load->line_position > 0)
  504. {
  505. if(uart0_echo) uart_putc(0x08);
  506. if(uart0_echo) uart_putc(' ');
  507. if(uart0_echo) uart_putc(0x08);
  508. load->line_position--;
  509. }
  510. load->line[load->line_position] = 0;
  511. continue;
  512. }
  513. /* EOT(ctrl+d) */
  514. // else if (ch == 0x04)
  515. // {
  516. // if (load->line_position == 0)
  517. // // No input which makes lua interpreter close
  518. // donejob(load);
  519. // else
  520. // continue;
  521. // }
  522. /* end of line */
  523. if (ch == '\r' || ch == '\n')
  524. {
  525. last_nl_char = ch;
  526. load->line[load->line_position] = 0;
  527. if(uart0_echo) uart_putc('\n');
  528. uart_on_data_cb(load->line, load->line_position);
  529. if (load->line_position == 0)
  530. {
  531. /* Get a empty line, then go to get a new line */
  532. printf(load->prmt);
  533. } else {
  534. load->done = 1;
  535. need_dojob = true;
  536. }
  537. continue;
  538. }
  539. /* other control character or not an acsii character */
  540. // if (ch < 0x20 || ch >= 0x80)
  541. // {
  542. // continue;
  543. // }
  544. /* echo */
  545. if(uart0_echo) uart_putc(ch);
  546. /* it's a large line, discard it */
  547. if ( load->line_position + 1 >= load->len ){
  548. load->line_position = 0;
  549. }
  550. }
  551. load->line[load->line_position] = ch;
  552. load->line_position++;
  553. if(!run_input)
  554. {
  555. if( ((need_len!=0) && (load->line_position >= need_len)) || \
  556. (load->line_position >= load->len) || \
  557. ((end_char>=0) && ((unsigned char)ch==(unsigned char)end_char)) )
  558. {
  559. uart_on_data_cb(load->line, load->line_position);
  560. load->line_position = 0;
  561. }
  562. }
  563. ch = 0;
  564. }
  565. if( (load->line_position > 0) && (!run_input) && (need_len==0) && (end_char<0) )
  566. {
  567. uart_on_data_cb(load->line, load->line_position);
  568. load->line_position = 0;
  569. }
  570. return need_dojob;
  571. }