X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=util%2Freadline.c;h=494a3d924e6a928d13af781d41a06aae174023ad;hb=29c8a9e31a982874ce4e2c15f2bf82d5f8dc3517;hp=8441be484c7b0ab0f63f71f9a2b272cd79b2f54f;hpb=7d64b2c2e22d956b358a97323f0d70060dcd9a06;p=mirror_qemu.git diff --git a/util/readline.c b/util/readline.c index 8441be484c..494a3d924e 100644 --- a/util/readline.c +++ b/util/readline.c @@ -22,8 +22,10 @@ * THE SOFTWARE. */ -#include "qemu-common.h" +#include "qemu/osdep.h" #include "qemu/readline.h" +#include "qemu/ctype.h" +#include "qemu/cutils.h" #define IS_NORM 0 #define IS_ESC 1 @@ -46,14 +48,15 @@ static void readline_update(ReadLineState *rs) 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++) { + for (i = 0; i < rs->last_cmd_buf_index; i++) { rs->printf_func(rs->opaque, "\033[D"); } rs->cmd_buf[rs->cmd_buf_size] = '\0'; if (rs->read_password) { len = strlen(rs->cmd_buf); - for(i = 0; i < len; i++) + for (i = 0; i < len; i++) { rs->printf_func(rs->opaque, "*"); + } } else { rs->printf_func(rs->opaque, "%s", rs->cmd_buf); } @@ -65,12 +68,12 @@ static void readline_update(ReadLineState *rs) 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++) { + for (i = 0; i < delta; i++) { rs->printf_func(rs->opaque, "\033[C"); } } else { delta = -delta; - for(i = 0;i < delta; i++) { + for (i = 0; i < delta; i++) { rs->printf_func(rs->opaque, "\033[D"); } } @@ -176,35 +179,38 @@ static void readline_up_char(ReadLineState *rs) { int idx; - if (rs->hist_entry == 0) - return; + if (rs->hist_entry == 0) { + return; + } if (rs->hist_entry == -1) { - /* Find latest entry */ - for (idx = 0; idx < READLINE_MAX_CMDS; idx++) { - if (rs->history[idx] == NULL) - break; - } - rs->hist_entry = idx; + /* Find latest entry */ + for (idx = 0; idx < READLINE_MAX_CMDS; idx++) { + if (rs->history[idx] == NULL) { + break; + } + } + rs->hist_entry = idx; } rs->hist_entry--; if (rs->hist_entry >= 0) { - pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf), + 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); + rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf); } } static void readline_down_char(ReadLineState *rs) { - if (rs->hist_entry == -1) + 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), + pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf), rs->history[rs->hist_entry]); } else { rs->cmd_buf[0] = 0; - rs->hist_entry = -1; + rs->hist_entry = -1; } rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf); } @@ -214,46 +220,53 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline) char *hist_entry, *new_entry; int idx; - if (cmdline[0] == '\0') - return; + if (cmdline[0] == '\0') { + return; + } new_entry = NULL; if (rs->hist_entry != -1) { - /* We were editing an existing history entry: replace it */ - hist_entry = rs->history[rs->hist_entry]; - idx = rs->hist_entry; - if (strcmp(hist_entry, cmdline) == 0) { - goto same_entry; - } + /* We were editing an existing history entry: replace it */ + 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 < 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(&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; - } + hist_entry = rs->history[idx]; + if (hist_entry == NULL) { + break; + } + if (strcmp(hist_entry, cmdline) == 0) { + same_entry: + if (idx == READLINE_MAX_CMDS - 1) { + return; + } + new_entry = hist_entry; + /* Put this entry at the end of history */ + 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 == READLINE_MAX_CMDS) { - /* Need to get one free slot */ + /* Need to get one free slot */ 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; + 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) + if (new_entry == NULL) { new_entry = g_strdup(cmdline); + } rs->history[idx] = new_entry; rs->hist_entry = -1; } @@ -263,15 +276,34 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline) void readline_add_completion(ReadLineState *rs, const char *str) { if (rs->nb_completions < READLINE_MAX_COMPLETIONS) { + int i; + for (i = 0; i < rs->nb_completions; i++) { + if (!strcmp(rs->completions[i], str)) { + return; + } + } rs->completions[rs->nb_completions++] = g_strdup(str); } } +void readline_add_completion_of(ReadLineState *rs, + const char *pfx, const char *str) +{ + if (!strncmp(str, pfx, strlen(pfx))) { + readline_add_completion(rs, str); + } +} + void readline_set_completion_index(ReadLineState *rs, int index) { rs->completion_index = index; } +static int completion_comp(const void *a, const void *b) +{ + return strcmp(*(const char **) a, *(const char **) b); +} + static void readline_completion(ReadLineState *rs) { int len, i, j, max_width, nb_cols, max_prefix; @@ -279,54 +311,60 @@ static void readline_completion(ReadLineState *rs) rs->nb_completions = 0; - cmdline = g_malloc(rs->cmd_buf_index + 1); - memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index); - cmdline[rs->cmd_buf_index] = '\0'; + cmdline = g_strndup(rs->cmd_buf, rs->cmd_buf_index); rs->completion_finder(rs->opaque, cmdline); g_free(cmdline); /* no completion found */ - if (rs->nb_completions <= 0) + if (rs->nb_completions <= 0) { return; + } if (rs->nb_completions == 1) { len = strlen(rs->completions[0]); - for(i = rs->completion_index; i < len; i++) { + 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 && rs->completions[0][len - 1] != '/') + if (len > 0 && rs->completions[0][len - 1] != '/') { readline_insert_char(rs, ' '); + } } else { + qsort(rs->completions, rs->nb_completions, sizeof(char *), + completion_comp); rs->printf_func(rs->opaque, "\n"); max_width = 0; - max_prefix = 0; - for(i = 0; i < rs->nb_completions; i++) { + max_prefix = 0; + for (i = 0; i < rs->nb_completions; i++) { len = strlen(rs->completions[i]); - if (i==0) { + if (i == 0) { max_prefix = len; } else { - if (len < max_prefix) + if (len < max_prefix) { max_prefix = len; - for(j=0; jcompletions[i][j] != rs->completions[0][j]) + } + for (j = 0; j < max_prefix; j++) { + if (rs->completions[i][j] != rs->completions[0][j]) { max_prefix = j; + } } } - if (len > max_width) + if (len > max_width) { max_width = len; + } } - if (max_prefix > 0) - for(i = rs->completion_index; i < max_prefix; i++) { + if (max_prefix > 0) + for (i = rs->completion_index; i < max_prefix; i++) { readline_insert_char(rs, rs->completions[0][i]); } max_width += 2; - if (max_width < 10) + if (max_width < 10) { max_width = 10; - else if (max_width > 80) + } else if (max_width > 80) { max_width = 80; + } nb_cols = 80 / max_width; j = 0; - for(i = 0; i < rs->nb_completions; i++) { + for (i = 0; i < rs->nb_completions; i++) { rs->printf_func(rs->opaque, "%-*s", max_width, rs->completions[i]); if (++j == nb_cols || i == (rs->nb_completions - 1)) { rs->printf_func(rs->opaque, "\n"); @@ -340,12 +378,18 @@ static void readline_completion(ReadLineState *rs) } } +static void readline_clear_screen(ReadLineState *rs) +{ + rs->printf_func(rs->opaque, "\033[2J\033[1;1H"); + readline_show_prompt(rs); +} + /* return true if command handled */ void readline_handle_byte(ReadLineState *rs, int ch) { - switch(rs->esc_state) { + switch (rs->esc_state) { case IS_NORM: - switch(ch) { + switch (ch) { case 1: readline_bol(rs); break; @@ -358,11 +402,15 @@ void readline_handle_byte(ReadLineState *rs, int ch) case 9: readline_completion(rs); break; + case 12: + readline_clear_screen(rs); + break; case 10: case 13: rs->cmd_buf[rs->cmd_buf_size] = '\0'; - if (!rs->read_password) + if (!rs->read_password) { readline_hist_add(rs, rs->cmd_buf); + } rs->printf_func(rs->opaque, "\n"); rs->cmd_buf_index = 0; rs->cmd_buf_size = 0; @@ -381,9 +429,9 @@ void readline_handle_byte(ReadLineState *rs, int ch) case 8: readline_backspace(rs); break; - case 155: + case 155: rs->esc_state = IS_CSI; - break; + break; default: if (ch >= 32) { readline_insert_char(rs, ch); @@ -403,15 +451,15 @@ void readline_handle_byte(ReadLineState *rs, int ch) } break; case IS_CSI: - switch(ch) { - case 'A': - case 'F': - readline_up_char(rs); - break; - case 'B': - case 'E': - readline_down_char(rs); - break; + switch (ch) { + case 'A': + case 'F': + readline_up_char(rs); + break; + case 'B': + case 'E': + readline_down_char(rs); + break; case 'D': readline_backward_char(rs); break; @@ -422,7 +470,7 @@ void readline_handle_byte(ReadLineState *rs, int ch) rs->esc_param = rs->esc_param * 10 + (ch - '0'); goto the_end; case '~': - switch(rs->esc_param) { + switch (rs->esc_param) { case 1: readline_bol(rs); break; @@ -441,7 +489,7 @@ void readline_handle_byte(ReadLineState *rs, int ch) the_end: break; case IS_SS3: - switch(ch) { + switch (ch) { case 'F': readline_eol(rs); break; @@ -473,17 +521,31 @@ void readline_restart(ReadLineState *rs) const char *readline_get_history(ReadLineState *rs, unsigned int index) { - if (index >= READLINE_MAX_CMDS) + if (index >= READLINE_MAX_CMDS) { return NULL; + } return rs->history[index]; } +void readline_free(ReadLineState *rs) +{ + int i; + + if (!rs) { + return; + } + for (i = 0; i < READLINE_MAX_CMDS; i++) { + g_free(rs->history[i]); + } + g_free(rs); +} + ReadLineState *readline_init(ReadLinePrintfFunc *printf_func, ReadLineFlushFunc *flush_func, void *opaque, ReadLineCompletionFunc *completion_finder) { - ReadLineState *rs = g_malloc0(sizeof(*rs)); + ReadLineState *rs = g_new0(ReadLineState, 1); rs->hist_entry = -1; rs->opaque = opaque;