Home | History | Annotate | Download | only in utils
      1 /*
      2  * Command line editing and history
      3  * Copyright (c) 2010, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 #include <termios.h>
     17 
     18 #include "common.h"
     19 #include "eloop.h"
     20 #include "list.h"
     21 #include "edit.h"
     22 
     23 #define CMD_BUF_LEN 256
     24 static char cmdbuf[CMD_BUF_LEN];
     25 static int cmdbuf_pos = 0;
     26 static int cmdbuf_len = 0;
     27 
     28 #define HISTORY_MAX 100
     29 
     30 struct edit_history {
     31 	struct dl_list list;
     32 	char str[1];
     33 };
     34 
     35 static struct dl_list history_list;
     36 static struct edit_history *history_curr;
     37 
     38 static void *edit_cb_ctx;
     39 static void (*edit_cmd_cb)(void *ctx, char *cmd);
     40 static void (*edit_eof_cb)(void *ctx);
     41 static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
     42 	NULL;
     43 
     44 static struct termios prevt, newt;
     45 
     46 
     47 #define CLEAR_END_LINE "\e[K"
     48 
     49 
     50 void edit_clear_line(void)
     51 {
     52 	int i;
     53 	putchar('\r');
     54 	for (i = 0; i < cmdbuf_len + 2; i++)
     55 		putchar(' ');
     56 }
     57 
     58 
     59 static void move_start(void)
     60 {
     61 	cmdbuf_pos = 0;
     62 	edit_redraw();
     63 }
     64 
     65 
     66 static void move_end(void)
     67 {
     68 	cmdbuf_pos = cmdbuf_len;
     69 	edit_redraw();
     70 }
     71 
     72 
     73 static void move_left(void)
     74 {
     75 	if (cmdbuf_pos > 0) {
     76 		cmdbuf_pos--;
     77 		edit_redraw();
     78 	}
     79 }
     80 
     81 
     82 static void move_right(void)
     83 {
     84 	if (cmdbuf_pos < cmdbuf_len) {
     85 		cmdbuf_pos++;
     86 		edit_redraw();
     87 	}
     88 }
     89 
     90 
     91 static void move_word_left(void)
     92 {
     93 	while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ')
     94 		cmdbuf_pos--;
     95 	while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ')
     96 		cmdbuf_pos--;
     97 	edit_redraw();
     98 }
     99 
    100 
    101 static void move_word_right(void)
    102 {
    103 	while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ')
    104 		cmdbuf_pos++;
    105 	while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ')
    106 		cmdbuf_pos++;
    107 	edit_redraw();
    108 }
    109 
    110 
    111 static void delete_left(void)
    112 {
    113 	if (cmdbuf_pos == 0)
    114 		return;
    115 
    116 	edit_clear_line();
    117 	os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos,
    118 		   cmdbuf_len - cmdbuf_pos);
    119 	cmdbuf_pos--;
    120 	cmdbuf_len--;
    121 	edit_redraw();
    122 }
    123 
    124 
    125 static void delete_current(void)
    126 {
    127 	if (cmdbuf_pos == cmdbuf_len)
    128 		return;
    129 
    130 	edit_clear_line();
    131 	os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1,
    132 		   cmdbuf_len - cmdbuf_pos);
    133 	cmdbuf_len--;
    134 	edit_redraw();
    135 }
    136 
    137 
    138 static void delete_word(void)
    139 {
    140 	int pos;
    141 
    142 	edit_clear_line();
    143 	pos = cmdbuf_pos;
    144 	while (pos > 0 && cmdbuf[pos - 1] == ' ')
    145 		pos--;
    146 	while (pos > 0 && cmdbuf[pos - 1] != ' ')
    147 		pos--;
    148 	os_memmove(cmdbuf + pos, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
    149 	cmdbuf_len -= cmdbuf_pos - pos;
    150 	cmdbuf_pos = pos;
    151 	edit_redraw();
    152 }
    153 
    154 
    155 static void clear_left(void)
    156 {
    157 	if (cmdbuf_pos == 0)
    158 		return;
    159 
    160 	edit_clear_line();
    161 	os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
    162 	cmdbuf_len -= cmdbuf_pos;
    163 	cmdbuf_pos = 0;
    164 	edit_redraw();
    165 }
    166 
    167 
    168 static void clear_right(void)
    169 {
    170 	if (cmdbuf_pos == cmdbuf_len)
    171 		return;
    172 
    173 	edit_clear_line();
    174 	cmdbuf_len = cmdbuf_pos;
    175 	edit_redraw();
    176 }
    177 
    178 
    179 static void history_add(const char *str)
    180 {
    181 	struct edit_history *h, *match = NULL, *last = NULL;
    182 	size_t len, count = 0;
    183 
    184 	if (str[0] == '\0')
    185 		return;
    186 
    187 	dl_list_for_each(h, &history_list, struct edit_history, list) {
    188 		if (os_strcmp(str, h->str) == 0) {
    189 			match = h;
    190 			break;
    191 		}
    192 		last = h;
    193 		count++;
    194 	}
    195 
    196 	if (match) {
    197 		dl_list_del(&h->list);
    198 		dl_list_add(&history_list, &h->list);
    199 		history_curr = h;
    200 		return;
    201 	}
    202 
    203 	if (count >= HISTORY_MAX && last) {
    204 		dl_list_del(&last->list);
    205 		os_free(last);
    206 	}
    207 
    208 	len = os_strlen(str);
    209 	h = os_zalloc(sizeof(*h) + len);
    210 	if (h == NULL)
    211 		return;
    212 	dl_list_add(&history_list, &h->list);
    213 	os_strlcpy(h->str, str, len + 1);
    214 	history_curr = h;
    215 }
    216 
    217 
    218 static void history_use(void)
    219 {
    220 	edit_clear_line();
    221 	cmdbuf_len = cmdbuf_pos = os_strlen(history_curr->str);
    222 	os_memcpy(cmdbuf, history_curr->str, cmdbuf_len);
    223 	edit_redraw();
    224 }
    225 
    226 
    227 static void history_prev(void)
    228 {
    229 	if (history_curr == NULL)
    230 		return;
    231 
    232 	if (history_curr ==
    233 	    dl_list_first(&history_list, struct edit_history, list)) {
    234 		cmdbuf[cmdbuf_len] = '\0';
    235 		history_add(cmdbuf);
    236 	}
    237 
    238 	history_use();
    239 
    240 	if (history_curr ==
    241 	    dl_list_last(&history_list, struct edit_history, list))
    242 		return;
    243 
    244 	history_curr = dl_list_entry(history_curr->list.next,
    245 				     struct edit_history, list);
    246 }
    247 
    248 
    249 static void history_next(void)
    250 {
    251 	if (history_curr == NULL ||
    252 	    history_curr ==
    253 	    dl_list_first(&history_list, struct edit_history, list))
    254 		return;
    255 
    256 	history_curr = dl_list_entry(history_curr->list.prev,
    257 				     struct edit_history, list);
    258 	history_use();
    259 }
    260 
    261 
    262 static void history_read(const char *fname)
    263 {
    264 	FILE *f;
    265 	char buf[CMD_BUF_LEN], *pos;
    266 
    267 	f = fopen(fname, "r");
    268 	if (f == NULL)
    269 		return;
    270 
    271 	while (fgets(buf, CMD_BUF_LEN, f)) {
    272 		for (pos = buf; *pos; pos++) {
    273 			if (*pos == '\r' || *pos == '\n') {
    274 				*pos = '\0';
    275 				break;
    276 			}
    277 		}
    278 		history_add(buf);
    279 	}
    280 
    281 	fclose(f);
    282 }
    283 
    284 
    285 static void history_write(const char *fname,
    286 			  int (*filter_cb)(void *ctx, const char *cmd))
    287 {
    288 	FILE *f;
    289 	struct edit_history *h;
    290 
    291 	f = fopen(fname, "w");
    292 	if (f == NULL)
    293 		return;
    294 
    295 	dl_list_for_each_reverse(h, &history_list, struct edit_history, list) {
    296 		if (filter_cb && filter_cb(edit_cb_ctx, h->str))
    297 			continue;
    298 		fprintf(f, "%s\n", h->str);
    299 	}
    300 
    301 	fclose(f);
    302 }
    303 
    304 
    305 static void history_debug_dump(void)
    306 {
    307 	struct edit_history *h;
    308 	edit_clear_line();
    309 	printf("\r");
    310 	dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
    311 		printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
    312 	edit_redraw();
    313 }
    314 
    315 
    316 static void insert_char(int c)
    317 {
    318 	if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1)
    319 		return;
    320 	if (cmdbuf_len == cmdbuf_pos) {
    321 		cmdbuf[cmdbuf_pos++] = c;
    322 		cmdbuf_len++;
    323 		putchar(c);
    324 		fflush(stdout);
    325 	} else {
    326 		os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos,
    327 			   cmdbuf_len - cmdbuf_pos);
    328 		cmdbuf[cmdbuf_pos++] = c;
    329 		cmdbuf_len++;
    330 		edit_redraw();
    331 	}
    332 }
    333 
    334 
    335 static void process_cmd(void)
    336 {
    337 
    338 	if (cmdbuf_len == 0) {
    339 		printf("\n> ");
    340 		fflush(stdout);
    341 		return;
    342 	}
    343 	printf("\n");
    344 	cmdbuf[cmdbuf_len] = '\0';
    345 	history_add(cmdbuf);
    346 	cmdbuf_pos = 0;
    347 	cmdbuf_len = 0;
    348 	edit_cmd_cb(edit_cb_ctx, cmdbuf);
    349 	printf("> ");
    350 	fflush(stdout);
    351 }
    352 
    353 
    354 static void free_completions(char **c)
    355 {
    356 	int i;
    357 	if (c == NULL)
    358 		return;
    359 	for (i = 0; c[i]; i++)
    360 		os_free(c[i]);
    361 	os_free(c);
    362 }
    363 
    364 
    365 static int filter_strings(char **c, char *str, size_t len)
    366 {
    367 	int i, j;
    368 
    369 	for (i = 0, j = 0; c[j]; j++) {
    370 		if (os_strncasecmp(c[j], str, len) == 0) {
    371 			if (i != j) {
    372 				c[i] = c[j];
    373 				c[j] = NULL;
    374 			}
    375 			i++;
    376 		} else {
    377 			os_free(c[j]);
    378 			c[j] = NULL;
    379 		}
    380 	}
    381 	c[i] = NULL;
    382 	return i;
    383 }
    384 
    385 
    386 static int common_len(const char *a, const char *b)
    387 {
    388 	int len = 0;
    389 	while (a[len] && a[len] == b[len])
    390 		len++;
    391 	return len;
    392 }
    393 
    394 
    395 static int max_common_length(char **c)
    396 {
    397 	int len, i;
    398 
    399 	len = os_strlen(c[0]);
    400 	for (i = 1; c[i]; i++) {
    401 		int same = common_len(c[0], c[i]);
    402 		if (same < len)
    403 			len = same;
    404 	}
    405 
    406 	return len;
    407 }
    408 
    409 
    410 static int cmp_str(const void *a, const void *b)
    411 {
    412 	return os_strcmp(* (const char **) a, * (const char **) b);
    413 }
    414 
    415 static void complete(int list)
    416 {
    417 	char **c;
    418 	int i, len, count;
    419 	int start, end;
    420 	int room, plen, add_space;
    421 
    422 	if (edit_completion_cb == NULL)
    423 		return;
    424 
    425 	cmdbuf[cmdbuf_len] = '\0';
    426 	c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos);
    427 	if (c == NULL)
    428 		return;
    429 
    430 	end = cmdbuf_pos;
    431 	start = end;
    432 	while (start > 0 && cmdbuf[start - 1] != ' ')
    433 		start--;
    434 	plen = end - start;
    435 
    436 	count = filter_strings(c, &cmdbuf[start], plen);
    437 	if (count == 0) {
    438 		free_completions(c);
    439 		return;
    440 	}
    441 
    442 	len = max_common_length(c);
    443 	if (len <= plen && count > 1) {
    444 		if (list) {
    445 			qsort(c, count, sizeof(char *), cmp_str);
    446 			edit_clear_line();
    447 			printf("\r");
    448 			for (i = 0; c[i]; i++)
    449 				printf("%s%s", i > 0 ? " " : "", c[i]);
    450 			printf("\n");
    451 			edit_redraw();
    452 		}
    453 		free_completions(c);
    454 		return;
    455 	}
    456 	len -= plen;
    457 
    458 	room = sizeof(cmdbuf) - 1 - cmdbuf_len;
    459 	if (room < len)
    460 		len = room;
    461 	add_space = count == 1 && len < room;
    462 
    463 	os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos,
    464 		   cmdbuf_len - cmdbuf_pos);
    465 	os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len);
    466 	if (add_space)
    467 		cmdbuf[cmdbuf_pos + len] = ' ';
    468 
    469 	cmdbuf_pos += len + add_space;
    470 	cmdbuf_len += len + add_space;
    471 
    472 	edit_redraw();
    473 
    474 	free_completions(c);
    475 }
    476 
    477 
    478 enum edit_key_code {
    479 	EDIT_KEY_NONE = 256,
    480 	EDIT_KEY_TAB,
    481 	EDIT_KEY_UP,
    482 	EDIT_KEY_DOWN,
    483 	EDIT_KEY_RIGHT,
    484 	EDIT_KEY_LEFT,
    485 	EDIT_KEY_ENTER,
    486 	EDIT_KEY_BACKSPACE,
    487 	EDIT_KEY_INSERT,
    488 	EDIT_KEY_DELETE,
    489 	EDIT_KEY_HOME,
    490 	EDIT_KEY_END,
    491 	EDIT_KEY_PAGE_UP,
    492 	EDIT_KEY_PAGE_DOWN,
    493 	EDIT_KEY_F1,
    494 	EDIT_KEY_F2,
    495 	EDIT_KEY_F3,
    496 	EDIT_KEY_F4,
    497 	EDIT_KEY_F5,
    498 	EDIT_KEY_F6,
    499 	EDIT_KEY_F7,
    500 	EDIT_KEY_F8,
    501 	EDIT_KEY_F9,
    502 	EDIT_KEY_F10,
    503 	EDIT_KEY_F11,
    504 	EDIT_KEY_F12,
    505 	EDIT_KEY_CTRL_UP,
    506 	EDIT_KEY_CTRL_DOWN,
    507 	EDIT_KEY_CTRL_RIGHT,
    508 	EDIT_KEY_CTRL_LEFT,
    509 	EDIT_KEY_CTRL_A,
    510 	EDIT_KEY_CTRL_B,
    511 	EDIT_KEY_CTRL_D,
    512 	EDIT_KEY_CTRL_E,
    513 	EDIT_KEY_CTRL_F,
    514 	EDIT_KEY_CTRL_G,
    515 	EDIT_KEY_CTRL_H,
    516 	EDIT_KEY_CTRL_J,
    517 	EDIT_KEY_CTRL_K,
    518 	EDIT_KEY_CTRL_L,
    519 	EDIT_KEY_CTRL_N,
    520 	EDIT_KEY_CTRL_O,
    521 	EDIT_KEY_CTRL_P,
    522 	EDIT_KEY_CTRL_R,
    523 	EDIT_KEY_CTRL_T,
    524 	EDIT_KEY_CTRL_U,
    525 	EDIT_KEY_CTRL_V,
    526 	EDIT_KEY_CTRL_W,
    527 	EDIT_KEY_ALT_UP,
    528 	EDIT_KEY_ALT_DOWN,
    529 	EDIT_KEY_ALT_RIGHT,
    530 	EDIT_KEY_ALT_LEFT,
    531 	EDIT_KEY_SHIFT_UP,
    532 	EDIT_KEY_SHIFT_DOWN,
    533 	EDIT_KEY_SHIFT_RIGHT,
    534 	EDIT_KEY_SHIFT_LEFT,
    535 	EDIT_KEY_ALT_SHIFT_UP,
    536 	EDIT_KEY_ALT_SHIFT_DOWN,
    537 	EDIT_KEY_ALT_SHIFT_RIGHT,
    538 	EDIT_KEY_ALT_SHIFT_LEFT,
    539 	EDIT_KEY_EOF
    540 };
    541 
    542 static void show_esc_buf(const char *esc_buf, char c, int i)
    543 {
    544 	edit_clear_line();
    545 	printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i);
    546 	edit_redraw();
    547 }
    548 
    549 
    550 static enum edit_key_code esc_seq_to_key1_no(char last)
    551 {
    552 	switch (last) {
    553 	case 'A':
    554 		return EDIT_KEY_UP;
    555 	case 'B':
    556 		return EDIT_KEY_DOWN;
    557 	case 'C':
    558 		return EDIT_KEY_RIGHT;
    559 	case 'D':
    560 		return EDIT_KEY_LEFT;
    561 	default:
    562 		return EDIT_KEY_NONE;
    563 	}
    564 }
    565 
    566 
    567 static enum edit_key_code esc_seq_to_key1_shift(char last)
    568 {
    569 	switch (last) {
    570 	case 'A':
    571 		return EDIT_KEY_SHIFT_UP;
    572 	case 'B':
    573 		return EDIT_KEY_SHIFT_DOWN;
    574 	case 'C':
    575 		return EDIT_KEY_SHIFT_RIGHT;
    576 	case 'D':
    577 		return EDIT_KEY_SHIFT_LEFT;
    578 	default:
    579 		return EDIT_KEY_NONE;
    580 	}
    581 }
    582 
    583 
    584 static enum edit_key_code esc_seq_to_key1_alt(char last)
    585 {
    586 	switch (last) {
    587 	case 'A':
    588 		return EDIT_KEY_ALT_UP;
    589 	case 'B':
    590 		return EDIT_KEY_ALT_DOWN;
    591 	case 'C':
    592 		return EDIT_KEY_ALT_RIGHT;
    593 	case 'D':
    594 		return EDIT_KEY_ALT_LEFT;
    595 	default:
    596 		return EDIT_KEY_NONE;
    597 	}
    598 }
    599 
    600 
    601 static enum edit_key_code esc_seq_to_key1_alt_shift(char last)
    602 {
    603 	switch (last) {
    604 	case 'A':
    605 		return EDIT_KEY_ALT_SHIFT_UP;
    606 	case 'B':
    607 		return EDIT_KEY_ALT_SHIFT_DOWN;
    608 	case 'C':
    609 		return EDIT_KEY_ALT_SHIFT_RIGHT;
    610 	case 'D':
    611 		return EDIT_KEY_ALT_SHIFT_LEFT;
    612 	default:
    613 		return EDIT_KEY_NONE;
    614 	}
    615 }
    616 
    617 
    618 static enum edit_key_code esc_seq_to_key1_ctrl(char last)
    619 {
    620 	switch (last) {
    621 	case 'A':
    622 		return EDIT_KEY_CTRL_UP;
    623 	case 'B':
    624 		return EDIT_KEY_CTRL_DOWN;
    625 	case 'C':
    626 		return EDIT_KEY_CTRL_RIGHT;
    627 	case 'D':
    628 		return EDIT_KEY_CTRL_LEFT;
    629 	default:
    630 		return EDIT_KEY_NONE;
    631 	}
    632 }
    633 
    634 
    635 static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last)
    636 {
    637 	/* ESC-[<param1>;<param2><last> */
    638 
    639 	if (param1 < 0 && param2 < 0)
    640 		return esc_seq_to_key1_no(last);
    641 
    642 	if (param1 == 1 && param2 == 2)
    643 		return esc_seq_to_key1_shift(last);
    644 
    645 	if (param1 == 1 && param2 == 3)
    646 		return esc_seq_to_key1_alt(last);
    647 
    648 	if (param1 == 1 && param2 == 4)
    649 		return esc_seq_to_key1_alt_shift(last);
    650 
    651 	if (param1 == 1 && param2 == 5)
    652 		return esc_seq_to_key1_ctrl(last);
    653 
    654 	if (param2 < 0) {
    655 		if (last != '~')
    656 			return EDIT_KEY_NONE;
    657 		switch (param1) {
    658 		case 2:
    659 			return EDIT_KEY_INSERT;
    660 		case 3:
    661 			return EDIT_KEY_DELETE;
    662 		case 5:
    663 			return EDIT_KEY_PAGE_UP;
    664 		case 6:
    665 			return EDIT_KEY_PAGE_DOWN;
    666 		case 15:
    667 			return EDIT_KEY_F5;
    668 		case 17:
    669 			return EDIT_KEY_F6;
    670 		case 18:
    671 			return EDIT_KEY_F7;
    672 		case 19:
    673 			return EDIT_KEY_F8;
    674 		case 20:
    675 			return EDIT_KEY_F9;
    676 		case 21:
    677 			return EDIT_KEY_F10;
    678 		case 23:
    679 			return EDIT_KEY_F11;
    680 		case 24:
    681 			return EDIT_KEY_F12;
    682 		}
    683 	}
    684 
    685 	return EDIT_KEY_NONE;
    686 }
    687 
    688 
    689 static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last)
    690 {
    691 	/* ESC-O<param1>;<param2><last> */
    692 
    693 	if (param1 >= 0 || param2 >= 0)
    694 		return EDIT_KEY_NONE;
    695 
    696 	switch (last) {
    697 	case 'F':
    698 		return EDIT_KEY_END;
    699 	case 'H':
    700 		return EDIT_KEY_HOME;
    701 	case 'P':
    702 		return EDIT_KEY_F1;
    703 	case 'Q':
    704 		return EDIT_KEY_F2;
    705 	case 'R':
    706 		return EDIT_KEY_F3;
    707 	case 'S':
    708 		return EDIT_KEY_F4;
    709 	default:
    710 		return EDIT_KEY_NONE;
    711 	}
    712 }
    713 
    714 
    715 static enum edit_key_code esc_seq_to_key(char *seq)
    716 {
    717 	char last, *pos;
    718 	int param1 = -1, param2 = -1;
    719 	enum edit_key_code ret = EDIT_KEY_NONE;
    720 
    721 	last = '\0';
    722 	for (pos = seq; *pos; pos++)
    723 		last = *pos;
    724 
    725 	if (seq[1] >= '0' && seq[1] <= '9') {
    726 		param1 = atoi(&seq[1]);
    727 		pos = os_strchr(seq, ';');
    728 		if (pos)
    729 			param2 = atoi(pos + 1);
    730 	}
    731 
    732 	if (seq[0] == '[')
    733 		ret = esc_seq_to_key1(param1, param2, last);
    734 	else if (seq[0] == 'O')
    735 		ret = esc_seq_to_key2(param1, param2, last);
    736 
    737 	if (ret != EDIT_KEY_NONE)
    738 		return ret;
    739 
    740 	edit_clear_line();
    741 	printf("\rUnknown escape sequence '%s'\n", seq);
    742 	edit_redraw();
    743 	return EDIT_KEY_NONE;
    744 }
    745 
    746 
    747 static enum edit_key_code edit_read_key(int sock)
    748 {
    749 	int c;
    750 	unsigned char buf[1];
    751 	int res;
    752 	static int esc = -1;
    753 	static char esc_buf[7];
    754 
    755 	res = read(sock, buf, 1);
    756 	if (res < 0)
    757 		perror("read");
    758 	if (res <= 0)
    759 		return EDIT_KEY_EOF;
    760 
    761 	c = buf[0];
    762 
    763 	if (esc >= 0) {
    764 		if (c == 27 /* ESC */) {
    765 			esc = 0;
    766 			return EDIT_KEY_NONE;
    767 		}
    768 
    769 		if (esc == 6) {
    770 			show_esc_buf(esc_buf, c, 0);
    771 			esc = -1;
    772 		} else {
    773 			esc_buf[esc++] = c;
    774 			esc_buf[esc] = '\0';
    775 		}
    776 	}
    777 
    778 	if (esc == 1) {
    779 		if (esc_buf[0] != '[' && esc_buf[0] != 'O') {
    780 			show_esc_buf(esc_buf, c, 1);
    781 			esc = -1;
    782 			return EDIT_KEY_NONE;
    783 		} else
    784 			return EDIT_KEY_NONE; /* Escape sequence continues */
    785 	}
    786 
    787 	if (esc > 1) {
    788 		if ((c >= '0' && c <= '9') || c == ';')
    789 			return EDIT_KEY_NONE; /* Escape sequence continues */
    790 
    791 		if (c == '~' || (c >= 'A' && c <= 'Z')) {
    792 			esc = -1;
    793 			return esc_seq_to_key(esc_buf);
    794 		}
    795 
    796 		show_esc_buf(esc_buf, c, 2);
    797 		esc = -1;
    798 		return EDIT_KEY_NONE;
    799 	}
    800 
    801 	switch (c) {
    802 	case 1:
    803 		return EDIT_KEY_CTRL_A;
    804 	case 2:
    805 		return EDIT_KEY_CTRL_B;
    806 	case 4:
    807 		return EDIT_KEY_CTRL_D;
    808 	case 5:
    809 		return EDIT_KEY_CTRL_E;
    810 	case 6:
    811 		return EDIT_KEY_CTRL_F;
    812 	case 7:
    813 		return EDIT_KEY_CTRL_G;
    814 	case 8:
    815 		return EDIT_KEY_CTRL_H;
    816 	case 9:
    817 		return EDIT_KEY_TAB;
    818 	case 10:
    819 		return EDIT_KEY_CTRL_J;
    820 	case 13: /* CR */
    821 		return EDIT_KEY_ENTER;
    822 	case 11:
    823 		return EDIT_KEY_CTRL_K;
    824 	case 12:
    825 		return EDIT_KEY_CTRL_L;
    826 	case 14:
    827 		return EDIT_KEY_CTRL_N;
    828 	case 15:
    829 		return EDIT_KEY_CTRL_O;
    830 	case 16:
    831 		return EDIT_KEY_CTRL_P;
    832 	case 18:
    833 		return EDIT_KEY_CTRL_R;
    834 	case 20:
    835 		return EDIT_KEY_CTRL_T;
    836 	case 21:
    837 		return EDIT_KEY_CTRL_U;
    838 	case 22:
    839 		return EDIT_KEY_CTRL_V;
    840 	case 23:
    841 		return EDIT_KEY_CTRL_W;
    842 	case 27: /* ESC */
    843 		esc = 0;
    844 		return EDIT_KEY_NONE;
    845 	case 127:
    846 		return EDIT_KEY_BACKSPACE;
    847 	default:
    848 		return c;
    849 	}
    850 }
    851 
    852 
    853 static char search_buf[21];
    854 static int search_skip;
    855 
    856 static char * search_find(void)
    857 {
    858 	struct edit_history *h;
    859 	size_t len = os_strlen(search_buf);
    860 	int skip = search_skip;
    861 
    862 	if (len == 0)
    863 		return NULL;
    864 
    865 	dl_list_for_each(h, &history_list, struct edit_history, list) {
    866 		if (os_strstr(h->str, search_buf)) {
    867 			if (skip == 0)
    868 				return h->str;
    869 			skip--;
    870 		}
    871 	}
    872 
    873 	search_skip = 0;
    874 	return NULL;
    875 }
    876 
    877 
    878 static void search_redraw(void)
    879 {
    880 	char *match = search_find();
    881 	printf("\rsearch '%s': %s" CLEAR_END_LINE,
    882 	       search_buf, match ? match : "");
    883 	printf("\rsearch '%s", search_buf);
    884 	fflush(stdout);
    885 }
    886 
    887 
    888 static void search_start(void)
    889 {
    890 	edit_clear_line();
    891 	search_buf[0] = '\0';
    892 	search_skip = 0;
    893 	search_redraw();
    894 }
    895 
    896 
    897 static void search_clear(void)
    898 {
    899 	search_redraw();
    900 	printf("\r" CLEAR_END_LINE);
    901 }
    902 
    903 
    904 static void search_stop(void)
    905 {
    906 	char *match = search_find();
    907 	search_buf[0] = '\0';
    908 	search_clear();
    909 	if (match) {
    910 		os_strlcpy(cmdbuf, match, CMD_BUF_LEN);
    911 		cmdbuf_len = os_strlen(cmdbuf);
    912 		cmdbuf_pos = cmdbuf_len;
    913 	}
    914 	edit_redraw();
    915 }
    916 
    917 
    918 static void search_cancel(void)
    919 {
    920 	search_buf[0] = '\0';
    921 	search_clear();
    922 	edit_redraw();
    923 }
    924 
    925 
    926 static void search_backspace(void)
    927 {
    928 	size_t len;
    929 	len = os_strlen(search_buf);
    930 	if (len == 0)
    931 		return;
    932 	search_buf[len - 1] = '\0';
    933 	search_skip = 0;
    934 	search_redraw();
    935 }
    936 
    937 
    938 static void search_next(void)
    939 {
    940 	search_skip++;
    941 	search_find();
    942 	search_redraw();
    943 }
    944 
    945 
    946 static void search_char(char c)
    947 {
    948 	size_t len;
    949 	len = os_strlen(search_buf);
    950 	if (len == sizeof(search_buf) - 1)
    951 		return;
    952 	search_buf[len] = c;
    953 	search_buf[len + 1] = '\0';
    954 	search_skip = 0;
    955 	search_redraw();
    956 }
    957 
    958 
    959 static enum edit_key_code search_key(enum edit_key_code c)
    960 {
    961 	switch (c) {
    962 	case EDIT_KEY_ENTER:
    963 	case EDIT_KEY_CTRL_J:
    964 	case EDIT_KEY_LEFT:
    965 	case EDIT_KEY_RIGHT:
    966 	case EDIT_KEY_HOME:
    967 	case EDIT_KEY_END:
    968 	case EDIT_KEY_CTRL_A:
    969 	case EDIT_KEY_CTRL_E:
    970 		search_stop();
    971 		return c;
    972 	case EDIT_KEY_DOWN:
    973 	case EDIT_KEY_UP:
    974 		search_cancel();
    975 		return EDIT_KEY_EOF;
    976 	case EDIT_KEY_CTRL_H:
    977 	case EDIT_KEY_BACKSPACE:
    978 		search_backspace();
    979 		break;
    980 	case EDIT_KEY_CTRL_R:
    981 		search_next();
    982 		break;
    983 	default:
    984 		if (c >= 32 && c <= 255)
    985 			search_char(c);
    986 		break;
    987 	}
    988 
    989 	return EDIT_KEY_NONE;
    990 }
    991 
    992 
    993 static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
    994 {
    995 	static int last_tab = 0;
    996 	static int search = 0;
    997 	enum edit_key_code c;
    998 
    999 	c = edit_read_key(sock);
   1000 
   1001 	if (search) {
   1002 		c = search_key(c);
   1003 		if (c == EDIT_KEY_NONE)
   1004 			return;
   1005 		search = 0;
   1006 		if (c == EDIT_KEY_EOF)
   1007 			return;
   1008 	}
   1009 
   1010 	if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE)
   1011 		last_tab = 0;
   1012 
   1013 	switch (c) {
   1014 	case EDIT_KEY_NONE:
   1015 		break;
   1016 	case EDIT_KEY_EOF:
   1017 		edit_eof_cb(edit_cb_ctx);
   1018 		break;
   1019 	case EDIT_KEY_TAB:
   1020 		complete(last_tab);
   1021 		last_tab = 1;
   1022 		break;
   1023 	case EDIT_KEY_UP:
   1024 	case EDIT_KEY_CTRL_P:
   1025 		history_prev();
   1026 		break;
   1027 	case EDIT_KEY_DOWN:
   1028 	case EDIT_KEY_CTRL_N:
   1029 		history_next();
   1030 		break;
   1031 	case EDIT_KEY_RIGHT:
   1032 	case EDIT_KEY_CTRL_F:
   1033 		move_right();
   1034 		break;
   1035 	case EDIT_KEY_LEFT:
   1036 	case EDIT_KEY_CTRL_B:
   1037 		move_left();
   1038 		break;
   1039 	case EDIT_KEY_CTRL_RIGHT:
   1040 		move_word_right();
   1041 		break;
   1042 	case EDIT_KEY_CTRL_LEFT:
   1043 		move_word_left();
   1044 		break;
   1045 	case EDIT_KEY_DELETE:
   1046 		delete_current();
   1047 		break;
   1048 	case EDIT_KEY_END:
   1049 		move_end();
   1050 		break;
   1051 	case EDIT_KEY_HOME:
   1052 	case EDIT_KEY_CTRL_A:
   1053 		move_start();
   1054 		break;
   1055 	case EDIT_KEY_F2:
   1056 		history_debug_dump();
   1057 		break;
   1058 	case EDIT_KEY_CTRL_D:
   1059 		if (cmdbuf_len > 0) {
   1060 			delete_current();
   1061 			return;
   1062 		}
   1063 		printf("\n");
   1064 		edit_eof_cb(edit_cb_ctx);
   1065 		break;
   1066 	case EDIT_KEY_CTRL_E:
   1067 		move_end();
   1068 		break;
   1069 	case EDIT_KEY_CTRL_H:
   1070 	case EDIT_KEY_BACKSPACE:
   1071 		delete_left();
   1072 		break;
   1073 	case EDIT_KEY_ENTER:
   1074 	case EDIT_KEY_CTRL_J:
   1075 		process_cmd();
   1076 		break;
   1077 	case EDIT_KEY_CTRL_K:
   1078 		clear_right();
   1079 		break;
   1080 	case EDIT_KEY_CTRL_L:
   1081 		edit_clear_line();
   1082 		edit_redraw();
   1083 		break;
   1084 	case EDIT_KEY_CTRL_R:
   1085 		search = 1;
   1086 		search_start();
   1087 		break;
   1088 	case EDIT_KEY_CTRL_U:
   1089 		clear_left();
   1090 		break;
   1091 	case EDIT_KEY_CTRL_W:
   1092 		delete_word();
   1093 		break;
   1094 	default:
   1095 		if (c >= 32 && c <= 255)
   1096 			insert_char(c);
   1097 		break;
   1098 	}
   1099 }
   1100 
   1101 
   1102 int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
   1103 	      void (*eof_cb)(void *ctx),
   1104 	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
   1105 	      void *ctx, const char *history_file)
   1106 {
   1107 	dl_list_init(&history_list);
   1108 	history_curr = NULL;
   1109 	if (history_file)
   1110 		history_read(history_file);
   1111 
   1112 	edit_cb_ctx = ctx;
   1113 	edit_cmd_cb = cmd_cb;
   1114 	edit_eof_cb = eof_cb;
   1115 	edit_completion_cb = completion_cb;
   1116 
   1117 	tcgetattr(STDIN_FILENO, &prevt);
   1118 	newt = prevt;
   1119 	newt.c_lflag &= ~(ICANON | ECHO);
   1120 	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
   1121 
   1122 	eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
   1123 
   1124 	printf("> ");
   1125 	fflush(stdout);
   1126 
   1127 	return 0;
   1128 }
   1129 
   1130 
   1131 void edit_deinit(const char *history_file,
   1132 		 int (*filter_cb)(void *ctx, const char *cmd))
   1133 {
   1134 	struct edit_history *h;
   1135 	if (history_file)
   1136 		history_write(history_file, filter_cb);
   1137 	while ((h = dl_list_first(&history_list, struct edit_history, list))) {
   1138 		dl_list_del(&h->list);
   1139 		os_free(h);
   1140 	}
   1141 	edit_clear_line();
   1142 	putchar('\r');
   1143 	fflush(stdout);
   1144 	eloop_unregister_read_sock(STDIN_FILENO);
   1145 	tcsetattr(STDIN_FILENO, TCSANOW, &prevt);
   1146 }
   1147 
   1148 
   1149 void edit_redraw(void)
   1150 {
   1151 	char tmp;
   1152 	cmdbuf[cmdbuf_len] = '\0';
   1153 	printf("\r> %s", cmdbuf);
   1154 	if (cmdbuf_pos != cmdbuf_len) {
   1155 		tmp = cmdbuf[cmdbuf_pos];
   1156 		cmdbuf[cmdbuf_pos] = '\0';
   1157 		printf("\r> %s", cmdbuf);
   1158 		cmdbuf[cmdbuf_pos] = tmp;
   1159 	}
   1160 	fflush(stdout);
   1161 }
   1162