X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=readline.c;h=abf27ddec36c158a2ec610a9b745426a5d691aed;hb=60aad298cb6de52f2716b2e82e1353ea9de95fd6;hp=e1e963a2cdfc243481e5326befcf9cd1d735e216;hpb=cd390083ad1fea1ddb93df9c5560eba0a9f26a0d;p=qemu.git diff --git a/readline.c b/readline.c index e1e963a2c..abf27ddec 100644 --- a/readline.c +++ b/readline.c @@ -21,155 +21,123 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "qemu-common.h" -#include "console.h" - -#define TERM_CMD_BUF_SIZE 4095 -#define TERM_MAX_CMDS 64 -#define NB_COMPLETIONS_MAX 256 +#include "monitor/readline.h" +#include "monitor/monitor.h" #define IS_NORM 0 #define IS_ESC 1 #define IS_CSI 2 +#define IS_SS3 3 +#undef printf #define printf do_not_use_printf -static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; -static int term_cmd_buf_index; -static int term_cmd_buf_size; - -static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1]; -static int term_last_cmd_buf_index; -static int term_last_cmd_buf_size; - -static int term_esc_state; -static int term_esc_param; - -static char *term_history[TERM_MAX_CMDS]; -static int term_hist_entry = -1; - -static int nb_completions; -int completion_index; -static char *completions[NB_COMPLETIONS_MAX]; - -static ReadLineFunc *term_readline_func; -static int term_is_password; -static char term_prompt[256]; -static void *term_readline_opaque; - -static void term_show_prompt2(void) +void readline_show_prompt(ReadLineState *rs) { - term_printf("%s", term_prompt); - term_flush(); - term_last_cmd_buf_index = 0; - term_last_cmd_buf_size = 0; - term_esc_state = IS_NORM; -} - -static void term_show_prompt(void) -{ - term_show_prompt2(); - term_cmd_buf_index = 0; - term_cmd_buf_size = 0; + monitor_printf(rs->mon, "%s", rs->prompt); + monitor_flush(rs->mon); + rs->last_cmd_buf_index = 0; + rs->last_cmd_buf_size = 0; + rs->esc_state = IS_NORM; } /* update the displayed command line */ -static void term_update(void) +static void readline_update(ReadLineState *rs) { int i, delta, len; - if (term_cmd_buf_size != term_last_cmd_buf_size || - memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) { - for(i = 0; i < term_last_cmd_buf_index; i++) { - term_printf("\033[D"); + if (rs->cmd_buf_size != rs->last_cmd_buf_size || + memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) { + for(i = 0; i < rs->last_cmd_buf_index; i++) { + monitor_printf(rs->mon, "\033[D"); } - term_cmd_buf[term_cmd_buf_size] = '\0'; - if (term_is_password) { - len = strlen(term_cmd_buf); + rs->cmd_buf[rs->cmd_buf_size] = '\0'; + if (rs->read_password) { + len = strlen(rs->cmd_buf); for(i = 0; i < len; i++) - term_printf("*"); + monitor_printf(rs->mon, "*"); } else { - term_printf("%s", term_cmd_buf); + monitor_printf(rs->mon, "%s", rs->cmd_buf); } - term_printf("\033[K"); - memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size); - term_last_cmd_buf_size = term_cmd_buf_size; - term_last_cmd_buf_index = term_cmd_buf_size; + monitor_printf(rs->mon, "\033[K"); + memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size); + rs->last_cmd_buf_size = rs->cmd_buf_size; + rs->last_cmd_buf_index = rs->cmd_buf_size; } - if (term_cmd_buf_index != term_last_cmd_buf_index) { - delta = term_cmd_buf_index - term_last_cmd_buf_index; + if (rs->cmd_buf_index != rs->last_cmd_buf_index) { + delta = rs->cmd_buf_index - rs->last_cmd_buf_index; if (delta > 0) { for(i = 0;i < delta; i++) { - term_printf("\033[C"); + monitor_printf(rs->mon, "\033[C"); } } else { delta = -delta; for(i = 0;i < delta; i++) { - term_printf("\033[D"); + monitor_printf(rs->mon, "\033[D"); } } - term_last_cmd_buf_index = term_cmd_buf_index; + rs->last_cmd_buf_index = rs->cmd_buf_index; } - term_flush(); + monitor_flush(rs->mon); } -static void term_insert_char(int ch) +static void readline_insert_char(ReadLineState *rs, int ch) { - if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) { - memmove(term_cmd_buf + term_cmd_buf_index + 1, - term_cmd_buf + term_cmd_buf_index, - term_cmd_buf_size - term_cmd_buf_index); - term_cmd_buf[term_cmd_buf_index] = ch; - term_cmd_buf_size++; - term_cmd_buf_index++; + if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) { + memmove(rs->cmd_buf + rs->cmd_buf_index + 1, + rs->cmd_buf + rs->cmd_buf_index, + rs->cmd_buf_size - rs->cmd_buf_index); + rs->cmd_buf[rs->cmd_buf_index] = ch; + rs->cmd_buf_size++; + rs->cmd_buf_index++; } } -static void term_backward_char(void) +static void readline_backward_char(ReadLineState *rs) { - if (term_cmd_buf_index > 0) { - term_cmd_buf_index--; + if (rs->cmd_buf_index > 0) { + rs->cmd_buf_index--; } } -static void term_forward_char(void) +static void readline_forward_char(ReadLineState *rs) { - if (term_cmd_buf_index < term_cmd_buf_size) { - term_cmd_buf_index++; + if (rs->cmd_buf_index < rs->cmd_buf_size) { + rs->cmd_buf_index++; } } -static void term_delete_char(void) +static void readline_delete_char(ReadLineState *rs) { - if (term_cmd_buf_index < term_cmd_buf_size) { - memmove(term_cmd_buf + term_cmd_buf_index, - term_cmd_buf + term_cmd_buf_index + 1, - term_cmd_buf_size - term_cmd_buf_index - 1); - term_cmd_buf_size--; + if (rs->cmd_buf_index < rs->cmd_buf_size) { + memmove(rs->cmd_buf + rs->cmd_buf_index, + rs->cmd_buf + rs->cmd_buf_index + 1, + rs->cmd_buf_size - rs->cmd_buf_index - 1); + rs->cmd_buf_size--; } } -static void term_backspace(void) +static void readline_backspace(ReadLineState *rs) { - if (term_cmd_buf_index > 0) { - term_backward_char(); - term_delete_char(); + if (rs->cmd_buf_index > 0) { + readline_backward_char(rs); + readline_delete_char(rs); } } -static void term_backword(void) +static void readline_backword(ReadLineState *rs) { int start; - if (term_cmd_buf_index == 0 || term_cmd_buf_index > term_cmd_buf_size) { + if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) { return; } - start = term_cmd_buf_index - 1; + start = rs->cmd_buf_index - 1; /* find first word (backwards) */ while (start > 0) { - if (!qemu_isspace(term_cmd_buf[start])) { + if (!qemu_isspace(rs->cmd_buf[start])) { break; } @@ -178,7 +146,7 @@ static void term_backword(void) /* find first space (backwards) */ while (start > 0) { - if (qemu_isspace(term_cmd_buf[start])) { + if (qemu_isspace(rs->cmd_buf[start])) { ++start; break; } @@ -187,61 +155,63 @@ static void term_backword(void) } /* remove word */ - if (start < term_cmd_buf_index) { - memmove(term_cmd_buf + start, - term_cmd_buf + term_cmd_buf_index, - term_cmd_buf_size - term_cmd_buf_index); - term_cmd_buf_size -= term_cmd_buf_index - start; - term_cmd_buf_index = start; + if (start < rs->cmd_buf_index) { + memmove(rs->cmd_buf + start, + rs->cmd_buf + rs->cmd_buf_index, + rs->cmd_buf_size - rs->cmd_buf_index); + rs->cmd_buf_size -= rs->cmd_buf_index - start; + rs->cmd_buf_index = start; } } -static void term_bol(void) +static void readline_bol(ReadLineState *rs) { - term_cmd_buf_index = 0; + rs->cmd_buf_index = 0; } -static void term_eol(void) +static void readline_eol(ReadLineState *rs) { - term_cmd_buf_index = term_cmd_buf_size; + rs->cmd_buf_index = rs->cmd_buf_size; } -static void term_up_char(void) +static void readline_up_char(ReadLineState *rs) { int idx; - if (term_hist_entry == 0) + if (rs->hist_entry == 0) return; - if (term_hist_entry == -1) { + if (rs->hist_entry == -1) { /* Find latest entry */ - for (idx = 0; idx < TERM_MAX_CMDS; idx++) { - if (term_history[idx] == NULL) + for (idx = 0; idx < READLINE_MAX_CMDS; idx++) { + if (rs->history[idx] == NULL) break; } - term_hist_entry = idx; + rs->hist_entry = idx; } - term_hist_entry--; - if (term_hist_entry >= 0) { - pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), - term_history[term_hist_entry]); - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); + rs->hist_entry--; + if (rs->hist_entry >= 0) { + pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf), + rs->history[rs->hist_entry]); + rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf); } } -static void term_down_char(void) +static void readline_down_char(ReadLineState *rs) { - if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1) - return; - if (term_history[++term_hist_entry] != NULL) { - pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), - term_history[term_hist_entry]); + if (rs->hist_entry == -1) + return; + if (rs->hist_entry < READLINE_MAX_CMDS - 1 && + rs->history[++rs->hist_entry] != NULL) { + pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf), + rs->history[rs->hist_entry]); } else { - term_hist_entry = -1; + rs->cmd_buf[0] = 0; + rs->hist_entry = -1; } - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); + rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf); } -static void term_hist_add(const char *cmdline) +static void readline_hist_add(ReadLineState *rs, const char *cmdline) { char *hist_entry, *new_entry; int idx; @@ -249,95 +219,98 @@ static void term_hist_add(const char *cmdline) if (cmdline[0] == '\0') return; new_entry = NULL; - if (term_hist_entry != -1) { + if (rs->hist_entry != -1) { /* We were editing an existing history entry: replace it */ - hist_entry = term_history[term_hist_entry]; - idx = term_hist_entry; + hist_entry = rs->history[rs->hist_entry]; + idx = rs->hist_entry; if (strcmp(hist_entry, cmdline) == 0) { goto same_entry; } } /* Search cmdline in history buffers */ - for (idx = 0; idx < TERM_MAX_CMDS; idx++) { - hist_entry = term_history[idx]; + for (idx = 0; idx < READLINE_MAX_CMDS; idx++) { + hist_entry = rs->history[idx]; if (hist_entry == NULL) break; if (strcmp(hist_entry, cmdline) == 0) { same_entry: new_entry = hist_entry; /* Put this entry at the end of history */ - memmove(&term_history[idx], &term_history[idx + 1], - (TERM_MAX_CMDS - idx + 1) * sizeof(char *)); - term_history[TERM_MAX_CMDS - 1] = NULL; - for (; idx < TERM_MAX_CMDS; idx++) { - if (term_history[idx] == NULL) + memmove(&rs->history[idx], &rs->history[idx + 1], + (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *)); + rs->history[READLINE_MAX_CMDS - 1] = NULL; + for (; idx < READLINE_MAX_CMDS; idx++) { + if (rs->history[idx] == NULL) break; } break; } } - if (idx == TERM_MAX_CMDS) { + if (idx == READLINE_MAX_CMDS) { /* Need to get one free slot */ - free(term_history[0]); - memcpy(term_history, &term_history[1], - (TERM_MAX_CMDS - 1) * sizeof(char *)); - term_history[TERM_MAX_CMDS - 1] = NULL; - idx = TERM_MAX_CMDS - 1; + g_free(rs->history[0]); + memmove(rs->history, &rs->history[1], + (READLINE_MAX_CMDS - 1) * sizeof(char *)); + rs->history[READLINE_MAX_CMDS - 1] = NULL; + idx = READLINE_MAX_CMDS - 1; } if (new_entry == NULL) - new_entry = strdup(cmdline); - term_history[idx] = new_entry; - term_hist_entry = -1; + new_entry = g_strdup(cmdline); + rs->history[idx] = new_entry; + rs->hist_entry = -1; } /* completion support */ -void add_completion(const char *str) +void readline_add_completion(ReadLineState *rs, const char *str) { - if (nb_completions < NB_COMPLETIONS_MAX) { - completions[nb_completions++] = qemu_strdup(str); + if (rs->nb_completions < READLINE_MAX_COMPLETIONS) { + rs->completions[rs->nb_completions++] = g_strdup(str); } } -static void term_completion(void) +void readline_set_completion_index(ReadLineState *rs, int index) +{ + rs->completion_index = index; +} + +static void readline_completion(ReadLineState *rs) { int len, i, j, max_width, nb_cols, max_prefix; char *cmdline; - nb_completions = 0; + rs->nb_completions = 0; - cmdline = qemu_malloc(term_cmd_buf_index + 1); - if (!cmdline) - return; - memcpy(cmdline, term_cmd_buf, term_cmd_buf_index); - cmdline[term_cmd_buf_index] = '\0'; - readline_find_completion(cmdline); - qemu_free(cmdline); + cmdline = g_malloc(rs->cmd_buf_index + 1); + memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index); + cmdline[rs->cmd_buf_index] = '\0'; + rs->completion_finder(rs->mon, cmdline); + g_free(cmdline); /* no completion found */ - if (nb_completions <= 0) + if (rs->nb_completions <= 0) return; - if (nb_completions == 1) { - len = strlen(completions[0]); - for(i = completion_index; i < len; i++) { - term_insert_char(completions[0][i]); + if (rs->nb_completions == 1) { + len = strlen(rs->completions[0]); + for(i = rs->completion_index; i < len; i++) { + readline_insert_char(rs, rs->completions[0][i]); } /* extra space for next argument. XXX: make it more generic */ - if (len > 0 && completions[0][len - 1] != '/') - term_insert_char(' '); + if (len > 0 && rs->completions[0][len - 1] != '/') + readline_insert_char(rs, ' '); } else { - term_printf("\n"); + monitor_printf(rs->mon, "\n"); max_width = 0; max_prefix = 0; - for(i = 0; i < nb_completions; i++) { - len = strlen(completions[i]); + for(i = 0; i < rs->nb_completions; i++) { + len = strlen(rs->completions[i]); if (i==0) { max_prefix = len; } else { if (len < max_prefix) max_prefix = len; for(j=0; jcompletions[i][j] != rs->completions[0][j]) max_prefix = j; } } @@ -345,8 +318,8 @@ static void term_completion(void) max_width = len; } if (max_prefix > 0) - for(i = completion_index; i < max_prefix; i++) { - term_insert_char(completions[0][i]); + for(i = rs->completion_index; i < max_prefix; i++) { + readline_insert_char(rs, rs->completions[0][i]); } max_width += 2; if (max_width < 10) @@ -355,134 +328,166 @@ static void term_completion(void) max_width = 80; nb_cols = 80 / max_width; j = 0; - for(i = 0; i < nb_completions; i++) { - term_printf("%-*s", max_width, completions[i]); - if (++j == nb_cols || i == (nb_completions - 1)) { - term_printf("\n"); + for(i = 0; i < rs->nb_completions; i++) { + monitor_printf(rs->mon, "%-*s", max_width, rs->completions[i]); + if (++j == nb_cols || i == (rs->nb_completions - 1)) { + monitor_printf(rs->mon, "\n"); j = 0; } } - term_show_prompt2(); + readline_show_prompt(rs); + } + for (i = 0; i < rs->nb_completions; i++) { + g_free(rs->completions[i]); } } /* return true if command handled */ -void readline_handle_byte(int ch) +void readline_handle_byte(ReadLineState *rs, int ch) { - switch(term_esc_state) { + switch(rs->esc_state) { case IS_NORM: switch(ch) { case 1: - term_bol(); + readline_bol(rs); break; case 4: - term_delete_char(); + readline_delete_char(rs); break; case 5: - term_eol(); + readline_eol(rs); break; case 9: - term_completion(); + readline_completion(rs); break; case 10: case 13: - term_cmd_buf[term_cmd_buf_size] = '\0'; - if (!term_is_password) - term_hist_add(term_cmd_buf); - term_printf("\n"); - term_cmd_buf_index = 0; - term_cmd_buf_size = 0; - term_last_cmd_buf_index = 0; - term_last_cmd_buf_size = 0; - /* NOTE: readline_start can be called here */ - term_readline_func(term_readline_opaque, term_cmd_buf); + rs->cmd_buf[rs->cmd_buf_size] = '\0'; + if (!rs->read_password) + readline_hist_add(rs, rs->cmd_buf); + monitor_printf(rs->mon, "\n"); + rs->cmd_buf_index = 0; + rs->cmd_buf_size = 0; + rs->last_cmd_buf_index = 0; + rs->last_cmd_buf_size = 0; + rs->readline_func(rs->mon, rs->cmd_buf, rs->readline_opaque); break; case 23: /* ^W */ - term_backword(); + readline_backword(rs); break; case 27: - term_esc_state = IS_ESC; + rs->esc_state = IS_ESC; break; case 127: case 8: - term_backspace(); + readline_backspace(rs); break; case 155: - term_esc_state = IS_CSI; + rs->esc_state = IS_CSI; break; default: if (ch >= 32) { - term_insert_char(ch); + readline_insert_char(rs, ch); } break; } break; case IS_ESC: if (ch == '[') { - term_esc_state = IS_CSI; - term_esc_param = 0; + rs->esc_state = IS_CSI; + rs->esc_param = 0; + } else if (ch == 'O') { + rs->esc_state = IS_SS3; + rs->esc_param = 0; } else { - term_esc_state = IS_NORM; + rs->esc_state = IS_NORM; } break; case IS_CSI: switch(ch) { case 'A': case 'F': - term_up_char(); + readline_up_char(rs); break; case 'B': case 'E': - term_down_char(); + readline_down_char(rs); break; case 'D': - term_backward_char(); + readline_backward_char(rs); break; case 'C': - term_forward_char(); + readline_forward_char(rs); break; case '0' ... '9': - term_esc_param = term_esc_param * 10 + (ch - '0'); + rs->esc_param = rs->esc_param * 10 + (ch - '0'); goto the_end; case '~': - switch(term_esc_param) { + switch(rs->esc_param) { case 1: - term_bol(); + readline_bol(rs); break; case 3: - term_delete_char(); + readline_delete_char(rs); break; case 4: - term_eol(); + readline_eol(rs); break; } break; default: break; } - term_esc_state = IS_NORM; + rs->esc_state = IS_NORM; the_end: break; + case IS_SS3: + switch(ch) { + case 'F': + readline_eol(rs); + break; + case 'H': + readline_bol(rs); + break; + } + rs->esc_state = IS_NORM; + break; } - term_update(); + readline_update(rs); } -void readline_start(const char *prompt, int is_password, +void readline_start(ReadLineState *rs, const char *prompt, int read_password, ReadLineFunc *readline_func, void *opaque) { - pstrcpy(term_prompt, sizeof(term_prompt), prompt); - term_readline_func = readline_func; - term_readline_opaque = opaque; - term_is_password = is_password; - term_show_prompt(); + pstrcpy(rs->prompt, sizeof(rs->prompt), prompt); + rs->readline_func = readline_func; + rs->readline_opaque = opaque; + rs->read_password = read_password; + readline_restart(rs); +} + +void readline_restart(ReadLineState *rs) +{ + rs->cmd_buf_index = 0; + rs->cmd_buf_size = 0; } -const char *readline_get_history(unsigned int index) +const char *readline_get_history(ReadLineState *rs, unsigned int index) { - if (index >= TERM_MAX_CMDS) + if (index >= READLINE_MAX_CMDS) return NULL; - return term_history[index]; + return rs->history[index]; } +ReadLineState *readline_init(Monitor *mon, + ReadLineCompletionFunc *completion_finder) +{ + ReadLineState *rs = g_malloc0(sizeof(*rs)); + + rs->hist_entry = -1; + rs->mon = mon; + rs->completion_finder = completion_finder; + return rs; +}