static unsigned int rdline_get_history_size(struct rdline *rdl);
#endif /* !NO_RDLINE_HISTORY */
+#ifndef NO_PAGER
+static int rdline_pager_next_page(struct rdline *rdl);
+static void rdline_asyncpager_reset(struct rdline *rdl);
+#endif /* !NO_PAGER */
+
/* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
* own. */
if (cmd == VT100_NOT_COMPLETE)
return RDLINE_RES_SUCCESS;
+#ifndef NO_PAGER
+ /* display asynchrounous printf if any */
+ if (rdl->pager_buf != NULL) {
+ if (cmd == VT100_STD_CHAR && c == 'q') {
+ rdline_asyncpager_reset(rdl);
+ 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);
+ 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;
+ }
+ /* async printf was called in cb() */
+ return RDLINE_RES_SUCCESS;
+ }
+#endif
+
+ /* process control chars */
if (cmd != VT100_STD_CHAR) {
switch (cmd) {
case CMDLINE_KEY_CTRL_B:
cirbuf_align_left(&rdl->left);
rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
rdline_printf(rdl, "\r\n");
+#ifndef NO_PAGER
+ 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;
}
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)
cirbuf_align_left(&rdl->left);
rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
rdline_printf(rdl, "\r\n");
+#ifndef NO_PAGER
+ 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;
}
}
case CMDLINE_KEY_RETURN:
- case CMDLINE_KEY_RETURN2:
+ case CMDLINE_KEY_RETURN2: {
+ char tmp;
+ while (!CIRBUF_IS_EMPTY(&rdl->right) &&
+ (tmp = cirbuf_get_head(&rdl->right))) {
+ cirbuf_del_head(&rdl->right);
+ cirbuf_add_tail(&rdl->left, tmp);
+ }
cirbuf_align_left(&rdl->left);
rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\n';
rdl->left_buf[CIRBUF_GET_LEN(&rdl->left) + 1] = '\0';
- rdl->status = RDLINE_INIT;
rdline_printf(rdl, "\r\n");
#ifndef NO_RDLINE_HISTORY
if (rdl->history_cur_line != -1)
if (rdl->validate)
rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
+#ifndef NO_PAGER
/* user may have stopped rdline */
+ if (rdl->status == RDLINE_EXITED) {
+ rdline_asyncpager_reset(rdl);
+ return RDLINE_RES_EXITED;
+ }
+ if (rdl->pager_buf != NULL)
+ return RDLINE_RES_SUCCESS;
+ else
+ rdline_asyncpager_reset(rdl);
+
+ rdl->status = RDLINE_INIT;
+#else
if (rdl->status == RDLINE_EXITED)
return RDLINE_RES_EXITED;
+#endif
return RDLINE_RES_VALIDATED;
-
+ }
#ifndef NO_RDLINE_HISTORY
case CMDLINE_KEY_UP_ARR:
case CMDLINE_KEY_CTRL_P:
break;
#endif /* !NO_RDLINE_HISTORY */
-
default:
break;
}
return ret;
}
+
+#ifndef NO_PAGER
+/* reset pager state */
+void
+rdline_asyncpager_reset(struct rdline *rdl)
+{
+ if (rdl->pager_buf) {
+ free(rdl->pager_buf);
+ rdl->pager_buf = NULL;
+ }
+ rdl->pager_lines = 0;
+ rdl->pager_len = 0;
+ rdl->pager_off = 0;
+}
+
+/* Return the offset of the i-th occurence of char c in string s. If
+ * there is less than i occurences, return -1 and fill i with the
+ * count. */
+static int
+strnchr(const char *s, char c, int *i)
+{
+ int n = 0;
+ const char *orig = s;
+
+ while (*s) {
+ if (*s == c)
+ n++;
+ if (*i == n)
+ return s - orig;
+ s++;
+ }
+ *i = n;
+ return -1;
+}
+
+/* display a page of data from pager, return 0 if all is displayed */
+static int
+rdline_pager_next_page(struct rdline *rdl)
+{
+ int lines = RDLINE_MAX_LINES;
+ int displen;
+ char *s;
+
+ s = rdl->pager_buf;
+ if (s == NULL)
+ return 0;
+
+ rdline_printf(rdl, vt100_home);
+ rdline_printf(rdl, vt100_clear_right);
+
+ s += rdl->pager_off;
+
+ /* we know that s is 0-terminated */
+ displen = strnchr(s, '\n', &lines);
+ rdl->pager_lines = lines;
+
+ /* we can display all the data */
+ if (displen == -1) {
+ write(rdl->fd_out, s, rdl->pager_len);
+ free(rdl->pager_buf);
+ rdl->pager_buf = NULL;
+ return 0;
+ }
+
+ displen = displen + 1; /* include \n */
+ write(rdl->fd_out, s, displen);
+ rdl->pager_off += displen;
+ rdl->pager_len -= displen;
+
+ rdline_printf(rdl, "--- press a key to continue ---");
+ return -1;
+}
+
+/* push data in pager */
+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;
+ int displen;
+
+ /* we know that s is 0-terminated */
+ displen = strnchr(s, '\n', &lines);
+ rdl->pager_lines += lines;
+
+ /* we can display all the data */
+ if (displen == -1) {
+ write(rdl->fd_out, s, len);
+ return 0;
+ }
+ displen = displen + 1; /* include \n */
+ write(rdl->fd_out, s, displen);
+ s += displen;
+ len -= displen;
+ }
+
+ if (rdl->pager_buf == NULL) {
+ rdline_printf(rdl, "--- press a key to continue ---");
+ }
+ rdl->pager_buf = realloc(rdl->pager_buf, rdl->pager_len + len);
+ if (rdl->pager_buf == NULL) {
+ rdline_asyncpager_reset(rdl);
+ return -1;
+ }
+
+ memcpy(rdl->pager_buf + rdl->pager_len, s, len);
+ rdl->pager_len += len;
+ return 0;
+}
+
+/* Print data asynchronously (using pager if needed) */
+int
+rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...)
+{
+ int n;
+ char *buf;
+ va_list ap;
+
+ if (rdl->fd_out < 0)
+ return -1;
+
+ buf = malloc(BUFSIZ);
+ if (buf == NULL)
+ return -1;
+
+ va_start(ap, fmt);
+ n = vsnprintf(buf, BUFSIZ, fmt, ap);
+ va_end(ap);
+
+ if (n >= BUFSIZ)
+ n = BUFSIZ-1;
+ if (n > 0)
+ 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 */