]>
git.ipfire.org Git - thirdparty/hostap.git/blob - src/utils/edit.c
2 * Command line editing and history
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
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;
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
) =
37 static struct termios prevt
, newt
;
40 void edit_clear_line(void)
44 for (i
= 0; i
< cmdbuf_len
+ 2; i
++)
49 static void move_start(void)
56 static void move_end(void)
58 cmdbuf_pos
= cmdbuf_len
;
63 static void move_left(void)
72 static void move_right(void)
74 if (cmdbuf_pos
< cmdbuf_len
) {
81 static void move_word_left(void)
83 while (cmdbuf_pos
> 0 && cmdbuf
[cmdbuf_pos
- 1] == ' ')
85 while (cmdbuf_pos
> 0 && cmdbuf
[cmdbuf_pos
- 1] != ' ')
91 static void move_word_right(void)
93 while (cmdbuf_pos
< cmdbuf_len
&& cmdbuf
[cmdbuf_pos
] == ' ')
95 while (cmdbuf_pos
< cmdbuf_len
&& cmdbuf
[cmdbuf_pos
] != ' ')
101 static void delete_left(void)
107 os_memmove(cmdbuf
+ cmdbuf_pos
- 1, cmdbuf
+ cmdbuf_pos
,
108 cmdbuf_len
- cmdbuf_pos
);
115 static void delete_current(void)
117 if (cmdbuf_pos
== cmdbuf_len
)
121 os_memmove(cmdbuf
+ cmdbuf_pos
, cmdbuf
+ cmdbuf_pos
+ 1,
122 cmdbuf_len
- cmdbuf_pos
);
128 static void delete_word(void)
131 while (cmdbuf_len
> 0 && cmdbuf
[cmdbuf_len
- 1] == ' ')
133 while (cmdbuf_len
> 0 && cmdbuf
[cmdbuf_len
- 1] != ' ')
139 static void clear_left(void)
145 os_memmove(cmdbuf
, cmdbuf
+ cmdbuf_pos
, cmdbuf_len
- cmdbuf_pos
);
146 cmdbuf_len
-= cmdbuf_pos
;
152 static void clear_right(void)
154 if (cmdbuf_pos
== cmdbuf_len
)
158 cmdbuf_len
= cmdbuf_pos
;
163 static void history_add(const char *str
)
170 if (history_pos
== 0)
171 prev
= CMD_HISTORY_LEN
- 1;
173 prev
= history_pos
- 1;
174 if (os_strcmp(history_buf
[prev
], str
) == 0)
177 os_strlcpy(history_buf
[history_pos
], str
, CMD_BUF_LEN
);
179 if (history_pos
== CMD_HISTORY_LEN
)
181 history_current
= history_pos
;
185 static void history_prev(void)
189 if (history_current
== (history_pos
+ 1) % CMD_HISTORY_LEN
)
192 pos
= history_current
;
194 if (history_current
== history_pos
&& cmdbuf_len
) {
195 cmdbuf
[cmdbuf_len
] = '\0';
202 pos
= CMD_HISTORY_LEN
- 1;
203 if (history_buf
[pos
][0] == '\0')
205 history_current
= pos
;
208 cmdbuf_len
= cmdbuf_pos
= os_strlen(history_buf
[history_current
]);
209 os_memcpy(cmdbuf
, history_buf
[history_current
], cmdbuf_len
);
214 static void history_next(void)
216 if (history_current
== history_pos
)
220 if (history_current
== CMD_HISTORY_LEN
)
224 cmdbuf_len
= cmdbuf_pos
= os_strlen(history_buf
[history_current
]);
225 os_memcpy(cmdbuf
, history_buf
[history_current
], cmdbuf_len
);
230 static void history_debug_dump(void)
235 p
= (history_pos
+ 1) % CMD_HISTORY_LEN
;
237 printf("[%d%s%s] %s\n",
238 p
, p
== history_current
? "C" : "",
239 p
== history_pos
? "P" : "", history_buf
[p
]);
240 if (p
== history_pos
)
243 if (p
== CMD_HISTORY_LEN
)
250 static void insert_char(int c
)
252 if (c
< 32 && c
> 255) {
258 if (cmdbuf_len
>= (int) sizeof(cmdbuf
) - 1)
260 if (cmdbuf_len
== cmdbuf_pos
) {
261 cmdbuf
[cmdbuf_pos
++] = c
;
266 os_memmove(cmdbuf
+ cmdbuf_pos
+ 1, cmdbuf
+ cmdbuf_pos
,
267 cmdbuf_len
- cmdbuf_pos
);
268 cmdbuf
[cmdbuf_pos
++] = c
;
275 static void process_cmd(void)
278 if (cmdbuf_len
== 0) {
284 cmdbuf
[cmdbuf_len
] = '\0';
288 edit_cmd_cb(edit_cb_ctx
, cmdbuf
);
294 static void free_completions(char **c
)
299 for (i
= 0; c
[i
]; i
++)
305 static int filter_strings(char **c
, char *str
, size_t len
)
309 for (i
= 0, j
= 0; c
[j
]; j
++) {
310 if (os_strncasecmp(c
[j
], str
, len
) == 0) {
326 static int common_len(const char *a
, const char *b
)
329 while (a
[len
] && a
[len
] == b
[len
])
335 static int max_common_length(char **c
)
339 len
= os_strlen(c
[0]);
340 for (i
= 1; c
[i
]; i
++) {
341 int same
= common_len(c
[0], c
[i
]);
350 static void complete(int list
)
355 int room
, plen
, add_space
;
357 if (edit_completion_cb
== NULL
)
360 cmdbuf
[cmdbuf_len
] = '\0';
361 c
= edit_completion_cb(edit_cb_ctx
, cmdbuf
, cmdbuf_pos
);
367 while (start
> 0 && cmdbuf
[start
- 1] != ' ')
371 count
= filter_strings(c
, &cmdbuf
[start
], plen
);
377 len
= max_common_length(c
);
382 for (i
= 0; c
[i
]; i
++)
383 printf("%s%s", i
> 0 ? " " : "", c
[i
]);
392 room
= sizeof(cmdbuf
) - 1 - cmdbuf_len
;
395 add_space
= count
== 1 && len
< room
;
397 os_memmove(cmdbuf
+ cmdbuf_pos
+ len
, cmdbuf
+ cmdbuf_pos
,
398 cmdbuf_len
- cmdbuf_pos
+ add_space
);
399 os_memcpy(&cmdbuf
[cmdbuf_pos
- plen
], c
[0], plen
+ len
);
401 cmdbuf
[cmdbuf_pos
+ len
] = ' ';
403 cmdbuf_pos
+= len
+ add_space
;
404 cmdbuf_len
+= len
+ add_space
;
412 static void edit_read_char(int sock
, void *eloop_ctx
, void *sock_ctx
)
415 unsigned char buf
[1];
418 static char esc_buf
[6];
419 static int last_tab
= 0;
421 res
= read(sock
, buf
, 1);
425 edit_eof_cb(edit_cb_ctx
);
434 printf("{ESC%s}[0]\n", esc_buf
);
445 if (esc
== 2 && esc_buf
[0] == '[' && c
>= 'A' && c
<= 'Z') {
453 case 'C': /* right */
460 printf("{ESC%s}[1]\n", esc_buf
);
468 if (esc
> 1 && esc_buf
[0] == '[') {
469 if ((c
>= '0' && c
<= '9') || c
== ';')
472 if (esc_buf
[1] == '1' && esc_buf
[2] == ';' &&
474 switch (esc_buf
[4]) {
475 case 'A': /* Ctrl-Up */
476 case 'B': /* Ctrl-Down */
478 case 'C': /* Ctrl-Right */
481 case 'D': /* Ctrl-Left */
485 printf("{ESC%s}[2]\n", esc_buf
);
495 switch (atoi(&esc_buf
[1])) {
501 case 5: /* Page Up */
502 case 6: /* Page Down */
513 printf("{ESC%s}[3]\n", esc_buf
);
519 printf("{ESC%s}[4]\n", esc_buf
);
528 if (esc
> 1 && esc_buf
[0] == 'O') {
529 switch (esc_buf
[1]) {
537 history_debug_dump();
544 printf("{ESC%s}[5]\n", esc_buf
);
553 printf("{ESC%s}[6]\n", esc_buf
);
564 if (cmdbuf_len
> 0) {
569 edit_eof_cb(edit_cb_ctx
);
574 case 8: /* ^H = BS */
577 case 9: /* ^I = TAB */
599 /* TODO: search history */
620 int edit_init(void (*cmd_cb
)(void *ctx
, char *cmd
),
621 void (*eof_cb
)(void *ctx
),
624 os_memset(history_buf
, 0, sizeof(history_buf
));
627 edit_cmd_cb
= cmd_cb
;
628 edit_eof_cb
= eof_cb
;
630 tcgetattr(STDIN_FILENO
, &prevt
);
632 newt
.c_lflag
&= ~(ICANON
| ECHO
);
633 tcsetattr(STDIN_FILENO
, TCSANOW
, &newt
);
635 eloop_register_read_sock(STDIN_FILENO
, edit_read_char
, NULL
, NULL
);
644 void edit_deinit(void)
646 eloop_unregister_read_sock(STDIN_FILENO
);
647 tcsetattr(STDIN_FILENO
, TCSANOW
, &prevt
);
651 void edit_redraw(void)
654 cmdbuf
[cmdbuf_len
] = '\0';
655 printf("\r> %s", cmdbuf
);
656 if (cmdbuf_pos
!= cmdbuf_len
) {
657 tmp
= cmdbuf
[cmdbuf_pos
];
658 cmdbuf
[cmdbuf_pos
] = '\0';
659 printf("\r> %s", cmdbuf
);
660 cmdbuf
[cmdbuf_pos
] = tmp
;
666 void edit_set_filter_history_cb(int (*cb
)(void *ctx
, const char *cmd
))
671 void edit_set_completion_cb(char ** (*cb
)(void *ctx
, const char *cmd
, int pos
))
673 edit_completion_cb
= cb
;