4 * Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * 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 FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * version: DPDK.L.1.2.3-3
37 * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
38 * All rights reserved.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions are met:
42 * * Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * * Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * * Neither the name of the University of California, Berkeley nor the
48 * names of its contributors may be used to endorse or promote products
49 * derived from this software without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
52 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
53 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
54 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
55 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
56 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
58 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 #include "cmdline_cirbuf.h"
71 #include "cmdline_rdline.h"
73 static void rdline_puts(struct rdline *rdl, const char *buf);
74 static void rdline_miniprintf(struct rdline *rdl,
75 const char *buf, unsigned int val);
77 #ifndef NO_RDLINE_HISTORY
78 static void rdline_remove_old_history_item(struct rdline *rdl);
79 static void rdline_remove_first_history_item(struct rdline *rdl);
80 static unsigned int rdline_get_history_size(struct rdline *rdl);
81 #endif /* !NO_RDLINE_HISTORY */
84 /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
96 rdline_init(struct rdline *rdl,
97 rdline_write_char_t *write_char,
98 rdline_validate_t *validate,
99 rdline_complete_t *complete)
101 memset(rdl, 0, sizeof(*rdl));
102 rdl->validate = validate;
103 rdl->complete = complete;
104 rdl->write_char = write_char;
105 rdl->status = RDLINE_INIT;
106 #ifndef NO_RDLINE_HISTORY
107 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
108 #endif /* !NO_RDLINE_HISTORY */
112 rdline_newline(struct rdline *rdl, const char *prompt)
116 vt100_init(&rdl->vt100);
117 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
118 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
120 if (prompt != rdl->prompt)
121 memcpy(rdl->prompt, prompt, sizeof(rdl->prompt)-1);
122 rdl->prompt_size = strnlen(prompt, RDLINE_PROMPT_SIZE);
124 for (i=0 ; i<rdl->prompt_size ; i++)
125 rdl->write_char(rdl, rdl->prompt[i]);
126 rdl->status = RDLINE_RUNNING;
128 #ifndef NO_RDLINE_HISTORY
129 rdl->history_cur_line = -1;
130 #endif /* !NO_RDLINE_HISTORY */
134 rdline_stop(struct rdline *rdl)
136 rdl->status = RDLINE_INIT;
140 rdline_quit(struct rdline *rdl)
142 rdl->status = RDLINE_EXITED;
146 rdline_restart(struct rdline *rdl)
148 rdl->status = RDLINE_RUNNING;
152 rdline_reset(struct rdline *rdl)
154 vt100_init(&rdl->vt100);
155 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
156 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
158 rdl->status = RDLINE_RUNNING;
160 #ifndef NO_RDLINE_HISTORY
161 rdl->history_cur_line = -1;
162 #endif /* !NO_RDLINE_HISTORY */
166 rdline_get_buffer(struct rdline *rdl)
168 unsigned int len_l, len_r;
169 cirbuf_align_left(&rdl->left);
170 cirbuf_align_left(&rdl->right);
172 len_l = CIRBUF_GET_LEN(&rdl->left);
173 len_r = CIRBUF_GET_LEN(&rdl->right);
174 memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
176 rdl->left_buf[len_l + len_r] = '\n';
177 rdl->left_buf[len_l + len_r + 1] = '\0';
178 return rdl->left_buf;
182 display_right_buffer(struct rdline *rdl, int force)
187 if (!force && CIRBUF_IS_EMPTY(&rdl->right))
190 rdline_puts(rdl, vt100_clear_right);
191 CIRBUF_FOREACH(&rdl->right, i, tmp) {
192 rdl->write_char(rdl, tmp);
194 if (!CIRBUF_IS_EMPTY(&rdl->right))
195 rdline_miniprintf(rdl, vt100_multi_left,
196 CIRBUF_GET_LEN(&rdl->right));
200 rdline_redisplay(struct rdline *rdl)
205 rdline_puts(rdl, vt100_home);
206 for (i=0 ; i<rdl->prompt_size ; i++)
207 rdl->write_char(rdl, rdl->prompt[i]);
208 CIRBUF_FOREACH(&rdl->left, i, tmp) {
209 rdl->write_char(rdl, tmp);
211 display_right_buffer(rdl, 1);
215 rdline_char_in(struct rdline *rdl, char c)
220 #ifndef NO_RDLINE_HISTORY
224 if (rdl->status == RDLINE_EXITED)
225 return RDLINE_RES_EXITED;
226 if (rdl->status != RDLINE_RUNNING)
227 return RDLINE_RES_NOT_RUNNING;
229 cmd = vt100_parser(&rdl->vt100, c);
231 return RDLINE_RES_SUCCESS;
235 case CMDLINE_KEY_CTRL_B:
236 case CMDLINE_KEY_LEFT_ARR:
237 if (CIRBUF_IS_EMPTY(&rdl->left))
239 tmp = cirbuf_get_tail(&rdl->left);
240 cirbuf_del_tail(&rdl->left);
241 cirbuf_add_head(&rdl->right, tmp);
242 rdline_puts(rdl, vt100_left_arr);
245 case CMDLINE_KEY_CTRL_F:
246 case CMDLINE_KEY_RIGHT_ARR:
247 if (CIRBUF_IS_EMPTY(&rdl->right))
249 tmp = cirbuf_get_head(&rdl->right);
250 cirbuf_del_head(&rdl->right);
251 cirbuf_add_tail(&rdl->left, tmp);
252 rdline_puts(rdl, vt100_right_arr);
255 case CMDLINE_KEY_WLEFT:
256 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
257 (tmp = cirbuf_get_tail(&rdl->left)) &&
259 rdline_puts(rdl, vt100_left_arr);
260 cirbuf_del_tail(&rdl->left);
261 cirbuf_add_head(&rdl->right, tmp);
263 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
264 (tmp = cirbuf_get_tail(&rdl->left)) &&
266 rdline_puts(rdl, vt100_left_arr);
267 cirbuf_del_tail(&rdl->left);
268 cirbuf_add_head(&rdl->right, tmp);
272 case CMDLINE_KEY_WRIGHT:
273 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
274 (tmp = cirbuf_get_head(&rdl->right)) &&
276 rdline_puts(rdl, vt100_right_arr);
277 cirbuf_del_head(&rdl->right);
278 cirbuf_add_tail(&rdl->left, tmp);
280 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
281 (tmp = cirbuf_get_head(&rdl->right)) &&
283 rdline_puts(rdl, vt100_right_arr);
284 cirbuf_del_head(&rdl->right);
285 cirbuf_add_tail(&rdl->left, tmp);
289 case CMDLINE_KEY_BKSPACE:
290 if(!cirbuf_del_tail_safe(&rdl->left)) {
291 rdline_puts(rdl, vt100_bs);
292 display_right_buffer(rdl, 1);
296 case CMDLINE_KEY_META_BKSPACE:
297 case CMDLINE_KEY_CTRL_W:
298 while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
299 rdline_puts(rdl, vt100_bs);
300 cirbuf_del_tail(&rdl->left);
302 while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank2(cirbuf_get_tail(&rdl->left))) {
303 rdline_puts(rdl, vt100_bs);
304 cirbuf_del_tail(&rdl->left);
306 display_right_buffer(rdl, 1);
309 case CMDLINE_KEY_META_D:
310 while (! CIRBUF_IS_EMPTY(&rdl->right) && isblank2(cirbuf_get_head(&rdl->right)))
311 cirbuf_del_head(&rdl->right);
312 while (! CIRBUF_IS_EMPTY(&rdl->right) && !isblank2(cirbuf_get_head(&rdl->right)))
313 cirbuf_del_head(&rdl->right);
314 display_right_buffer(rdl, 1);
317 case CMDLINE_KEY_SUPPR:
318 case CMDLINE_KEY_CTRL_D:
319 if (cmd == CMDLINE_KEY_CTRL_D &&
320 CIRBUF_IS_EMPTY(&rdl->left) &&
321 CIRBUF_IS_EMPTY(&rdl->right)) {
322 return RDLINE_RES_EOF;
324 if (!cirbuf_del_head_safe(&rdl->right)) {
325 display_right_buffer(rdl, 1);
329 case CMDLINE_KEY_CTRL_A:
330 if (CIRBUF_IS_EMPTY(&rdl->left))
332 rdline_miniprintf(rdl, vt100_multi_left,
333 CIRBUF_GET_LEN(&rdl->left));
334 while (! CIRBUF_IS_EMPTY(&rdl->left)) {
335 tmp = cirbuf_get_tail(&rdl->left);
336 cirbuf_del_tail(&rdl->left);
337 cirbuf_add_head(&rdl->right, tmp);
341 case CMDLINE_KEY_CTRL_E:
342 if (CIRBUF_IS_EMPTY(&rdl->right))
344 rdline_miniprintf(rdl, vt100_multi_right,
345 CIRBUF_GET_LEN(&rdl->right));
346 while (! CIRBUF_IS_EMPTY(&rdl->right)) {
347 tmp = cirbuf_get_head(&rdl->right);
348 cirbuf_del_head(&rdl->right);
349 cirbuf_add_tail(&rdl->left, tmp);
353 #ifndef NO_RDLINE_KILL_BUF
354 case CMDLINE_KEY_CTRL_K:
355 cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
356 rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
357 cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
358 rdline_puts(rdl, vt100_clear_right);
361 case CMDLINE_KEY_CTRL_Y:
363 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
365 i < rdl->kill_size) {
366 cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
367 rdl->write_char(rdl, rdl->kill_buf[i]);
370 display_right_buffer(rdl, 0);
372 #endif /* !NO_RDLINE_KILL_BUF */
374 case CMDLINE_KEY_CTRL_C:
375 rdline_puts(rdl, "\r\n");
376 rdline_newline(rdl, rdl->prompt);
379 case CMDLINE_KEY_CTRL_L:
380 rdline_redisplay(rdl);
383 case CMDLINE_KEY_TAB:
384 case CMDLINE_KEY_HELP:
385 cirbuf_align_left(&rdl->left);
386 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
388 char tmp_buf[BUFSIZ];
391 unsigned int tmp_size;
393 if (cmd == CMDLINE_KEY_TAB)
398 /* see in parse.h for help on complete() */
399 ret = rdl->complete(rdl, rdl->left_buf,
400 tmp_buf, sizeof(tmp_buf),
402 /* no completion or error */
404 return RDLINE_RES_COMPLETE;
407 tmp_size = strnlen(tmp_buf, sizeof(tmp_buf));
409 if (ret == RDLINE_RES_COMPLETE) {
411 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
414 cirbuf_add_tail(&rdl->left, tmp_buf[i]);
415 rdl->write_char(rdl, tmp_buf[i]);
418 display_right_buffer(rdl, 1);
419 return RDLINE_RES_COMPLETE; /* ?? */
423 rdline_puts(rdl, "\r\n");
425 rdl->write_char(rdl, ' ');
426 for (i=0 ; tmp_buf[i] ; i++)
427 rdl->write_char(rdl, tmp_buf[i]);
428 rdline_puts(rdl, "\r\n");
429 ret = rdl->complete(rdl, rdl->left_buf,
430 tmp_buf, sizeof(tmp_buf),
434 rdline_redisplay(rdl);
436 return RDLINE_RES_COMPLETE;
438 case CMDLINE_KEY_RETURN:
439 case CMDLINE_KEY_RETURN2:
440 rdline_get_buffer(rdl);
441 rdl->status = RDLINE_INIT;
442 rdline_puts(rdl, "\r\n");
443 #ifndef NO_RDLINE_HISTORY
444 if (rdl->history_cur_line != -1)
445 rdline_remove_first_history_item(rdl);
449 rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
450 /* user may have stopped rdline */
451 if (rdl->status == RDLINE_EXITED)
452 return RDLINE_RES_EXITED;
453 return RDLINE_RES_VALIDATED;
455 #ifndef NO_RDLINE_HISTORY
456 case CMDLINE_KEY_UP_ARR:
457 case CMDLINE_KEY_CTRL_P:
458 if (rdl->history_cur_line == 0) {
459 rdline_remove_first_history_item(rdl);
461 if (rdl->history_cur_line <= 0) {
462 rdline_add_history(rdl, rdline_get_buffer(rdl));
463 rdl->history_cur_line = 0;
466 buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
470 rdl->history_cur_line ++;
471 vt100_init(&rdl->vt100);
472 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
473 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
474 cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
475 rdline_redisplay(rdl);
478 case CMDLINE_KEY_DOWN_ARR:
479 case CMDLINE_KEY_CTRL_N:
480 if (rdl->history_cur_line - 1 < 0)
483 rdl->history_cur_line --;
484 buf = rdline_get_history_item(rdl, rdl->history_cur_line);
487 vt100_init(&rdl->vt100);
488 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
489 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
490 cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
491 rdline_redisplay(rdl);
494 #endif /* !NO_RDLINE_HISTORY */
501 return RDLINE_RES_SUCCESS;
504 if (!isprint((int)c))
505 return RDLINE_RES_SUCCESS;
508 if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
509 return RDLINE_RES_SUCCESS;
511 if (cirbuf_add_tail_safe(&rdl->left, c))
512 return RDLINE_RES_SUCCESS;
514 rdl->write_char(rdl, c);
515 display_right_buffer(rdl, 0);
517 return RDLINE_RES_SUCCESS;
523 #ifndef NO_RDLINE_HISTORY
525 rdline_remove_old_history_item(struct rdline * rdl)
529 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
530 tmp = cirbuf_get_head(&rdl->history);
531 cirbuf_del_head(&rdl->history);
538 rdline_remove_first_history_item(struct rdline * rdl)
542 if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
546 cirbuf_del_tail(&rdl->history);
549 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
550 tmp = cirbuf_get_tail(&rdl->history);
553 cirbuf_del_tail(&rdl->history);
558 rdline_get_history_size(struct rdline * rdl)
560 unsigned int i, tmp, ret=0;
562 CIRBUF_FOREACH(&rdl->history, i, tmp) {
571 rdline_get_history_item(struct rdline * rdl, unsigned int idx)
573 unsigned int len, i, tmp;
575 len = rdline_get_history_size(rdl);
580 cirbuf_align_left(&rdl->history);
582 CIRBUF_FOREACH(&rdl->history, i, tmp) {
583 if ( idx == len - 1) {
584 return rdl->history_buf + i;
594 rdline_add_history(struct rdline * rdl, const char * buf)
598 len = strnlen(buf, RDLINE_BUF_SIZE);
599 for (i=0; i<len ; i++) {
600 if (buf[i] == '\n') {
606 if ( len >= RDLINE_HISTORY_BUF_SIZE )
609 while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
610 rdline_remove_old_history_item(rdl);
613 cirbuf_add_buf_tail(&rdl->history, buf, len);
614 cirbuf_add_tail(&rdl->history, 0);
620 rdline_clear_history(struct rdline * rdl)
622 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
625 #else /* !NO_RDLINE_HISTORY */
627 int rdline_add_history(struct rdline * rdl, const char * buf) {return -1;}
628 void rdline_clear_history(struct rdline * rdl) {}
629 char * rdline_get_history_item(struct rdline * rdl, unsigned int i) {return NULL;}
632 #endif /* !NO_RDLINE_HISTORY */
635 /* STATIC USEFUL FUNCS */
638 rdline_puts(struct rdline * rdl, const char * buf)
641 while ( (c = *(buf++)) != '\0' ) {
642 rdl->write_char(rdl, c);
646 /* a very very basic printf with one arg and one format 'u' */
648 rdline_miniprintf(struct rdline *rdl, const char * buf, unsigned int val)
650 char c, started=0, div=100;
652 while ( (c=*(buf++)) ) {
654 rdl->write_char(rdl, c);
659 rdl->write_char(rdl, '%');
660 rdl->write_char(rdl, c);
663 /* val is never more than 255 */
665 c = (char)(val / div);
667 rdl->write_char(rdl, (char)(c+'0'));