rdline: support pager during completion
authorOlivier Matz <zer0@droids-corp.org>
Sun, 13 Mar 2011 09:48:46 +0000 (10:48 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Sun, 13 Mar 2011 10:09:25 +0000 (11:09 +0100)
Signed-off-by: Olivier Matz <zer0@droids-corp.org>
src/lib/cmdline.c
src/lib/cmdline_rdline.c
src/lib/cmdline_rdline.h

index 6e8d7b8..7423cc0 100644 (file)
@@ -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
index 16fda43..ee78cb2 100644 (file)
@@ -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 */
index 23b8cb6..152c8b5 100644 (file)
@@ -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