]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/utils/edit.c
edit: Clean up escape code parser
[thirdparty/hostap.git] / src / utils / edit.c
1 /*
2 * Command line editing and history
3 * Copyright (c) 2010, Jouni Malinen <j@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 "edit.h"
21
22 #define CMD_BUF_LEN 256
23 static char cmdbuf[CMD_BUF_LEN];
24 static int cmdbuf_pos = 0;
25 static int cmdbuf_len = 0;
26 #define CMD_HISTORY_LEN 20
27 static char history_buf[CMD_HISTORY_LEN][CMD_BUF_LEN];
28 static int history_pos = 0;
29 static int history_current = 0;
30
31 static void *edit_cb_ctx;
32 static void (*edit_cmd_cb)(void *ctx, char *cmd);
33 static void (*edit_eof_cb)(void *ctx);
34 static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
35 NULL;
36
37 static struct termios prevt, newt;
38
39
40 void edit_clear_line(void)
41 {
42 int i;
43 putchar('\r');
44 for (i = 0; i < cmdbuf_len + 2; i++)
45 putchar(' ');
46 }
47
48
49 static void move_start(void)
50 {
51 cmdbuf_pos = 0;
52 edit_redraw();
53 }
54
55
56 static void move_end(void)
57 {
58 cmdbuf_pos = cmdbuf_len;
59 edit_redraw();
60 }
61
62
63 static void move_left(void)
64 {
65 if (cmdbuf_pos > 0) {
66 cmdbuf_pos--;
67 edit_redraw();
68 }
69 }
70
71
72 static void move_right(void)
73 {
74 if (cmdbuf_pos < cmdbuf_len) {
75 cmdbuf_pos++;
76 edit_redraw();
77 }
78 }
79
80
81 static void move_word_left(void)
82 {
83 while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ')
84 cmdbuf_pos--;
85 while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ')
86 cmdbuf_pos--;
87 edit_redraw();
88 }
89
90
91 static void move_word_right(void)
92 {
93 while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ')
94 cmdbuf_pos++;
95 while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ')
96 cmdbuf_pos++;
97 edit_redraw();
98 }
99
100
101 static void delete_left(void)
102 {
103 if (cmdbuf_pos == 0)
104 return;
105
106 edit_clear_line();
107 os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos,
108 cmdbuf_len - cmdbuf_pos);
109 cmdbuf_pos--;
110 cmdbuf_len--;
111 edit_redraw();
112 }
113
114
115 static void delete_current(void)
116 {
117 if (cmdbuf_pos == cmdbuf_len)
118 return;
119
120 edit_clear_line();
121 os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1,
122 cmdbuf_len - cmdbuf_pos);
123 cmdbuf_len--;
124 edit_redraw();
125 }
126
127
128 static void delete_word(void)
129 {
130 edit_clear_line();
131 while (cmdbuf_len > 0 && cmdbuf[cmdbuf_len - 1] == ' ')
132 cmdbuf_len--;
133 while (cmdbuf_len > 0 && cmdbuf[cmdbuf_len - 1] != ' ')
134 cmdbuf_len--;
135 if (cmdbuf_pos > cmdbuf_len)
136 cmdbuf_pos = cmdbuf_len;
137 edit_redraw();
138 }
139
140
141 static void clear_left(void)
142 {
143 if (cmdbuf_pos == 0)
144 return;
145
146 edit_clear_line();
147 os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
148 cmdbuf_len -= cmdbuf_pos;
149 cmdbuf_pos = 0;
150 edit_redraw();
151 }
152
153
154 static void clear_right(void)
155 {
156 if (cmdbuf_pos == cmdbuf_len)
157 return;
158
159 edit_clear_line();
160 cmdbuf_len = cmdbuf_pos;
161 edit_redraw();
162 }
163
164
165 static void history_add(const char *str)
166 {
167 int prev;
168
169 if (str[0] == '\0')
170 return;
171
172 if (history_pos == 0)
173 prev = CMD_HISTORY_LEN - 1;
174 else
175 prev = history_pos - 1;
176 if (os_strcmp(history_buf[prev], str) == 0)
177 return;
178
179 os_strlcpy(history_buf[history_pos], str, CMD_BUF_LEN);
180 history_pos++;
181 if (history_pos == CMD_HISTORY_LEN)
182 history_pos = 0;
183 history_current = history_pos;
184 }
185
186
187 static void history_prev(void)
188 {
189 int pos;
190
191 if (history_current == (history_pos + 1) % CMD_HISTORY_LEN)
192 return;
193
194 pos = history_current;
195
196 if (history_current == history_pos && cmdbuf_len) {
197 cmdbuf[cmdbuf_len] = '\0';
198 history_add(cmdbuf);
199 }
200
201 if (pos > 0)
202 pos--;
203 else
204 pos = CMD_HISTORY_LEN - 1;
205 if (history_buf[pos][0] == '\0')
206 return;
207 history_current = pos;
208
209 edit_clear_line();
210 cmdbuf_len = cmdbuf_pos = os_strlen(history_buf[history_current]);
211 os_memcpy(cmdbuf, history_buf[history_current], cmdbuf_len);
212 edit_redraw();
213 }
214
215
216 static void history_next(void)
217 {
218 if (history_current == history_pos)
219 return;
220
221 history_current++;
222 if (history_current == CMD_HISTORY_LEN)
223 history_current = 0;
224
225 edit_clear_line();
226 cmdbuf_len = cmdbuf_pos = os_strlen(history_buf[history_current]);
227 os_memcpy(cmdbuf, history_buf[history_current], cmdbuf_len);
228 edit_redraw();
229 }
230
231
232 static void history_debug_dump(void)
233 {
234 int p;
235 edit_clear_line();
236 printf("\r");
237 p = (history_pos + 1) % CMD_HISTORY_LEN;
238 for (;;) {
239 printf("[%d%s%s] %s\n",
240 p, p == history_current ? "C" : "",
241 p == history_pos ? "P" : "", history_buf[p]);
242 if (p == history_pos)
243 break;
244 p++;
245 if (p == CMD_HISTORY_LEN)
246 p = 0;
247 }
248 edit_redraw();
249 }
250
251
252 static void insert_char(int c)
253 {
254 if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1)
255 return;
256 if (cmdbuf_len == cmdbuf_pos) {
257 cmdbuf[cmdbuf_pos++] = c;
258 cmdbuf_len++;
259 putchar(c);
260 fflush(stdout);
261 } else {
262 os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos,
263 cmdbuf_len - cmdbuf_pos);
264 cmdbuf[cmdbuf_pos++] = c;
265 cmdbuf_len++;
266 edit_redraw();
267 }
268 }
269
270
271 static void process_cmd(void)
272 {
273
274 if (cmdbuf_len == 0) {
275 printf("\n> ");
276 fflush(stdout);
277 return;
278 }
279 printf("\n");
280 cmdbuf[cmdbuf_len] = '\0';
281 history_add(cmdbuf);
282 cmdbuf_pos = 0;
283 cmdbuf_len = 0;
284 edit_cmd_cb(edit_cb_ctx, cmdbuf);
285 printf("> ");
286 fflush(stdout);
287 }
288
289
290 static void free_completions(char **c)
291 {
292 int i;
293 if (c == NULL)
294 return;
295 for (i = 0; c[i]; i++)
296 os_free(c[i]);
297 os_free(c);
298 }
299
300
301 static int filter_strings(char **c, char *str, size_t len)
302 {
303 int i, j;
304
305 for (i = 0, j = 0; c[j]; j++) {
306 if (os_strncasecmp(c[j], str, len) == 0) {
307 if (i != j) {
308 c[i] = c[j];
309 c[j] = NULL;
310 }
311 i++;
312 } else {
313 os_free(c[j]);
314 c[j] = NULL;
315 }
316 }
317 c[i] = NULL;
318 return i;
319 }
320
321
322 static int common_len(const char *a, const char *b)
323 {
324 int len = 0;
325 while (a[len] && a[len] == b[len])
326 len++;
327 return len;
328 }
329
330
331 static int max_common_length(char **c)
332 {
333 int len, i;
334
335 len = os_strlen(c[0]);
336 for (i = 1; c[i]; i++) {
337 int same = common_len(c[0], c[i]);
338 if (same < len)
339 len = same;
340 }
341
342 return len;
343 }
344
345
346 static int cmp_str(const void *a, const void *b)
347 {
348 return os_strcmp(* (const char **) a, * (const char **) b);
349 }
350
351 static void complete(int list)
352 {
353 char **c;
354 int i, len, count;
355 int start, end;
356 int room, plen, add_space;
357
358 if (edit_completion_cb == NULL)
359 return;
360
361 cmdbuf[cmdbuf_len] = '\0';
362 c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos);
363 if (c == NULL)
364 return;
365
366 end = cmdbuf_pos;
367 start = end;
368 while (start > 0 && cmdbuf[start - 1] != ' ')
369 start--;
370 plen = end - start;
371
372 count = filter_strings(c, &cmdbuf[start], plen);
373 if (count == 0) {
374 free_completions(c);
375 return;
376 }
377
378 len = max_common_length(c);
379 if (len <= plen && count > 1) {
380 if (list) {
381 qsort(c, count, sizeof(char *), cmp_str);
382 edit_clear_line();
383 printf("\r");
384 for (i = 0; c[i]; i++)
385 printf("%s%s", i > 0 ? " " : "", c[i]);
386 printf("\n");
387 edit_redraw();
388 }
389 free_completions(c);
390 return;
391 }
392 len -= plen;
393
394 room = sizeof(cmdbuf) - 1 - cmdbuf_len;
395 if (room < len)
396 len = room;
397 add_space = count == 1 && len < room;
398
399 os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos,
400 cmdbuf_len - cmdbuf_pos);
401 os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len);
402 if (add_space)
403 cmdbuf[cmdbuf_pos + len] = ' ';
404
405 cmdbuf_pos += len + add_space;
406 cmdbuf_len += len + add_space;
407
408 edit_redraw();
409
410 free_completions(c);
411 }
412
413
414 enum edit_key_code {
415 EDIT_KEY_NONE = 256,
416 EDIT_KEY_TAB,
417 EDIT_KEY_UP,
418 EDIT_KEY_DOWN,
419 EDIT_KEY_RIGHT,
420 EDIT_KEY_LEFT,
421 EDIT_KEY_ENTER,
422 EDIT_KEY_BACKSPACE,
423 EDIT_KEY_INSERT,
424 EDIT_KEY_DELETE,
425 EDIT_KEY_HOME,
426 EDIT_KEY_END,
427 EDIT_KEY_PAGE_UP,
428 EDIT_KEY_PAGE_DOWN,
429 EDIT_KEY_F1,
430 EDIT_KEY_F2,
431 EDIT_KEY_F3,
432 EDIT_KEY_F4,
433 EDIT_KEY_F5,
434 EDIT_KEY_F6,
435 EDIT_KEY_F7,
436 EDIT_KEY_F8,
437 EDIT_KEY_F9,
438 EDIT_KEY_F10,
439 EDIT_KEY_F11,
440 EDIT_KEY_F12,
441 EDIT_KEY_CTRL_UP,
442 EDIT_KEY_CTRL_DOWN,
443 EDIT_KEY_CTRL_RIGHT,
444 EDIT_KEY_CTRL_LEFT,
445 EDIT_KEY_CTRL_A,
446 EDIT_KEY_CTRL_B,
447 EDIT_KEY_CTRL_D,
448 EDIT_KEY_CTRL_E,
449 EDIT_KEY_CTRL_F,
450 EDIT_KEY_CTRL_G,
451 EDIT_KEY_CTRL_H,
452 EDIT_KEY_CTRL_J,
453 EDIT_KEY_CTRL_K,
454 EDIT_KEY_CTRL_L,
455 EDIT_KEY_CTRL_N,
456 EDIT_KEY_CTRL_O,
457 EDIT_KEY_CTRL_P,
458 EDIT_KEY_CTRL_R,
459 EDIT_KEY_CTRL_T,
460 EDIT_KEY_CTRL_U,
461 EDIT_KEY_CTRL_V,
462 EDIT_KEY_CTRL_W,
463 EDIT_KEY_ALT_UP,
464 EDIT_KEY_ALT_DOWN,
465 EDIT_KEY_ALT_RIGHT,
466 EDIT_KEY_ALT_LEFT,
467 EDIT_KEY_SHIFT_UP,
468 EDIT_KEY_SHIFT_DOWN,
469 EDIT_KEY_SHIFT_RIGHT,
470 EDIT_KEY_SHIFT_LEFT,
471 EDIT_KEY_ALT_SHIFT_UP,
472 EDIT_KEY_ALT_SHIFT_DOWN,
473 EDIT_KEY_ALT_SHIFT_RIGHT,
474 EDIT_KEY_ALT_SHIFT_LEFT,
475 EDIT_KEY_EOF
476 };
477
478 static void show_esc_buf(const char *esc_buf, char c, int i)
479 {
480 edit_clear_line();
481 printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i);
482 edit_redraw();
483 }
484
485
486 static enum edit_key_code esc_seq_to_key1_no(char last)
487 {
488 switch (last) {
489 case 'A':
490 return EDIT_KEY_UP;
491 case 'B':
492 return EDIT_KEY_DOWN;
493 case 'C':
494 return EDIT_KEY_RIGHT;
495 case 'D':
496 return EDIT_KEY_LEFT;
497 default:
498 return EDIT_KEY_NONE;
499 }
500 }
501
502
503 static enum edit_key_code esc_seq_to_key1_shift(char last)
504 {
505 switch (last) {
506 case 'A':
507 return EDIT_KEY_SHIFT_UP;
508 case 'B':
509 return EDIT_KEY_SHIFT_DOWN;
510 case 'C':
511 return EDIT_KEY_SHIFT_RIGHT;
512 case 'D':
513 return EDIT_KEY_SHIFT_LEFT;
514 default:
515 return EDIT_KEY_NONE;
516 }
517 }
518
519
520 static enum edit_key_code esc_seq_to_key1_alt(char last)
521 {
522 switch (last) {
523 case 'A':
524 return EDIT_KEY_ALT_UP;
525 case 'B':
526 return EDIT_KEY_ALT_DOWN;
527 case 'C':
528 return EDIT_KEY_ALT_RIGHT;
529 case 'D':
530 return EDIT_KEY_ALT_LEFT;
531 default:
532 return EDIT_KEY_NONE;
533 }
534 }
535
536
537 static enum edit_key_code esc_seq_to_key1_alt_shift(char last)
538 {
539 switch (last) {
540 case 'A':
541 return EDIT_KEY_ALT_SHIFT_UP;
542 case 'B':
543 return EDIT_KEY_ALT_SHIFT_DOWN;
544 case 'C':
545 return EDIT_KEY_ALT_SHIFT_RIGHT;
546 case 'D':
547 return EDIT_KEY_ALT_SHIFT_LEFT;
548 default:
549 return EDIT_KEY_NONE;
550 }
551 }
552
553
554 static enum edit_key_code esc_seq_to_key1_ctrl(char last)
555 {
556 switch (last) {
557 case 'A':
558 return EDIT_KEY_CTRL_UP;
559 case 'B':
560 return EDIT_KEY_CTRL_DOWN;
561 case 'C':
562 return EDIT_KEY_CTRL_RIGHT;
563 case 'D':
564 return EDIT_KEY_CTRL_LEFT;
565 default:
566 return EDIT_KEY_NONE;
567 }
568 }
569
570
571 static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last)
572 {
573 /* ESC-[<param1>;<param2><last> */
574
575 if (param1 < 0 && param2 < 0)
576 return esc_seq_to_key1_no(last);
577
578 if (param1 == 1 && param2 == 2)
579 return esc_seq_to_key1_shift(last);
580
581 if (param1 == 1 && param2 == 3)
582 return esc_seq_to_key1_alt(last);
583
584 if (param1 == 1 && param2 == 4)
585 return esc_seq_to_key1_alt_shift(last);
586
587 if (param1 == 1 && param2 == 5)
588 return esc_seq_to_key1_ctrl(last);
589
590 if (param2 < 0) {
591 if (last != '~')
592 return EDIT_KEY_NONE;
593 switch (param1) {
594 case 2:
595 return EDIT_KEY_INSERT;
596 case 3:
597 return EDIT_KEY_DELETE;
598 case 5:
599 return EDIT_KEY_PAGE_UP;
600 case 6:
601 return EDIT_KEY_PAGE_DOWN;
602 case 15:
603 return EDIT_KEY_F5;
604 case 17:
605 return EDIT_KEY_F6;
606 case 18:
607 return EDIT_KEY_F7;
608 case 19:
609 return EDIT_KEY_F8;
610 case 20:
611 return EDIT_KEY_F9;
612 case 21:
613 return EDIT_KEY_F10;
614 case 23:
615 return EDIT_KEY_F11;
616 case 24:
617 return EDIT_KEY_F12;
618 }
619 }
620
621 return EDIT_KEY_NONE;
622 }
623
624
625 static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last)
626 {
627 /* ESC-O<param1>;<param2><last> */
628
629 if (param1 >= 0 || param2 >= 0)
630 return EDIT_KEY_NONE;
631
632 switch (last) {
633 case 'F':
634 return EDIT_KEY_END;
635 case 'H':
636 return EDIT_KEY_HOME;
637 case 'P':
638 return EDIT_KEY_F1;
639 case 'Q':
640 return EDIT_KEY_F2;
641 case 'R':
642 return EDIT_KEY_F3;
643 case 'S':
644 return EDIT_KEY_F4;
645 default:
646 return EDIT_KEY_NONE;
647 }
648 }
649
650
651 static enum edit_key_code esc_seq_to_key(char *seq)
652 {
653 char last, *pos;
654 int param1 = -1, param2 = -1;
655 enum edit_key_code ret = EDIT_KEY_NONE;
656
657 for (pos = seq; *pos; pos++)
658 last = *pos;
659
660 if (seq[1] >= '0' && seq[1] <= '9') {
661 param1 = atoi(&seq[1]);
662 pos = os_strchr(seq, ';');
663 if (pos)
664 param2 = atoi(pos + 1);
665 }
666
667 if (seq[0] == '[')
668 ret = esc_seq_to_key1(param1, param2, last);
669 else if (seq[0] == 'O')
670 ret = esc_seq_to_key2(param1, param2, last);
671
672 if (ret != EDIT_KEY_NONE)
673 return ret;
674
675 edit_clear_line();
676 printf("\rUnknown escape sequence '%s'\n", seq);
677 edit_redraw();
678 return EDIT_KEY_NONE;
679 }
680
681
682 static enum edit_key_code edit_read_key(int sock)
683 {
684 int c;
685 unsigned char buf[1];
686 int res;
687 static int esc = -1;
688 static char esc_buf[7];
689
690 res = read(sock, buf, 1);
691 if (res < 0)
692 perror("read");
693 if (res <= 0)
694 return EDIT_KEY_EOF;
695
696 c = buf[0];
697
698 if (esc >= 0) {
699 if (c == 27 /* ESC */) {
700 esc = 0;
701 return EDIT_KEY_NONE;
702 }
703
704 if (esc == 6) {
705 show_esc_buf(esc_buf, c, 0);
706 esc = -1;
707 } else {
708 esc_buf[esc++] = c;
709 esc_buf[esc] = '\0';
710 }
711 }
712
713 if (esc == 1) {
714 if (esc_buf[0] != '[' && esc_buf[0] != 'O') {
715 show_esc_buf(esc_buf, c, 1);
716 esc = -1;
717 return EDIT_KEY_NONE;
718 } else
719 return EDIT_KEY_NONE; /* Escape sequence continues */
720 }
721
722 if (esc > 1) {
723 if ((c >= '0' && c <= '9') || c == ';')
724 return EDIT_KEY_NONE; /* Escape sequence continues */
725
726 if (c == '~' || (c >= 'A' && c <= 'Z')) {
727 esc = -1;
728 return esc_seq_to_key(esc_buf);
729 }
730
731 show_esc_buf(esc_buf, c, 2);
732 esc = -1;
733 return EDIT_KEY_NONE;
734 }
735
736 switch (c) {
737 case 1:
738 return EDIT_KEY_CTRL_A;
739 case 2:
740 return EDIT_KEY_CTRL_B;
741 case 4:
742 return EDIT_KEY_CTRL_D;
743 case 5:
744 return EDIT_KEY_CTRL_E;
745 case 6:
746 return EDIT_KEY_CTRL_F;
747 case 7:
748 return EDIT_KEY_CTRL_G;
749 case 8:
750 return EDIT_KEY_CTRL_H;
751 case 9:
752 return EDIT_KEY_TAB;
753 case 10:
754 return EDIT_KEY_CTRL_J;
755 case 13: /* CR */
756 return EDIT_KEY_ENTER;
757 case 11:
758 return EDIT_KEY_CTRL_K;
759 case 12:
760 return EDIT_KEY_CTRL_L;
761 case 14:
762 return EDIT_KEY_CTRL_N;
763 case 15:
764 return EDIT_KEY_CTRL_O;
765 case 16:
766 return EDIT_KEY_CTRL_P;
767 case 18:
768 return EDIT_KEY_CTRL_R;
769 case 20:
770 return EDIT_KEY_CTRL_T;
771 case 21:
772 return EDIT_KEY_CTRL_U;
773 case 22:
774 return EDIT_KEY_CTRL_V;
775 case 23:
776 return EDIT_KEY_CTRL_W;
777 case 27: /* ESC */
778 esc = 0;
779 return EDIT_KEY_NONE;
780 case 127:
781 return EDIT_KEY_BACKSPACE;
782 default:
783 return c;
784 }
785 }
786
787
788 static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
789 {
790 static int last_tab = 0;
791 enum edit_key_code c;
792
793 c = edit_read_key(sock);
794
795 if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE)
796 last_tab = 0;
797
798 switch (c) {
799 case EDIT_KEY_NONE:
800 break;
801 case EDIT_KEY_EOF:
802 edit_eof_cb(edit_cb_ctx);
803 break;
804 case EDIT_KEY_TAB:
805 complete(last_tab);
806 last_tab = 1;
807 break;
808 case EDIT_KEY_UP:
809 case EDIT_KEY_CTRL_P:
810 history_prev();
811 break;
812 case EDIT_KEY_DOWN:
813 case EDIT_KEY_CTRL_N:
814 history_next();
815 break;
816 case EDIT_KEY_RIGHT:
817 case EDIT_KEY_CTRL_F:
818 move_right();
819 break;
820 case EDIT_KEY_LEFT:
821 case EDIT_KEY_CTRL_B:
822 move_left();
823 break;
824 case EDIT_KEY_CTRL_RIGHT:
825 move_word_right();
826 break;
827 case EDIT_KEY_CTRL_LEFT:
828 move_word_left();
829 break;
830 case EDIT_KEY_DELETE:
831 delete_current();
832 break;
833 case EDIT_KEY_END:
834 move_end();
835 break;
836 case EDIT_KEY_HOME:
837 case EDIT_KEY_CTRL_A:
838 move_start();
839 break;
840 case EDIT_KEY_F2:
841 history_debug_dump();
842 break;
843 case EDIT_KEY_CTRL_D:
844 if (cmdbuf_len > 0) {
845 delete_current();
846 return;
847 }
848 printf("\n");
849 edit_eof_cb(edit_cb_ctx);
850 break;
851 case EDIT_KEY_CTRL_E:
852 move_end();
853 break;
854 case EDIT_KEY_CTRL_H:
855 case EDIT_KEY_BACKSPACE:
856 delete_left();
857 break;
858 case EDIT_KEY_ENTER:
859 case EDIT_KEY_CTRL_J:
860 process_cmd();
861 break;
862 case EDIT_KEY_CTRL_K:
863 clear_right();
864 break;
865 case EDIT_KEY_CTRL_L:
866 edit_clear_line();
867 edit_redraw();
868 break;
869 case EDIT_KEY_CTRL_R:
870 /* TODO: search history */
871 break;
872 case EDIT_KEY_CTRL_U:
873 clear_left();
874 break;
875 case EDIT_KEY_CTRL_W:
876 delete_word();
877 break;
878 default:
879 if (c >= 32 && c <= 255)
880 insert_char(c);
881 break;
882 }
883 }
884
885
886 int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
887 void (*eof_cb)(void *ctx),
888 void *ctx)
889 {
890 os_memset(history_buf, 0, sizeof(history_buf));
891
892 edit_cb_ctx = ctx;
893 edit_cmd_cb = cmd_cb;
894 edit_eof_cb = eof_cb;
895
896 tcgetattr(STDIN_FILENO, &prevt);
897 newt = prevt;
898 newt.c_lflag &= ~(ICANON | ECHO);
899 tcsetattr(STDIN_FILENO, TCSANOW, &newt);
900
901 eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
902
903 printf("> ");
904 fflush(stdout);
905
906 return 0;
907 }
908
909
910 void edit_deinit(void)
911 {
912 eloop_unregister_read_sock(STDIN_FILENO);
913 tcsetattr(STDIN_FILENO, TCSANOW, &prevt);
914 }
915
916
917 void edit_redraw(void)
918 {
919 char tmp;
920 cmdbuf[cmdbuf_len] = '\0';
921 printf("\r> %s", cmdbuf);
922 if (cmdbuf_pos != cmdbuf_len) {
923 tmp = cmdbuf[cmdbuf_pos];
924 cmdbuf[cmdbuf_pos] = '\0';
925 printf("\r> %s", cmdbuf);
926 cmdbuf[cmdbuf_pos] = tmp;
927 }
928 fflush(stdout);
929 }
930
931
932 void edit_set_filter_history_cb(int (*cb)(void *ctx, const char *cmd))
933 {
934 }
935
936
937 void edit_set_completion_cb(char ** (*cb)(void *ctx, const char *cmd, int pos))
938 {
939 edit_completion_cb = cb;
940 }