2 * Copyright (c) <2010>, Intel Corporation
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
17 * - Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
32 * OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
37 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions are met:
41 * * Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * * Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * * Neither the name of the University of California, Berkeley nor the
47 * names of its contributors may be used to endorse or promote products
48 * derived from this software without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
51 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
52 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
53 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
54 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
55 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
59 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 #include "cmdline_cirbuf.h"
70 #include "cmdline_rdline.h"
72 static void rdline_puts(struct rdline *rdl, const char *buf);
73 static void rdline_miniprintf(struct rdline *rdl,
74 const char *buf, unsigned int val);
76 #ifndef NO_RDLINE_HISTORY
77 static void rdline_remove_old_history_item(struct rdline *rdl);
78 static void rdline_remove_first_history_item(struct rdline *rdl);
79 static unsigned int rdline_get_history_size(struct rdline *rdl);
80 #endif /* !NO_RDLINE_HISTORY */
83 /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
94 void rdline_init(struct rdline *rdl,
95 rdline_write_char_t *write_char,
96 rdline_validate_t *validate,
97 rdline_complete_t *complete)
99 memset(rdl, 0, sizeof(*rdl));
100 rdl->validate = validate;
101 rdl->complete = complete;
102 rdl->write_char = write_char;
103 rdl->status = RDLINE_INIT;
104 #ifndef NO_RDLINE_HISTORY
105 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
106 #endif /* !NO_RDLINE_HISTORY */
110 rdline_newline(struct rdline *rdl, const char *prompt)
114 vt100_init(&rdl->vt100);
115 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
116 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
118 if (prompt != rdl->prompt)
119 memcpy(rdl->prompt, prompt, sizeof(rdl->prompt)-1);
120 rdl->prompt_size = strlen(prompt);
122 for (i=0 ; i<rdl->prompt_size ; i++)
123 rdl->write_char(rdl, rdl->prompt[i]);
124 rdl->status = RDLINE_RUNNING;
126 #ifndef NO_RDLINE_HISTORY
127 rdl->history_cur_line = -1;
128 #endif /* !NO_RDLINE_HISTORY */
132 rdline_stop(struct rdline *rdl)
134 rdl->status = RDLINE_INIT;
138 rdline_restart(struct rdline *rdl)
140 rdl->status = RDLINE_RUNNING;
144 rdline_get_buffer(struct rdline *rdl)
146 unsigned int len_l, len_r;
147 cirbuf_align_left(&rdl->left);
148 cirbuf_align_left(&rdl->right);
150 len_l = CIRBUF_GET_LEN(&rdl->left);
151 len_r = CIRBUF_GET_LEN(&rdl->right);
152 memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
154 rdl->left_buf[len_l + len_r] = '\n';
155 rdl->left_buf[len_l + len_r + 1] = '\0';
156 return rdl->left_buf;
160 display_right_buffer(struct rdline *rdl)
165 rdline_puts(rdl, vt100_clear_right);
166 if (!CIRBUF_IS_EMPTY(&rdl->right)) {
167 CIRBUF_FOREACH(&rdl->right, i, tmp) {
168 rdl->write_char(rdl, tmp);
170 rdline_miniprintf(rdl, vt100_multi_left,
171 CIRBUF_GET_LEN(&rdl->right));
175 void rdline_redisplay(struct rdline *rdl)
180 rdline_puts(rdl, vt100_home);
181 for (i=0 ; i<rdl->prompt_size ; i++)
182 rdl->write_char(rdl, rdl->prompt[i]);
183 CIRBUF_FOREACH(&rdl->left, i, tmp) {
184 rdl->write_char(rdl, tmp);
186 display_right_buffer(rdl);
190 rdline_char_in(struct rdline *rdl, char c)
195 #ifndef NO_RDLINE_HISTORY
199 if (rdl->status != RDLINE_RUNNING)
202 cmd = vt100_parser(&rdl->vt100, c);
208 case CMDLINE_KEY_CTRL_B:
209 case CMDLINE_KEY_LEFT_ARR:
210 if (CIRBUF_IS_EMPTY(&rdl->left))
212 tmp = cirbuf_get_tail(&rdl->left);
213 cirbuf_del_tail(&rdl->left);
214 cirbuf_add_head(&rdl->right, tmp);
215 rdline_puts(rdl, vt100_left_arr);
218 case CMDLINE_KEY_CTRL_F:
219 case CMDLINE_KEY_RIGHT_ARR:
220 if (CIRBUF_IS_EMPTY(&rdl->right))
222 tmp = cirbuf_get_head(&rdl->right);
223 cirbuf_del_head(&rdl->right);
224 cirbuf_add_tail(&rdl->left, tmp);
225 rdline_puts(rdl, vt100_right_arr);
228 case CMDLINE_KEY_WLEFT:
229 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
230 (tmp = cirbuf_get_tail(&rdl->left)) &&
232 rdline_puts(rdl, vt100_left_arr);
233 cirbuf_del_tail(&rdl->left);
234 cirbuf_add_head(&rdl->right, tmp);
236 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
237 (tmp = cirbuf_get_tail(&rdl->left)) &&
239 rdline_puts(rdl, vt100_left_arr);
240 cirbuf_del_tail(&rdl->left);
241 cirbuf_add_head(&rdl->right, tmp);
245 case CMDLINE_KEY_WRIGHT:
246 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
247 (tmp = cirbuf_get_head(&rdl->right)) &&
249 rdline_puts(rdl, vt100_right_arr);
250 cirbuf_del_head(&rdl->right);
251 cirbuf_add_tail(&rdl->left, tmp);
253 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
254 (tmp = cirbuf_get_head(&rdl->right)) &&
256 rdline_puts(rdl, vt100_right_arr);
257 cirbuf_del_head(&rdl->right);
258 cirbuf_add_tail(&rdl->left, tmp);
262 case CMDLINE_KEY_BKSPACE:
263 if(!cirbuf_del_tail_safe(&rdl->left)) {
264 rdline_puts(rdl, vt100_bs);
265 display_right_buffer(rdl);
269 case CMDLINE_KEY_META_BKSPACE:
270 while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
271 rdline_puts(rdl, vt100_bs);
272 cirbuf_del_tail(&rdl->left);
274 while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank2(cirbuf_get_tail(&rdl->left))) {
275 rdline_puts(rdl, vt100_bs);
276 cirbuf_del_tail(&rdl->left);
278 display_right_buffer(rdl);
281 case CMDLINE_KEY_SUPPR:
282 case CMDLINE_KEY_CTRL_D:
283 if (cmd == CMDLINE_KEY_CTRL_D &&
284 CIRBUF_IS_EMPTY(&rdl->left) &&
285 CIRBUF_IS_EMPTY(&rdl->right)) {
288 if (!cirbuf_del_head_safe(&rdl->right)) {
289 display_right_buffer(rdl);
293 case CMDLINE_KEY_CTRL_A:
294 if (CIRBUF_IS_EMPTY(&rdl->left))
296 rdline_miniprintf(rdl, vt100_multi_left,
297 CIRBUF_GET_LEN(&rdl->left));
298 while (! CIRBUF_IS_EMPTY(&rdl->left)) {
299 tmp = cirbuf_get_tail(&rdl->left);
300 cirbuf_del_tail(&rdl->left);
301 cirbuf_add_head(&rdl->right, tmp);
305 case CMDLINE_KEY_CTRL_E:
306 if (CIRBUF_IS_EMPTY(&rdl->right))
308 rdline_miniprintf(rdl, vt100_multi_right,
309 CIRBUF_GET_LEN(&rdl->right));
310 while (! CIRBUF_IS_EMPTY(&rdl->right)) {
311 tmp = cirbuf_get_head(&rdl->right);
312 cirbuf_del_head(&rdl->right);
313 cirbuf_add_tail(&rdl->left, tmp);
317 #ifndef NO_RDLINE_KILL_BUF
318 case CMDLINE_KEY_CTRL_K:
319 cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
320 rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
321 cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
322 rdline_puts(rdl, vt100_clear_right);
325 case CMDLINE_KEY_CTRL_Y:
327 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
329 i < rdl->kill_size) {
330 cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
331 rdl->write_char(rdl, rdl->kill_buf[i]);
334 display_right_buffer(rdl);
336 #endif /* !NO_RDLINE_KILL_BUF */
338 case CMDLINE_KEY_CTRL_C:
339 rdline_puts(rdl, "\r\n");
340 rdline_newline(rdl, rdl->prompt);
343 case CMDLINE_KEY_CTRL_L:
344 rdline_redisplay(rdl);
347 case CMDLINE_KEY_TAB:
348 case CMDLINE_KEY_HELP:
349 cirbuf_align_left(&rdl->left);
350 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
352 char tmp_buf[BUFSIZ];
355 unsigned int tmp_size;
357 if (cmd == CMDLINE_KEY_TAB)
362 /* see in parse.h for help on complete() */
363 ret = rdl->complete(rdl, rdl->left_buf,
364 tmp_buf, sizeof(tmp_buf),
366 /* no completion or error */
371 tmp_size = strlen(tmp_buf);
375 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
378 cirbuf_add_tail(&rdl->left, tmp_buf[i]);
379 rdl->write_char(rdl, tmp_buf[i]);
382 display_right_buffer(rdl);
387 rdline_puts(rdl, "\r\n");
389 rdl->write_char(rdl, ' ');
390 for (i=0 ; tmp_buf[i] ; i++)
391 rdl->write_char(rdl, tmp_buf[i]);
392 rdline_puts(rdl, "\r\n");
393 ret = rdl->complete(rdl, rdl->left_buf,
394 tmp_buf, sizeof(tmp_buf),
398 rdline_redisplay(rdl);
402 case CMDLINE_KEY_RETURN:
403 case CMDLINE_KEY_RETURN2:
404 rdline_get_buffer(rdl);
405 rdl->status = RDLINE_INIT;
406 rdline_puts(rdl, "\r\n");
407 #ifndef NO_RDLINE_HISTORY
408 if (rdl->history_cur_line != -1)
409 rdline_remove_first_history_item(rdl);
413 rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
416 #ifndef NO_RDLINE_HISTORY
417 case CMDLINE_KEY_UP_ARR:
418 if (rdl->history_cur_line == 0) {
419 rdline_remove_first_history_item(rdl);
421 if (rdl->history_cur_line <= 0) {
422 rdline_add_history(rdl, rdline_get_buffer(rdl));
423 rdl->history_cur_line = 0;
426 buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
430 rdl->history_cur_line ++;
431 vt100_init(&rdl->vt100);
432 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
433 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
434 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
435 rdline_redisplay(rdl);
438 case CMDLINE_KEY_DOWN_ARR:
439 if (rdl->history_cur_line - 1 < 0)
442 rdl->history_cur_line --;
443 buf = rdline_get_history_item(rdl, rdl->history_cur_line);
446 vt100_init(&rdl->vt100);
447 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
448 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
449 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
450 rdline_redisplay(rdl);
453 #endif /* !NO_RDLINE_HISTORY */
467 if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
470 if (cirbuf_add_tail_safe(&rdl->left, c))
473 rdl->write_char(rdl, c);
474 display_right_buffer(rdl);
482 #ifndef NO_RDLINE_HISTORY
484 rdline_remove_old_history_item(struct rdline * rdl)
488 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
489 tmp = cirbuf_get_head(&rdl->history);
490 cirbuf_del_head(&rdl->history);
497 rdline_remove_first_history_item(struct rdline * rdl)
501 if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
505 cirbuf_del_tail(&rdl->history);
508 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
509 tmp = cirbuf_get_tail(&rdl->history);
512 cirbuf_del_tail(&rdl->history);
517 rdline_get_history_size(struct rdline * rdl)
519 unsigned int i, tmp, ret=0;
521 CIRBUF_FOREACH(&rdl->history, i, tmp) {
530 rdline_get_history_item(struct rdline * rdl, unsigned int idx)
532 unsigned int len, i, tmp;
534 len = rdline_get_history_size(rdl);
539 cirbuf_align_left(&rdl->history);
541 CIRBUF_FOREACH(&rdl->history, i, tmp) {
542 if ( idx == len - 1) {
543 return rdl->history_buf + i;
553 rdline_add_history(struct rdline * rdl, const char * buf)
558 for (i=0; i<len ; i++) {
559 if (buf[i] == '\n') {
565 if ( len >= RDLINE_HISTORY_BUF_SIZE )
568 while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
569 rdline_remove_old_history_item(rdl);
572 cirbuf_add_buf_tail(&rdl->history, buf, len);
573 cirbuf_add_tail(&rdl->history, 0);
579 rdline_clear_history(struct rdline * rdl)
581 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
584 #else /* !NO_RDLINE_HISTORY */
586 int rdline_add_history(struct rdline * rdl, const char * buf) {return -1;}
587 void rdline_clear_history(struct rdline * rdl) {}
588 char * rdline_get_history_item(struct rdline * rdl, unsigned int i) {return NULL;}
591 #endif /* !NO_RDLINE_HISTORY */
594 /* STATIC USEFUL FUNCS */
597 rdline_puts(struct rdline * rdl, const char * buf)
600 while ( (c = *(buf++)) != '\0' ) {
601 rdl->write_char(rdl, c);
605 /* a very very basic printf with one arg and one format 'u' */
607 rdline_miniprintf(struct rdline *rdl, const char * buf, unsigned int val)
609 char c, started=0, div=100;
611 while ( (c=*(buf++)) ) {
613 rdl->write_char(rdl, c);
618 rdl->write_char(rdl, '%');
619 rdl->write_char(rdl, c);
622 /* val is never more than 255 */
626 rdl->write_char(rdl, c+'0');