]>
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] != ' ')
135 if (cmdbuf_pos
> cmdbuf_len
)
136 cmdbuf_pos
= cmdbuf_len
;
141 static void clear_left(void)
147 os_memmove(cmdbuf
, cmdbuf
+ cmdbuf_pos
, cmdbuf_len
- cmdbuf_pos
);
148 cmdbuf_len
-= cmdbuf_pos
;
154 static void clear_right(void)
156 if (cmdbuf_pos
== cmdbuf_len
)
160 cmdbuf_len
= cmdbuf_pos
;
165 static void history_add(const char *str
)
172 if (history_pos
== 0)
173 prev
= CMD_HISTORY_LEN
- 1;
175 prev
= history_pos
- 1;
176 if (os_strcmp(history_buf
[prev
], str
) == 0)
179 os_strlcpy(history_buf
[history_pos
], str
, CMD_BUF_LEN
);
181 if (history_pos
== CMD_HISTORY_LEN
)
183 history_current
= history_pos
;
187 static void history_prev(void)
191 if (history_current
== (history_pos
+ 1) % CMD_HISTORY_LEN
)
194 pos
= history_current
;
196 if (history_current
== history_pos
&& cmdbuf_len
) {
197 cmdbuf
[cmdbuf_len
] = '\0';
204 pos
= CMD_HISTORY_LEN
- 1;
205 if (history_buf
[pos
][0] == '\0')
207 history_current
= pos
;
210 cmdbuf_len
= cmdbuf_pos
= os_strlen(history_buf
[history_current
]);
211 os_memcpy(cmdbuf
, history_buf
[history_current
], cmdbuf_len
);
216 static void history_next(void)
218 if (history_current
== history_pos
)
222 if (history_current
== CMD_HISTORY_LEN
)
226 cmdbuf_len
= cmdbuf_pos
= os_strlen(history_buf
[history_current
]);
227 os_memcpy(cmdbuf
, history_buf
[history_current
], cmdbuf_len
);
232 static void history_debug_dump(void)
237 p
= (history_pos
+ 1) % CMD_HISTORY_LEN
;
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
)
245 if (p
== CMD_HISTORY_LEN
)
252 static void insert_char(int c
)
254 if (c
< 32 && c
> 255) {
260 if (cmdbuf_len
>= (int) sizeof(cmdbuf
) - 1)
262 if (cmdbuf_len
== cmdbuf_pos
) {
263 cmdbuf
[cmdbuf_pos
++] = c
;
268 os_memmove(cmdbuf
+ cmdbuf_pos
+ 1, cmdbuf
+ cmdbuf_pos
,
269 cmdbuf_len
- cmdbuf_pos
);
270 cmdbuf
[cmdbuf_pos
++] = c
;
277 static void process_cmd(void)
280 if (cmdbuf_len
== 0) {
286 cmdbuf
[cmdbuf_len
] = '\0';
290 edit_cmd_cb(edit_cb_ctx
, cmdbuf
);
296 static void free_completions(char **c
)
301 for (i
= 0; c
[i
]; i
++)
307 static int filter_strings(char **c
, char *str
, size_t len
)
311 for (i
= 0, j
= 0; c
[j
]; j
++) {
312 if (os_strncasecmp(c
[j
], str
, len
) == 0) {
328 static int common_len(const char *a
, const char *b
)
331 while (a
[len
] && a
[len
] == b
[len
])
337 static int max_common_length(char **c
)
341 len
= os_strlen(c
[0]);
342 for (i
= 1; c
[i
]; i
++) {
343 int same
= common_len(c
[0], c
[i
]);
352 static void complete(int list
)
357 int room
, plen
, add_space
;
359 if (edit_completion_cb
== NULL
)
362 cmdbuf
[cmdbuf_len
] = '\0';
363 c
= edit_completion_cb(edit_cb_ctx
, cmdbuf
, cmdbuf_pos
);
369 while (start
> 0 && cmdbuf
[start
- 1] != ' ')
373 count
= filter_strings(c
, &cmdbuf
[start
], plen
);
379 len
= max_common_length(c
);
384 for (i
= 0; c
[i
]; i
++)
385 printf("%s%s", i
> 0 ? " " : "", c
[i
]);
394 room
= sizeof(cmdbuf
) - 1 - cmdbuf_len
;
397 add_space
= count
== 1 && len
< room
;
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
);
403 cmdbuf
[cmdbuf_pos
+ len
] = ' ';
405 cmdbuf_pos
+= len
+ add_space
;
406 cmdbuf_len
+= len
+ add_space
;
414 static void edit_read_char(int sock
, void *eloop_ctx
, void *sock_ctx
)
417 unsigned char buf
[1];
420 static char esc_buf
[6];
421 static int last_tab
= 0;
423 res
= read(sock
, buf
, 1);
427 edit_eof_cb(edit_cb_ctx
);
436 printf("{ESC%s}[0]\n", esc_buf
);
447 if (esc
== 2 && esc_buf
[0] == '[' && c
>= 'A' && c
<= 'Z') {
455 case 'C': /* right */
462 printf("{ESC%s}[1]\n", esc_buf
);
470 if (esc
> 1 && esc_buf
[0] == '[') {
471 if ((c
>= '0' && c
<= '9') || c
== ';')
474 if (esc_buf
[1] == '1' && esc_buf
[2] == ';' &&
476 switch (esc_buf
[4]) {
477 case 'A': /* Ctrl-Up */
478 case 'B': /* Ctrl-Down */
480 case 'C': /* Ctrl-Right */
483 case 'D': /* Ctrl-Left */
487 printf("{ESC%s}[2]\n", esc_buf
);
497 switch (atoi(&esc_buf
[1])) {
503 case 5: /* Page Up */
504 case 6: /* Page Down */
515 printf("{ESC%s}[3]\n", esc_buf
);
521 printf("{ESC%s}[4]\n", esc_buf
);
530 if (esc
> 1 && esc_buf
[0] == 'O') {
531 switch (esc_buf
[1]) {
539 history_debug_dump();
546 printf("{ESC%s}[5]\n", esc_buf
);
555 printf("{ESC%s}[6]\n", esc_buf
);
566 if (cmdbuf_len
> 0) {
571 edit_eof_cb(edit_cb_ctx
);
576 case 8: /* ^H = BS */
579 case 9: /* ^I = TAB */
601 /* TODO: search history */
622 int edit_init(void (*cmd_cb
)(void *ctx
, char *cmd
),
623 void (*eof_cb
)(void *ctx
),
626 os_memset(history_buf
, 0, sizeof(history_buf
));
629 edit_cmd_cb
= cmd_cb
;
630 edit_eof_cb
= eof_cb
;
632 tcgetattr(STDIN_FILENO
, &prevt
);
634 newt
.c_lflag
&= ~(ICANON
| ECHO
);
635 tcsetattr(STDIN_FILENO
, TCSANOW
, &newt
);
637 eloop_register_read_sock(STDIN_FILENO
, edit_read_char
, NULL
, NULL
);
646 void edit_deinit(void)
648 eloop_unregister_read_sock(STDIN_FILENO
);
649 tcsetattr(STDIN_FILENO
, TCSANOW
, &prevt
);
653 void edit_redraw(void)
656 cmdbuf
[cmdbuf_len
] = '\0';
657 printf("\r> %s", cmdbuf
);
658 if (cmdbuf_pos
!= cmdbuf_len
) {
659 tmp
= cmdbuf
[cmdbuf_pos
];
660 cmdbuf
[cmdbuf_pos
] = '\0';
661 printf("\r> %s", cmdbuf
);
662 cmdbuf
[cmdbuf_pos
] = tmp
;
668 void edit_set_filter_history_cb(int (*cb
)(void *ctx
, const char *cmd
))
673 void edit_set_completion_cb(char ** (*cb
)(void *ctx
, const char *cmd
, int pos
))
675 edit_completion_cb
= cb
;