2 * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Copyright (c) <2010>, Intel Corporation
30 * All rights reserved.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
36 * - Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
39 * - Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in
41 * the documentation and/or other materials provided with the
44 * - Neither the name of Intel Corporation nor the names of its
45 * contributors may be used to endorse or promote products derived
46 * from this software without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
51 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
52 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
53 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
54 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
55 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
57 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
59 * OF THE POSSIBILITY OF SUCH DAMAGE.
62 #ifndef UCG_CMD_NO_PAGER
63 #define _GNU_SOURCE /* for vasprintf */
75 #include <ucg_cirbuf.h>
77 #include "ucg_cmd_rdline.h"
78 #include "ucg_cmd_parse.h"
80 #ifndef UCG_CMD_NO_RDLINE_HISTORY
81 static void rdline_remove_old_history_item(struct ucg_rdline *rdl);
82 static void rdline_remove_first_history_item(struct ucg_rdline *rdl);
83 static unsigned int rdline_get_history_size(struct ucg_rdline *rdl);
84 #endif /* !UCG_CMD_NO_RDLINE_HISTORY */
86 #ifndef UCG_CMD_NO_PAGER
87 static int rdline_pager_next_page(struct ucg_rdline *rdl);
88 static void rdline_pager_reset(struct ucg_rdline *rdl);
89 #endif /* !UCG_CMD_NO_PAGER */
92 /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
104 ucg_rdline_init(struct ucg_rdline *rdl,
105 FILE *f_in, FILE *f_out,
106 ucg_rdline_validate_t *validate,
107 ucg_rdline_complete_t *complete,
108 ucg_rdline_help_t *help)
110 memset(rdl, 0, sizeof(*rdl));
113 rdl->validate = validate;
114 rdl->complete = complete;
116 rdl->status = UCG_RDLINE_STOPPED;
118 /* Disable buffering */
122 #ifndef UCG_CMD_NO_RDLINE_HISTORY
123 ucg_cirbuf_init(&rdl->history, rdl->history_buf, 0,
124 UCG_RDLINE_HISTORY_BUF_SIZE);
125 #endif /* !UCG_CMD_NO_RDLINE_HISTORY */
129 ucg_rdline_newline(struct ucg_rdline *rdl, const char *prompt)
131 ucg_vt100_init(&rdl->vt100);
132 ucg_cirbuf_init(&rdl->left, rdl->left_buf, 0, UCG_RDLINE_BUF_SIZE);
133 ucg_cirbuf_init(&rdl->right, rdl->right_buf, 0, UCG_RDLINE_BUF_SIZE);
135 /* if pointer is the same or NULL, don't copy it */
136 if (prompt != NULL && prompt != rdl->prompt)
137 snprintf(rdl->prompt, sizeof(rdl->prompt), "%s", prompt);
139 ucg_rdline_printf(rdl, "%s", rdl->prompt);
140 rdl->status = UCG_RDLINE_RUNNING;
142 #ifndef UCG_CMD_NO_RDLINE_HISTORY
143 rdl->history_cur_line = -1;
144 #endif /* !UCG_CMD_NO_RDLINE_HISTORY */
148 ucg_rdline_stop(struct ucg_rdline *rdl)
150 rdl->status = UCG_RDLINE_STOPPED;
154 ucg_rdline_quit(struct ucg_rdline *rdl)
156 rdl->status = UCG_RDLINE_EXITED;
160 ucg_rdline_restart(struct ucg_rdline *rdl)
162 rdl->status = UCG_RDLINE_RUNNING;
166 ucg_rdline_get_buffer(struct ucg_rdline *rdl)
168 unsigned int len_l, len_r;
169 ucg_cirbuf_align_left(&rdl->left);
170 ucg_cirbuf_align_left(&rdl->right);
172 len_l = ucg_cirbuf_get_len(&rdl->left);
173 len_r = ucg_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] = '\0';
177 return rdl->left_buf;
181 display_right_buffer(struct ucg_rdline *rdl, int force)
186 if (!force && ucg_cirbuf_is_empty(&rdl->right))
189 ucg_rdline_printf(rdl, ucg_vt100_clear_right);
190 UCG_CIRBUF_FOREACH(&rdl->right, i, tmp) {
191 ucg_rdline_printf(rdl, "%c", tmp);
193 if (!ucg_cirbuf_is_empty(&rdl->right))
194 ucg_rdline_printf(rdl, ucg_vt100_multi_left,
195 ucg_cirbuf_get_len(&rdl->right));
199 ucg_rdline_redisplay(struct ucg_rdline *rdl)
204 ucg_rdline_printf(rdl, ucg_vt100_home);
205 ucg_rdline_printf(rdl, "%s", rdl->prompt);
206 UCG_CIRBUF_FOREACH(&rdl->left, i, tmp) {
207 ucg_rdline_printf(rdl, "%c", tmp);
209 display_right_buffer(rdl, 1);
213 rdline_parse_char(struct ucg_rdline *rdl, char c)
218 #ifndef UCG_CMD_NO_RDLINE_HISTORY
222 cmd = ucg_vt100_parser(&rdl->vt100, c);
223 if (cmd == UCG_VT100_NOT_COMPLETE)
224 return UCG_RDLINE_RES_SUCCESS;
226 #ifndef UCG_CMD_NO_PAGER
227 /* display asynchrounous printf if any */
228 if (rdl->pager_buf != NULL) {
230 /* user ask to exit pager, or last page is displayed*/
231 if ((cmd == UCG_VT100_STD_CHAR && c == 'q') ||
232 rdline_pager_next_page(rdl) == 0) {
235 ret = rdl->pager_ret;
236 rdline_pager_reset(rdl);
237 if (rdl->pager_cb != NULL) {
238 rdl->pager_cb(rdl, rdl->pager_arg);
239 rdl->pager_cb = NULL;
241 /* maybe the pager was reloaded in the
243 if (rdl->pager_buf != NULL)
244 return UCG_RDLINE_RES_SUCCESS;
246 /* else, redisplay prompt and return the saved status */
247 ucg_rdline_redisplay(rdl);
251 /* Some pages remain, lines were displayed in
252 * rdline_pager_next_page() */
253 return UCG_RDLINE_RES_SUCCESS;
257 /* process control chars */
258 if (cmd != UCG_VT100_STD_CHAR) {
260 case UCG_CMD_KEY_CTRL_B:
261 case UCG_CMD_KEY_LEFT_ARR:
262 if (ucg_cirbuf_is_empty(&rdl->left))
264 tmp = ucg_cirbuf_get_tail(&rdl->left);
265 ucg_cirbuf_del_tail(&rdl->left);
266 ucg_cirbuf_add_head(&rdl->right, tmp);
267 ucg_rdline_printf(rdl, ucg_vt100_left_arr);
270 case UCG_CMD_KEY_CTRL_F:
271 case UCG_CMD_KEY_RIGHT_ARR:
272 if (ucg_cirbuf_is_empty(&rdl->right))
274 tmp = ucg_cirbuf_get_head(&rdl->right);
275 ucg_cirbuf_del_head(&rdl->right);
276 ucg_cirbuf_add_tail(&rdl->left, tmp);
277 ucg_rdline_printf(rdl, ucg_vt100_right_arr);
280 case UCG_CMD_KEY_WLEFT:
281 while (! ucg_cirbuf_is_empty(&rdl->left) &&
282 (tmp = ucg_cirbuf_get_tail(&rdl->left)) &&
284 ucg_rdline_printf(rdl, ucg_vt100_left_arr);
285 ucg_cirbuf_del_tail(&rdl->left);
286 ucg_cirbuf_add_head(&rdl->right, tmp);
288 while (! ucg_cirbuf_is_empty(&rdl->left) &&
289 (tmp = ucg_cirbuf_get_tail(&rdl->left)) &&
291 ucg_rdline_printf(rdl, ucg_vt100_left_arr);
292 ucg_cirbuf_del_tail(&rdl->left);
293 ucg_cirbuf_add_head(&rdl->right, tmp);
297 case UCG_CMD_KEY_WRIGHT:
298 while (! ucg_cirbuf_is_empty(&rdl->right) &&
299 (tmp = ucg_cirbuf_get_head(&rdl->right)) &&
301 ucg_rdline_printf(rdl, ucg_vt100_right_arr);
302 ucg_cirbuf_del_head(&rdl->right);
303 ucg_cirbuf_add_tail(&rdl->left, tmp);
305 while (! ucg_cirbuf_is_empty(&rdl->right) &&
306 (tmp = ucg_cirbuf_get_head(&rdl->right)) &&
308 ucg_rdline_printf(rdl, ucg_vt100_right_arr);
309 ucg_cirbuf_del_head(&rdl->right);
310 ucg_cirbuf_add_tail(&rdl->left, tmp);
314 case UCG_CMD_KEY_BKSPACE:
315 if(!ucg_cirbuf_del_tail_safe(&rdl->left)) {
316 ucg_rdline_printf(rdl, ucg_vt100_bs);
317 display_right_buffer(rdl, 1);
321 case UCG_CMD_KEY_META_BKSPACE:
322 case UCG_CMD_KEY_CTRL_W:
323 while (! ucg_cirbuf_is_empty(&rdl->left) &&
324 isblank2(ucg_cirbuf_get_tail(&rdl->left))) {
325 ucg_rdline_printf(rdl, ucg_vt100_bs);
326 ucg_cirbuf_del_tail(&rdl->left);
328 while (! ucg_cirbuf_is_empty(&rdl->left) &&
329 !isblank2(ucg_cirbuf_get_tail(&rdl->left))) {
330 ucg_rdline_printf(rdl, ucg_vt100_bs);
331 ucg_cirbuf_del_tail(&rdl->left);
333 display_right_buffer(rdl, 1);
336 case UCG_CMD_KEY_META_D:
337 while (! ucg_cirbuf_is_empty(&rdl->right) &&
338 isblank2(ucg_cirbuf_get_head(&rdl->right)))
339 ucg_cirbuf_del_head(&rdl->right);
340 while (! ucg_cirbuf_is_empty(&rdl->right) &&
341 !isblank2(ucg_cirbuf_get_head(&rdl->right)))
342 ucg_cirbuf_del_head(&rdl->right);
343 display_right_buffer(rdl, 1);
346 case UCG_CMD_KEY_SUPPR:
347 case UCG_CMD_KEY_CTRL_D:
348 if (cmd == UCG_CMD_KEY_CTRL_D &&
349 ucg_cirbuf_is_empty(&rdl->left) &&
350 ucg_cirbuf_is_empty(&rdl->right)) {
351 return UCG_RDLINE_RES_EOF;
353 if (!ucg_cirbuf_del_head_safe(&rdl->right)) {
354 display_right_buffer(rdl, 1);
358 case UCG_CMD_KEY_CTRL_A:
359 if (ucg_cirbuf_is_empty(&rdl->left))
361 ucg_rdline_printf(rdl, ucg_vt100_multi_left,
362 ucg_cirbuf_get_len(&rdl->left));
363 while (! ucg_cirbuf_is_empty(&rdl->left)) {
364 tmp = ucg_cirbuf_get_tail(&rdl->left);
365 ucg_cirbuf_del_tail(&rdl->left);
366 ucg_cirbuf_add_head(&rdl->right, tmp);
370 case UCG_CMD_KEY_CTRL_E:
371 if (ucg_cirbuf_is_empty(&rdl->right))
373 ucg_rdline_printf(rdl, ucg_vt100_multi_right,
374 ucg_cirbuf_get_len(&rdl->right));
375 while (! ucg_cirbuf_is_empty(&rdl->right)) {
376 tmp = ucg_cirbuf_get_head(&rdl->right);
377 ucg_cirbuf_del_head(&rdl->right);
378 ucg_cirbuf_add_tail(&rdl->left, tmp);
382 #ifndef UCG_CMD_NO_RDLINE_KILL_BUF
383 case UCG_CMD_KEY_CTRL_K:
384 ucg_cirbuf_get_buf_head(&rdl->right, rdl->kill_buf,
385 UCG_RDLINE_BUF_SIZE);
386 rdl->kill_size = ucg_cirbuf_get_len(&rdl->right);
387 ucg_cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
388 ucg_rdline_printf(rdl, ucg_vt100_clear_right);
391 case UCG_CMD_KEY_CTRL_Y:
393 while (ucg_cirbuf_get_len(&rdl->right) +
394 ucg_cirbuf_get_len(&rdl->left) <
395 UCG_RDLINE_BUF_SIZE &&
396 i < rdl->kill_size) {
397 ucg_cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
398 ucg_rdline_printf(rdl, "%c", rdl->kill_buf[i]);
401 display_right_buffer(rdl, 0);
403 #endif /* !UCG_CMD_NO_RDLINE_KILL_BUF */
405 case UCG_CMD_KEY_CTRL_C:
406 ucg_rdline_printf(rdl, "\r\n");
407 ucg_rdline_newline(rdl, rdl->prompt);
410 case UCG_CMD_KEY_CTRL_L:
411 ucg_rdline_redisplay(rdl);
414 case UCG_CMD_KEY_HELP: {
415 if (rdl->help == NULL)
418 ucg_cirbuf_align_left(&rdl->left);
419 rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
420 ucg_rdline_printf(rdl, "\r\n");
421 rdl->help(rdl, rdl->left_buf);
422 #ifndef UCG_CMD_NO_PAGER
423 if (rdl->pager_buf != NULL)
424 return UCG_RDLINE_RES_SUCCESS;
426 rdline_pager_reset(rdl);
428 ucg_rdline_redisplay(rdl);
432 case UCG_CMD_KEY_TAB: {
433 char tmp_buf[UCG_CMD_MAX_TOKEN_SIZE];
435 unsigned int tmp_size;
437 if (rdl->complete == NULL)
440 ucg_cirbuf_align_left(&rdl->left);
441 rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
443 /* try to complete the complete() */
444 ret = rdl->complete(rdl, rdl->left_buf,
445 tmp_buf, sizeof(tmp_buf));
447 /* no completion or error */
449 ucg_cirbuf_align_left(&rdl->left);
450 rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
451 ucg_rdline_printf(rdl, "\r\n");
452 rdl->help(rdl, rdl->left_buf);
453 #ifndef UCG_CMD_NO_PAGER
454 if (rdl->pager_buf != NULL)
455 return UCG_RDLINE_RES_SUCCESS;
457 rdline_pager_reset(rdl);
459 ucg_rdline_redisplay(rdl);
463 tmp_size = strlen(tmp_buf);
466 while(ucg_cirbuf_get_len(&rdl->right) +
467 ucg_cirbuf_get_len(&rdl->left) <
468 UCG_RDLINE_BUF_SIZE &&
470 ucg_cirbuf_add_tail(&rdl->left, tmp_buf[i]);
471 ucg_rdline_printf(rdl, "%c", tmp_buf[i]);
474 display_right_buffer(rdl, 1);
478 case UCG_CMD_KEY_RETURN:
479 case UCG_CMD_KEY_RETURN2: {
481 while (!ucg_cirbuf_is_empty(&rdl->right) &&
482 (tmp = ucg_cirbuf_get_head(&rdl->right))) {
483 ucg_cirbuf_del_head(&rdl->right);
484 ucg_cirbuf_add_tail(&rdl->left, tmp);
486 ucg_cirbuf_align_left(&rdl->left);
487 rdl->left_buf[ucg_cirbuf_get_len(&rdl->left)] = '\0';
488 ucg_rdline_printf(rdl, "\r\n");
489 #ifndef UCG_CMD_NO_RDLINE_HISTORY
490 if (rdl->history_cur_line != -1)
491 rdline_remove_first_history_item(rdl);
495 rdl->validate(rdl, rdl->left_buf);
496 #ifndef UCG_CMD_NO_PAGER
497 /* user may have stopped rdline */
498 if (rdl->status == UCG_RDLINE_EXITED) {
499 rdline_pager_reset(rdl);
500 return UCG_RDLINE_RES_EXITED;
502 /* there is something in pager buffer, save
503 * return value that will be return once
504 * paging is finished */
505 if (rdl->pager_buf != NULL) {
506 rdl->pager_ret = UCG_RDLINE_RES_VALIDATED;
507 return UCG_RDLINE_RES_SUCCESS;
510 rdline_pager_reset(rdl);
512 if (rdl->status == UCG_RDLINE_EXITED)
513 return UCG_RDLINE_RES_EXITED;
515 return UCG_RDLINE_RES_VALIDATED;
517 #ifndef UCG_CMD_NO_RDLINE_HISTORY
518 case UCG_CMD_KEY_UP_ARR:
519 case UCG_CMD_KEY_CTRL_P:
520 if (rdl->history_cur_line == 0) {
521 rdline_remove_first_history_item(rdl);
523 if (rdl->history_cur_line <= 0) {
524 ucg_rdline_add_history(rdl,
525 ucg_rdline_get_buffer(rdl));
526 rdl->history_cur_line = 0;
529 history = ucg_rdline_get_history_item(rdl,
530 rdl->history_cur_line + 1);
534 rdl->history_cur_line++;
535 ucg_vt100_init(&rdl->vt100);
536 ucg_cirbuf_init(&rdl->left, rdl->left_buf, 0,
537 UCG_RDLINE_BUF_SIZE);
538 ucg_cirbuf_init(&rdl->right, rdl->right_buf, 0,
539 UCG_RDLINE_BUF_SIZE);
540 ucg_cirbuf_add_buf_tail(&rdl->left, history,
542 ucg_rdline_redisplay(rdl);
545 case UCG_CMD_KEY_DOWN_ARR:
546 case UCG_CMD_KEY_CTRL_N:
547 if (rdl->history_cur_line - 1 < 0)
550 rdl->history_cur_line--;
551 history = ucg_rdline_get_history_item(rdl,
552 rdl->history_cur_line);
556 ucg_vt100_init(&rdl->vt100);
557 ucg_cirbuf_init(&rdl->left, rdl->left_buf, 0,
558 UCG_RDLINE_BUF_SIZE);
559 ucg_cirbuf_init(&rdl->right, rdl->right_buf, 0,
560 UCG_RDLINE_BUF_SIZE);
561 ucg_cirbuf_add_buf_tail(&rdl->left, history,
563 ucg_rdline_redisplay(rdl);
566 #endif /* !UCG_CMD_NO_RDLINE_HISTORY */
572 return UCG_RDLINE_RES_SUCCESS;
575 if (!isprint((int)c))
576 return UCG_RDLINE_RES_SUCCESS;
579 if (ucg_cirbuf_get_len(&rdl->left) +
580 ucg_cirbuf_get_len(&rdl->right) >= UCG_RDLINE_BUF_SIZE)
581 return UCG_RDLINE_RES_SUCCESS;
583 if (ucg_cirbuf_add_tail_safe(&rdl->left, c))
584 return UCG_RDLINE_RES_SUCCESS;
586 ucg_rdline_printf(rdl, "%c", c);
587 display_right_buffer(rdl, 0);
589 return UCG_RDLINE_RES_SUCCESS;
593 ucg_rdline_char_in(struct ucg_rdline *rdl, char c)
596 const char *history, *buffer;
598 if (rdl->status == UCG_RDLINE_EXITED)
599 return UCG_RDLINE_RES_EXITED;
600 if (rdl->status != UCG_RDLINE_RUNNING)
601 return UCG_RDLINE_RES_NOT_RUNNING;
603 ret = rdline_parse_char(rdl, c);
605 /* add line to history */
606 if (ret == UCG_RDLINE_RES_VALIDATED) {
607 buffer = ucg_rdline_get_buffer(rdl);
608 history = ucg_rdline_get_history_item(rdl, 0);
610 same = !strcmp(buffer, history);
612 if (strlen(buffer) >= 1 && same == 0)
613 ucg_rdline_add_history(rdl, buffer);
620 ucg_rdline(struct ucg_rdline *rdl, const char *prompt, unsigned flags)
623 int ret = UCG_RDLINE_RES_NOT_RUNNING;
625 ucg_rdline_newline(rdl, prompt);
627 if (fread(&c, 1, 1, rdl->f_in) == 0) {
628 if (flags & UCG_RDLINE_F_IGNORE_EOF) {
634 ret = ucg_rdline_char_in(rdl, c);
635 if (ret != UCG_RDLINE_RES_SUCCESS)
644 #ifndef UCG_CMD_NO_RDLINE_HISTORY
646 rdline_remove_old_history_item(struct ucg_rdline *rdl)
650 while (! ucg_cirbuf_is_empty(&rdl->history) ) {
651 tmp = ucg_cirbuf_get_head(&rdl->history);
652 ucg_cirbuf_del_head(&rdl->history);
659 rdline_remove_first_history_item(struct ucg_rdline *rdl)
663 if ( ucg_cirbuf_is_empty(&rdl->history) ) {
667 ucg_cirbuf_del_tail(&rdl->history);
670 while (! ucg_cirbuf_is_empty(&rdl->history) ) {
671 tmp = ucg_cirbuf_get_tail(&rdl->history);
674 ucg_cirbuf_del_tail(&rdl->history);
679 rdline_get_history_size(struct ucg_rdline *rdl)
681 unsigned int i, tmp, ret=0;
683 UCG_CIRBUF_FOREACH(&rdl->history, i, tmp) {
692 ucg_rdline_get_history_item(struct ucg_rdline *rdl, unsigned int idx)
694 unsigned int len, i, tmp;
696 len = rdline_get_history_size(rdl);
700 ucg_cirbuf_align_left(&rdl->history);
702 UCG_CIRBUF_FOREACH(&rdl->history, i, tmp) {
703 if (idx == len - 1) {
704 return rdl->history_buf + i;
714 ucg_rdline_add_history(struct ucg_rdline *rdl, const char *buf)
719 if (len >= UCG_RDLINE_HISTORY_BUF_SIZE)
722 while (len >= ucg_cirbuf_get_freelen(&rdl->history)) {
723 rdline_remove_old_history_item(rdl);
726 ucg_cirbuf_add_buf_tail(&rdl->history, buf, len);
727 ucg_cirbuf_add_tail(&rdl->history, 0);
733 ucg_rdline_clear_history(struct ucg_rdline *rdl)
735 ucg_cirbuf_init(&rdl->history, rdl->history_buf, 0,
736 UCG_RDLINE_HISTORY_BUF_SIZE);
739 #else /* !UCG_CMD_NO_RDLINE_HISTORY */
741 int ucg_rdline_add_history(struct ucg_rdline *rdl, const char *buf)
746 void ucg_rdline_clear_history(struct ucg_rdline *rdl)
751 char *ucg_rdline_get_history_item(struct ucg_rdline *rdl, unsigned int i)
757 #endif /* !UCG_CMD_NO_RDLINE_HISTORY */
761 ucg_rdline_write(struct ucg_rdline *rdl, void *buf, size_t count)
763 return fwrite(buf, 1, count, rdl->f_out);
767 ucg_rdline_vprintf(struct ucg_rdline *rdl, const char *fmt, va_list ap)
769 if (rdl->f_out == NULL)
772 return vfprintf(rdl->f_out, fmt, ap);
776 ucg_rdline_printf(struct ucg_rdline *rdl, const char *fmt, ...)
782 ret = ucg_rdline_vprintf(rdl, fmt, ap);
788 #ifndef UCG_CMD_NO_PAGER
789 /* reset pager state */
791 rdline_pager_reset(struct ucg_rdline *rdl)
793 if (rdl->pager_buf) {
794 free(rdl->pager_buf);
795 rdl->pager_buf = NULL;
797 rdl->pager_lines = 0;
800 rdl->pager_cb = NULL;
801 rdl->pager_arg = NULL;
802 rdl->pager_ret = UCG_RDLINE_RES_SUCCESS;
805 /* Return the offset of the i-th occurence of char c in string s. If
806 * there is less than i occurences, return -1 and fill i with the
809 strnchr(const char *s, char c, int *i)
812 const char *orig = s;
825 /* display a page of data from pager, return 0 if all is displayed */
827 rdline_pager_next_page(struct ucg_rdline *rdl)
829 int lines = UCG_RDLINE_MAX_LINES;
837 ucg_rdline_printf(rdl, ucg_vt100_home);
838 ucg_rdline_printf(rdl, ucg_vt100_clear_right);
842 /* we know that s is 0-terminated */
843 displen = strnchr(s, '\n', &lines);
844 rdl->pager_lines = lines;
846 /* we can display all the data */
848 fwrite(s, 1, rdl->pager_len, rdl->f_out);
849 free(rdl->pager_buf);
850 rdl->pager_buf = NULL;
854 displen = displen + 1; /* include \n */
855 fwrite(s, 1, displen, rdl->f_out);
856 rdl->pager_off += displen;
857 rdl->pager_len -= displen;
859 ucg_rdline_printf(rdl, "--- press a key to continue ---");
863 /* push data in pager */
865 ucg_rdline_pager_write(struct ucg_rdline *rdl, void *buf, size_t len)
869 /* display as many lines as we can */
870 if (rdl->pager_lines < UCG_RDLINE_MAX_LINES) {
871 int lines = UCG_RDLINE_MAX_LINES - rdl->pager_lines;
874 /* we know that s is 0-terminated */
875 displen = strnchr(s, '\n', &lines);
876 rdl->pager_lines += lines;
878 /* we can display all the data */
880 fwrite(s, 1, len, rdl->f_out);
883 displen = displen + 1; /* include \n */
884 fwrite(s, 1, displen, rdl->f_out);
889 if (rdl->pager_buf == NULL) {
890 ucg_rdline_printf(rdl, "--- press a key to continue ---");
892 rdl->pager_buf = realloc(rdl->pager_buf, rdl->pager_len + len);
893 if (rdl->pager_buf == NULL) {
894 rdline_pager_reset(rdl);
898 memcpy(rdl->pager_buf + rdl->pager_len, s, len);
899 rdl->pager_len += len;
903 /* Print data asynchronously (using pager if needed) */
905 ucg_rdline_pager_printf(struct ucg_rdline *rdl, const char *fmt, ...)
911 if (rdl->f_out == NULL)
915 n = vasprintf(&buf, fmt, ap);
919 ucg_rdline_pager_write(rdl, buf, n);
924 int ucg_rdline_pager_set_cb(struct ucg_rdline *rdl,
925 ucg_rdline_pager_cb_t *cb, void *arg)
927 if (rdl->pager_buf == NULL)
931 rdl->pager_arg = arg;
934 #endif /* !UCG_CMD_NO_PAGER */