X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=interactive.c;h=6831643878761be2da1c4ee8f79b7ce6ccf2f21f;hp=f9ea3612ee8a1b0e80bef508051ed737b9a0ba05;hb=6cb789ba07d3830f1d7fbff9daa059eb1c99c166;hpb=c48df6b449e219418b837954df90660b08dde75e diff --git a/interactive.c b/interactive.c index f9ea3612..68316438 100644 --- a/interactive.c +++ b/interactive.c @@ -27,15 +27,31 @@ struct i9e_private { struct i9e_client_info *ici; FILE *stderr_stream; + int num_columns; char empty_line[1000]; struct task task; struct btr_node *stdout_btrn; bool line_handler_running; bool input_eof; bool caught_sigint; + bool caught_sigterm; }; static struct i9e_private i9e_private, *i9ep = &i9e_private; +/** + * Return the error state of the i9e task. + * + * This is mainly useful for other tasks to tell whether the i9e task is still + * running. + * + * \return A negative return value of zero means the i9e task terminated. Only + * in this case it is safe to call ie9_close(). + */ +int i9e_get_error(void) +{ + return i9ep->task.error; +} + static bool is_prefix(const char *partial, const char *full, size_t len) { if (len == 0) @@ -178,11 +194,35 @@ static char **i9e_completer(const char *text, int start, __a_unused int end) */ void i9e_attach_to_stdout(struct btr_node *producer) { - assert(!i9ep->stdout_btrn); + btr_remove_node(&i9ep->stdout_btrn); i9ep->stdout_btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "interactive_stdout", .parent = producer)); } +static void wipe_bottom_line(void) +{ + char x[] = " "; + int n = i9ep->num_columns; + + /* + * For reasons beyond my understanding, writing more than 68 characters + * here causes MacOS to mess up the terminal. Writing a line of spaces + * in smaller chunks works fine though. Weird. + */ + fprintf(i9ep->stderr_stream, "\r"); + while (n > 0) { + if (n >= sizeof(x)) { + fprintf(i9ep->stderr_stream, "%s", x); + n -= sizeof(x); + continue; + } + x[n] = '\0'; + fprintf(i9ep->stderr_stream, "%s", x); + break; + } + fprintf(i9ep->stderr_stream, "\r"); +} + /** * Reset the terminal and save the in-memory command line history. * @@ -193,15 +233,9 @@ void i9e_close(void) char *hf = i9ep->ici->history_file; rl_deprep_terminal(); - fprintf(i9ep->stderr_stream, "\n"); if (hf) write_history(hf); - fclose(i9ep->stderr_stream); -} - -static void wipe_bottom_line(void) -{ - fprintf(i9ep->stderr_stream, "\r%s\r", i9ep->empty_line); + wipe_bottom_line(); } static void clear_bottom_line(void) @@ -241,9 +275,7 @@ static void i9e_line_handler(char *line) { int ret; - i9ep->line_handler_running = true; ret = i9ep->ici->line_handler(line); - i9ep->line_handler_running = false; if (ret < 0) PARA_WARNING_LOG("%s\n", para_strerror(-ret)); rl_set_prompt(""); @@ -274,16 +306,19 @@ static void i9e_post_select(struct sched *s, struct task *t) char *buf; size_t sz; - if (i9ep->input_eof) { - t->error = -E_I9E_EOF; - return; - } + ret = -E_I9E_EOF; + if (i9ep->input_eof) + goto rm_btrn; + ret = -E_I9E_TERM_RQ; + if (i9ep->caught_sigterm) + goto rm_btrn; if (!btrn) { i9ep->caught_sigint = false; if (FD_ISSET(ici->fds[0], &s->rfds)) i9e_input(); return; } + ret = 0; if (i9ep->caught_sigint) goto rm_btrn; ret = btr_node_status(i9ep->stdout_btrn, 0, BTR_NT_LEAF); @@ -298,11 +333,9 @@ static void i9e_post_select(struct sched *s, struct task *t) btr_consume(btrn, ret); goto out; rm_btrn: - btr_remove_node(btrn); - btr_free_node(btrn); - i9ep->stdout_btrn = NULL; + btr_remove_node(&i9ep->stdout_btrn); rl_set_prompt(i9ep->ici->prompt); - rl_forced_update_display(); + rl_redisplay(); out: t->error = 0; } @@ -311,7 +344,7 @@ static void i9e_pre_select(struct sched *s, __a_unused struct task *t) { int ret; - if (i9ep->input_eof || i9ep->caught_sigint) { + if (i9ep->input_eof || i9ep->caught_sigint || i9ep->caught_sigterm) { sched_min_delay(s); return; } @@ -340,14 +373,15 @@ static void update_winsize(void) { struct winsize w; int ret = ioctl(i9ep->ici->fds[2], TIOCGWINSZ, (char *)&w); - int num_columns = 80; if (ret >= 0) { assert(w.ws_col < sizeof(i9ep->empty_line)); - num_columns = w.ws_col; - } - memset(i9ep->empty_line, ' ', num_columns); - i9ep->empty_line[num_columns] = '\0'; + i9ep->num_columns = w.ws_col; + } else + i9ep->num_columns = 80; + + memset(i9ep->empty_line, ' ', i9ep->num_columns); + i9ep->empty_line[i9ep->num_columns] = '\0'; } /** @@ -387,13 +421,17 @@ int i9e_open(struct i9e_client_info *ici, struct sched *s) if (ici->history_file) read_history(ici->history_file); update_winsize(); - rl_callback_handler_install(i9ep->ici->prompt, i9e_line_handler); + if (ici->producer) { + rl_callback_handler_install("", i9e_line_handler); + i9e_attach_to_stdout(ici->producer); + } else + rl_callback_handler_install(i9ep->ici->prompt, i9e_line_handler); return 1; } static void reset_line_state(void) { - if (i9ep->line_handler_running) + if (i9ep->stdout_btrn) return; rl_on_new_line(); rl_reset_line_state(); @@ -416,8 +454,7 @@ __printf_2_3 void i9e_log(int ll, const char* fmt,...) if (ll < i9ep->ici->loglevel) return; - if (i9ep->line_handler_running == false) - clear_bottom_line(); + clear_bottom_line(); va_start(argp, fmt); vfprintf(i9ep->stderr_stream, fmt, argp); va_end(argp); @@ -433,12 +470,16 @@ __printf_2_3 void i9e_log(int ll, const char* fmt,...) */ void i9e_signal_dispatch(int sig_num) { + if (sig_num == SIGWINCH) + return update_winsize(); if (sig_num == SIGINT) { fprintf(i9ep->stderr_stream, "\n"); rl_replace_line ("", false /* clear_undo */); reset_line_state(); i9ep->caught_sigint = true; } + if (sig_num == SIGTERM) + i9ep->caught_sigterm = true; } /**