From: Olivier Matz Date: Sun, 13 Mar 2011 09:48:46 +0000 (+0100) Subject: rdline: support pager during completion X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=07b56132836475e2231868771a53a7d2b1ee2fd7;p=libcmdline.git rdline: support pager during completion Signed-off-by: Olivier Matz --- diff --git a/src/lib/cmdline.c b/src/lib/cmdline.c index 6e8d7b8..7423cc0 100644 --- a/src/lib/cmdline.c +++ b/src/lib/cmdline.c @@ -112,8 +112,12 @@ cmdline_default_help(struct rdline *rdl, const char *buf, ssize_t cmdline_write(void *arg, void *buf, size_t count) { - const struct rdline *rdl = arg; + struct rdline *rdl = arg; +#ifdef NO_PAGER return rdline_write(rdl, buf, count); +#else + return rdline_asyncpager_write(rdl, buf, count); +#endif } void diff --git a/src/lib/cmdline_rdline.c b/src/lib/cmdline_rdline.c index 16fda43..ee78cb2 100644 --- a/src/lib/cmdline_rdline.c +++ b/src/lib/cmdline_rdline.c @@ -216,14 +216,20 @@ rdline_parse_char(struct rdline *rdl, char c) if (rdl->pager_buf != NULL) { if (cmd == VT100_STD_CHAR && c == 'q') { rdline_asyncpager_reset(rdl); - // call cb() + if (rdl->pager_cb != NULL) { + rdl->pager_cb(rdl, rdl->pager_arg); + rdl->pager_cb = NULL; + } if (rdl->pager_buf == NULL) return RDLINE_RES_VALIDATED; } if (rdline_pager_next_page(rdl) == 0) { rdline_asyncpager_reset(rdl); - // call cb() + if (rdl->pager_cb != NULL) { + rdl->pager_cb(rdl, rdl->pager_arg); + rdl->pager_cb = NULL; + } if (rdl->pager_buf == NULL) return RDLINE_RES_VALIDATED; } @@ -394,12 +400,14 @@ rdline_parse_char(struct rdline *rdl, char c) cirbuf_align_left(&rdl->left); rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0'; rdline_printf(rdl, "\r\n"); - rdl->help(rdl, rdl->left_buf, rdline_write, rdl); #ifndef NO_PAGER - if (rdl->pager_buf != NULL) { - // XXX set cb + rdl->help(rdl, rdl->left_buf, rdline_asyncpager_write, rdl); + if (rdl->pager_buf != NULL) return RDLINE_RES_SUCCESS; - } + else + rdline_asyncpager_reset(rdl); +#else + rdl->help(rdl, rdl->left_buf, rdline_write, rdl); #endif rdline_redisplay(rdl); break; @@ -407,7 +415,7 @@ rdline_parse_char(struct rdline *rdl, char c) case CMDLINE_KEY_TAB: { char tmp_buf[CMDLINE_MAX_TOKEN_SIZE]; - int ret; //, curline = 0; + int ret; unsigned int tmp_size; if (rdl->complete == NULL) @@ -425,12 +433,15 @@ rdline_parse_char(struct rdline *rdl, char c) cirbuf_align_left(&rdl->left); rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0'; rdline_printf(rdl, "\r\n"); - rdl->help(rdl, rdl->left_buf, rdline_write, rdl); #ifndef NO_PAGER - if (rdl->pager_buf != NULL) { - // XXX set cb + rdl->help(rdl, rdl->left_buf, rdline_asyncpager_write, + rdl); + if (rdl->pager_buf != NULL) return RDLINE_RES_SUCCESS; - } + else + rdline_asyncpager_reset(rdl); +#else + rdl->help(rdl, rdl->left_buf, rdline_write, rdl); #endif rdline_redisplay(rdl); break; @@ -469,10 +480,11 @@ rdline_parse_char(struct rdline *rdl, char c) rdline_asyncpager_reset(rdl); return RDLINE_RES_EXITED; } - if (rdl->pager_buf != NULL) { - // XXX set cb + if (rdl->pager_buf != NULL) return RDLINE_RES_SUCCESS; - } + else + rdline_asyncpager_reset(rdl); + rdl->status = RDLINE_INIT; #else if (rdl->status == RDLINE_EXITED) @@ -521,7 +533,6 @@ rdline_parse_char(struct rdline *rdl, char c) break; #endif /* !NO_RDLINE_HISTORY */ - default: break; } @@ -828,9 +839,11 @@ rdline_pager_next_page(struct rdline *rdl) } /* push data in pager */ -static int -rdline_pager_push(struct rdline *rdl, char *s, int len) +ssize_t +rdline_asyncpager_write(struct rdline *rdl, void *buf, size_t len) { + char *s = buf; + /* display as many lines as we can */ if (rdl->pager_lines < RDLINE_MAX_LINES) { int lines = RDLINE_MAX_LINES - rdl->pager_lines; @@ -865,8 +878,7 @@ rdline_pager_push(struct rdline *rdl, char *s, int len) return 0; } -/* XXX we should have a specific return value when displaying will be - * asynchronous, we may also have a callback */ +/* Print data asynchronously (using pager if needed) */ int rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...) { @@ -888,8 +900,19 @@ rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...) if (n >= BUFSIZ) n = BUFSIZ-1; if (n > 0) - rdline_pager_push(rdl, buf, n); + rdline_asyncpager_write(rdl, buf, n); free(buf); return n; } + +int rdline_asyncpager_set_cb(struct rdline *rdl, rdline_asyncpager_cb_t *cb, + void *arg) +{ + if (rdl->pager_buf == NULL) + return -1; + + rdl->pager_cb = cb; + rdl->pager_arg = arg; + return 0; +} #endif /* !NO_PAGER */ diff --git a/src/lib/cmdline_rdline.h b/src/lib/cmdline_rdline.h index 23b8cb6..152c8b5 100644 --- a/src/lib/cmdline_rdline.h +++ b/src/lib/cmdline_rdline.h @@ -87,7 +87,7 @@ #define RDLINE_VT100_BUF_SIZE 8 #define RDLINE_HISTORY_BUF_SIZE BUFSIZ #define RDLINE_HISTORY_MAX_LINE 64 -#define RDLINE_MAX_LINES 39 +#define RDLINE_MAX_LINES 23 enum rdline_status { RDLINE_INIT, @@ -102,7 +102,7 @@ struct rdline; * help. The first argument is an opaque pointer. The other args * are buffer and size. */ -typedef ssize_t (rdline_write_t)(const struct rdline *, void *, size_t); +typedef ssize_t (rdline_write_t)(struct rdline *, void *, size_t); typedef void (rdline_validate_t)(struct rdline *rdl, @@ -112,6 +112,8 @@ typedef int (rdline_complete_t)(struct rdline *rdl, const char *buf, typedef int (rdline_help_t)(struct rdline *rdl, const char *buf, rdline_write_t *write, void *opaque); +typedef void (rdline_asyncpager_cb_t)(struct rdline *, void *); + struct rdline { enum rdline_status status; int fd_in; @@ -153,6 +155,8 @@ struct rdline { int pager_len; /* total len of buffer */ int pager_off; /* offset of next data */ int pager_lines; /* number of lines displayed */ + rdline_asyncpager_cb_t *pager_cb; + void *pager_arg; #endif }; @@ -359,6 +363,27 @@ void rdline_clear_history(struct rdline *rdl); char *rdline_get_history_item(struct rdline *rdl, unsigned int i); #ifndef NO_PAGER +/** + * Write data asynchronously (using pager if needed) + * + * If there is enough place to print data on the current page, it is + * printed synchronously. Else, a temporary buffer is allocated and + * the data is stored in it. When the main rdline is called again, the + * pager is flushed before parsing any other commands. + * + * @param rdl + * The rdline descriptor + * @param buf + * Buffer to be sent + * @param len + * Length of buffer to be sent + * @return + * On success, the number of bytes written is returned (zero + * indicates nothing was written). On error, -1 is returned, and + * errno is set appropriately + */ +ssize_t rdline_asyncpager_write(struct rdline *rdl, void *buf, size_t len); + /** * Print data asynchronously (using pager if needed) * @@ -377,6 +402,23 @@ char *rdline_get_history_item(struct rdline *rdl, unsigned int i); * output to strings). On error, a negative value is returned. */ int rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...); + +/** + * Set the callback for the pager + * + * If there is some data in the pager to be printed, set a callback + * function that will be called when all the data will be printed. If + * the pager is empty, don't do anything and return -1. + * @param rdl + * The rdline descriptor + * @return + * - 0 if there is some data in the pager buffer and the callback + * is loaded + * - -1 if there is no data in pager buffer (in this case the callback + * is not called) + */ +int rdline_asyncpager_set_cb(struct rdline *rdl, rdline_asyncpager_cb_t *cb, + void *arg); #endif