* 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
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);
}
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");
}
}
{
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);
}
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:
+ 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;
}
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);
}
}
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;
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; j<max_prefix; j++) {
- if (rs->completions[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");
}
}
+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;
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;
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);
}
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;
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;
the_end:
break;
case IS_SS3:
- switch(ch) {
+ switch (ch) {
case 'F':
readline_eol(rs);
break;
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;