diff --git a/src/main.c b/src/main.c index 8434caa..3c2a47a 100644 --- a/src/main.c +++ b/src/main.c @@ -123,6 +123,12 @@ int main(int argc, char *argv[]) socket_configure(); } + /* Script interpreter init */ + script_interp_init(); + + /* Initialize tty module once on program start */ + tty_init(); + /* Spawn input handling into separate thread */ tty_input_thread_create(); diff --git a/src/script.c b/src/script.c index 13c5048..4c85d4e 100644 --- a/src/script.c +++ b/src/script.c @@ -44,7 +44,7 @@ #define MAX_BUFFER_SIZE 2000 // Maximum size of circular buffer #define READ_LINE_SIZE 4096 // read_line buffer length -static int device_fd; +static int device_fd = 0; static lua_State *script_interp = NULL; // clang-format off @@ -203,6 +203,11 @@ static int line_set(lua_State *L) int cd = lua_tointeger(L, 5); int ri = lua_tointeger(L, 6); + if (device_fd == 0) + { + return luaL_error(L, "tty device not ready"); + } + if (dtr != -1) { line_config[0].mask = TIOCM_DTR; @@ -252,6 +257,11 @@ static int api_send(lua_State *L) int protocol = luaL_checkinteger(L, 2); int ret; + if (device_fd == 0) + { + return luaL_error(L, "tty device not ready"); + } + if (file == NULL) { return 0; @@ -295,6 +305,11 @@ static int api_write(lua_State *L) ssize_t ret; int attempts = 100; + if (device_fd == 0) + { + return luaL_error(L, "tty device not ready"); + } + do { ret = write(device_fd, string, len); @@ -322,6 +337,11 @@ static int api_twrite(lua_State *L) size_t len = 0; const char *string = luaL_checklstring(L, 1, &len); + if (device_fd == 0) + { + return luaL_error(L, "tty device not ready"); + } + for (; len > 0; --len, string++) { forward_to_tty(device_fd, *string); @@ -339,6 +359,11 @@ static int api_read(lua_State *L) int size = luaL_checkinteger(L, 1); int timeout = luaL_optinteger(L, 2, -1); // ms, negative value means forever. + if (device_fd == 0) + { + return luaL_error(L, "tty device not ready"); + } + luaL_Buffer buffer; luaL_buffinit(L, &buffer); @@ -378,6 +403,11 @@ static int api_readline(lua_State *L) luaL_Buffer b; char ch; + if (device_fd == 0) + { + return luaL_error(L, "tty device not ready"); + } + luaL_buffinit(L, &b); luaL_prepbuffer(&b); while (true) @@ -581,24 +611,36 @@ static lua_State *script_interp_new(void) return L; } -void script_run(int fd, const char *script_filename) +void script_device_bind(int fd) +{ + device_fd = fd; +} + +void script_device_unbind(void) +{ + device_fd = 0; +} + +void script_do_line(const char *script_line) +{ + assert(script_line != NULL); + assert(script_interp != NULL); + + script_buffer_run(script_interp, script_line); +} + +void script_run(const char *script_filename) { static bool doopt_by_nul = true; - device_fd = fd; assert(script_filename != NULL); - - if (script_interp == NULL) - { - if (script_interp_new() == NULL) - return; - } + assert(script_interp != NULL); if (script_filename[0] == '\0') { if (doopt_by_nul) { - script_run_as_specified_by_options(fd); + script_run_as_specified_by_options(); } return; } @@ -611,7 +653,7 @@ void script_run(int fd, const char *script_filename) } else if (strcmp(script_filename, "@doopt") == 0) { - script_run_as_specified_by_options(fd); + script_run_as_specified_by_options(); } else if (strcmp(script_filename, "@nuldo=opt") == 0) { @@ -643,15 +685,9 @@ void script_run(int fd, const char *script_filename) } } -void script_run_as_specified_by_options(int fd) +void script_run_as_specified_by_options(void) { - device_fd = fd; - - if (script_interp == NULL) - { - if (script_interp_new() == NULL) - return; - } + assert(script_interp != NULL); if (option.script_filename != NULL) { @@ -682,3 +718,12 @@ const char *script_run_state_to_string(script_run_t state) return "Unknown"; } } + +void script_interp_init(void) +{ + if (script_interp_new() == NULL) + { + tio_error_printf("Could not start script interpreter."); + exit(EXIT_FAILURE); + } +} diff --git a/src/script.h b/src/script.h index 7cf68c8..c0f14e6 100644 --- a/src/script.h +++ b/src/script.h @@ -29,6 +29,10 @@ typedef enum SCRIPT_RUN_END, } script_run_t; -void script_run(int fd, const char *script_filename); -void script_run_as_specified_by_options(int fd); +void script_interp_init(void); +void script_device_bind(int fd); +void script_device_unbind(void); +void script_run(const char *script_filename); +void script_run_as_specified_by_options(void); +void script_do_line(const char *script_line); const char *script_run_state_to_string(script_run_t state); diff --git a/src/tty.c b/src/tty.c index 5e39d47..b1fe6d7 100644 --- a/src/tty.c +++ b/src/tty.c @@ -147,6 +147,8 @@ typedef enum SUBCOMMAND_MAP, } sub_command_t; +#define MLINE_MAX 4096 + // clang-format off const char random_array[] = { @@ -183,7 +185,7 @@ static char *tty_buffer_write_ptr = tty_buffer; static pthread_t thread; static int pipefd[2]; static pthread_mutex_t mutex_input_ready = PTHREAD_MUTEX_INITIALIZER; -static char line[PATH_MAX]; +static char line[PATH_MAX], mline[MLINE_MAX]; static size_t listing_device_name_length_max = 0; static readline_t *readline_ctx = NULL; static readline_t *subcmd_readline_ctx = NULL; @@ -593,7 +595,9 @@ static void tty_line_poke(int fd, int mask, tty_line_mode_t mode, unsigned int d static int tio_subcmd_readln(const char *title_prompt) { - tio_printf_raw("%s\r\n", title_prompt); + if (title_prompt && (title_prompt[0] != '\0')) { + tio_printf_raw("%s\r\n", title_prompt); + } readline_prompt_for_input(subcmd_readline_ctx); /* Read line with line edit and history. */ @@ -660,6 +664,50 @@ static void mappings_print(void) // clang-format on } +static void handle_script_repl(void) +{ + bool local_echo_bkup = option.local_echo; + int line_len; + int mline_len = 0; + + option.local_echo = true; + tio_printf("Enter Lua REPL mode (@exit to exit)"); + + strcpy(mline, ""); + while (true) + { + tio_subcmd_readln(""); + if (strcmp(line, "@exit") == 0) + break; + line_len = strlen(line); + + if (line_len > 0) + { + if (mline_len + line_len + 1 > MLINE_MAX) + { + tio_printf("Too long lines. The size should be lesser then %d bytes", MLINE_MAX); + strcpy(mline, ""); + mline_len = 0; + continue; + } + + strcat(&mline[mline_len], line); + mline_len += line_len; + + if (mline_len > 0 && mline[mline_len - 1] == '\\') + { + mline[mline_len - 1] = '\n'; + continue; + } + } + script_do_line(mline); + strcpy(mline, ""); + mline_len = 0; + } + + option.local_echo = local_echo_bkup; +} + void handle_command_sequence(char input_char, char *output_char, bool *forward) { char unused_char; @@ -1079,8 +1127,15 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward) /* Run script */ tio_printf("Run Lua script"); tio_subcmd_readln("Enter file name or \"!\" lua commands or \"@\" direction to interpreter: "); - clear_line(); - script_run(device_fd, line); + if (strcmp(line, "@repl") == 0) + { + handle_script_repl(); + } + else + { + clear_line(); + script_run(line); + } break; case KEY_SHIFT_R: @@ -2545,6 +2600,21 @@ void forward_to_tty(int fd, char output_char) } } +void tty_init(void) +{ + // Initialize readline like history + readline_ctx = readline_create(); + subcmd_readline_ctx = readline_create(); + if (readline_ctx == NULL || subcmd_readline_ctx == NULL) + { + tio_error_printf("Could not allocate readline buffer."); + exit(EXIT_FAILURE); + } + readline_set_prompt(readline_ctx, "> "); + readline_set_prompt(subcmd_readline_ctx, ">> "); + +} + int tty_connect(void) { fd_set rdfs; /* Read file descriptor set */ @@ -2676,9 +2746,11 @@ int tty_connect(void) } /* Manage script activation */ + script_device_bind(device_fd); + if (option.script_run != SCRIPT_RUN_NEVER) { - script_run_as_specified_by_options(device_fd); + script_run_as_specified_by_options(); if (option.script_run == SCRIPT_RUN_ONCE) { @@ -2698,17 +2770,6 @@ int tty_connect(void) exit(status); } - // Initialize readline like history - readline_ctx = readline_create(); - subcmd_readline_ctx = readline_create(); - if (readline_ctx == NULL || subcmd_readline_ctx == NULL) - { - tio_error_printf("Could not allocate readline buffer."); - exit(EXIT_FAILURE); - } - readline_set_prompt(readline_ctx, "> "); - readline_set_prompt(subcmd_readline_ctx, ">> "); - /* Input loop */ while (true) { @@ -3035,6 +3096,7 @@ error_setspeed: error_tcsetattr: error_tcgetattr: error_read: + script_device_unbind(); tty_disconnect(); error_open: return TIO_ERROR; diff --git a/src/tty.h b/src/tty.h index eb3dfd4..4ef210d 100644 --- a/src/tty.h +++ b/src/tty.h @@ -76,6 +76,7 @@ void stdout_configure(void); void stdin_configure(void); void tty_configure(void); void tty_reconfigure(void); +void tty_init(void); int tty_connect(void); void tty_wait_for_device(void); void list_serial_devices(void);