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.
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
95 rdline_init(struct rdline *rdl,
96 rdline_write_char_t *write_char,
97 rdline_validate_t *validate,
98 rdline_complete_t *complete)
100 memset(rdl, 0, sizeof(*rdl));
101 rdl->validate = validate;
102 rdl->complete = complete;
103 rdl->write_char = write_char;
104 rdl->status = RDLINE_INIT;
105 #ifndef NO_RDLINE_HISTORY
106 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
107 #endif /* !NO_RDLINE_HISTORY */
111 rdline_newline(struct rdline *rdl, const char *prompt)
115 vt100_init(&rdl->vt100);
116 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
117 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
119 if (prompt != rdl->prompt)
120 memcpy(rdl->prompt, prompt, sizeof(rdl->prompt)-1);
121 rdl->prompt_size = strnlen(prompt, RDLINE_PROMPT_SIZE);
123 for (i=0 ; i<rdl->prompt_size ; i++)
124 rdl->write_char(rdl, rdl->prompt[i]);
125 rdl->status = RDLINE_RUNNING;
127 #ifndef NO_RDLINE_HISTORY
128 rdl->history_cur_line = -1;
129 #endif /* !NO_RDLINE_HISTORY */
133 rdline_stop(struct rdline *rdl)
135 rdl->status = RDLINE_INIT;
139 rdline_quit(struct rdline *rdl)
141 rdl->status = RDLINE_EXITED;
145 rdline_restart(struct rdline *rdl)
147 rdl->status = RDLINE_RUNNING;
151 rdline_reset(struct rdline *rdl)
153 vt100_init(&rdl->vt100);
154 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
155 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
157 rdl->status = RDLINE_RUNNING;
159 #ifndef NO_RDLINE_HISTORY
160 rdl->history_cur_line = -1;
161 #endif /* !NO_RDLINE_HISTORY */
165 rdline_get_buffer(struct rdline *rdl)
167 unsigned int len_l, len_r;
168 cirbuf_align_left(&rdl->left);
169 cirbuf_align_left(&rdl->right);
171 len_l = CIRBUF_GET_LEN(&rdl->left);
172 len_r = CIRBUF_GET_LEN(&rdl->right);
173 memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
175 rdl->left_buf[len_l + len_r] = '\n';
176 rdl->left_buf[len_l + len_r + 1] = '\0';
177 return rdl->left_buf;
181 display_right_buffer(struct rdline *rdl, int force)
186 if (!force && CIRBUF_IS_EMPTY(&rdl->right))
189 rdline_puts(rdl, vt100_clear_right);
190 CIRBUF_FOREACH(&rdl->right, i, tmp) {
191 rdl->write_char(rdl, tmp);
193 if (!CIRBUF_IS_EMPTY(&rdl->right))
194 rdline_miniprintf(rdl, vt100_multi_left,
195 CIRBUF_GET_LEN(&rdl->right));
199 rdline_redisplay(struct rdline *rdl)
204 rdline_puts(rdl, vt100_home);
205 for (i=0 ; i<rdl->prompt_size ; i++)
206 rdl->write_char(rdl, rdl->prompt[i]);
207 CIRBUF_FOREACH(&rdl->left, i, tmp) {
208 rdl->write_char(rdl, tmp);
210 display_right_buffer(rdl, 1);
214 rdline_char_in(struct rdline *rdl, char c)
219 #ifndef NO_RDLINE_HISTORY
223 if (rdl->status == RDLINE_EXITED)
224 return RDLINE_RES_EXITED;
225 if (rdl->status != RDLINE_RUNNING)
226 return RDLINE_RES_NOT_RUNNING;
228 cmd = vt100_parser(&rdl->vt100, c);
230 return RDLINE_RES_SUCCESS;
234 case CMDLINE_KEY_CTRL_B:
235 case CMDLINE_KEY_LEFT_ARR:
236 if (CIRBUF_IS_EMPTY(&rdl->left))
238 tmp = cirbuf_get_tail(&rdl->left);
239 cirbuf_del_tail(&rdl->left);
240 cirbuf_add_head(&rdl->right, tmp);
241 rdline_puts(rdl, vt100_left_arr);
244 case CMDLINE_KEY_CTRL_F:
245 case CMDLINE_KEY_RIGHT_ARR:
246 if (CIRBUF_IS_EMPTY(&rdl->right))
248 tmp = cirbuf_get_head(&rdl->right);
249 cirbuf_del_head(&rdl->right);
250 cirbuf_add_tail(&rdl->left, tmp);
251 rdline_puts(rdl, vt100_right_arr);
254 case CMDLINE_KEY_WLEFT:
255 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
256 (tmp = cirbuf_get_tail(&rdl->left)) &&
258 rdline_puts(rdl, vt100_left_arr);
259 cirbuf_del_tail(&rdl->left);
260 cirbuf_add_head(&rdl->right, tmp);
262 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
263 (tmp = cirbuf_get_tail(&rdl->left)) &&
265 rdline_puts(rdl, vt100_left_arr);
266 cirbuf_del_tail(&rdl->left);
267 cirbuf_add_head(&rdl->right, tmp);
271 case CMDLINE_KEY_WRIGHT:
272 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
273 (tmp = cirbuf_get_head(&rdl->right)) &&
275 rdline_puts(rdl, vt100_right_arr);
276 cirbuf_del_head(&rdl->right);
277 cirbuf_add_tail(&rdl->left, tmp);
279 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
280 (tmp = cirbuf_get_head(&rdl->right)) &&
282 rdline_puts(rdl, vt100_right_arr);
283 cirbuf_del_head(&rdl->right);
284 cirbuf_add_tail(&rdl->left, tmp);
288 case CMDLINE_KEY_BKSPACE:
289 if(!cirbuf_del_tail_safe(&rdl->left)) {
290 rdline_puts(rdl, vt100_bs);
291 display_right_buffer(rdl, 1);
295 case CMDLINE_KEY_META_BKSPACE:
296 case CMDLINE_KEY_CTRL_W:
297 while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
298 rdline_puts(rdl, vt100_bs);
299 cirbuf_del_tail(&rdl->left);
301 while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank2(cirbuf_get_tail(&rdl->left))) {
302 rdline_puts(rdl, vt100_bs);
303 cirbuf_del_tail(&rdl->left);
305 display_right_buffer(rdl, 1);
308 case CMDLINE_KEY_META_D:
309 while (! CIRBUF_IS_EMPTY(&rdl->right) && isblank2(cirbuf_get_head(&rdl->right)))
310 cirbuf_del_head(&rdl->right);
311 while (! CIRBUF_IS_EMPTY(&rdl->right) && !isblank2(cirbuf_get_head(&rdl->right)))
312 cirbuf_del_head(&rdl->right);
313 display_right_buffer(rdl, 1);
316 case CMDLINE_KEY_SUPPR:
317 case CMDLINE_KEY_CTRL_D:
318 if (cmd == CMDLINE_KEY_CTRL_D &&
319 CIRBUF_IS_EMPTY(&rdl->left) &&
320 CIRBUF_IS_EMPTY(&rdl->right)) {
321 return RDLINE_RES_EOF;
323 if (!cirbuf_del_head_safe(&rdl->right)) {
324 display_right_buffer(rdl, 1);
328 case CMDLINE_KEY_CTRL_A:
329 if (CIRBUF_IS_EMPTY(&rdl->left))
331 rdline_miniprintf(rdl, vt100_multi_left,
332 CIRBUF_GET_LEN(&rdl->left));
333 while (! CIRBUF_IS_EMPTY(&rdl->left)) {
334 tmp = cirbuf_get_tail(&rdl->left);
335 cirbuf_del_tail(&rdl->left);
336 cirbuf_add_head(&rdl->right, tmp);
340 case CMDLINE_KEY_CTRL_E:
341 if (CIRBUF_IS_EMPTY(&rdl->right))
343 rdline_miniprintf(rdl, vt100_multi_right,
344 CIRBUF_GET_LEN(&rdl->right));
345 while (! CIRBUF_IS_EMPTY(&rdl->right)) {
346 tmp = cirbuf_get_head(&rdl->right);
347 cirbuf_del_head(&rdl->right);
348 cirbuf_add_tail(&rdl->left, tmp);
352 #ifndef NO_RDLINE_KILL_BUF
353 case CMDLINE_KEY_CTRL_K:
354 cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
355 rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
356 cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
357 rdline_puts(rdl, vt100_clear_right);
360 case CMDLINE_KEY_CTRL_Y:
362 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
364 i < rdl->kill_size) {
365 cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
366 rdl->write_char(rdl, rdl->kill_buf[i]);
369 display_right_buffer(rdl, 0);
371 #endif /* !NO_RDLINE_KILL_BUF */
373 case CMDLINE_KEY_CTRL_C:
374 rdline_puts(rdl, "\r\n");
375 rdline_newline(rdl, rdl->prompt);
378 case CMDLINE_KEY_CTRL_L:
379 rdline_redisplay(rdl);
382 case CMDLINE_KEY_TAB:
383 case CMDLINE_KEY_HELP:
384 cirbuf_align_left(&rdl->left);
385 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
387 char tmp_buf[BUFSIZ];
390 unsigned int tmp_size;
392 if (cmd == CMDLINE_KEY_TAB)
397 /* see in parse.h for help on complete() */
398 ret = rdl->complete(rdl, rdl->left_buf,
399 tmp_buf, sizeof(tmp_buf),
401 /* no completion or error */
403 return RDLINE_RES_COMPLETE;
406 tmp_size = strnlen(tmp_buf, sizeof(tmp_buf));
408 if (ret == RDLINE_RES_COMPLETE) {
410 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
413 cirbuf_add_tail(&rdl->left, tmp_buf[i]);
414 rdl->write_char(rdl, tmp_buf[i]);
417 display_right_buffer(rdl, 1);
418 return RDLINE_RES_COMPLETE; /* ?? */
422 rdline_puts(rdl, "\r\n");
424 rdl->write_char(rdl, ' ');
425 for (i=0 ; tmp_buf[i] ; i++)
426 rdl->write_char(rdl, tmp_buf[i]);
427 rdline_puts(rdl, "\r\n");
428 ret = rdl->complete(rdl, rdl->left_buf,
429 tmp_buf, sizeof(tmp_buf),
433 rdline_redisplay(rdl);
435 return RDLINE_RES_COMPLETE;
437 case CMDLINE_KEY_RETURN:
438 case CMDLINE_KEY_RETURN2:
439 rdline_get_buffer(rdl);
440 rdl->status = RDLINE_INIT;
441 rdline_puts(rdl, "\r\n");
442 #ifndef NO_RDLINE_HISTORY
443 if (rdl->history_cur_line != -1)
444 rdline_remove_first_history_item(rdl);
448 rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
449 /* user may have stopped rdline */
450 if (rdl->status == RDLINE_EXITED)
451 return RDLINE_RES_EXITED;
452 return RDLINE_RES_VALIDATED;
454 #ifndef NO_RDLINE_HISTORY
455 case CMDLINE_KEY_UP_ARR:
456 case CMDLINE_KEY_CTRL_P:
457 if (rdl->history_cur_line == 0) {
458 rdline_remove_first_history_item(rdl);
460 if (rdl->history_cur_line <= 0) {
461 rdline_add_history(rdl, rdline_get_buffer(rdl));
462 rdl->history_cur_line = 0;
465 buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
469 rdl->history_cur_line ++;
470 vt100_init(&rdl->vt100);
471 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
472 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
473 cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
474 rdline_redisplay(rdl);
477 case CMDLINE_KEY_DOWN_ARR:
478 case CMDLINE_KEY_CTRL_N:
479 if (rdl->history_cur_line - 1 < 0)
482 rdl->history_cur_line --;
483 buf = rdline_get_history_item(rdl, rdl->history_cur_line);
486 vt100_init(&rdl->vt100);
487 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
488 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
489 cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
490 rdline_redisplay(rdl);
493 #endif /* !NO_RDLINE_HISTORY */
500 return RDLINE_RES_SUCCESS;
503 if (!isprint((int)c))
504 return RDLINE_RES_SUCCESS;
507 if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
508 return RDLINE_RES_SUCCESS;
510 if (cirbuf_add_tail_safe(&rdl->left, c))
511 return RDLINE_RES_SUCCESS;
513 rdl->write_char(rdl, c);
514 display_right_buffer(rdl, 0);
516 return RDLINE_RES_SUCCESS;
522 #ifndef NO_RDLINE_HISTORY
524 rdline_remove_old_history_item(struct rdline * rdl)
528 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
529 tmp = cirbuf_get_head(&rdl->history);
530 cirbuf_del_head(&rdl->history);
537 rdline_remove_first_history_item(struct rdline * rdl)
541 if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
545 cirbuf_del_tail(&rdl->history);
548 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
549 tmp = cirbuf_get_tail(&rdl->history);
552 cirbuf_del_tail(&rdl->history);
557 rdline_get_history_size(struct rdline * rdl)
559 unsigned int i, tmp, ret=0;
561 CIRBUF_FOREACH(&rdl->history, i, tmp) {
570 rdline_get_history_item(struct rdline * rdl, unsigned int idx)
572 unsigned int len, i, tmp;
574 len = rdline_get_history_size(rdl);
579 cirbuf_align_left(&rdl->history);
581 CIRBUF_FOREACH(&rdl->history, i, tmp) {
582 if ( idx == len - 1) {
583 return rdl->history_buf + i;
593 rdline_add_history(struct rdline * rdl, const char * buf)
597 len = strnlen(buf, RDLINE_BUF_SIZE);
598 for (i=0; i<len ; i++) {
599 if (buf[i] == '\n') {
605 if ( len >= RDLINE_HISTORY_BUF_SIZE )
608 while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
609 rdline_remove_old_history_item(rdl);
612 cirbuf_add_buf_tail(&rdl->history, buf, len);
613 cirbuf_add_tail(&rdl->history, 0);
619 rdline_clear_history(struct rdline * rdl)
621 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
624 #else /* !NO_RDLINE_HISTORY */
626 int rdline_add_history(struct rdline * rdl, const char * buf) {return -1;}
627 void rdline_clear_history(struct rdline * rdl) {}
628 char * rdline_get_history_item(struct rdline * rdl, unsigned int i) {return NULL;}
631 #endif /* !NO_RDLINE_HISTORY */
634 /* STATIC USEFUL FUNCS */
637 rdline_puts(struct rdline * rdl, const char * buf)
640 while ( (c = *(buf++)) != '\0' ) {
641 rdl->write_char(rdl, c);
645 /* a very very basic printf with one arg and one format 'u' */
647 rdline_miniprintf(struct rdline *rdl, const char * buf, unsigned int val)
649 char c, started=0, div=100;
651 while ( (c=*(buf++)) ) {
653 rdl->write_char(rdl, c);
658 rdl->write_char(rdl, '%');
659 rdl->write_char(rdl, c);
662 /* val is never more than 255 */
664 c = (char)(val / div);
666 rdl->write_char(rdl, (char)(c+'0'));