#include <string.h>
#include <stdarg.h>
#include <ctype.h>
+#include <unistd.h>
#include "cmdline_cirbuf.h"
#include "cmdline_rdline.h"
-
-static void rdline_puts(struct rdline *rdl, const char *buf);
-static void rdline_miniprintf(struct rdline *rdl,
- const char *buf, unsigned int val);
+#include "cmdline_parse.h"
#ifndef NO_RDLINE_HISTORY
static void rdline_remove_old_history_item(struct rdline *rdl);
return 0;
}
-void rdline_init(struct rdline *rdl,
- rdline_write_char_t *write_char,
- rdline_validate_t *validate,
- rdline_complete_t *complete)
+void
+rdline_init(struct rdline *rdl,
+ int fd_in, int fd_out,
+ rdline_validate_t *validate,
+ rdline_complete_t *complete,
+ rdline_help_t *help)
{
memset(rdl, 0, sizeof(*rdl));
+ rdl->fd_in = fd_in;
+ rdl->fd_out = fd_out;
rdl->validate = validate;
rdl->complete = complete;
- rdl->write_char = write_char;
+ rdl->help = help;
rdl->status = RDLINE_INIT;
#ifndef NO_RDLINE_HISTORY
cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
void
rdline_newline(struct rdline *rdl, const char *prompt)
{
- unsigned int i;
-
vt100_init(&rdl->vt100);
cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
+ /* if pointer is the same, don't copy it */
if (prompt != rdl->prompt)
- memcpy(rdl->prompt, prompt, sizeof(rdl->prompt)-1);
- rdl->prompt_size = strlen(prompt);
+ snprintf(rdl->prompt, sizeof(rdl->prompt), "%s", prompt);
- for (i=0 ; i<rdl->prompt_size ; i++)
- rdl->write_char(rdl, rdl->prompt[i]);
+ rdline_printf(rdl, "%s", rdl->prompt);
rdl->status = RDLINE_RUNNING;
#ifndef NO_RDLINE_HISTORY
rdl->status = RDLINE_INIT;
}
+void
+rdline_quit(struct rdline *rdl)
+{
+ rdl->status = RDLINE_EXITED;
+}
+
void
rdline_restart(struct rdline *rdl)
{
len_r = CIRBUF_GET_LEN(&rdl->right);
memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
- rdl->left_buf[len_l + len_r] = '\n';
- rdl->left_buf[len_l + len_r + 1] = '\0';
+ rdl->left_buf[len_l + len_r] = '\0';
return rdl->left_buf;
}
static void
-display_right_buffer(struct rdline *rdl)
+display_right_buffer(struct rdline *rdl, int force)
{
unsigned int i;
char tmp;
- rdline_puts(rdl, vt100_clear_right);
- if (!CIRBUF_IS_EMPTY(&rdl->right)) {
- CIRBUF_FOREACH(&rdl->right, i, tmp) {
- rdl->write_char(rdl, tmp);
- }
- rdline_miniprintf(rdl, vt100_multi_left,
- CIRBUF_GET_LEN(&rdl->right));
+ if (!force && CIRBUF_IS_EMPTY(&rdl->right))
+ return;
+
+ rdline_printf(rdl, vt100_clear_right);
+ CIRBUF_FOREACH(&rdl->right, i, tmp) {
+ rdline_printf(rdl, "%c", tmp);
}
+ if (!CIRBUF_IS_EMPTY(&rdl->right))
+ rdline_printf(rdl, vt100_multi_left,
+ CIRBUF_GET_LEN(&rdl->right));
}
-void rdline_redisplay(struct rdline *rdl)
+void
+rdline_redisplay(struct rdline *rdl)
{
unsigned int i;
char tmp;
- rdline_puts(rdl, vt100_home);
- for (i=0 ; i<rdl->prompt_size ; i++)
- rdl->write_char(rdl, rdl->prompt[i]);
+ rdline_printf(rdl, vt100_home);
+ rdline_printf(rdl, "%s", rdl->prompt);
CIRBUF_FOREACH(&rdl->left, i, tmp) {
- rdl->write_char(rdl, tmp);
+ rdline_printf(rdl, "%c", tmp);
}
- display_right_buffer(rdl);
+ display_right_buffer(rdl, 1);
}
-int
-rdline_char_in(struct rdline *rdl, char c)
+static int
+rdline_parse_char(struct rdline *rdl, char c)
{
unsigned int i;
int cmd;
char *buf;
#endif
- if (rdl->status != RDLINE_RUNNING)
- return -1;
-
cmd = vt100_parser(&rdl->vt100, c);
- if (cmd == -2)
- return 0;
+ if (cmd == VT100_NOT_COMPLETE)
+ return RDLINE_RES_SUCCESS;
- if (cmd >= 0) {
+ if (cmd != VT100_STD_CHAR) {
switch (cmd) {
case CMDLINE_KEY_CTRL_B:
case CMDLINE_KEY_LEFT_ARR:
tmp = cirbuf_get_tail(&rdl->left);
cirbuf_del_tail(&rdl->left);
cirbuf_add_head(&rdl->right, tmp);
- rdline_puts(rdl, vt100_left_arr);
+ rdline_printf(rdl, vt100_left_arr);
break;
case CMDLINE_KEY_CTRL_F:
tmp = cirbuf_get_head(&rdl->right);
cirbuf_del_head(&rdl->right);
cirbuf_add_tail(&rdl->left, tmp);
- rdline_puts(rdl, vt100_right_arr);
+ rdline_printf(rdl, vt100_right_arr);
break;
case CMDLINE_KEY_WLEFT:
while (! CIRBUF_IS_EMPTY(&rdl->left) &&
(tmp = cirbuf_get_tail(&rdl->left)) &&
isblank2(tmp)) {
- rdline_puts(rdl, vt100_left_arr);
+ rdline_printf(rdl, vt100_left_arr);
cirbuf_del_tail(&rdl->left);
cirbuf_add_head(&rdl->right, tmp);
}
while (! CIRBUF_IS_EMPTY(&rdl->left) &&
(tmp = cirbuf_get_tail(&rdl->left)) &&
!isblank2(tmp)) {
- rdline_puts(rdl, vt100_left_arr);
+ rdline_printf(rdl, vt100_left_arr);
cirbuf_del_tail(&rdl->left);
cirbuf_add_head(&rdl->right, tmp);
}
while (! CIRBUF_IS_EMPTY(&rdl->right) &&
(tmp = cirbuf_get_head(&rdl->right)) &&
isblank2(tmp)) {
- rdline_puts(rdl, vt100_right_arr);
+ rdline_printf(rdl, vt100_right_arr);
cirbuf_del_head(&rdl->right);
cirbuf_add_tail(&rdl->left, tmp);
}
while (! CIRBUF_IS_EMPTY(&rdl->right) &&
(tmp = cirbuf_get_head(&rdl->right)) &&
!isblank2(tmp)) {
- rdline_puts(rdl, vt100_right_arr);
+ rdline_printf(rdl, vt100_right_arr);
cirbuf_del_head(&rdl->right);
cirbuf_add_tail(&rdl->left, tmp);
}
case CMDLINE_KEY_BKSPACE:
if(!cirbuf_del_tail_safe(&rdl->left)) {
- rdline_puts(rdl, vt100_bs);
- display_right_buffer(rdl);
+ rdline_printf(rdl, vt100_bs);
+ display_right_buffer(rdl, 1);
}
break;
case CMDLINE_KEY_META_BKSPACE:
- while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
- rdline_puts(rdl, vt100_bs);
+ case CMDLINE_KEY_CTRL_W:
+ while (! CIRBUF_IS_EMPTY(&rdl->left) &&
+ isblank2(cirbuf_get_tail(&rdl->left))) {
+ rdline_printf(rdl, vt100_bs);
cirbuf_del_tail(&rdl->left);
}
- while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank2(cirbuf_get_tail(&rdl->left))) {
- rdline_puts(rdl, vt100_bs);
+ while (! CIRBUF_IS_EMPTY(&rdl->left) &&
+ !isblank2(cirbuf_get_tail(&rdl->left))) {
+ rdline_printf(rdl, vt100_bs);
cirbuf_del_tail(&rdl->left);
}
- display_right_buffer(rdl);
+ display_right_buffer(rdl, 1);
+ break;
+
+ case CMDLINE_KEY_META_D:
+ while (! CIRBUF_IS_EMPTY(&rdl->right) &&
+ isblank2(cirbuf_get_head(&rdl->right)))
+ cirbuf_del_head(&rdl->right);
+ while (! CIRBUF_IS_EMPTY(&rdl->right) &&
+ !isblank2(cirbuf_get_head(&rdl->right)))
+ cirbuf_del_head(&rdl->right);
+ display_right_buffer(rdl, 1);
break;
case CMDLINE_KEY_SUPPR:
if (cmd == CMDLINE_KEY_CTRL_D &&
CIRBUF_IS_EMPTY(&rdl->left) &&
CIRBUF_IS_EMPTY(&rdl->right)) {
- return -2;
+ return RDLINE_RES_EOF;
}
if (!cirbuf_del_head_safe(&rdl->right)) {
- display_right_buffer(rdl);
+ display_right_buffer(rdl, 1);
}
break;
case CMDLINE_KEY_CTRL_A:
if (CIRBUF_IS_EMPTY(&rdl->left))
break;
- rdline_miniprintf(rdl, vt100_multi_left,
- CIRBUF_GET_LEN(&rdl->left));
+ rdline_printf(rdl, vt100_multi_left,
+ CIRBUF_GET_LEN(&rdl->left));
while (! CIRBUF_IS_EMPTY(&rdl->left)) {
tmp = cirbuf_get_tail(&rdl->left);
cirbuf_del_tail(&rdl->left);
case CMDLINE_KEY_CTRL_E:
if (CIRBUF_IS_EMPTY(&rdl->right))
break;
- rdline_miniprintf(rdl, vt100_multi_right,
- CIRBUF_GET_LEN(&rdl->right));
+ rdline_printf(rdl, vt100_multi_right,
+ CIRBUF_GET_LEN(&rdl->right));
while (! CIRBUF_IS_EMPTY(&rdl->right)) {
tmp = cirbuf_get_head(&rdl->right);
cirbuf_del_head(&rdl->right);
cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
- rdline_puts(rdl, vt100_clear_right);
+ rdline_printf(rdl, vt100_clear_right);
break;
case CMDLINE_KEY_CTRL_Y:
RDLINE_BUF_SIZE &&
i < rdl->kill_size) {
cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
- rdl->write_char(rdl, rdl->kill_buf[i]);
+ rdline_printf(rdl, "%c", rdl->kill_buf[i]);
i++;
}
- display_right_buffer(rdl);
+ display_right_buffer(rdl, 0);
break;
#endif /* !NO_RDLINE_KILL_BUF */
case CMDLINE_KEY_CTRL_C:
- rdline_puts(rdl, "\r\n");
+ rdline_printf(rdl, "\r\n");
rdline_newline(rdl, rdl->prompt);
break;
rdline_redisplay(rdl);
break;
- case CMDLINE_KEY_TAB:
- case CMDLINE_KEY_HELP:
+ case CMDLINE_KEY_HELP: {
+ if (rdl->help == NULL)
+ break;
+
+ 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);
+ rdline_redisplay(rdl);
+ break;
+ }
+
+ case CMDLINE_KEY_TAB: {
+ char tmp_buf[CMDLINE_MAX_TOKEN_SIZE];
+ int ret; //, curline = 0;
+ unsigned int tmp_size;
+
+ if (rdl->complete == NULL)
+ break;
+
cirbuf_align_left(&rdl->left);
rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
- if (rdl->complete) {
- char tmp_buf[BUFSIZ];
- int complete_state;
- int ret;
- unsigned int tmp_size;
-
- if (cmd == CMDLINE_KEY_TAB)
- complete_state = 0;
- else
- complete_state = -1;
-
- /* see in parse.h for help on complete() */
- ret = rdl->complete(rdl, rdl->left_buf,
- tmp_buf, sizeof(tmp_buf),
- &complete_state);
- /* no completion or error */
- if (ret <= 0) {
- return 2;
- }
-
- tmp_size = strlen(tmp_buf);
- /* add chars */
- if (ret == 2) {
- i=0;
- while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
- RDLINE_BUF_SIZE &&
- i < tmp_size) {
- cirbuf_add_tail(&rdl->left, tmp_buf[i]);
- rdl->write_char(rdl, tmp_buf[i]);
- i++;
- }
- display_right_buffer(rdl);
- return 2; /* ?? */
- }
-
- /* choice */
- rdline_puts(rdl, "\r\n");
- while (ret) {
- rdl->write_char(rdl, ' ');
- for (i=0 ; tmp_buf[i] ; i++)
- rdl->write_char(rdl, tmp_buf[i]);
- rdline_puts(rdl, "\r\n");
- ret = rdl->complete(rdl, rdl->left_buf,
- tmp_buf, sizeof(tmp_buf),
- &complete_state);
- }
+ /* see in parse.h for help on complete() */
+ ret = rdl->complete(rdl, rdl->left_buf,
+ tmp_buf, sizeof(tmp_buf));
+ /* no completion or error */
+ if (ret == CMDLINE_COMPLETE_NONE ||
+ ret == CMDLINE_COMPLETE_MANY) {
+ 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);
rdline_redisplay(rdl);
+ break;
}
- return 2;
+
+ tmp_size = strlen(tmp_buf);
+ /* add chars */
+ i = 0;
+ while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
+ RDLINE_BUF_SIZE &&
+ i < tmp_size) {
+ cirbuf_add_tail(&rdl->left, tmp_buf[i]);
+ rdline_printf(rdl, "%c", tmp_buf[i]);
+ i++;
+ }
+ display_right_buffer(rdl, 1);
+ break;
+ }
case CMDLINE_KEY_RETURN:
case CMDLINE_KEY_RETURN2:
- rdline_get_buffer(rdl);
+ 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_puts(rdl, "\r\n");
+ rdline_printf(rdl, "\r\n");
#ifndef NO_RDLINE_HISTORY
if (rdl->history_cur_line != -1)
rdline_remove_first_history_item(rdl);
if (rdl->validate)
rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
- return 1;
+ /* user may have stopped rdline */
+ if (rdl->status == RDLINE_EXITED)
+ return RDLINE_RES_EXITED;
+ return RDLINE_RES_VALIDATED;
#ifndef NO_RDLINE_HISTORY
case CMDLINE_KEY_UP_ARR:
+ case CMDLINE_KEY_CTRL_P:
if (rdl->history_cur_line == 0) {
rdline_remove_first_history_item(rdl);
}
break;
case CMDLINE_KEY_DOWN_ARR:
+ case CMDLINE_KEY_CTRL_N:
if (rdl->history_cur_line - 1 < 0)
break;
break;
}
- return 0;
+ return RDLINE_RES_SUCCESS;
}
if (!isprint((int)c))
- return 0;
+ return RDLINE_RES_SUCCESS;
/* standard chars */
if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
- return 0;
+ return RDLINE_RES_SUCCESS;
if (cirbuf_add_tail_safe(&rdl->left, c))
- return 0;
+ return RDLINE_RES_SUCCESS;
- rdl->write_char(rdl, c);
- display_right_buffer(rdl);
+ rdline_printf(rdl, "%c", c);
+ display_right_buffer(rdl, 0);
- return 0;
+ return RDLINE_RES_SUCCESS;
+}
+
+int
+rdline_char_in(struct rdline *rdl, char c)
+{
+ int ret, same = 0;
+ const char *history, *buffer;
+
+ if (rdl->status == RDLINE_EXITED)
+ return RDLINE_RES_EXITED;
+ if (rdl->status != RDLINE_RUNNING)
+ return RDLINE_RES_NOT_RUNNING;
+
+ ret = rdline_parse_char(rdl, c);
+
+ /* add line to history */
+ if (ret == RDLINE_RES_VALIDATED) {
+ buffer = rdline_get_buffer(rdl);
+ history = rdline_get_history_item(rdl, 0);
+ if (history)
+ same = !strcmp(buffer, history);
+
+ if (strlen(buffer) >= 1 && same == 0)
+ rdline_add_history(rdl, buffer);
+ }
+
+ return ret;
}
+int
+rdline(struct rdline *rdl, const char *prompt)
+{
+ char c;
+ int ret = RDLINE_RES_NOT_RUNNING;
+
+ rdline_newline(rdl, prompt);
+ while (1) {
+ if (read(rdl->fd_in, &c, 1) < 0)
+ break;
+ ret = rdline_char_in(rdl, c);
+ if (ret != RDLINE_RES_SUCCESS)
+ break;
+ }
+
+ return ret;
+}
/* HISTORY */
int
rdline_add_history(struct rdline * rdl, const char * buf)
{
- unsigned int len, i;
+ unsigned int len;
len = strlen(buf);
- for (i=0; i<len ; i++) {
- if (buf[i] == '\n') {
- len = i;
- break;
- }
- }
-
- if ( len >= RDLINE_HISTORY_BUF_SIZE )
+ if (len >= RDLINE_HISTORY_BUF_SIZE)
return -1;
- while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
+ while (len >= CIRBUF_GET_FREELEN(&rdl->history)) {
rdline_remove_old_history_item(rdl);
}
#else /* !NO_RDLINE_HISTORY */
-int rdline_add_history(struct rdline * rdl, const char * buf) {return -1;}
-void rdline_clear_history(struct rdline * rdl) {}
-char * rdline_get_history_item(struct rdline * rdl, unsigned int i) {return NULL;}
+int rdline_add_history(struct rdline * rdl, const char * buf)
+{
+ return -1;
+}
+void rdline_clear_history(struct rdline * rdl)
+{
+ return;
+}
-#endif /* !NO_RDLINE_HISTORY */
+char * rdline_get_history_item(struct rdline * rdl, unsigned int i)
+{
+ return NULL;
+}
-/* STATIC USEFUL FUNCS */
+#endif /* !NO_RDLINE_HISTORY */
-static void
-rdline_puts(struct rdline * rdl, const char * buf)
+
+ssize_t
+rdline_write(const struct rdline *rdl, void *buf, size_t count)
{
- char c;
- while ( (c = *(buf++)) != '\0' ) {
- rdl->write_char(rdl, c);
- }
+ return write(rdl->fd_out, buf, count);
}
-/* a very very basic printf with one arg and one format 'u' */
-static void
-rdline_miniprintf(struct rdline *rdl, const char * buf, unsigned int val)
+int
+rdline_vprintf(const struct rdline *rdl, const char *fmt, va_list ap)
{
- char c, started=0, div=100;
+ int ret;
+#ifndef _GNU_SOURCE
+ char *buf;
+#endif
- while ( (c=*(buf++)) ) {
- if (c != '%') {
- rdl->write_char(rdl, c);
- continue;
- }
- c = *(buf++);
- if (c != 'u') {
- rdl->write_char(rdl, '%');
- rdl->write_char(rdl, c);
- continue;
- }
- /* val is never more than 255 */
- while (div) {
- c = val / div;
- if (c || started) {
- rdl->write_char(rdl, c+'0');
- started = 1;
- }
- val %= div;
- div /= 10;
- }
- }
+ if (rdl->fd_out < 0)
+ return -1;
+
+#ifdef _GNU_SOURCE
+ ret = vdprintf(rdl->fd_out, fmt, ap);
+#else
+ buf = malloc(BUFSIZ);
+ if (buf == NULL)
+ return -1;
+
+ ret = vsnprintf(buf, BUFSIZ, fmt, ap);
+
+ if (ret > 0)
+ write(rdl->fd_out, buf, (ret >= BUFSIZ) ? BUFSIZ : ret);
+ free(buf);
+#endif
+
+ return ret;
}
+int
+rdline_printf(const struct rdline *rdl, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = rdline_vprintf(rdl, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}