xref: /dflybsd-src/contrib/wpa_supplicant/src/utils/edit.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * Command line editing and history
33ff40c12SJohn Marino  * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino #include <termios.h>
113ff40c12SJohn Marino 
123ff40c12SJohn Marino #include "common.h"
133ff40c12SJohn Marino #include "eloop.h"
143ff40c12SJohn Marino #include "list.h"
153ff40c12SJohn Marino #include "edit.h"
163ff40c12SJohn Marino 
17*a1157835SDaniel Fojt #define CMD_BUF_LEN 4096
183ff40c12SJohn Marino static char cmdbuf[CMD_BUF_LEN];
193ff40c12SJohn Marino static int cmdbuf_pos = 0;
203ff40c12SJohn Marino static int cmdbuf_len = 0;
213ff40c12SJohn Marino static char currbuf[CMD_BUF_LEN];
223ff40c12SJohn Marino static int currbuf_valid = 0;
233ff40c12SJohn Marino static const char *ps2 = NULL;
243ff40c12SJohn Marino 
253ff40c12SJohn Marino #define HISTORY_MAX 100
263ff40c12SJohn Marino 
273ff40c12SJohn Marino struct edit_history {
283ff40c12SJohn Marino 	struct dl_list list;
293ff40c12SJohn Marino 	char str[1];
303ff40c12SJohn Marino };
313ff40c12SJohn Marino 
323ff40c12SJohn Marino static struct dl_list history_list;
333ff40c12SJohn Marino static struct edit_history *history_curr;
343ff40c12SJohn Marino 
353ff40c12SJohn Marino static void *edit_cb_ctx;
363ff40c12SJohn Marino static void (*edit_cmd_cb)(void *ctx, char *cmd);
373ff40c12SJohn Marino static void (*edit_eof_cb)(void *ctx);
383ff40c12SJohn Marino static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
393ff40c12SJohn Marino 	NULL;
403ff40c12SJohn Marino 
413ff40c12SJohn Marino static struct termios prevt, newt;
423ff40c12SJohn Marino 
433ff40c12SJohn Marino 
443ff40c12SJohn Marino #define CLEAR_END_LINE "\e[K"
453ff40c12SJohn Marino 
463ff40c12SJohn Marino 
edit_clear_line(void)473ff40c12SJohn Marino void edit_clear_line(void)
483ff40c12SJohn Marino {
493ff40c12SJohn Marino 	int i;
503ff40c12SJohn Marino 	putchar('\r');
513ff40c12SJohn Marino 	for (i = 0; i < cmdbuf_len + 2 + (ps2 ? (int) os_strlen(ps2) : 0); i++)
523ff40c12SJohn Marino 		putchar(' ');
533ff40c12SJohn Marino }
543ff40c12SJohn Marino 
553ff40c12SJohn Marino 
move_start(void)563ff40c12SJohn Marino static void move_start(void)
573ff40c12SJohn Marino {
583ff40c12SJohn Marino 	cmdbuf_pos = 0;
593ff40c12SJohn Marino 	edit_redraw();
603ff40c12SJohn Marino }
613ff40c12SJohn Marino 
623ff40c12SJohn Marino 
move_end(void)633ff40c12SJohn Marino static void move_end(void)
643ff40c12SJohn Marino {
653ff40c12SJohn Marino 	cmdbuf_pos = cmdbuf_len;
663ff40c12SJohn Marino 	edit_redraw();
673ff40c12SJohn Marino }
683ff40c12SJohn Marino 
693ff40c12SJohn Marino 
move_left(void)703ff40c12SJohn Marino static void move_left(void)
713ff40c12SJohn Marino {
723ff40c12SJohn Marino 	if (cmdbuf_pos > 0) {
733ff40c12SJohn Marino 		cmdbuf_pos--;
743ff40c12SJohn Marino 		edit_redraw();
753ff40c12SJohn Marino 	}
763ff40c12SJohn Marino }
773ff40c12SJohn Marino 
783ff40c12SJohn Marino 
move_right(void)793ff40c12SJohn Marino static void move_right(void)
803ff40c12SJohn Marino {
813ff40c12SJohn Marino 	if (cmdbuf_pos < cmdbuf_len) {
823ff40c12SJohn Marino 		cmdbuf_pos++;
833ff40c12SJohn Marino 		edit_redraw();
843ff40c12SJohn Marino 	}
853ff40c12SJohn Marino }
863ff40c12SJohn Marino 
873ff40c12SJohn Marino 
move_word_left(void)883ff40c12SJohn Marino static void move_word_left(void)
893ff40c12SJohn Marino {
903ff40c12SJohn Marino 	while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ')
913ff40c12SJohn Marino 		cmdbuf_pos--;
923ff40c12SJohn Marino 	while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ')
933ff40c12SJohn Marino 		cmdbuf_pos--;
943ff40c12SJohn Marino 	edit_redraw();
953ff40c12SJohn Marino }
963ff40c12SJohn Marino 
973ff40c12SJohn Marino 
move_word_right(void)983ff40c12SJohn Marino static void move_word_right(void)
993ff40c12SJohn Marino {
1003ff40c12SJohn Marino 	while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ')
1013ff40c12SJohn Marino 		cmdbuf_pos++;
1023ff40c12SJohn Marino 	while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ')
1033ff40c12SJohn Marino 		cmdbuf_pos++;
1043ff40c12SJohn Marino 	edit_redraw();
1053ff40c12SJohn Marino }
1063ff40c12SJohn Marino 
1073ff40c12SJohn Marino 
delete_left(void)1083ff40c12SJohn Marino static void delete_left(void)
1093ff40c12SJohn Marino {
1103ff40c12SJohn Marino 	if (cmdbuf_pos == 0)
1113ff40c12SJohn Marino 		return;
1123ff40c12SJohn Marino 
1133ff40c12SJohn Marino 	edit_clear_line();
1143ff40c12SJohn Marino 	os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos,
1153ff40c12SJohn Marino 		   cmdbuf_len - cmdbuf_pos);
1163ff40c12SJohn Marino 	cmdbuf_pos--;
1173ff40c12SJohn Marino 	cmdbuf_len--;
1183ff40c12SJohn Marino 	edit_redraw();
1193ff40c12SJohn Marino }
1203ff40c12SJohn Marino 
1213ff40c12SJohn Marino 
delete_current(void)1223ff40c12SJohn Marino static void delete_current(void)
1233ff40c12SJohn Marino {
1243ff40c12SJohn Marino 	if (cmdbuf_pos == cmdbuf_len)
1253ff40c12SJohn Marino 		return;
1263ff40c12SJohn Marino 
1273ff40c12SJohn Marino 	edit_clear_line();
1283ff40c12SJohn Marino 	os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1,
1293ff40c12SJohn Marino 		   cmdbuf_len - cmdbuf_pos);
1303ff40c12SJohn Marino 	cmdbuf_len--;
1313ff40c12SJohn Marino 	edit_redraw();
1323ff40c12SJohn Marino }
1333ff40c12SJohn Marino 
1343ff40c12SJohn Marino 
delete_word(void)1353ff40c12SJohn Marino static void delete_word(void)
1363ff40c12SJohn Marino {
1373ff40c12SJohn Marino 	int pos;
1383ff40c12SJohn Marino 
1393ff40c12SJohn Marino 	edit_clear_line();
1403ff40c12SJohn Marino 	pos = cmdbuf_pos;
1413ff40c12SJohn Marino 	while (pos > 0 && cmdbuf[pos - 1] == ' ')
1423ff40c12SJohn Marino 		pos--;
1433ff40c12SJohn Marino 	while (pos > 0 && cmdbuf[pos - 1] != ' ')
1443ff40c12SJohn Marino 		pos--;
1453ff40c12SJohn Marino 	os_memmove(cmdbuf + pos, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
1463ff40c12SJohn Marino 	cmdbuf_len -= cmdbuf_pos - pos;
1473ff40c12SJohn Marino 	cmdbuf_pos = pos;
1483ff40c12SJohn Marino 	edit_redraw();
1493ff40c12SJohn Marino }
1503ff40c12SJohn Marino 
1513ff40c12SJohn Marino 
clear_left(void)1523ff40c12SJohn Marino static void clear_left(void)
1533ff40c12SJohn Marino {
1543ff40c12SJohn Marino 	if (cmdbuf_pos == 0)
1553ff40c12SJohn Marino 		return;
1563ff40c12SJohn Marino 
1573ff40c12SJohn Marino 	edit_clear_line();
1583ff40c12SJohn Marino 	os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
1593ff40c12SJohn Marino 	cmdbuf_len -= cmdbuf_pos;
1603ff40c12SJohn Marino 	cmdbuf_pos = 0;
1613ff40c12SJohn Marino 	edit_redraw();
1623ff40c12SJohn Marino }
1633ff40c12SJohn Marino 
1643ff40c12SJohn Marino 
clear_right(void)1653ff40c12SJohn Marino static void clear_right(void)
1663ff40c12SJohn Marino {
1673ff40c12SJohn Marino 	if (cmdbuf_pos == cmdbuf_len)
1683ff40c12SJohn Marino 		return;
1693ff40c12SJohn Marino 
1703ff40c12SJohn Marino 	edit_clear_line();
1713ff40c12SJohn Marino 	cmdbuf_len = cmdbuf_pos;
1723ff40c12SJohn Marino 	edit_redraw();
1733ff40c12SJohn Marino }
1743ff40c12SJohn Marino 
1753ff40c12SJohn Marino 
history_add(const char * str)1763ff40c12SJohn Marino static void history_add(const char *str)
1773ff40c12SJohn Marino {
1783ff40c12SJohn Marino 	struct edit_history *h, *match = NULL, *last = NULL;
1793ff40c12SJohn Marino 	size_t len, count = 0;
1803ff40c12SJohn Marino 
1813ff40c12SJohn Marino 	if (str[0] == '\0')
1823ff40c12SJohn Marino 		return;
1833ff40c12SJohn Marino 
1843ff40c12SJohn Marino 	dl_list_for_each(h, &history_list, struct edit_history, list) {
1853ff40c12SJohn Marino 		if (os_strcmp(str, h->str) == 0) {
1863ff40c12SJohn Marino 			match = h;
1873ff40c12SJohn Marino 			break;
1883ff40c12SJohn Marino 		}
1893ff40c12SJohn Marino 		last = h;
1903ff40c12SJohn Marino 		count++;
1913ff40c12SJohn Marino 	}
1923ff40c12SJohn Marino 
1933ff40c12SJohn Marino 	if (match) {
1943ff40c12SJohn Marino 		dl_list_del(&h->list);
1953ff40c12SJohn Marino 		dl_list_add(&history_list, &h->list);
1963ff40c12SJohn Marino 		history_curr = h;
1973ff40c12SJohn Marino 		return;
1983ff40c12SJohn Marino 	}
1993ff40c12SJohn Marino 
2003ff40c12SJohn Marino 	if (count >= HISTORY_MAX && last) {
2013ff40c12SJohn Marino 		dl_list_del(&last->list);
2023ff40c12SJohn Marino 		os_free(last);
2033ff40c12SJohn Marino 	}
2043ff40c12SJohn Marino 
2053ff40c12SJohn Marino 	len = os_strlen(str);
2063ff40c12SJohn Marino 	h = os_zalloc(sizeof(*h) + len);
2073ff40c12SJohn Marino 	if (h == NULL)
2083ff40c12SJohn Marino 		return;
2093ff40c12SJohn Marino 	dl_list_add(&history_list, &h->list);
2103ff40c12SJohn Marino 	os_strlcpy(h->str, str, len + 1);
2113ff40c12SJohn Marino 	history_curr = h;
2123ff40c12SJohn Marino }
2133ff40c12SJohn Marino 
2143ff40c12SJohn Marino 
history_use(void)2153ff40c12SJohn Marino static void history_use(void)
2163ff40c12SJohn Marino {
2173ff40c12SJohn Marino 	edit_clear_line();
2183ff40c12SJohn Marino 	cmdbuf_len = cmdbuf_pos = os_strlen(history_curr->str);
2193ff40c12SJohn Marino 	os_memcpy(cmdbuf, history_curr->str, cmdbuf_len);
2203ff40c12SJohn Marino 	edit_redraw();
2213ff40c12SJohn Marino }
2223ff40c12SJohn Marino 
2233ff40c12SJohn Marino 
history_prev(void)2243ff40c12SJohn Marino static void history_prev(void)
2253ff40c12SJohn Marino {
2263ff40c12SJohn Marino 	if (history_curr == NULL)
2273ff40c12SJohn Marino 		return;
2283ff40c12SJohn Marino 
2293ff40c12SJohn Marino 	if (history_curr ==
2303ff40c12SJohn Marino 	    dl_list_first(&history_list, struct edit_history, list)) {
2313ff40c12SJohn Marino 		if (!currbuf_valid) {
2323ff40c12SJohn Marino 			cmdbuf[cmdbuf_len] = '\0';
2333ff40c12SJohn Marino 			os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1);
2343ff40c12SJohn Marino 			currbuf_valid = 1;
2353ff40c12SJohn Marino 			history_use();
2363ff40c12SJohn Marino 			return;
2373ff40c12SJohn Marino 		}
2383ff40c12SJohn Marino 	}
2393ff40c12SJohn Marino 
2403ff40c12SJohn Marino 	if (history_curr ==
2413ff40c12SJohn Marino 	    dl_list_last(&history_list, struct edit_history, list))
2423ff40c12SJohn Marino 		return;
2433ff40c12SJohn Marino 
2443ff40c12SJohn Marino 	history_curr = dl_list_entry(history_curr->list.next,
2453ff40c12SJohn Marino 				     struct edit_history, list);
2463ff40c12SJohn Marino 	history_use();
2473ff40c12SJohn Marino }
2483ff40c12SJohn Marino 
2493ff40c12SJohn Marino 
history_next(void)2503ff40c12SJohn Marino static void history_next(void)
2513ff40c12SJohn Marino {
2523ff40c12SJohn Marino 	if (history_curr == NULL ||
2533ff40c12SJohn Marino 	    history_curr ==
2543ff40c12SJohn Marino 	    dl_list_first(&history_list, struct edit_history, list)) {
2553ff40c12SJohn Marino 		if (currbuf_valid) {
2563ff40c12SJohn Marino 			currbuf_valid = 0;
2573ff40c12SJohn Marino 			edit_clear_line();
2583ff40c12SJohn Marino 			cmdbuf_len = cmdbuf_pos = os_strlen(currbuf);
2593ff40c12SJohn Marino 			os_memcpy(cmdbuf, currbuf, cmdbuf_len);
2603ff40c12SJohn Marino 			edit_redraw();
2613ff40c12SJohn Marino 		}
2623ff40c12SJohn Marino 		return;
2633ff40c12SJohn Marino 	}
2643ff40c12SJohn Marino 
2653ff40c12SJohn Marino 	history_curr = dl_list_entry(history_curr->list.prev,
2663ff40c12SJohn Marino 				     struct edit_history, list);
2673ff40c12SJohn Marino 	history_use();
2683ff40c12SJohn Marino }
2693ff40c12SJohn Marino 
2703ff40c12SJohn Marino 
history_read(const char * fname)2713ff40c12SJohn Marino static void history_read(const char *fname)
2723ff40c12SJohn Marino {
2733ff40c12SJohn Marino 	FILE *f;
2743ff40c12SJohn Marino 	char buf[CMD_BUF_LEN], *pos;
2753ff40c12SJohn Marino 
2763ff40c12SJohn Marino 	f = fopen(fname, "r");
2773ff40c12SJohn Marino 	if (f == NULL)
2783ff40c12SJohn Marino 		return;
2793ff40c12SJohn Marino 
2803ff40c12SJohn Marino 	while (fgets(buf, CMD_BUF_LEN, f)) {
2813ff40c12SJohn Marino 		for (pos = buf; *pos; pos++) {
2823ff40c12SJohn Marino 			if (*pos == '\r' || *pos == '\n') {
2833ff40c12SJohn Marino 				*pos = '\0';
2843ff40c12SJohn Marino 				break;
2853ff40c12SJohn Marino 			}
2863ff40c12SJohn Marino 		}
2873ff40c12SJohn Marino 		history_add(buf);
2883ff40c12SJohn Marino 	}
2893ff40c12SJohn Marino 
2903ff40c12SJohn Marino 	fclose(f);
2913ff40c12SJohn Marino }
2923ff40c12SJohn Marino 
2933ff40c12SJohn Marino 
history_write(const char * fname,int (* filter_cb)(void * ctx,const char * cmd))2943ff40c12SJohn Marino static void history_write(const char *fname,
2953ff40c12SJohn Marino 			  int (*filter_cb)(void *ctx, const char *cmd))
2963ff40c12SJohn Marino {
2973ff40c12SJohn Marino 	FILE *f;
2983ff40c12SJohn Marino 	struct edit_history *h;
2993ff40c12SJohn Marino 
3003ff40c12SJohn Marino 	f = fopen(fname, "w");
3013ff40c12SJohn Marino 	if (f == NULL)
3023ff40c12SJohn Marino 		return;
3033ff40c12SJohn Marino 
3043ff40c12SJohn Marino 	dl_list_for_each_reverse(h, &history_list, struct edit_history, list) {
3053ff40c12SJohn Marino 		if (filter_cb && filter_cb(edit_cb_ctx, h->str))
3063ff40c12SJohn Marino 			continue;
3073ff40c12SJohn Marino 		fprintf(f, "%s\n", h->str);
3083ff40c12SJohn Marino 	}
3093ff40c12SJohn Marino 
3103ff40c12SJohn Marino 	fclose(f);
3113ff40c12SJohn Marino }
3123ff40c12SJohn Marino 
3133ff40c12SJohn Marino 
history_debug_dump(void)3143ff40c12SJohn Marino static void history_debug_dump(void)
3153ff40c12SJohn Marino {
3163ff40c12SJohn Marino 	struct edit_history *h;
3173ff40c12SJohn Marino 	edit_clear_line();
3183ff40c12SJohn Marino 	printf("\r");
3193ff40c12SJohn Marino 	dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
3203ff40c12SJohn Marino 		printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
3213ff40c12SJohn Marino 	if (currbuf_valid)
3223ff40c12SJohn Marino 		printf("{%s}\n", currbuf);
3233ff40c12SJohn Marino 	edit_redraw();
3243ff40c12SJohn Marino }
3253ff40c12SJohn Marino 
3263ff40c12SJohn Marino 
insert_char(int c)3273ff40c12SJohn Marino static void insert_char(int c)
3283ff40c12SJohn Marino {
3293ff40c12SJohn Marino 	if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1)
3303ff40c12SJohn Marino 		return;
3313ff40c12SJohn Marino 	if (cmdbuf_len == cmdbuf_pos) {
3323ff40c12SJohn Marino 		cmdbuf[cmdbuf_pos++] = c;
3333ff40c12SJohn Marino 		cmdbuf_len++;
3343ff40c12SJohn Marino 		putchar(c);
3353ff40c12SJohn Marino 		fflush(stdout);
3363ff40c12SJohn Marino 	} else {
3373ff40c12SJohn Marino 		os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos,
3383ff40c12SJohn Marino 			   cmdbuf_len - cmdbuf_pos);
3393ff40c12SJohn Marino 		cmdbuf[cmdbuf_pos++] = c;
3403ff40c12SJohn Marino 		cmdbuf_len++;
3413ff40c12SJohn Marino 		edit_redraw();
3423ff40c12SJohn Marino 	}
3433ff40c12SJohn Marino }
3443ff40c12SJohn Marino 
3453ff40c12SJohn Marino 
process_cmd(void)3463ff40c12SJohn Marino static void process_cmd(void)
3473ff40c12SJohn Marino {
3483ff40c12SJohn Marino 	currbuf_valid = 0;
3493ff40c12SJohn Marino 	if (cmdbuf_len == 0) {
3503ff40c12SJohn Marino 		printf("\n%s> ", ps2 ? ps2 : "");
3513ff40c12SJohn Marino 		fflush(stdout);
3523ff40c12SJohn Marino 		return;
3533ff40c12SJohn Marino 	}
3543ff40c12SJohn Marino 	printf("\n");
3553ff40c12SJohn Marino 	cmdbuf[cmdbuf_len] = '\0';
3563ff40c12SJohn Marino 	history_add(cmdbuf);
3573ff40c12SJohn Marino 	cmdbuf_pos = 0;
3583ff40c12SJohn Marino 	cmdbuf_len = 0;
3593ff40c12SJohn Marino 	edit_cmd_cb(edit_cb_ctx, cmdbuf);
3603ff40c12SJohn Marino 	printf("%s> ", ps2 ? ps2 : "");
3613ff40c12SJohn Marino 	fflush(stdout);
3623ff40c12SJohn Marino }
3633ff40c12SJohn Marino 
3643ff40c12SJohn Marino 
free_completions(char ** c)3653ff40c12SJohn Marino static void free_completions(char **c)
3663ff40c12SJohn Marino {
3673ff40c12SJohn Marino 	int i;
3683ff40c12SJohn Marino 	if (c == NULL)
3693ff40c12SJohn Marino 		return;
3703ff40c12SJohn Marino 	for (i = 0; c[i]; i++)
3713ff40c12SJohn Marino 		os_free(c[i]);
3723ff40c12SJohn Marino 	os_free(c);
3733ff40c12SJohn Marino }
3743ff40c12SJohn Marino 
3753ff40c12SJohn Marino 
filter_strings(char ** c,char * str,size_t len)3763ff40c12SJohn Marino static int filter_strings(char **c, char *str, size_t len)
3773ff40c12SJohn Marino {
3783ff40c12SJohn Marino 	int i, j;
3793ff40c12SJohn Marino 
3803ff40c12SJohn Marino 	for (i = 0, j = 0; c[j]; j++) {
3813ff40c12SJohn Marino 		if (os_strncasecmp(c[j], str, len) == 0) {
3823ff40c12SJohn Marino 			if (i != j) {
3833ff40c12SJohn Marino 				c[i] = c[j];
3843ff40c12SJohn Marino 				c[j] = NULL;
3853ff40c12SJohn Marino 			}
3863ff40c12SJohn Marino 			i++;
3873ff40c12SJohn Marino 		} else {
3883ff40c12SJohn Marino 			os_free(c[j]);
3893ff40c12SJohn Marino 			c[j] = NULL;
3903ff40c12SJohn Marino 		}
3913ff40c12SJohn Marino 	}
3923ff40c12SJohn Marino 	c[i] = NULL;
3933ff40c12SJohn Marino 	return i;
3943ff40c12SJohn Marino }
3953ff40c12SJohn Marino 
3963ff40c12SJohn Marino 
common_len(const char * a,const char * b)3973ff40c12SJohn Marino static int common_len(const char *a, const char *b)
3983ff40c12SJohn Marino {
3993ff40c12SJohn Marino 	int len = 0;
4003ff40c12SJohn Marino 	while (a[len] && a[len] == b[len])
4013ff40c12SJohn Marino 		len++;
4023ff40c12SJohn Marino 	return len;
4033ff40c12SJohn Marino }
4043ff40c12SJohn Marino 
4053ff40c12SJohn Marino 
max_common_length(char ** c)4063ff40c12SJohn Marino static int max_common_length(char **c)
4073ff40c12SJohn Marino {
4083ff40c12SJohn Marino 	int len, i;
4093ff40c12SJohn Marino 
4103ff40c12SJohn Marino 	len = os_strlen(c[0]);
4113ff40c12SJohn Marino 	for (i = 1; c[i]; i++) {
4123ff40c12SJohn Marino 		int same = common_len(c[0], c[i]);
4133ff40c12SJohn Marino 		if (same < len)
4143ff40c12SJohn Marino 			len = same;
4153ff40c12SJohn Marino 	}
4163ff40c12SJohn Marino 
4173ff40c12SJohn Marino 	return len;
4183ff40c12SJohn Marino }
4193ff40c12SJohn Marino 
4203ff40c12SJohn Marino 
cmp_str(const void * a,const void * b)4213ff40c12SJohn Marino static int cmp_str(const void *a, const void *b)
4223ff40c12SJohn Marino {
4233ff40c12SJohn Marino 	return os_strcmp(* (const char **) a, * (const char **) b);
4243ff40c12SJohn Marino }
4253ff40c12SJohn Marino 
complete(int list)4263ff40c12SJohn Marino static void complete(int list)
4273ff40c12SJohn Marino {
4283ff40c12SJohn Marino 	char **c;
4293ff40c12SJohn Marino 	int i, len, count;
4303ff40c12SJohn Marino 	int start, end;
4313ff40c12SJohn Marino 	int room, plen, add_space;
4323ff40c12SJohn Marino 
4333ff40c12SJohn Marino 	if (edit_completion_cb == NULL)
4343ff40c12SJohn Marino 		return;
4353ff40c12SJohn Marino 
4363ff40c12SJohn Marino 	cmdbuf[cmdbuf_len] = '\0';
4373ff40c12SJohn Marino 	c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos);
4383ff40c12SJohn Marino 	if (c == NULL)
4393ff40c12SJohn Marino 		return;
4403ff40c12SJohn Marino 
4413ff40c12SJohn Marino 	end = cmdbuf_pos;
4423ff40c12SJohn Marino 	start = end;
4433ff40c12SJohn Marino 	while (start > 0 && cmdbuf[start - 1] != ' ')
4443ff40c12SJohn Marino 		start--;
4453ff40c12SJohn Marino 	plen = end - start;
4463ff40c12SJohn Marino 
4473ff40c12SJohn Marino 	count = filter_strings(c, &cmdbuf[start], plen);
4483ff40c12SJohn Marino 	if (count == 0) {
4493ff40c12SJohn Marino 		free_completions(c);
4503ff40c12SJohn Marino 		return;
4513ff40c12SJohn Marino 	}
4523ff40c12SJohn Marino 
4533ff40c12SJohn Marino 	len = max_common_length(c);
4543ff40c12SJohn Marino 	if (len <= plen && count > 1) {
4553ff40c12SJohn Marino 		if (list) {
4563ff40c12SJohn Marino 			qsort(c, count, sizeof(char *), cmp_str);
4573ff40c12SJohn Marino 			edit_clear_line();
4583ff40c12SJohn Marino 			printf("\r");
4593ff40c12SJohn Marino 			for (i = 0; c[i]; i++)
4603ff40c12SJohn Marino 				printf("%s%s", i > 0 ? " " : "", c[i]);
4613ff40c12SJohn Marino 			printf("\n");
4623ff40c12SJohn Marino 			edit_redraw();
4633ff40c12SJohn Marino 		}
4643ff40c12SJohn Marino 		free_completions(c);
4653ff40c12SJohn Marino 		return;
4663ff40c12SJohn Marino 	}
4673ff40c12SJohn Marino 	len -= plen;
4683ff40c12SJohn Marino 
4693ff40c12SJohn Marino 	room = sizeof(cmdbuf) - 1 - cmdbuf_len;
4703ff40c12SJohn Marino 	if (room < len)
4713ff40c12SJohn Marino 		len = room;
4723ff40c12SJohn Marino 	add_space = count == 1 && len < room;
4733ff40c12SJohn Marino 
4743ff40c12SJohn Marino 	os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos,
4753ff40c12SJohn Marino 		   cmdbuf_len - cmdbuf_pos);
4763ff40c12SJohn Marino 	os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len);
4773ff40c12SJohn Marino 	if (add_space)
4783ff40c12SJohn Marino 		cmdbuf[cmdbuf_pos + len] = ' ';
4793ff40c12SJohn Marino 
4803ff40c12SJohn Marino 	cmdbuf_pos += len + add_space;
4813ff40c12SJohn Marino 	cmdbuf_len += len + add_space;
4823ff40c12SJohn Marino 
4833ff40c12SJohn Marino 	edit_redraw();
4843ff40c12SJohn Marino 
4853ff40c12SJohn Marino 	free_completions(c);
4863ff40c12SJohn Marino }
4873ff40c12SJohn Marino 
4883ff40c12SJohn Marino 
4893ff40c12SJohn Marino enum edit_key_code {
4903ff40c12SJohn Marino 	EDIT_KEY_NONE = 256,
4913ff40c12SJohn Marino 	EDIT_KEY_TAB,
4923ff40c12SJohn Marino 	EDIT_KEY_UP,
4933ff40c12SJohn Marino 	EDIT_KEY_DOWN,
4943ff40c12SJohn Marino 	EDIT_KEY_RIGHT,
4953ff40c12SJohn Marino 	EDIT_KEY_LEFT,
4963ff40c12SJohn Marino 	EDIT_KEY_ENTER,
4973ff40c12SJohn Marino 	EDIT_KEY_BACKSPACE,
4983ff40c12SJohn Marino 	EDIT_KEY_INSERT,
4993ff40c12SJohn Marino 	EDIT_KEY_DELETE,
5003ff40c12SJohn Marino 	EDIT_KEY_HOME,
5013ff40c12SJohn Marino 	EDIT_KEY_END,
5023ff40c12SJohn Marino 	EDIT_KEY_PAGE_UP,
5033ff40c12SJohn Marino 	EDIT_KEY_PAGE_DOWN,
5043ff40c12SJohn Marino 	EDIT_KEY_F1,
5053ff40c12SJohn Marino 	EDIT_KEY_F2,
5063ff40c12SJohn Marino 	EDIT_KEY_F3,
5073ff40c12SJohn Marino 	EDIT_KEY_F4,
5083ff40c12SJohn Marino 	EDIT_KEY_F5,
5093ff40c12SJohn Marino 	EDIT_KEY_F6,
5103ff40c12SJohn Marino 	EDIT_KEY_F7,
5113ff40c12SJohn Marino 	EDIT_KEY_F8,
5123ff40c12SJohn Marino 	EDIT_KEY_F9,
5133ff40c12SJohn Marino 	EDIT_KEY_F10,
5143ff40c12SJohn Marino 	EDIT_KEY_F11,
5153ff40c12SJohn Marino 	EDIT_KEY_F12,
5163ff40c12SJohn Marino 	EDIT_KEY_CTRL_UP,
5173ff40c12SJohn Marino 	EDIT_KEY_CTRL_DOWN,
5183ff40c12SJohn Marino 	EDIT_KEY_CTRL_RIGHT,
5193ff40c12SJohn Marino 	EDIT_KEY_CTRL_LEFT,
5203ff40c12SJohn Marino 	EDIT_KEY_CTRL_A,
5213ff40c12SJohn Marino 	EDIT_KEY_CTRL_B,
5223ff40c12SJohn Marino 	EDIT_KEY_CTRL_D,
5233ff40c12SJohn Marino 	EDIT_KEY_CTRL_E,
5243ff40c12SJohn Marino 	EDIT_KEY_CTRL_F,
5253ff40c12SJohn Marino 	EDIT_KEY_CTRL_G,
5263ff40c12SJohn Marino 	EDIT_KEY_CTRL_H,
5273ff40c12SJohn Marino 	EDIT_KEY_CTRL_J,
5283ff40c12SJohn Marino 	EDIT_KEY_CTRL_K,
5293ff40c12SJohn Marino 	EDIT_KEY_CTRL_L,
5303ff40c12SJohn Marino 	EDIT_KEY_CTRL_N,
5313ff40c12SJohn Marino 	EDIT_KEY_CTRL_O,
5323ff40c12SJohn Marino 	EDIT_KEY_CTRL_P,
5333ff40c12SJohn Marino 	EDIT_KEY_CTRL_R,
5343ff40c12SJohn Marino 	EDIT_KEY_CTRL_T,
5353ff40c12SJohn Marino 	EDIT_KEY_CTRL_U,
5363ff40c12SJohn Marino 	EDIT_KEY_CTRL_V,
5373ff40c12SJohn Marino 	EDIT_KEY_CTRL_W,
5383ff40c12SJohn Marino 	EDIT_KEY_ALT_UP,
5393ff40c12SJohn Marino 	EDIT_KEY_ALT_DOWN,
5403ff40c12SJohn Marino 	EDIT_KEY_ALT_RIGHT,
5413ff40c12SJohn Marino 	EDIT_KEY_ALT_LEFT,
5423ff40c12SJohn Marino 	EDIT_KEY_SHIFT_UP,
5433ff40c12SJohn Marino 	EDIT_KEY_SHIFT_DOWN,
5443ff40c12SJohn Marino 	EDIT_KEY_SHIFT_RIGHT,
5453ff40c12SJohn Marino 	EDIT_KEY_SHIFT_LEFT,
5463ff40c12SJohn Marino 	EDIT_KEY_ALT_SHIFT_UP,
5473ff40c12SJohn Marino 	EDIT_KEY_ALT_SHIFT_DOWN,
5483ff40c12SJohn Marino 	EDIT_KEY_ALT_SHIFT_RIGHT,
5493ff40c12SJohn Marino 	EDIT_KEY_ALT_SHIFT_LEFT,
5503ff40c12SJohn Marino 	EDIT_KEY_EOF
5513ff40c12SJohn Marino };
5523ff40c12SJohn Marino 
show_esc_buf(const char * esc_buf,char c,int i)5533ff40c12SJohn Marino static void show_esc_buf(const char *esc_buf, char c, int i)
5543ff40c12SJohn Marino {
5553ff40c12SJohn Marino 	edit_clear_line();
5563ff40c12SJohn Marino 	printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i);
5573ff40c12SJohn Marino 	edit_redraw();
5583ff40c12SJohn Marino }
5593ff40c12SJohn Marino 
5603ff40c12SJohn Marino 
esc_seq_to_key1_no(char last)5613ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key1_no(char last)
5623ff40c12SJohn Marino {
5633ff40c12SJohn Marino 	switch (last) {
5643ff40c12SJohn Marino 	case 'A':
5653ff40c12SJohn Marino 		return EDIT_KEY_UP;
5663ff40c12SJohn Marino 	case 'B':
5673ff40c12SJohn Marino 		return EDIT_KEY_DOWN;
5683ff40c12SJohn Marino 	case 'C':
5693ff40c12SJohn Marino 		return EDIT_KEY_RIGHT;
5703ff40c12SJohn Marino 	case 'D':
5713ff40c12SJohn Marino 		return EDIT_KEY_LEFT;
5723ff40c12SJohn Marino 	default:
5733ff40c12SJohn Marino 		return EDIT_KEY_NONE;
5743ff40c12SJohn Marino 	}
5753ff40c12SJohn Marino }
5763ff40c12SJohn Marino 
5773ff40c12SJohn Marino 
esc_seq_to_key1_shift(char last)5783ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key1_shift(char last)
5793ff40c12SJohn Marino {
5803ff40c12SJohn Marino 	switch (last) {
5813ff40c12SJohn Marino 	case 'A':
5823ff40c12SJohn Marino 		return EDIT_KEY_SHIFT_UP;
5833ff40c12SJohn Marino 	case 'B':
5843ff40c12SJohn Marino 		return EDIT_KEY_SHIFT_DOWN;
5853ff40c12SJohn Marino 	case 'C':
5863ff40c12SJohn Marino 		return EDIT_KEY_SHIFT_RIGHT;
5873ff40c12SJohn Marino 	case 'D':
5883ff40c12SJohn Marino 		return EDIT_KEY_SHIFT_LEFT;
5893ff40c12SJohn Marino 	default:
5903ff40c12SJohn Marino 		return EDIT_KEY_NONE;
5913ff40c12SJohn Marino 	}
5923ff40c12SJohn Marino }
5933ff40c12SJohn Marino 
5943ff40c12SJohn Marino 
esc_seq_to_key1_alt(char last)5953ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key1_alt(char last)
5963ff40c12SJohn Marino {
5973ff40c12SJohn Marino 	switch (last) {
5983ff40c12SJohn Marino 	case 'A':
5993ff40c12SJohn Marino 		return EDIT_KEY_ALT_UP;
6003ff40c12SJohn Marino 	case 'B':
6013ff40c12SJohn Marino 		return EDIT_KEY_ALT_DOWN;
6023ff40c12SJohn Marino 	case 'C':
6033ff40c12SJohn Marino 		return EDIT_KEY_ALT_RIGHT;
6043ff40c12SJohn Marino 	case 'D':
6053ff40c12SJohn Marino 		return EDIT_KEY_ALT_LEFT;
6063ff40c12SJohn Marino 	default:
6073ff40c12SJohn Marino 		return EDIT_KEY_NONE;
6083ff40c12SJohn Marino 	}
6093ff40c12SJohn Marino }
6103ff40c12SJohn Marino 
6113ff40c12SJohn Marino 
esc_seq_to_key1_alt_shift(char last)6123ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key1_alt_shift(char last)
6133ff40c12SJohn Marino {
6143ff40c12SJohn Marino 	switch (last) {
6153ff40c12SJohn Marino 	case 'A':
6163ff40c12SJohn Marino 		return EDIT_KEY_ALT_SHIFT_UP;
6173ff40c12SJohn Marino 	case 'B':
6183ff40c12SJohn Marino 		return EDIT_KEY_ALT_SHIFT_DOWN;
6193ff40c12SJohn Marino 	case 'C':
6203ff40c12SJohn Marino 		return EDIT_KEY_ALT_SHIFT_RIGHT;
6213ff40c12SJohn Marino 	case 'D':
6223ff40c12SJohn Marino 		return EDIT_KEY_ALT_SHIFT_LEFT;
6233ff40c12SJohn Marino 	default:
6243ff40c12SJohn Marino 		return EDIT_KEY_NONE;
6253ff40c12SJohn Marino 	}
6263ff40c12SJohn Marino }
6273ff40c12SJohn Marino 
6283ff40c12SJohn Marino 
esc_seq_to_key1_ctrl(char last)6293ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key1_ctrl(char last)
6303ff40c12SJohn Marino {
6313ff40c12SJohn Marino 	switch (last) {
6323ff40c12SJohn Marino 	case 'A':
6333ff40c12SJohn Marino 		return EDIT_KEY_CTRL_UP;
6343ff40c12SJohn Marino 	case 'B':
6353ff40c12SJohn Marino 		return EDIT_KEY_CTRL_DOWN;
6363ff40c12SJohn Marino 	case 'C':
6373ff40c12SJohn Marino 		return EDIT_KEY_CTRL_RIGHT;
6383ff40c12SJohn Marino 	case 'D':
6393ff40c12SJohn Marino 		return EDIT_KEY_CTRL_LEFT;
6403ff40c12SJohn Marino 	default:
6413ff40c12SJohn Marino 		return EDIT_KEY_NONE;
6423ff40c12SJohn Marino 	}
6433ff40c12SJohn Marino }
6443ff40c12SJohn Marino 
6453ff40c12SJohn Marino 
esc_seq_to_key1(int param1,int param2,char last)6463ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last)
6473ff40c12SJohn Marino {
6483ff40c12SJohn Marino 	/* ESC-[<param1>;<param2><last> */
6493ff40c12SJohn Marino 
6503ff40c12SJohn Marino 	if (param1 < 0 && param2 < 0)
6513ff40c12SJohn Marino 		return esc_seq_to_key1_no(last);
6523ff40c12SJohn Marino 
6533ff40c12SJohn Marino 	if (param1 == 1 && param2 == 2)
6543ff40c12SJohn Marino 		return esc_seq_to_key1_shift(last);
6553ff40c12SJohn Marino 
6563ff40c12SJohn Marino 	if (param1 == 1 && param2 == 3)
6573ff40c12SJohn Marino 		return esc_seq_to_key1_alt(last);
6583ff40c12SJohn Marino 
6593ff40c12SJohn Marino 	if (param1 == 1 && param2 == 4)
6603ff40c12SJohn Marino 		return esc_seq_to_key1_alt_shift(last);
6613ff40c12SJohn Marino 
6623ff40c12SJohn Marino 	if (param1 == 1 && param2 == 5)
6633ff40c12SJohn Marino 		return esc_seq_to_key1_ctrl(last);
6643ff40c12SJohn Marino 
6653ff40c12SJohn Marino 	if (param2 < 0) {
6663ff40c12SJohn Marino 		if (last != '~')
6673ff40c12SJohn Marino 			return EDIT_KEY_NONE;
6683ff40c12SJohn Marino 		switch (param1) {
6693ff40c12SJohn Marino 		case 2:
6703ff40c12SJohn Marino 			return EDIT_KEY_INSERT;
6713ff40c12SJohn Marino 		case 3:
6723ff40c12SJohn Marino 			return EDIT_KEY_DELETE;
6733ff40c12SJohn Marino 		case 5:
6743ff40c12SJohn Marino 			return EDIT_KEY_PAGE_UP;
6753ff40c12SJohn Marino 		case 6:
6763ff40c12SJohn Marino 			return EDIT_KEY_PAGE_DOWN;
6773ff40c12SJohn Marino 		case 15:
6783ff40c12SJohn Marino 			return EDIT_KEY_F5;
6793ff40c12SJohn Marino 		case 17:
6803ff40c12SJohn Marino 			return EDIT_KEY_F6;
6813ff40c12SJohn Marino 		case 18:
6823ff40c12SJohn Marino 			return EDIT_KEY_F7;
6833ff40c12SJohn Marino 		case 19:
6843ff40c12SJohn Marino 			return EDIT_KEY_F8;
6853ff40c12SJohn Marino 		case 20:
6863ff40c12SJohn Marino 			return EDIT_KEY_F9;
6873ff40c12SJohn Marino 		case 21:
6883ff40c12SJohn Marino 			return EDIT_KEY_F10;
6893ff40c12SJohn Marino 		case 23:
6903ff40c12SJohn Marino 			return EDIT_KEY_F11;
6913ff40c12SJohn Marino 		case 24:
6923ff40c12SJohn Marino 			return EDIT_KEY_F12;
6933ff40c12SJohn Marino 		}
6943ff40c12SJohn Marino 	}
6953ff40c12SJohn Marino 
6963ff40c12SJohn Marino 	return EDIT_KEY_NONE;
6973ff40c12SJohn Marino }
6983ff40c12SJohn Marino 
6993ff40c12SJohn Marino 
esc_seq_to_key2(int param1,int param2,char last)7003ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last)
7013ff40c12SJohn Marino {
7023ff40c12SJohn Marino 	/* ESC-O<param1>;<param2><last> */
7033ff40c12SJohn Marino 
7043ff40c12SJohn Marino 	if (param1 >= 0 || param2 >= 0)
7053ff40c12SJohn Marino 		return EDIT_KEY_NONE;
7063ff40c12SJohn Marino 
7073ff40c12SJohn Marino 	switch (last) {
7083ff40c12SJohn Marino 	case 'F':
7093ff40c12SJohn Marino 		return EDIT_KEY_END;
7103ff40c12SJohn Marino 	case 'H':
7113ff40c12SJohn Marino 		return EDIT_KEY_HOME;
7123ff40c12SJohn Marino 	case 'P':
7133ff40c12SJohn Marino 		return EDIT_KEY_F1;
7143ff40c12SJohn Marino 	case 'Q':
7153ff40c12SJohn Marino 		return EDIT_KEY_F2;
7163ff40c12SJohn Marino 	case 'R':
7173ff40c12SJohn Marino 		return EDIT_KEY_F3;
7183ff40c12SJohn Marino 	case 'S':
7193ff40c12SJohn Marino 		return EDIT_KEY_F4;
7203ff40c12SJohn Marino 	default:
7213ff40c12SJohn Marino 		return EDIT_KEY_NONE;
7223ff40c12SJohn Marino 	}
7233ff40c12SJohn Marino }
7243ff40c12SJohn Marino 
7253ff40c12SJohn Marino 
esc_seq_to_key(char * seq)7263ff40c12SJohn Marino static enum edit_key_code esc_seq_to_key(char *seq)
7273ff40c12SJohn Marino {
7283ff40c12SJohn Marino 	char last, *pos;
7293ff40c12SJohn Marino 	int param1 = -1, param2 = -1;
7303ff40c12SJohn Marino 	enum edit_key_code ret = EDIT_KEY_NONE;
7313ff40c12SJohn Marino 
7323ff40c12SJohn Marino 	last = '\0';
7333ff40c12SJohn Marino 	for (pos = seq; *pos; pos++)
7343ff40c12SJohn Marino 		last = *pos;
7353ff40c12SJohn Marino 
7363ff40c12SJohn Marino 	if (seq[1] >= '0' && seq[1] <= '9') {
7373ff40c12SJohn Marino 		param1 = atoi(&seq[1]);
7383ff40c12SJohn Marino 		pos = os_strchr(seq, ';');
7393ff40c12SJohn Marino 		if (pos)
7403ff40c12SJohn Marino 			param2 = atoi(pos + 1);
7413ff40c12SJohn Marino 	}
7423ff40c12SJohn Marino 
7433ff40c12SJohn Marino 	if (seq[0] == '[')
7443ff40c12SJohn Marino 		ret = esc_seq_to_key1(param1, param2, last);
7453ff40c12SJohn Marino 	else if (seq[0] == 'O')
7463ff40c12SJohn Marino 		ret = esc_seq_to_key2(param1, param2, last);
7473ff40c12SJohn Marino 
7483ff40c12SJohn Marino 	if (ret != EDIT_KEY_NONE)
7493ff40c12SJohn Marino 		return ret;
7503ff40c12SJohn Marino 
7513ff40c12SJohn Marino 	edit_clear_line();
7523ff40c12SJohn Marino 	printf("\rUnknown escape sequence '%s'\n", seq);
7533ff40c12SJohn Marino 	edit_redraw();
7543ff40c12SJohn Marino 	return EDIT_KEY_NONE;
7553ff40c12SJohn Marino }
7563ff40c12SJohn Marino 
7573ff40c12SJohn Marino 
edit_read_key(int sock)7583ff40c12SJohn Marino static enum edit_key_code edit_read_key(int sock)
7593ff40c12SJohn Marino {
7603ff40c12SJohn Marino 	int c;
7613ff40c12SJohn Marino 	unsigned char buf[1];
7623ff40c12SJohn Marino 	int res;
7633ff40c12SJohn Marino 	static int esc = -1;
7643ff40c12SJohn Marino 	static char esc_buf[7];
7653ff40c12SJohn Marino 
7663ff40c12SJohn Marino 	res = read(sock, buf, 1);
7673ff40c12SJohn Marino 	if (res < 0)
7683ff40c12SJohn Marino 		perror("read");
7693ff40c12SJohn Marino 	if (res <= 0)
7703ff40c12SJohn Marino 		return EDIT_KEY_EOF;
7713ff40c12SJohn Marino 
7723ff40c12SJohn Marino 	c = buf[0];
7733ff40c12SJohn Marino 
7743ff40c12SJohn Marino 	if (esc >= 0) {
7753ff40c12SJohn Marino 		if (c == 27 /* ESC */) {
7763ff40c12SJohn Marino 			esc = 0;
7773ff40c12SJohn Marino 			return EDIT_KEY_NONE;
7783ff40c12SJohn Marino 		}
7793ff40c12SJohn Marino 
7803ff40c12SJohn Marino 		if (esc == 6) {
7813ff40c12SJohn Marino 			show_esc_buf(esc_buf, c, 0);
7823ff40c12SJohn Marino 			esc = -1;
7833ff40c12SJohn Marino 		} else {
7843ff40c12SJohn Marino 			esc_buf[esc++] = c;
7853ff40c12SJohn Marino 			esc_buf[esc] = '\0';
7863ff40c12SJohn Marino 		}
7873ff40c12SJohn Marino 	}
7883ff40c12SJohn Marino 
7893ff40c12SJohn Marino 	if (esc == 1) {
7903ff40c12SJohn Marino 		if (esc_buf[0] != '[' && esc_buf[0] != 'O') {
7913ff40c12SJohn Marino 			show_esc_buf(esc_buf, c, 1);
7923ff40c12SJohn Marino 			esc = -1;
7933ff40c12SJohn Marino 			return EDIT_KEY_NONE;
7943ff40c12SJohn Marino 		} else
7953ff40c12SJohn Marino 			return EDIT_KEY_NONE; /* Escape sequence continues */
7963ff40c12SJohn Marino 	}
7973ff40c12SJohn Marino 
7983ff40c12SJohn Marino 	if (esc > 1) {
7993ff40c12SJohn Marino 		if ((c >= '0' && c <= '9') || c == ';')
8003ff40c12SJohn Marino 			return EDIT_KEY_NONE; /* Escape sequence continues */
8013ff40c12SJohn Marino 
8023ff40c12SJohn Marino 		if (c == '~' || (c >= 'A' && c <= 'Z')) {
8033ff40c12SJohn Marino 			esc = -1;
8043ff40c12SJohn Marino 			return esc_seq_to_key(esc_buf);
8053ff40c12SJohn Marino 		}
8063ff40c12SJohn Marino 
8073ff40c12SJohn Marino 		show_esc_buf(esc_buf, c, 2);
8083ff40c12SJohn Marino 		esc = -1;
8093ff40c12SJohn Marino 		return EDIT_KEY_NONE;
8103ff40c12SJohn Marino 	}
8113ff40c12SJohn Marino 
8123ff40c12SJohn Marino 	switch (c) {
8133ff40c12SJohn Marino 	case 1:
8143ff40c12SJohn Marino 		return EDIT_KEY_CTRL_A;
8153ff40c12SJohn Marino 	case 2:
8163ff40c12SJohn Marino 		return EDIT_KEY_CTRL_B;
8173ff40c12SJohn Marino 	case 4:
8183ff40c12SJohn Marino 		return EDIT_KEY_CTRL_D;
8193ff40c12SJohn Marino 	case 5:
8203ff40c12SJohn Marino 		return EDIT_KEY_CTRL_E;
8213ff40c12SJohn Marino 	case 6:
8223ff40c12SJohn Marino 		return EDIT_KEY_CTRL_F;
8233ff40c12SJohn Marino 	case 7:
8243ff40c12SJohn Marino 		return EDIT_KEY_CTRL_G;
8253ff40c12SJohn Marino 	case 8:
8263ff40c12SJohn Marino 		return EDIT_KEY_CTRL_H;
8273ff40c12SJohn Marino 	case 9:
8283ff40c12SJohn Marino 		return EDIT_KEY_TAB;
8293ff40c12SJohn Marino 	case 10:
8303ff40c12SJohn Marino 		return EDIT_KEY_CTRL_J;
8313ff40c12SJohn Marino 	case 13: /* CR */
8323ff40c12SJohn Marino 		return EDIT_KEY_ENTER;
8333ff40c12SJohn Marino 	case 11:
8343ff40c12SJohn Marino 		return EDIT_KEY_CTRL_K;
8353ff40c12SJohn Marino 	case 12:
8363ff40c12SJohn Marino 		return EDIT_KEY_CTRL_L;
8373ff40c12SJohn Marino 	case 14:
8383ff40c12SJohn Marino 		return EDIT_KEY_CTRL_N;
8393ff40c12SJohn Marino 	case 15:
8403ff40c12SJohn Marino 		return EDIT_KEY_CTRL_O;
8413ff40c12SJohn Marino 	case 16:
8423ff40c12SJohn Marino 		return EDIT_KEY_CTRL_P;
8433ff40c12SJohn Marino 	case 18:
8443ff40c12SJohn Marino 		return EDIT_KEY_CTRL_R;
8453ff40c12SJohn Marino 	case 20:
8463ff40c12SJohn Marino 		return EDIT_KEY_CTRL_T;
8473ff40c12SJohn Marino 	case 21:
8483ff40c12SJohn Marino 		return EDIT_KEY_CTRL_U;
8493ff40c12SJohn Marino 	case 22:
8503ff40c12SJohn Marino 		return EDIT_KEY_CTRL_V;
8513ff40c12SJohn Marino 	case 23:
8523ff40c12SJohn Marino 		return EDIT_KEY_CTRL_W;
8533ff40c12SJohn Marino 	case 27: /* ESC */
8543ff40c12SJohn Marino 		esc = 0;
8553ff40c12SJohn Marino 		return EDIT_KEY_NONE;
8563ff40c12SJohn Marino 	case 127:
8573ff40c12SJohn Marino 		return EDIT_KEY_BACKSPACE;
8583ff40c12SJohn Marino 	default:
8593ff40c12SJohn Marino 		return c;
8603ff40c12SJohn Marino 	}
8613ff40c12SJohn Marino }
8623ff40c12SJohn Marino 
8633ff40c12SJohn Marino 
8643ff40c12SJohn Marino static char search_buf[21];
8653ff40c12SJohn Marino static int search_skip;
8663ff40c12SJohn Marino 
search_find(void)8673ff40c12SJohn Marino static char * search_find(void)
8683ff40c12SJohn Marino {
8693ff40c12SJohn Marino 	struct edit_history *h;
8703ff40c12SJohn Marino 	size_t len = os_strlen(search_buf);
8713ff40c12SJohn Marino 	int skip = search_skip;
8723ff40c12SJohn Marino 
8733ff40c12SJohn Marino 	if (len == 0)
8743ff40c12SJohn Marino 		return NULL;
8753ff40c12SJohn Marino 
8763ff40c12SJohn Marino 	dl_list_for_each(h, &history_list, struct edit_history, list) {
8773ff40c12SJohn Marino 		if (os_strstr(h->str, search_buf)) {
8783ff40c12SJohn Marino 			if (skip == 0)
8793ff40c12SJohn Marino 				return h->str;
8803ff40c12SJohn Marino 			skip--;
8813ff40c12SJohn Marino 		}
8823ff40c12SJohn Marino 	}
8833ff40c12SJohn Marino 
8843ff40c12SJohn Marino 	search_skip = 0;
8853ff40c12SJohn Marino 	return NULL;
8863ff40c12SJohn Marino }
8873ff40c12SJohn Marino 
8883ff40c12SJohn Marino 
search_redraw(void)8893ff40c12SJohn Marino static void search_redraw(void)
8903ff40c12SJohn Marino {
8913ff40c12SJohn Marino 	char *match = search_find();
8923ff40c12SJohn Marino 	printf("\rsearch '%s': %s" CLEAR_END_LINE,
8933ff40c12SJohn Marino 	       search_buf, match ? match : "");
8943ff40c12SJohn Marino 	printf("\rsearch '%s", search_buf);
8953ff40c12SJohn Marino 	fflush(stdout);
8963ff40c12SJohn Marino }
8973ff40c12SJohn Marino 
8983ff40c12SJohn Marino 
search_start(void)8993ff40c12SJohn Marino static void search_start(void)
9003ff40c12SJohn Marino {
9013ff40c12SJohn Marino 	edit_clear_line();
9023ff40c12SJohn Marino 	search_buf[0] = '\0';
9033ff40c12SJohn Marino 	search_skip = 0;
9043ff40c12SJohn Marino 	search_redraw();
9053ff40c12SJohn Marino }
9063ff40c12SJohn Marino 
9073ff40c12SJohn Marino 
search_clear(void)9083ff40c12SJohn Marino static void search_clear(void)
9093ff40c12SJohn Marino {
9103ff40c12SJohn Marino 	search_redraw();
9113ff40c12SJohn Marino 	printf("\r" CLEAR_END_LINE);
9123ff40c12SJohn Marino }
9133ff40c12SJohn Marino 
9143ff40c12SJohn Marino 
search_stop(void)9153ff40c12SJohn Marino static void search_stop(void)
9163ff40c12SJohn Marino {
9173ff40c12SJohn Marino 	char *match = search_find();
9183ff40c12SJohn Marino 	search_buf[0] = '\0';
9193ff40c12SJohn Marino 	search_clear();
9203ff40c12SJohn Marino 	if (match) {
9213ff40c12SJohn Marino 		os_strlcpy(cmdbuf, match, CMD_BUF_LEN);
9223ff40c12SJohn Marino 		cmdbuf_len = os_strlen(cmdbuf);
9233ff40c12SJohn Marino 		cmdbuf_pos = cmdbuf_len;
9243ff40c12SJohn Marino 	}
9253ff40c12SJohn Marino 	edit_redraw();
9263ff40c12SJohn Marino }
9273ff40c12SJohn Marino 
9283ff40c12SJohn Marino 
search_cancel(void)9293ff40c12SJohn Marino static void search_cancel(void)
9303ff40c12SJohn Marino {
9313ff40c12SJohn Marino 	search_buf[0] = '\0';
9323ff40c12SJohn Marino 	search_clear();
9333ff40c12SJohn Marino 	edit_redraw();
9343ff40c12SJohn Marino }
9353ff40c12SJohn Marino 
9363ff40c12SJohn Marino 
search_backspace(void)9373ff40c12SJohn Marino static void search_backspace(void)
9383ff40c12SJohn Marino {
9393ff40c12SJohn Marino 	size_t len;
9403ff40c12SJohn Marino 	len = os_strlen(search_buf);
9413ff40c12SJohn Marino 	if (len == 0)
9423ff40c12SJohn Marino 		return;
9433ff40c12SJohn Marino 	search_buf[len - 1] = '\0';
9443ff40c12SJohn Marino 	search_skip = 0;
9453ff40c12SJohn Marino 	search_redraw();
9463ff40c12SJohn Marino }
9473ff40c12SJohn Marino 
9483ff40c12SJohn Marino 
search_next(void)9493ff40c12SJohn Marino static void search_next(void)
9503ff40c12SJohn Marino {
9513ff40c12SJohn Marino 	search_skip++;
9523ff40c12SJohn Marino 	search_find();
9533ff40c12SJohn Marino 	search_redraw();
9543ff40c12SJohn Marino }
9553ff40c12SJohn Marino 
9563ff40c12SJohn Marino 
search_char(char c)9573ff40c12SJohn Marino static void search_char(char c)
9583ff40c12SJohn Marino {
9593ff40c12SJohn Marino 	size_t len;
9603ff40c12SJohn Marino 	len = os_strlen(search_buf);
9613ff40c12SJohn Marino 	if (len == sizeof(search_buf) - 1)
9623ff40c12SJohn Marino 		return;
9633ff40c12SJohn Marino 	search_buf[len] = c;
9643ff40c12SJohn Marino 	search_buf[len + 1] = '\0';
9653ff40c12SJohn Marino 	search_skip = 0;
9663ff40c12SJohn Marino 	search_redraw();
9673ff40c12SJohn Marino }
9683ff40c12SJohn Marino 
9693ff40c12SJohn Marino 
search_key(enum edit_key_code c)9703ff40c12SJohn Marino static enum edit_key_code search_key(enum edit_key_code c)
9713ff40c12SJohn Marino {
9723ff40c12SJohn Marino 	switch (c) {
9733ff40c12SJohn Marino 	case EDIT_KEY_ENTER:
9743ff40c12SJohn Marino 	case EDIT_KEY_CTRL_J:
9753ff40c12SJohn Marino 	case EDIT_KEY_LEFT:
9763ff40c12SJohn Marino 	case EDIT_KEY_RIGHT:
9773ff40c12SJohn Marino 	case EDIT_KEY_HOME:
9783ff40c12SJohn Marino 	case EDIT_KEY_END:
9793ff40c12SJohn Marino 	case EDIT_KEY_CTRL_A:
9803ff40c12SJohn Marino 	case EDIT_KEY_CTRL_E:
9813ff40c12SJohn Marino 		search_stop();
9823ff40c12SJohn Marino 		return c;
9833ff40c12SJohn Marino 	case EDIT_KEY_DOWN:
9843ff40c12SJohn Marino 	case EDIT_KEY_UP:
9853ff40c12SJohn Marino 		search_cancel();
9863ff40c12SJohn Marino 		return EDIT_KEY_EOF;
9873ff40c12SJohn Marino 	case EDIT_KEY_CTRL_H:
9883ff40c12SJohn Marino 	case EDIT_KEY_BACKSPACE:
9893ff40c12SJohn Marino 		search_backspace();
9903ff40c12SJohn Marino 		break;
9913ff40c12SJohn Marino 	case EDIT_KEY_CTRL_R:
9923ff40c12SJohn Marino 		search_next();
9933ff40c12SJohn Marino 		break;
9943ff40c12SJohn Marino 	default:
9953ff40c12SJohn Marino 		if (c >= 32 && c <= 255)
9963ff40c12SJohn Marino 			search_char(c);
9973ff40c12SJohn Marino 		break;
9983ff40c12SJohn Marino 	}
9993ff40c12SJohn Marino 
10003ff40c12SJohn Marino 	return EDIT_KEY_NONE;
10013ff40c12SJohn Marino }
10023ff40c12SJohn Marino 
10033ff40c12SJohn Marino 
edit_read_char(int sock,void * eloop_ctx,void * sock_ctx)10043ff40c12SJohn Marino static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
10053ff40c12SJohn Marino {
10063ff40c12SJohn Marino 	static int last_tab = 0;
10073ff40c12SJohn Marino 	static int search = 0;
10083ff40c12SJohn Marino 	enum edit_key_code c;
10093ff40c12SJohn Marino 
10103ff40c12SJohn Marino 	c = edit_read_key(sock);
10113ff40c12SJohn Marino 
10123ff40c12SJohn Marino 	if (search) {
10133ff40c12SJohn Marino 		c = search_key(c);
10143ff40c12SJohn Marino 		if (c == EDIT_KEY_NONE)
10153ff40c12SJohn Marino 			return;
10163ff40c12SJohn Marino 		search = 0;
10173ff40c12SJohn Marino 		if (c == EDIT_KEY_EOF)
10183ff40c12SJohn Marino 			return;
10193ff40c12SJohn Marino 	}
10203ff40c12SJohn Marino 
10213ff40c12SJohn Marino 	if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE)
10223ff40c12SJohn Marino 		last_tab = 0;
10233ff40c12SJohn Marino 
10243ff40c12SJohn Marino 	switch (c) {
10253ff40c12SJohn Marino 	case EDIT_KEY_NONE:
10263ff40c12SJohn Marino 		break;
10273ff40c12SJohn Marino 	case EDIT_KEY_EOF:
10283ff40c12SJohn Marino 		edit_eof_cb(edit_cb_ctx);
10293ff40c12SJohn Marino 		break;
10303ff40c12SJohn Marino 	case EDIT_KEY_TAB:
10313ff40c12SJohn Marino 		complete(last_tab);
10323ff40c12SJohn Marino 		last_tab = 1;
10333ff40c12SJohn Marino 		break;
10343ff40c12SJohn Marino 	case EDIT_KEY_UP:
10353ff40c12SJohn Marino 	case EDIT_KEY_CTRL_P:
10363ff40c12SJohn Marino 		history_prev();
10373ff40c12SJohn Marino 		break;
10383ff40c12SJohn Marino 	case EDIT_KEY_DOWN:
10393ff40c12SJohn Marino 	case EDIT_KEY_CTRL_N:
10403ff40c12SJohn Marino 		history_next();
10413ff40c12SJohn Marino 		break;
10423ff40c12SJohn Marino 	case EDIT_KEY_RIGHT:
10433ff40c12SJohn Marino 	case EDIT_KEY_CTRL_F:
10443ff40c12SJohn Marino 		move_right();
10453ff40c12SJohn Marino 		break;
10463ff40c12SJohn Marino 	case EDIT_KEY_LEFT:
10473ff40c12SJohn Marino 	case EDIT_KEY_CTRL_B:
10483ff40c12SJohn Marino 		move_left();
10493ff40c12SJohn Marino 		break;
10503ff40c12SJohn Marino 	case EDIT_KEY_CTRL_RIGHT:
10513ff40c12SJohn Marino 		move_word_right();
10523ff40c12SJohn Marino 		break;
10533ff40c12SJohn Marino 	case EDIT_KEY_CTRL_LEFT:
10543ff40c12SJohn Marino 		move_word_left();
10553ff40c12SJohn Marino 		break;
10563ff40c12SJohn Marino 	case EDIT_KEY_DELETE:
10573ff40c12SJohn Marino 		delete_current();
10583ff40c12SJohn Marino 		break;
10593ff40c12SJohn Marino 	case EDIT_KEY_END:
10603ff40c12SJohn Marino 		move_end();
10613ff40c12SJohn Marino 		break;
10623ff40c12SJohn Marino 	case EDIT_KEY_HOME:
10633ff40c12SJohn Marino 	case EDIT_KEY_CTRL_A:
10643ff40c12SJohn Marino 		move_start();
10653ff40c12SJohn Marino 		break;
10663ff40c12SJohn Marino 	case EDIT_KEY_F2:
10673ff40c12SJohn Marino 		history_debug_dump();
10683ff40c12SJohn Marino 		break;
10693ff40c12SJohn Marino 	case EDIT_KEY_CTRL_D:
10703ff40c12SJohn Marino 		if (cmdbuf_len > 0) {
10713ff40c12SJohn Marino 			delete_current();
10723ff40c12SJohn Marino 			return;
10733ff40c12SJohn Marino 		}
10743ff40c12SJohn Marino 		printf("\n");
10753ff40c12SJohn Marino 		edit_eof_cb(edit_cb_ctx);
10763ff40c12SJohn Marino 		break;
10773ff40c12SJohn Marino 	case EDIT_KEY_CTRL_E:
10783ff40c12SJohn Marino 		move_end();
10793ff40c12SJohn Marino 		break;
10803ff40c12SJohn Marino 	case EDIT_KEY_CTRL_H:
10813ff40c12SJohn Marino 	case EDIT_KEY_BACKSPACE:
10823ff40c12SJohn Marino 		delete_left();
10833ff40c12SJohn Marino 		break;
10843ff40c12SJohn Marino 	case EDIT_KEY_ENTER:
10853ff40c12SJohn Marino 	case EDIT_KEY_CTRL_J:
10863ff40c12SJohn Marino 		process_cmd();
10873ff40c12SJohn Marino 		break;
10883ff40c12SJohn Marino 	case EDIT_KEY_CTRL_K:
10893ff40c12SJohn Marino 		clear_right();
10903ff40c12SJohn Marino 		break;
10913ff40c12SJohn Marino 	case EDIT_KEY_CTRL_L:
10923ff40c12SJohn Marino 		edit_clear_line();
10933ff40c12SJohn Marino 		edit_redraw();
10943ff40c12SJohn Marino 		break;
10953ff40c12SJohn Marino 	case EDIT_KEY_CTRL_R:
10963ff40c12SJohn Marino 		search = 1;
10973ff40c12SJohn Marino 		search_start();
10983ff40c12SJohn Marino 		break;
10993ff40c12SJohn Marino 	case EDIT_KEY_CTRL_U:
11003ff40c12SJohn Marino 		clear_left();
11013ff40c12SJohn Marino 		break;
11023ff40c12SJohn Marino 	case EDIT_KEY_CTRL_W:
11033ff40c12SJohn Marino 		delete_word();
11043ff40c12SJohn Marino 		break;
11053ff40c12SJohn Marino 	default:
11063ff40c12SJohn Marino 		if (c >= 32 && c <= 255)
11073ff40c12SJohn Marino 			insert_char(c);
11083ff40c12SJohn Marino 		break;
11093ff40c12SJohn Marino 	}
11103ff40c12SJohn Marino }
11113ff40c12SJohn Marino 
11123ff40c12SJohn Marino 
edit_init(void (* cmd_cb)(void * ctx,char * cmd),void (* eof_cb)(void * ctx),char ** (* completion_cb)(void * ctx,const char * cmd,int pos),void * ctx,const char * history_file,const char * ps)11133ff40c12SJohn Marino int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
11143ff40c12SJohn Marino 	      void (*eof_cb)(void *ctx),
11153ff40c12SJohn Marino 	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
11163ff40c12SJohn Marino 	      void *ctx, const char *history_file, const char *ps)
11173ff40c12SJohn Marino {
11183ff40c12SJohn Marino 	currbuf[0] = '\0';
11193ff40c12SJohn Marino 	dl_list_init(&history_list);
11203ff40c12SJohn Marino 	history_curr = NULL;
11213ff40c12SJohn Marino 	if (history_file)
11223ff40c12SJohn Marino 		history_read(history_file);
11233ff40c12SJohn Marino 
11243ff40c12SJohn Marino 	edit_cb_ctx = ctx;
11253ff40c12SJohn Marino 	edit_cmd_cb = cmd_cb;
11263ff40c12SJohn Marino 	edit_eof_cb = eof_cb;
11273ff40c12SJohn Marino 	edit_completion_cb = completion_cb;
11283ff40c12SJohn Marino 
11293ff40c12SJohn Marino 	tcgetattr(STDIN_FILENO, &prevt);
11303ff40c12SJohn Marino 	newt = prevt;
11313ff40c12SJohn Marino 	newt.c_lflag &= ~(ICANON | ECHO);
11323ff40c12SJohn Marino 	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
11333ff40c12SJohn Marino 
11343ff40c12SJohn Marino 	eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
11353ff40c12SJohn Marino 
11363ff40c12SJohn Marino 	ps2 = ps;
11373ff40c12SJohn Marino 	printf("%s> ", ps2 ? ps2 : "");
11383ff40c12SJohn Marino 	fflush(stdout);
11393ff40c12SJohn Marino 
11403ff40c12SJohn Marino 	return 0;
11413ff40c12SJohn Marino }
11423ff40c12SJohn Marino 
11433ff40c12SJohn Marino 
edit_deinit(const char * history_file,int (* filter_cb)(void * ctx,const char * cmd))11443ff40c12SJohn Marino void edit_deinit(const char *history_file,
11453ff40c12SJohn Marino 		 int (*filter_cb)(void *ctx, const char *cmd))
11463ff40c12SJohn Marino {
11473ff40c12SJohn Marino 	struct edit_history *h;
11483ff40c12SJohn Marino 	if (history_file)
11493ff40c12SJohn Marino 		history_write(history_file, filter_cb);
11503ff40c12SJohn Marino 	while ((h = dl_list_first(&history_list, struct edit_history, list))) {
11513ff40c12SJohn Marino 		dl_list_del(&h->list);
11523ff40c12SJohn Marino 		os_free(h);
11533ff40c12SJohn Marino 	}
11543ff40c12SJohn Marino 	edit_clear_line();
11553ff40c12SJohn Marino 	putchar('\r');
11563ff40c12SJohn Marino 	fflush(stdout);
11573ff40c12SJohn Marino 	eloop_unregister_read_sock(STDIN_FILENO);
11583ff40c12SJohn Marino 	tcsetattr(STDIN_FILENO, TCSANOW, &prevt);
11593ff40c12SJohn Marino }
11603ff40c12SJohn Marino 
11613ff40c12SJohn Marino 
edit_redraw(void)11623ff40c12SJohn Marino void edit_redraw(void)
11633ff40c12SJohn Marino {
11643ff40c12SJohn Marino 	char tmp;
11653ff40c12SJohn Marino 	cmdbuf[cmdbuf_len] = '\0';
11663ff40c12SJohn Marino 	printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
11673ff40c12SJohn Marino 	if (cmdbuf_pos != cmdbuf_len) {
11683ff40c12SJohn Marino 		tmp = cmdbuf[cmdbuf_pos];
11693ff40c12SJohn Marino 		cmdbuf[cmdbuf_pos] = '\0';
11703ff40c12SJohn Marino 		printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
11713ff40c12SJohn Marino 		cmdbuf[cmdbuf_pos] = tmp;
11723ff40c12SJohn Marino 	}
11733ff40c12SJohn Marino 	fflush(stdout);
11743ff40c12SJohn Marino }
1175