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.
70 #include "cmdline_cirbuf.h"
71 #include "cmdline_rdline.h"
72 #include "cmdline_parse.h"
74 #ifndef NO_RDLINE_HISTORY
75 static void rdline_remove_old_history_item(struct rdline *rdl);
76 static void rdline_remove_first_history_item(struct rdline *rdl);
77 static unsigned int rdline_get_history_size(struct rdline *rdl);
78 #endif /* !NO_RDLINE_HISTORY */
81 /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
93 rdline_init(struct rdline *rdl,
94 int fd_in, int fd_out,
95 rdline_validate_t *validate,
96 rdline_complete_t *complete,
99 memset(rdl, 0, sizeof(*rdl));
101 rdl->fd_out = fd_out;
102 rdl->validate = validate;
103 rdl->complete = complete;
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)
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 pointer is the same, don't copy it */
119 if (prompt != rdl->prompt)
120 snprintf(rdl->prompt, sizeof(rdl->prompt), "%s", prompt);
122 rdline_printf(rdl, "%s", rdl->prompt);
123 rdl->status = RDLINE_RUNNING;
125 #ifndef NO_RDLINE_HISTORY
126 rdl->history_cur_line = -1;
127 #endif /* !NO_RDLINE_HISTORY */
131 rdline_stop(struct rdline *rdl)
133 rdl->status = RDLINE_INIT;
137 rdline_quit(struct rdline *rdl)
139 rdl->status = RDLINE_EXITED;
143 rdline_restart(struct rdline *rdl)
145 rdl->status = RDLINE_RUNNING;
149 rdline_get_buffer(struct rdline *rdl)
151 unsigned int len_l, len_r;
152 cirbuf_align_left(&rdl->left);
153 cirbuf_align_left(&rdl->right);
155 len_l = CIRBUF_GET_LEN(&rdl->left);
156 len_r = CIRBUF_GET_LEN(&rdl->right);
157 memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
159 rdl->left_buf[len_l + len_r] = '\0';
160 return rdl->left_buf;
164 display_right_buffer(struct rdline *rdl, int force)
169 if (!force && CIRBUF_IS_EMPTY(&rdl->right))
172 rdline_printf(rdl, vt100_clear_right);
173 CIRBUF_FOREACH(&rdl->right, i, tmp) {
174 rdline_printf(rdl, "%c", tmp);
176 if (!CIRBUF_IS_EMPTY(&rdl->right))
177 rdline_printf(rdl, vt100_multi_left,
178 CIRBUF_GET_LEN(&rdl->right));
182 rdline_redisplay(struct rdline *rdl)
187 rdline_printf(rdl, vt100_home);
188 rdline_printf(rdl, "%s", rdl->prompt);
189 CIRBUF_FOREACH(&rdl->left, i, tmp) {
190 rdline_printf(rdl, "%c", tmp);
192 display_right_buffer(rdl, 1);
196 rdline_parse_char(struct rdline *rdl, char c)
201 #ifndef NO_RDLINE_HISTORY
205 cmd = vt100_parser(&rdl->vt100, c);
206 if (cmd == VT100_NOT_COMPLETE)
207 return RDLINE_RES_SUCCESS;
209 if (cmd != VT100_STD_CHAR) {
211 case CMDLINE_KEY_CTRL_B:
212 case CMDLINE_KEY_LEFT_ARR:
213 if (CIRBUF_IS_EMPTY(&rdl->left))
215 tmp = cirbuf_get_tail(&rdl->left);
216 cirbuf_del_tail(&rdl->left);
217 cirbuf_add_head(&rdl->right, tmp);
218 rdline_printf(rdl, vt100_left_arr);
221 case CMDLINE_KEY_CTRL_F:
222 case CMDLINE_KEY_RIGHT_ARR:
223 if (CIRBUF_IS_EMPTY(&rdl->right))
225 tmp = cirbuf_get_head(&rdl->right);
226 cirbuf_del_head(&rdl->right);
227 cirbuf_add_tail(&rdl->left, tmp);
228 rdline_printf(rdl, vt100_right_arr);
231 case CMDLINE_KEY_WLEFT:
232 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
233 (tmp = cirbuf_get_tail(&rdl->left)) &&
235 rdline_printf(rdl, vt100_left_arr);
236 cirbuf_del_tail(&rdl->left);
237 cirbuf_add_head(&rdl->right, tmp);
239 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
240 (tmp = cirbuf_get_tail(&rdl->left)) &&
242 rdline_printf(rdl, vt100_left_arr);
243 cirbuf_del_tail(&rdl->left);
244 cirbuf_add_head(&rdl->right, tmp);
248 case CMDLINE_KEY_WRIGHT:
249 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
250 (tmp = cirbuf_get_head(&rdl->right)) &&
252 rdline_printf(rdl, vt100_right_arr);
253 cirbuf_del_head(&rdl->right);
254 cirbuf_add_tail(&rdl->left, tmp);
256 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
257 (tmp = cirbuf_get_head(&rdl->right)) &&
259 rdline_printf(rdl, vt100_right_arr);
260 cirbuf_del_head(&rdl->right);
261 cirbuf_add_tail(&rdl->left, tmp);
265 case CMDLINE_KEY_BKSPACE:
266 if(!cirbuf_del_tail_safe(&rdl->left)) {
267 rdline_printf(rdl, vt100_bs);
268 display_right_buffer(rdl, 1);
272 case CMDLINE_KEY_META_BKSPACE:
273 case CMDLINE_KEY_CTRL_W:
274 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
275 isblank2(cirbuf_get_tail(&rdl->left))) {
276 rdline_printf(rdl, vt100_bs);
277 cirbuf_del_tail(&rdl->left);
279 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
280 !isblank2(cirbuf_get_tail(&rdl->left))) {
281 rdline_printf(rdl, vt100_bs);
282 cirbuf_del_tail(&rdl->left);
284 display_right_buffer(rdl, 1);
287 case CMDLINE_KEY_META_D:
288 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
289 isblank2(cirbuf_get_head(&rdl->right)))
290 cirbuf_del_head(&rdl->right);
291 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
292 !isblank2(cirbuf_get_head(&rdl->right)))
293 cirbuf_del_head(&rdl->right);
294 display_right_buffer(rdl, 1);
297 case CMDLINE_KEY_SUPPR:
298 case CMDLINE_KEY_CTRL_D:
299 if (cmd == CMDLINE_KEY_CTRL_D &&
300 CIRBUF_IS_EMPTY(&rdl->left) &&
301 CIRBUF_IS_EMPTY(&rdl->right)) {
302 return RDLINE_RES_EOF;
304 if (!cirbuf_del_head_safe(&rdl->right)) {
305 display_right_buffer(rdl, 1);
309 case CMDLINE_KEY_CTRL_A:
310 if (CIRBUF_IS_EMPTY(&rdl->left))
312 rdline_printf(rdl, vt100_multi_left,
313 CIRBUF_GET_LEN(&rdl->left));
314 while (! CIRBUF_IS_EMPTY(&rdl->left)) {
315 tmp = cirbuf_get_tail(&rdl->left);
316 cirbuf_del_tail(&rdl->left);
317 cirbuf_add_head(&rdl->right, tmp);
321 case CMDLINE_KEY_CTRL_E:
322 if (CIRBUF_IS_EMPTY(&rdl->right))
324 rdline_printf(rdl, vt100_multi_right,
325 CIRBUF_GET_LEN(&rdl->right));
326 while (! CIRBUF_IS_EMPTY(&rdl->right)) {
327 tmp = cirbuf_get_head(&rdl->right);
328 cirbuf_del_head(&rdl->right);
329 cirbuf_add_tail(&rdl->left, tmp);
333 #ifndef NO_RDLINE_KILL_BUF
334 case CMDLINE_KEY_CTRL_K:
335 cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
336 rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
337 cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
338 rdline_printf(rdl, vt100_clear_right);
341 case CMDLINE_KEY_CTRL_Y:
343 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
345 i < rdl->kill_size) {
346 cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
347 rdline_printf(rdl, "%c", rdl->kill_buf[i]);
350 display_right_buffer(rdl, 0);
352 #endif /* !NO_RDLINE_KILL_BUF */
354 case CMDLINE_KEY_CTRL_C:
355 rdline_printf(rdl, "\r\n");
356 rdline_newline(rdl, rdl->prompt);
359 case CMDLINE_KEY_CTRL_L:
360 rdline_redisplay(rdl);
363 case CMDLINE_KEY_HELP: {
364 if (rdl->help == NULL)
367 cirbuf_align_left(&rdl->left);
368 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
369 rdline_printf(rdl, "\r\n");
370 rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
371 rdline_redisplay(rdl);
375 case CMDLINE_KEY_TAB: {
376 char tmp_buf[CMDLINE_MAX_TOKEN_SIZE];
377 int ret; //, curline = 0;
378 unsigned int tmp_size;
380 if (rdl->complete == NULL)
383 cirbuf_align_left(&rdl->left);
384 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
386 /* see in parse.h for help on complete() */
387 ret = rdl->complete(rdl, rdl->left_buf,
388 tmp_buf, sizeof(tmp_buf));
389 /* no completion or error */
390 if (ret == CMDLINE_COMPLETE_NONE ||
391 ret == CMDLINE_COMPLETE_MANY) {
392 cirbuf_align_left(&rdl->left);
393 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
394 rdline_printf(rdl, "\r\n");
395 rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
396 rdline_redisplay(rdl);
400 tmp_size = strlen(tmp_buf);
403 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
406 cirbuf_add_tail(&rdl->left, tmp_buf[i]);
407 rdline_printf(rdl, "%c", tmp_buf[i]);
410 display_right_buffer(rdl, 1);
414 case CMDLINE_KEY_RETURN:
415 case CMDLINE_KEY_RETURN2:
416 cirbuf_align_left(&rdl->left);
417 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\n';
418 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left) + 1] = '\0';
419 rdl->status = RDLINE_INIT;
420 rdline_printf(rdl, "\r\n");
421 #ifndef NO_RDLINE_HISTORY
422 if (rdl->history_cur_line != -1)
423 rdline_remove_first_history_item(rdl);
427 rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
428 /* user may have stopped rdline */
429 if (rdl->status == RDLINE_EXITED)
430 return RDLINE_RES_EXITED;
431 return RDLINE_RES_VALIDATED;
433 #ifndef NO_RDLINE_HISTORY
434 case CMDLINE_KEY_UP_ARR:
435 case CMDLINE_KEY_CTRL_P:
436 if (rdl->history_cur_line == 0) {
437 rdline_remove_first_history_item(rdl);
439 if (rdl->history_cur_line <= 0) {
440 rdline_add_history(rdl, rdline_get_buffer(rdl));
441 rdl->history_cur_line = 0;
444 buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
448 rdl->history_cur_line ++;
449 vt100_init(&rdl->vt100);
450 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
451 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
452 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
453 rdline_redisplay(rdl);
456 case CMDLINE_KEY_DOWN_ARR:
457 case CMDLINE_KEY_CTRL_N:
458 if (rdl->history_cur_line - 1 < 0)
461 rdl->history_cur_line --;
462 buf = rdline_get_history_item(rdl, rdl->history_cur_line);
465 vt100_init(&rdl->vt100);
466 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
467 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
468 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
469 rdline_redisplay(rdl);
472 #endif /* !NO_RDLINE_HISTORY */
479 return RDLINE_RES_SUCCESS;
482 if (!isprint((int)c))
483 return RDLINE_RES_SUCCESS;
486 if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
487 return RDLINE_RES_SUCCESS;
489 if (cirbuf_add_tail_safe(&rdl->left, c))
490 return RDLINE_RES_SUCCESS;
492 rdline_printf(rdl, "%c", c);
493 display_right_buffer(rdl, 0);
495 return RDLINE_RES_SUCCESS;
499 rdline_char_in(struct rdline *rdl, char c)
502 const char *history, *buffer;
504 if (rdl->status == RDLINE_EXITED)
505 return RDLINE_RES_EXITED;
506 if (rdl->status != RDLINE_RUNNING)
507 return RDLINE_RES_NOT_RUNNING;
509 ret = rdline_parse_char(rdl, c);
511 /* add line to history */
512 if (ret == RDLINE_RES_VALIDATED) {
513 buffer = rdline_get_buffer(rdl);
514 history = rdline_get_history_item(rdl, 0);
516 same = !strcmp(buffer, history);
518 if (strlen(buffer) >= 1 && same == 0)
519 rdline_add_history(rdl, buffer);
526 rdline(struct rdline *rdl, const char *prompt)
529 int ret = RDLINE_RES_NOT_RUNNING;
531 rdline_newline(rdl, prompt);
533 if (read(rdl->fd_in, &c, 1) < 0)
535 ret = rdline_char_in(rdl, c);
536 if (ret != RDLINE_RES_SUCCESS)
545 #ifndef NO_RDLINE_HISTORY
547 rdline_remove_old_history_item(struct rdline * rdl)
551 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
552 tmp = cirbuf_get_head(&rdl->history);
553 cirbuf_del_head(&rdl->history);
560 rdline_remove_first_history_item(struct rdline * rdl)
564 if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
568 cirbuf_del_tail(&rdl->history);
571 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
572 tmp = cirbuf_get_tail(&rdl->history);
575 cirbuf_del_tail(&rdl->history);
580 rdline_get_history_size(struct rdline * rdl)
582 unsigned int i, tmp, ret=0;
584 CIRBUF_FOREACH(&rdl->history, i, tmp) {
593 rdline_get_history_item(struct rdline * rdl, unsigned int idx)
595 unsigned int len, i, tmp;
597 len = rdline_get_history_size(rdl);
602 cirbuf_align_left(&rdl->history);
604 CIRBUF_FOREACH(&rdl->history, i, tmp) {
605 if ( idx == len - 1) {
606 return rdl->history_buf + i;
616 rdline_add_history(struct rdline * rdl, const char * buf)
621 if (len >= RDLINE_HISTORY_BUF_SIZE)
624 while (len >= CIRBUF_GET_FREELEN(&rdl->history)) {
625 rdline_remove_old_history_item(rdl);
628 cirbuf_add_buf_tail(&rdl->history, buf, len);
629 cirbuf_add_tail(&rdl->history, 0);
635 rdline_clear_history(struct rdline * rdl)
637 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
640 #else /* !NO_RDLINE_HISTORY */
642 int rdline_add_history(struct rdline * rdl, const char * buf)
647 void rdline_clear_history(struct rdline * rdl)
652 char * rdline_get_history_item(struct rdline * rdl, unsigned int i)
658 #endif /* !NO_RDLINE_HISTORY */
662 rdline_write(const struct rdline *rdl, void *buf, size_t count)
664 return write(rdl->fd_out, buf, count);
668 rdline_vprintf(const struct rdline *rdl, const char *fmt, va_list ap)
679 ret = vdprintf(rdl->fd_out, fmt, ap);
681 buf = malloc(BUFSIZ);
685 ret = vsnprintf(buf, BUFSIZ, fmt, ap);
688 write(rdl->fd_out, buf, (ret >= BUFSIZ) ? BUFSIZ : ret);
696 rdline_printf(const struct rdline *rdl, const char *fmt, ...)
702 ret = rdline_vprintf(rdl, fmt, ap);