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 static int rdline_pager_next_page(struct rdline *rdl);
82 static void rdline_asyncpager_reset(struct rdline *rdl);
83 #endif /* !NO_PAGER */
86 /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
98 rdline_init(struct rdline *rdl,
99 int fd_in, int fd_out,
100 rdline_validate_t *validate,
101 rdline_complete_t *complete,
104 memset(rdl, 0, sizeof(*rdl));
106 rdl->fd_out = fd_out;
107 rdl->validate = validate;
108 rdl->complete = complete;
110 rdl->status = RDLINE_INIT;
111 #ifndef NO_RDLINE_HISTORY
112 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
113 #endif /* !NO_RDLINE_HISTORY */
117 rdline_newline(struct rdline *rdl, const char *prompt)
119 vt100_init(&rdl->vt100);
120 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
121 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
123 /* if pointer is the same, don't copy it */
124 if (prompt != rdl->prompt)
125 snprintf(rdl->prompt, sizeof(rdl->prompt), "%s", prompt);
127 rdline_printf(rdl, "%s", rdl->prompt);
128 rdl->status = RDLINE_RUNNING;
130 #ifndef NO_RDLINE_HISTORY
131 rdl->history_cur_line = -1;
132 #endif /* !NO_RDLINE_HISTORY */
136 rdline_stop(struct rdline *rdl)
138 rdl->status = RDLINE_INIT;
142 rdline_quit(struct rdline *rdl)
144 rdl->status = RDLINE_EXITED;
148 rdline_restart(struct rdline *rdl)
150 rdl->status = RDLINE_RUNNING;
154 rdline_get_buffer(struct rdline *rdl)
156 unsigned int len_l, len_r;
157 cirbuf_align_left(&rdl->left);
158 cirbuf_align_left(&rdl->right);
160 len_l = CIRBUF_GET_LEN(&rdl->left);
161 len_r = CIRBUF_GET_LEN(&rdl->right);
162 memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
164 rdl->left_buf[len_l + len_r] = '\0';
165 return rdl->left_buf;
169 display_right_buffer(struct rdline *rdl, int force)
174 if (!force && CIRBUF_IS_EMPTY(&rdl->right))
177 rdline_printf(rdl, vt100_clear_right);
178 CIRBUF_FOREACH(&rdl->right, i, tmp) {
179 rdline_printf(rdl, "%c", tmp);
181 if (!CIRBUF_IS_EMPTY(&rdl->right))
182 rdline_printf(rdl, vt100_multi_left,
183 CIRBUF_GET_LEN(&rdl->right));
187 rdline_redisplay(struct rdline *rdl)
192 rdline_printf(rdl, vt100_home);
193 rdline_printf(rdl, "%s", rdl->prompt);
194 CIRBUF_FOREACH(&rdl->left, i, tmp) {
195 rdline_printf(rdl, "%c", tmp);
197 display_right_buffer(rdl, 1);
201 rdline_parse_char(struct rdline *rdl, char c)
206 #ifndef NO_RDLINE_HISTORY
210 cmd = vt100_parser(&rdl->vt100, c);
211 if (cmd == VT100_NOT_COMPLETE)
212 return RDLINE_RES_SUCCESS;
215 /* display asynchrounous printf if any */
216 if (rdl->pager_buf != NULL) {
218 /* user ask to exit pager, or last page is displayed*/
219 if ((cmd == VT100_STD_CHAR && c == 'q') ||
220 rdline_pager_next_page(rdl) == 0) {
223 ret = rdl->pager_ret;
224 rdline_asyncpager_reset(rdl);
225 if (rdl->pager_cb != NULL) {
226 rdl->pager_cb(rdl, rdl->pager_arg);
227 rdl->pager_cb = NULL;
229 /* maybe the pager was reloaded in the
231 if (rdl->pager_buf != NULL)
232 return RDLINE_RES_SUCCESS;
234 /* else, redisplay prompt and return the saved status */
235 rdline_redisplay(rdl);
239 /* Some pages remain, lines were displayed in
240 * rdline_pager_next_page() */
241 return RDLINE_RES_SUCCESS;
245 /* process control chars */
246 if (cmd != VT100_STD_CHAR) {
248 case CMDLINE_KEY_CTRL_B:
249 case CMDLINE_KEY_LEFT_ARR:
250 if (CIRBUF_IS_EMPTY(&rdl->left))
252 tmp = cirbuf_get_tail(&rdl->left);
253 cirbuf_del_tail(&rdl->left);
254 cirbuf_add_head(&rdl->right, tmp);
255 rdline_printf(rdl, vt100_left_arr);
258 case CMDLINE_KEY_CTRL_F:
259 case CMDLINE_KEY_RIGHT_ARR:
260 if (CIRBUF_IS_EMPTY(&rdl->right))
262 tmp = cirbuf_get_head(&rdl->right);
263 cirbuf_del_head(&rdl->right);
264 cirbuf_add_tail(&rdl->left, tmp);
265 rdline_printf(rdl, vt100_right_arr);
268 case CMDLINE_KEY_WLEFT:
269 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
270 (tmp = cirbuf_get_tail(&rdl->left)) &&
272 rdline_printf(rdl, vt100_left_arr);
273 cirbuf_del_tail(&rdl->left);
274 cirbuf_add_head(&rdl->right, tmp);
276 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
277 (tmp = cirbuf_get_tail(&rdl->left)) &&
279 rdline_printf(rdl, vt100_left_arr);
280 cirbuf_del_tail(&rdl->left);
281 cirbuf_add_head(&rdl->right, tmp);
285 case CMDLINE_KEY_WRIGHT:
286 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
287 (tmp = cirbuf_get_head(&rdl->right)) &&
289 rdline_printf(rdl, vt100_right_arr);
290 cirbuf_del_head(&rdl->right);
291 cirbuf_add_tail(&rdl->left, tmp);
293 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
294 (tmp = cirbuf_get_head(&rdl->right)) &&
296 rdline_printf(rdl, vt100_right_arr);
297 cirbuf_del_head(&rdl->right);
298 cirbuf_add_tail(&rdl->left, tmp);
302 case CMDLINE_KEY_BKSPACE:
303 if(!cirbuf_del_tail_safe(&rdl->left)) {
304 rdline_printf(rdl, vt100_bs);
305 display_right_buffer(rdl, 1);
309 case CMDLINE_KEY_META_BKSPACE:
310 case CMDLINE_KEY_CTRL_W:
311 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
312 isblank2(cirbuf_get_tail(&rdl->left))) {
313 rdline_printf(rdl, vt100_bs);
314 cirbuf_del_tail(&rdl->left);
316 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
317 !isblank2(cirbuf_get_tail(&rdl->left))) {
318 rdline_printf(rdl, vt100_bs);
319 cirbuf_del_tail(&rdl->left);
321 display_right_buffer(rdl, 1);
324 case CMDLINE_KEY_META_D:
325 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
326 isblank2(cirbuf_get_head(&rdl->right)))
327 cirbuf_del_head(&rdl->right);
328 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
329 !isblank2(cirbuf_get_head(&rdl->right)))
330 cirbuf_del_head(&rdl->right);
331 display_right_buffer(rdl, 1);
334 case CMDLINE_KEY_SUPPR:
335 case CMDLINE_KEY_CTRL_D:
336 if (cmd == CMDLINE_KEY_CTRL_D &&
337 CIRBUF_IS_EMPTY(&rdl->left) &&
338 CIRBUF_IS_EMPTY(&rdl->right)) {
339 return RDLINE_RES_EOF;
341 if (!cirbuf_del_head_safe(&rdl->right)) {
342 display_right_buffer(rdl, 1);
346 case CMDLINE_KEY_CTRL_A:
347 if (CIRBUF_IS_EMPTY(&rdl->left))
349 rdline_printf(rdl, vt100_multi_left,
350 CIRBUF_GET_LEN(&rdl->left));
351 while (! CIRBUF_IS_EMPTY(&rdl->left)) {
352 tmp = cirbuf_get_tail(&rdl->left);
353 cirbuf_del_tail(&rdl->left);
354 cirbuf_add_head(&rdl->right, tmp);
358 case CMDLINE_KEY_CTRL_E:
359 if (CIRBUF_IS_EMPTY(&rdl->right))
361 rdline_printf(rdl, vt100_multi_right,
362 CIRBUF_GET_LEN(&rdl->right));
363 while (! CIRBUF_IS_EMPTY(&rdl->right)) {
364 tmp = cirbuf_get_head(&rdl->right);
365 cirbuf_del_head(&rdl->right);
366 cirbuf_add_tail(&rdl->left, tmp);
370 #ifndef NO_RDLINE_KILL_BUF
371 case CMDLINE_KEY_CTRL_K:
372 cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
373 rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
374 cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
375 rdline_printf(rdl, vt100_clear_right);
378 case CMDLINE_KEY_CTRL_Y:
380 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
382 i < rdl->kill_size) {
383 cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
384 rdline_printf(rdl, "%c", rdl->kill_buf[i]);
387 display_right_buffer(rdl, 0);
389 #endif /* !NO_RDLINE_KILL_BUF */
391 case CMDLINE_KEY_CTRL_C:
392 rdline_printf(rdl, "\r\n");
393 rdline_newline(rdl, rdl->prompt);
396 case CMDLINE_KEY_CTRL_L:
397 rdline_redisplay(rdl);
400 case CMDLINE_KEY_HELP: {
401 if (rdl->help == NULL)
404 cirbuf_align_left(&rdl->left);
405 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
406 rdline_printf(rdl, "\r\n");
408 rdl->help(rdl, rdl->left_buf, rdline_asyncpager_write, rdl);
409 if (rdl->pager_buf != NULL)
410 return RDLINE_RES_SUCCESS;
412 rdline_asyncpager_reset(rdl);
414 rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
416 rdline_redisplay(rdl);
420 case CMDLINE_KEY_TAB: {
421 char tmp_buf[CMDLINE_MAX_TOKEN_SIZE];
423 unsigned int tmp_size;
425 if (rdl->complete == NULL)
428 cirbuf_align_left(&rdl->left);
429 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
431 /* see in parse.h for help on complete() */
432 ret = rdl->complete(rdl, rdl->left_buf,
433 tmp_buf, sizeof(tmp_buf));
434 /* no completion or error */
435 if (ret == CMDLINE_COMPLETE_NONE ||
436 ret == CMDLINE_COMPLETE_MANY) {
437 cirbuf_align_left(&rdl->left);
438 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
439 rdline_printf(rdl, "\r\n");
441 rdl->help(rdl, rdl->left_buf, rdline_asyncpager_write,
443 if (rdl->pager_buf != NULL)
444 return RDLINE_RES_SUCCESS;
446 rdline_asyncpager_reset(rdl);
448 rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
450 rdline_redisplay(rdl);
454 tmp_size = strlen(tmp_buf);
457 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
460 cirbuf_add_tail(&rdl->left, tmp_buf[i]);
461 rdline_printf(rdl, "%c", tmp_buf[i]);
464 display_right_buffer(rdl, 1);
468 case CMDLINE_KEY_RETURN:
469 case CMDLINE_KEY_RETURN2: {
471 while (!CIRBUF_IS_EMPTY(&rdl->right) &&
472 (tmp = cirbuf_get_head(&rdl->right))) {
473 cirbuf_del_head(&rdl->right);
474 cirbuf_add_tail(&rdl->left, tmp);
476 cirbuf_align_left(&rdl->left);
477 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\n';
478 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left) + 1] = '\0';
479 rdline_printf(rdl, "\r\n");
480 #ifndef NO_RDLINE_HISTORY
481 if (rdl->history_cur_line != -1)
482 rdline_remove_first_history_item(rdl);
486 rdl->validate(rdl, rdl->left_buf,
487 CIRBUF_GET_LEN(&rdl->left)+2);
489 /* user may have stopped rdline */
490 if (rdl->status == RDLINE_EXITED) {
491 rdline_asyncpager_reset(rdl);
492 return RDLINE_RES_EXITED;
494 /* there is something in pager buffer, save
495 * return value that will be return once
496 * paging is finished */
497 if (rdl->pager_buf != NULL) {
498 rdl->pager_ret = RDLINE_RES_VALIDATED;
499 return RDLINE_RES_SUCCESS;
502 rdline_asyncpager_reset(rdl);
503 rdl->status = RDLINE_INIT;
505 if (rdl->status == RDLINE_EXITED)
506 return RDLINE_RES_EXITED;
508 return RDLINE_RES_VALIDATED;
510 #ifndef NO_RDLINE_HISTORY
511 case CMDLINE_KEY_UP_ARR:
512 case CMDLINE_KEY_CTRL_P:
513 if (rdl->history_cur_line == 0) {
514 rdline_remove_first_history_item(rdl);
516 if (rdl->history_cur_line <= 0) {
517 rdline_add_history(rdl, rdline_get_buffer(rdl));
518 rdl->history_cur_line = 0;
521 buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
525 rdl->history_cur_line ++;
526 vt100_init(&rdl->vt100);
527 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
528 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
529 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
530 rdline_redisplay(rdl);
533 case CMDLINE_KEY_DOWN_ARR:
534 case CMDLINE_KEY_CTRL_N:
535 if (rdl->history_cur_line - 1 < 0)
538 rdl->history_cur_line --;
539 buf = rdline_get_history_item(rdl, rdl->history_cur_line);
542 vt100_init(&rdl->vt100);
543 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
544 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
545 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
546 rdline_redisplay(rdl);
549 #endif /* !NO_RDLINE_HISTORY */
555 return RDLINE_RES_SUCCESS;
558 if (!isprint((int)c))
559 return RDLINE_RES_SUCCESS;
562 if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
563 return RDLINE_RES_SUCCESS;
565 if (cirbuf_add_tail_safe(&rdl->left, c))
566 return RDLINE_RES_SUCCESS;
568 rdline_printf(rdl, "%c", c);
569 display_right_buffer(rdl, 0);
571 return RDLINE_RES_SUCCESS;
575 rdline_char_in(struct rdline *rdl, char c)
578 const char *history, *buffer;
580 if (rdl->status == RDLINE_EXITED)
581 return RDLINE_RES_EXITED;
582 if (rdl->status != RDLINE_RUNNING)
583 return RDLINE_RES_NOT_RUNNING;
585 ret = rdline_parse_char(rdl, c);
587 /* add line to history */
588 if (ret == RDLINE_RES_VALIDATED) {
589 buffer = rdline_get_buffer(rdl);
590 history = rdline_get_history_item(rdl, 0);
592 same = !strcmp(buffer, history);
594 if (strlen(buffer) >= 1 && same == 0)
595 rdline_add_history(rdl, buffer);
602 rdline(struct rdline *rdl, const char *prompt)
605 int ret = RDLINE_RES_NOT_RUNNING;
607 rdline_newline(rdl, prompt);
609 if (read(rdl->fd_in, &c, 1) < 0)
611 ret = rdline_char_in(rdl, c);
612 if (ret != RDLINE_RES_SUCCESS)
621 #ifndef NO_RDLINE_HISTORY
623 rdline_remove_old_history_item(struct rdline * rdl)
627 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
628 tmp = cirbuf_get_head(&rdl->history);
629 cirbuf_del_head(&rdl->history);
636 rdline_remove_first_history_item(struct rdline * rdl)
640 if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
644 cirbuf_del_tail(&rdl->history);
647 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
648 tmp = cirbuf_get_tail(&rdl->history);
651 cirbuf_del_tail(&rdl->history);
656 rdline_get_history_size(struct rdline * rdl)
658 unsigned int i, tmp, ret=0;
660 CIRBUF_FOREACH(&rdl->history, i, tmp) {
669 rdline_get_history_item(struct rdline * rdl, unsigned int idx)
671 unsigned int len, i, tmp;
673 len = rdline_get_history_size(rdl);
678 cirbuf_align_left(&rdl->history);
680 CIRBUF_FOREACH(&rdl->history, i, tmp) {
681 if ( idx == len - 1) {
682 return rdl->history_buf + i;
692 rdline_add_history(struct rdline * rdl, const char * buf)
697 if (len >= RDLINE_HISTORY_BUF_SIZE)
700 while (len >= CIRBUF_GET_FREELEN(&rdl->history)) {
701 rdline_remove_old_history_item(rdl);
704 cirbuf_add_buf_tail(&rdl->history, buf, len);
705 cirbuf_add_tail(&rdl->history, 0);
711 rdline_clear_history(struct rdline * rdl)
713 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
716 #else /* !NO_RDLINE_HISTORY */
718 int rdline_add_history(struct rdline * rdl, const char * buf)
723 void rdline_clear_history(struct rdline * rdl)
728 char * rdline_get_history_item(struct rdline * rdl, unsigned int i)
734 #endif /* !NO_RDLINE_HISTORY */
738 rdline_write(const struct rdline *rdl, void *buf, size_t count)
740 return write(rdl->fd_out, buf, count);
744 rdline_vprintf(const struct rdline *rdl, const char *fmt, va_list ap)
755 ret = vdprintf(rdl->fd_out, fmt, ap);
757 buf = malloc(BUFSIZ);
761 ret = vsnprintf(buf, BUFSIZ, fmt, ap);
764 write(rdl->fd_out, buf, (ret >= BUFSIZ) ? BUFSIZ : ret);
772 rdline_printf(const struct rdline *rdl, const char *fmt, ...)
778 ret = rdline_vprintf(rdl, fmt, ap);
785 /* reset pager state */
787 rdline_asyncpager_reset(struct rdline *rdl)
789 if (rdl->pager_buf) {
790 free(rdl->pager_buf);
791 rdl->pager_buf = NULL;
793 rdl->pager_lines = 0;
796 rdl->pager_cb = NULL;
797 rdl->pager_arg = NULL;
798 rdl->pager_ret = RDLINE_RES_SUCCESS;
801 /* Return the offset of the i-th occurence of char c in string s. If
802 * there is less than i occurences, return -1 and fill i with the
805 strnchr(const char *s, char c, int *i)
808 const char *orig = s;
821 /* display a page of data from pager, return 0 if all is displayed */
823 rdline_pager_next_page(struct rdline *rdl)
825 int lines = RDLINE_MAX_LINES;
833 rdline_printf(rdl, vt100_home);
834 rdline_printf(rdl, vt100_clear_right);
838 /* we know that s is 0-terminated */
839 displen = strnchr(s, '\n', &lines);
840 rdl->pager_lines = lines;
842 /* we can display all the data */
844 write(rdl->fd_out, s, rdl->pager_len);
845 free(rdl->pager_buf);
846 rdl->pager_buf = NULL;
850 displen = displen + 1; /* include \n */
851 write(rdl->fd_out, s, displen);
852 rdl->pager_off += displen;
853 rdl->pager_len -= displen;
855 rdline_printf(rdl, "--- press a key to continue ---");
859 /* push data in pager */
861 rdline_asyncpager_write(struct rdline *rdl, void *buf, size_t len)
865 /* display as many lines as we can */
866 if (rdl->pager_lines < RDLINE_MAX_LINES) {
867 int lines = RDLINE_MAX_LINES - rdl->pager_lines;
870 /* we know that s is 0-terminated */
871 displen = strnchr(s, '\n', &lines);
872 rdl->pager_lines += lines;
874 /* we can display all the data */
876 write(rdl->fd_out, s, len);
879 displen = displen + 1; /* include \n */
880 write(rdl->fd_out, s, displen);
885 if (rdl->pager_buf == NULL) {
886 rdline_printf(rdl, "--- press a key to continue ---");
888 rdl->pager_buf = realloc(rdl->pager_buf, rdl->pager_len + len);
889 if (rdl->pager_buf == NULL) {
890 rdline_asyncpager_reset(rdl);
894 memcpy(rdl->pager_buf + rdl->pager_len, s, len);
895 rdl->pager_len += len;
899 /* Print data asynchronously (using pager if needed) */
901 rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...)
910 buf = malloc(BUFSIZ);
915 n = vsnprintf(buf, BUFSIZ, fmt, ap);
921 rdline_asyncpager_write(rdl, buf, n);
926 int rdline_asyncpager_set_cb(struct rdline *rdl, rdline_asyncpager_cb_t *cb,
929 if (rdl->pager_buf == NULL)
933 rdl->pager_arg = arg;
936 #endif /* !NO_PAGER */