199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation.
399a2dd95SBruce Richardson * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
499a2dd95SBruce Richardson * All rights reserved.
599a2dd95SBruce Richardson */
699a2dd95SBruce Richardson
799a2dd95SBruce Richardson #include <stdlib.h>
899a2dd95SBruce Richardson #include <stdio.h>
999a2dd95SBruce Richardson #include <string.h>
1099a2dd95SBruce Richardson #include <errno.h>
1199a2dd95SBruce Richardson #include <ctype.h>
1299a2dd95SBruce Richardson
1399a2dd95SBruce Richardson #include "cmdline_cirbuf.h"
14*f8f8dc28SDmitry Kozlyuk #include "cmdline_private.h"
1599a2dd95SBruce Richardson #include "cmdline_rdline.h"
1699a2dd95SBruce Richardson
1799a2dd95SBruce Richardson static void rdline_puts(struct rdline *rdl, const char *buf);
1899a2dd95SBruce Richardson static void rdline_miniprintf(struct rdline *rdl,
1999a2dd95SBruce Richardson const char *buf, unsigned int val);
2099a2dd95SBruce Richardson
2199a2dd95SBruce Richardson static void rdline_remove_old_history_item(struct rdline *rdl);
2299a2dd95SBruce Richardson static void rdline_remove_first_history_item(struct rdline *rdl);
2399a2dd95SBruce Richardson static unsigned int rdline_get_history_size(struct rdline *rdl);
2499a2dd95SBruce Richardson
2599a2dd95SBruce Richardson
2699a2dd95SBruce Richardson /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
2799a2dd95SBruce Richardson * own. */
2899a2dd95SBruce Richardson static int
isblank2(char c)2999a2dd95SBruce Richardson isblank2(char c)
3099a2dd95SBruce Richardson {
3199a2dd95SBruce Richardson if (c == ' ' ||
3299a2dd95SBruce Richardson c == '\t' )
3399a2dd95SBruce Richardson return 1;
3499a2dd95SBruce Richardson return 0;
3599a2dd95SBruce Richardson }
3699a2dd95SBruce Richardson
3799a2dd95SBruce Richardson int
rdline_init(struct rdline * rdl,rdline_write_char_t * write_char,rdline_validate_t * validate,rdline_complete_t * complete,void * opaque)3899a2dd95SBruce Richardson rdline_init(struct rdline *rdl,
3999a2dd95SBruce Richardson rdline_write_char_t *write_char,
4099a2dd95SBruce Richardson rdline_validate_t *validate,
41*f8f8dc28SDmitry Kozlyuk rdline_complete_t *complete,
42*f8f8dc28SDmitry Kozlyuk void *opaque)
4399a2dd95SBruce Richardson {
4499a2dd95SBruce Richardson if (!rdl || !write_char || !validate || !complete)
4599a2dd95SBruce Richardson return -EINVAL;
4699a2dd95SBruce Richardson memset(rdl, 0, sizeof(*rdl));
4799a2dd95SBruce Richardson rdl->validate = validate;
4899a2dd95SBruce Richardson rdl->complete = complete;
4999a2dd95SBruce Richardson rdl->write_char = write_char;
50*f8f8dc28SDmitry Kozlyuk rdl->opaque = opaque;
5199a2dd95SBruce Richardson rdl->status = RDLINE_INIT;
5299a2dd95SBruce Richardson return cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
5399a2dd95SBruce Richardson }
5499a2dd95SBruce Richardson
55*f8f8dc28SDmitry Kozlyuk struct rdline *
rdline_new(rdline_write_char_t * write_char,rdline_validate_t * validate,rdline_complete_t * complete,void * opaque)56*f8f8dc28SDmitry Kozlyuk rdline_new(rdline_write_char_t *write_char,
57*f8f8dc28SDmitry Kozlyuk rdline_validate_t *validate,
58*f8f8dc28SDmitry Kozlyuk rdline_complete_t *complete,
59*f8f8dc28SDmitry Kozlyuk void *opaque)
60*f8f8dc28SDmitry Kozlyuk {
61*f8f8dc28SDmitry Kozlyuk struct rdline *rdl;
62*f8f8dc28SDmitry Kozlyuk
63*f8f8dc28SDmitry Kozlyuk rdl = malloc(sizeof(*rdl));
64*f8f8dc28SDmitry Kozlyuk if (rdline_init(rdl, write_char, validate, complete, opaque) < 0) {
65*f8f8dc28SDmitry Kozlyuk free(rdl);
66*f8f8dc28SDmitry Kozlyuk rdl = NULL;
67*f8f8dc28SDmitry Kozlyuk }
68*f8f8dc28SDmitry Kozlyuk return rdl;
69*f8f8dc28SDmitry Kozlyuk }
70*f8f8dc28SDmitry Kozlyuk
71*f8f8dc28SDmitry Kozlyuk void
rdline_free(struct rdline * rdl)72*f8f8dc28SDmitry Kozlyuk rdline_free(struct rdline *rdl)
73*f8f8dc28SDmitry Kozlyuk {
74*f8f8dc28SDmitry Kozlyuk free(rdl);
75*f8f8dc28SDmitry Kozlyuk }
76*f8f8dc28SDmitry Kozlyuk
7799a2dd95SBruce Richardson void
rdline_newline(struct rdline * rdl,const char * prompt)7899a2dd95SBruce Richardson rdline_newline(struct rdline *rdl, const char *prompt)
7999a2dd95SBruce Richardson {
8099a2dd95SBruce Richardson unsigned int i;
8199a2dd95SBruce Richardson
8299a2dd95SBruce Richardson if (!rdl || !prompt)
8399a2dd95SBruce Richardson return;
8499a2dd95SBruce Richardson
8599a2dd95SBruce Richardson vt100_init(&rdl->vt100);
8699a2dd95SBruce Richardson cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
8799a2dd95SBruce Richardson cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
8899a2dd95SBruce Richardson
8999a2dd95SBruce Richardson rdl->prompt_size = strnlen(prompt, RDLINE_PROMPT_SIZE-1);
9099a2dd95SBruce Richardson if (prompt != rdl->prompt)
9199a2dd95SBruce Richardson memcpy(rdl->prompt, prompt, rdl->prompt_size);
9299a2dd95SBruce Richardson rdl->prompt[RDLINE_PROMPT_SIZE-1] = '\0';
9399a2dd95SBruce Richardson
9499a2dd95SBruce Richardson for (i=0 ; i<rdl->prompt_size ; i++)
9599a2dd95SBruce Richardson rdl->write_char(rdl, rdl->prompt[i]);
9699a2dd95SBruce Richardson rdl->status = RDLINE_RUNNING;
9799a2dd95SBruce Richardson
9899a2dd95SBruce Richardson rdl->history_cur_line = -1;
9999a2dd95SBruce Richardson }
10099a2dd95SBruce Richardson
10199a2dd95SBruce Richardson void
rdline_stop(struct rdline * rdl)10299a2dd95SBruce Richardson rdline_stop(struct rdline *rdl)
10399a2dd95SBruce Richardson {
10499a2dd95SBruce Richardson if (!rdl)
10599a2dd95SBruce Richardson return;
10699a2dd95SBruce Richardson rdl->status = RDLINE_INIT;
10799a2dd95SBruce Richardson }
10899a2dd95SBruce Richardson
10999a2dd95SBruce Richardson void
rdline_quit(struct rdline * rdl)11099a2dd95SBruce Richardson rdline_quit(struct rdline *rdl)
11199a2dd95SBruce Richardson {
11299a2dd95SBruce Richardson if (!rdl)
11399a2dd95SBruce Richardson return;
11499a2dd95SBruce Richardson rdl->status = RDLINE_EXITED;
11599a2dd95SBruce Richardson }
11699a2dd95SBruce Richardson
11799a2dd95SBruce Richardson void
rdline_restart(struct rdline * rdl)11899a2dd95SBruce Richardson rdline_restart(struct rdline *rdl)
11999a2dd95SBruce Richardson {
12099a2dd95SBruce Richardson if (!rdl)
12199a2dd95SBruce Richardson return;
12299a2dd95SBruce Richardson rdl->status = RDLINE_RUNNING;
12399a2dd95SBruce Richardson }
12499a2dd95SBruce Richardson
12599a2dd95SBruce Richardson void
rdline_reset(struct rdline * rdl)12699a2dd95SBruce Richardson rdline_reset(struct rdline *rdl)
12799a2dd95SBruce Richardson {
12899a2dd95SBruce Richardson if (!rdl)
12999a2dd95SBruce Richardson return;
13099a2dd95SBruce Richardson vt100_init(&rdl->vt100);
13199a2dd95SBruce Richardson cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
13299a2dd95SBruce Richardson cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
13399a2dd95SBruce Richardson
13499a2dd95SBruce Richardson rdl->status = RDLINE_RUNNING;
13599a2dd95SBruce Richardson
13699a2dd95SBruce Richardson rdl->history_cur_line = -1;
13799a2dd95SBruce Richardson }
13899a2dd95SBruce Richardson
13999a2dd95SBruce Richardson const char *
rdline_get_buffer(struct rdline * rdl)14099a2dd95SBruce Richardson rdline_get_buffer(struct rdline *rdl)
14199a2dd95SBruce Richardson {
14299a2dd95SBruce Richardson if (!rdl)
14399a2dd95SBruce Richardson return NULL;
14499a2dd95SBruce Richardson unsigned int len_l, len_r;
14599a2dd95SBruce Richardson cirbuf_align_left(&rdl->left);
14699a2dd95SBruce Richardson cirbuf_align_left(&rdl->right);
14799a2dd95SBruce Richardson
14899a2dd95SBruce Richardson len_l = CIRBUF_GET_LEN(&rdl->left);
14999a2dd95SBruce Richardson len_r = CIRBUF_GET_LEN(&rdl->right);
15099a2dd95SBruce Richardson memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
15199a2dd95SBruce Richardson
15299a2dd95SBruce Richardson rdl->left_buf[len_l + len_r] = '\n';
15399a2dd95SBruce Richardson rdl->left_buf[len_l + len_r + 1] = '\0';
15499a2dd95SBruce Richardson return rdl->left_buf;
15599a2dd95SBruce Richardson }
15699a2dd95SBruce Richardson
15799a2dd95SBruce Richardson static void
display_right_buffer(struct rdline * rdl,int force)15899a2dd95SBruce Richardson display_right_buffer(struct rdline *rdl, int force)
15999a2dd95SBruce Richardson {
16099a2dd95SBruce Richardson unsigned int i;
16199a2dd95SBruce Richardson char tmp;
16299a2dd95SBruce Richardson
16399a2dd95SBruce Richardson if (!force && CIRBUF_IS_EMPTY(&rdl->right))
16499a2dd95SBruce Richardson return;
16599a2dd95SBruce Richardson
16699a2dd95SBruce Richardson rdline_puts(rdl, vt100_clear_right);
16799a2dd95SBruce Richardson CIRBUF_FOREACH(&rdl->right, i, tmp) {
16899a2dd95SBruce Richardson rdl->write_char(rdl, tmp);
16999a2dd95SBruce Richardson }
17099a2dd95SBruce Richardson if (!CIRBUF_IS_EMPTY(&rdl->right))
17199a2dd95SBruce Richardson rdline_miniprintf(rdl, vt100_multi_left,
17299a2dd95SBruce Richardson CIRBUF_GET_LEN(&rdl->right));
17399a2dd95SBruce Richardson }
17499a2dd95SBruce Richardson
17599a2dd95SBruce Richardson void
rdline_redisplay(struct rdline * rdl)17699a2dd95SBruce Richardson rdline_redisplay(struct rdline *rdl)
17799a2dd95SBruce Richardson {
17899a2dd95SBruce Richardson unsigned int i;
17999a2dd95SBruce Richardson char tmp;
18099a2dd95SBruce Richardson
18199a2dd95SBruce Richardson if (!rdl)
18299a2dd95SBruce Richardson return;
18399a2dd95SBruce Richardson
18499a2dd95SBruce Richardson rdline_puts(rdl, vt100_home);
18599a2dd95SBruce Richardson for (i=0 ; i<rdl->prompt_size ; i++)
18699a2dd95SBruce Richardson rdl->write_char(rdl, rdl->prompt[i]);
18799a2dd95SBruce Richardson CIRBUF_FOREACH(&rdl->left, i, tmp) {
18899a2dd95SBruce Richardson rdl->write_char(rdl, tmp);
18999a2dd95SBruce Richardson }
19099a2dd95SBruce Richardson display_right_buffer(rdl, 1);
19199a2dd95SBruce Richardson }
19299a2dd95SBruce Richardson
19399a2dd95SBruce Richardson int
rdline_char_in(struct rdline * rdl,char c)19499a2dd95SBruce Richardson rdline_char_in(struct rdline *rdl, char c)
19599a2dd95SBruce Richardson {
19699a2dd95SBruce Richardson unsigned int i;
19799a2dd95SBruce Richardson int cmd;
19899a2dd95SBruce Richardson char tmp;
19999a2dd95SBruce Richardson char *buf;
20099a2dd95SBruce Richardson
20199a2dd95SBruce Richardson if (!rdl)
20299a2dd95SBruce Richardson return -EINVAL;
20399a2dd95SBruce Richardson
20499a2dd95SBruce Richardson if (rdl->status == RDLINE_EXITED)
20599a2dd95SBruce Richardson return RDLINE_RES_EXITED;
20699a2dd95SBruce Richardson if (rdl->status != RDLINE_RUNNING)
20799a2dd95SBruce Richardson return RDLINE_RES_NOT_RUNNING;
20899a2dd95SBruce Richardson
20999a2dd95SBruce Richardson cmd = vt100_parser(&rdl->vt100, c);
21099a2dd95SBruce Richardson if (cmd == -2)
21199a2dd95SBruce Richardson return RDLINE_RES_SUCCESS;
21299a2dd95SBruce Richardson
21399a2dd95SBruce Richardson if (cmd >= 0) {
21499a2dd95SBruce Richardson switch (cmd) {
21599a2dd95SBruce Richardson /* move caret 1 char to the left */
21699a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_B:
21799a2dd95SBruce Richardson case CMDLINE_KEY_LEFT_ARR:
21899a2dd95SBruce Richardson if (CIRBUF_IS_EMPTY(&rdl->left))
21999a2dd95SBruce Richardson break;
22099a2dd95SBruce Richardson tmp = cirbuf_get_tail(&rdl->left);
22199a2dd95SBruce Richardson cirbuf_del_tail(&rdl->left);
22299a2dd95SBruce Richardson cirbuf_add_head(&rdl->right, tmp);
22399a2dd95SBruce Richardson rdline_puts(rdl, vt100_left_arr);
22499a2dd95SBruce Richardson break;
22599a2dd95SBruce Richardson
22699a2dd95SBruce Richardson /* move caret 1 char to the right */
22799a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_F:
22899a2dd95SBruce Richardson case CMDLINE_KEY_RIGHT_ARR:
22999a2dd95SBruce Richardson if (CIRBUF_IS_EMPTY(&rdl->right))
23099a2dd95SBruce Richardson break;
23199a2dd95SBruce Richardson tmp = cirbuf_get_head(&rdl->right);
23299a2dd95SBruce Richardson cirbuf_del_head(&rdl->right);
23399a2dd95SBruce Richardson cirbuf_add_tail(&rdl->left, tmp);
23499a2dd95SBruce Richardson rdline_puts(rdl, vt100_right_arr);
23599a2dd95SBruce Richardson break;
23699a2dd95SBruce Richardson
23799a2dd95SBruce Richardson /* move caret 1 word to the left */
23899a2dd95SBruce Richardson /* keyboard equivalent: Alt+B */
23999a2dd95SBruce Richardson case CMDLINE_KEY_WLEFT:
24099a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->left) &&
24199a2dd95SBruce Richardson (tmp = cirbuf_get_tail(&rdl->left)) &&
24299a2dd95SBruce Richardson isblank2(tmp)) {
24399a2dd95SBruce Richardson rdline_puts(rdl, vt100_left_arr);
24499a2dd95SBruce Richardson cirbuf_del_tail(&rdl->left);
24599a2dd95SBruce Richardson cirbuf_add_head(&rdl->right, tmp);
24699a2dd95SBruce Richardson }
24799a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->left) &&
24899a2dd95SBruce Richardson (tmp = cirbuf_get_tail(&rdl->left)) &&
24999a2dd95SBruce Richardson !isblank2(tmp)) {
25099a2dd95SBruce Richardson rdline_puts(rdl, vt100_left_arr);
25199a2dd95SBruce Richardson cirbuf_del_tail(&rdl->left);
25299a2dd95SBruce Richardson cirbuf_add_head(&rdl->right, tmp);
25399a2dd95SBruce Richardson }
25499a2dd95SBruce Richardson break;
25599a2dd95SBruce Richardson
25699a2dd95SBruce Richardson /* move caret 1 word to the right */
25799a2dd95SBruce Richardson /* keyboard equivalent: Alt+F */
25899a2dd95SBruce Richardson case CMDLINE_KEY_WRIGHT:
25999a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->right) &&
26099a2dd95SBruce Richardson (tmp = cirbuf_get_head(&rdl->right)) &&
26199a2dd95SBruce Richardson isblank2(tmp)) {
26299a2dd95SBruce Richardson rdline_puts(rdl, vt100_right_arr);
26399a2dd95SBruce Richardson cirbuf_del_head(&rdl->right);
26499a2dd95SBruce Richardson cirbuf_add_tail(&rdl->left, tmp);
26599a2dd95SBruce Richardson }
26699a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->right) &&
26799a2dd95SBruce Richardson (tmp = cirbuf_get_head(&rdl->right)) &&
26899a2dd95SBruce Richardson !isblank2(tmp)) {
26999a2dd95SBruce Richardson rdline_puts(rdl, vt100_right_arr);
27099a2dd95SBruce Richardson cirbuf_del_head(&rdl->right);
27199a2dd95SBruce Richardson cirbuf_add_tail(&rdl->left, tmp);
27299a2dd95SBruce Richardson }
27399a2dd95SBruce Richardson break;
27499a2dd95SBruce Richardson
27599a2dd95SBruce Richardson /* move caret to the left */
27699a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_A:
27799a2dd95SBruce Richardson if (CIRBUF_IS_EMPTY(&rdl->left))
27899a2dd95SBruce Richardson break;
27999a2dd95SBruce Richardson rdline_miniprintf(rdl, vt100_multi_left,
28099a2dd95SBruce Richardson CIRBUF_GET_LEN(&rdl->left));
28199a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->left)) {
28299a2dd95SBruce Richardson tmp = cirbuf_get_tail(&rdl->left);
28399a2dd95SBruce Richardson cirbuf_del_tail(&rdl->left);
28499a2dd95SBruce Richardson cirbuf_add_head(&rdl->right, tmp);
28599a2dd95SBruce Richardson }
28699a2dd95SBruce Richardson break;
28799a2dd95SBruce Richardson
28899a2dd95SBruce Richardson /* move caret to the right */
28999a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_E:
29099a2dd95SBruce Richardson if (CIRBUF_IS_EMPTY(&rdl->right))
29199a2dd95SBruce Richardson break;
29299a2dd95SBruce Richardson rdline_miniprintf(rdl, vt100_multi_right,
29399a2dd95SBruce Richardson CIRBUF_GET_LEN(&rdl->right));
29499a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->right)) {
29599a2dd95SBruce Richardson tmp = cirbuf_get_head(&rdl->right);
29699a2dd95SBruce Richardson cirbuf_del_head(&rdl->right);
29799a2dd95SBruce Richardson cirbuf_add_tail(&rdl->left, tmp);
29899a2dd95SBruce Richardson }
29999a2dd95SBruce Richardson break;
30099a2dd95SBruce Richardson
30199a2dd95SBruce Richardson /* delete 1 char from the left */
30299a2dd95SBruce Richardson case CMDLINE_KEY_BKSPACE:
30399a2dd95SBruce Richardson case CMDLINE_KEY_BKSPACE2:
30499a2dd95SBruce Richardson if(!cirbuf_del_tail_safe(&rdl->left)) {
30599a2dd95SBruce Richardson rdline_puts(rdl, vt100_bs);
30699a2dd95SBruce Richardson display_right_buffer(rdl, 1);
30799a2dd95SBruce Richardson }
30899a2dd95SBruce Richardson break;
30999a2dd95SBruce Richardson
31099a2dd95SBruce Richardson /* delete 1 char from the right */
31199a2dd95SBruce Richardson case CMDLINE_KEY_SUPPR:
31299a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_D:
31399a2dd95SBruce Richardson if (cmd == CMDLINE_KEY_CTRL_D &&
31499a2dd95SBruce Richardson CIRBUF_IS_EMPTY(&rdl->left) &&
31599a2dd95SBruce Richardson CIRBUF_IS_EMPTY(&rdl->right)) {
31699a2dd95SBruce Richardson return RDLINE_RES_EOF;
31799a2dd95SBruce Richardson }
31899a2dd95SBruce Richardson if (!cirbuf_del_head_safe(&rdl->right)) {
31999a2dd95SBruce Richardson display_right_buffer(rdl, 1);
32099a2dd95SBruce Richardson }
32199a2dd95SBruce Richardson break;
32299a2dd95SBruce Richardson
32399a2dd95SBruce Richardson /* delete 1 word from the left */
32499a2dd95SBruce Richardson case CMDLINE_KEY_META_BKSPACE:
32599a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_W:
32699a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
32799a2dd95SBruce Richardson rdline_puts(rdl, vt100_bs);
32899a2dd95SBruce Richardson cirbuf_del_tail(&rdl->left);
32999a2dd95SBruce Richardson }
33099a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank2(cirbuf_get_tail(&rdl->left))) {
33199a2dd95SBruce Richardson rdline_puts(rdl, vt100_bs);
33299a2dd95SBruce Richardson cirbuf_del_tail(&rdl->left);
33399a2dd95SBruce Richardson }
33499a2dd95SBruce Richardson display_right_buffer(rdl, 1);
33599a2dd95SBruce Richardson break;
33699a2dd95SBruce Richardson
33799a2dd95SBruce Richardson /* delete 1 word from the right */
33899a2dd95SBruce Richardson case CMDLINE_KEY_META_D:
33999a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->right) && isblank2(cirbuf_get_head(&rdl->right)))
34099a2dd95SBruce Richardson cirbuf_del_head(&rdl->right);
34199a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->right) && !isblank2(cirbuf_get_head(&rdl->right)))
34299a2dd95SBruce Richardson cirbuf_del_head(&rdl->right);
34399a2dd95SBruce Richardson display_right_buffer(rdl, 1);
34499a2dd95SBruce Richardson break;
34599a2dd95SBruce Richardson
34699a2dd95SBruce Richardson /* set kill buffer to contents on the right side of caret */
34799a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_K:
34899a2dd95SBruce Richardson cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
34999a2dd95SBruce Richardson rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
35099a2dd95SBruce Richardson cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
35199a2dd95SBruce Richardson rdline_puts(rdl, vt100_clear_right);
35299a2dd95SBruce Richardson break;
35399a2dd95SBruce Richardson
35499a2dd95SBruce Richardson /* paste contents of kill buffer to the left side of caret */
35599a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_Y:
35699a2dd95SBruce Richardson i=0;
35799a2dd95SBruce Richardson while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
35899a2dd95SBruce Richardson RDLINE_BUF_SIZE &&
35999a2dd95SBruce Richardson i < rdl->kill_size) {
36099a2dd95SBruce Richardson cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
36199a2dd95SBruce Richardson rdl->write_char(rdl, rdl->kill_buf[i]);
36299a2dd95SBruce Richardson i++;
36399a2dd95SBruce Richardson }
36499a2dd95SBruce Richardson display_right_buffer(rdl, 0);
36599a2dd95SBruce Richardson break;
36699a2dd95SBruce Richardson
36799a2dd95SBruce Richardson /* clear and newline */
36899a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_C:
36999a2dd95SBruce Richardson rdline_puts(rdl, "\r\n");
37099a2dd95SBruce Richardson rdline_newline(rdl, rdl->prompt);
37199a2dd95SBruce Richardson break;
37299a2dd95SBruce Richardson
37399a2dd95SBruce Richardson /* redisplay (helps when prompt is lost in other output) */
37499a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_L:
37599a2dd95SBruce Richardson rdline_redisplay(rdl);
37699a2dd95SBruce Richardson break;
37799a2dd95SBruce Richardson
37899a2dd95SBruce Richardson /* autocomplete */
37999a2dd95SBruce Richardson case CMDLINE_KEY_TAB:
38099a2dd95SBruce Richardson case CMDLINE_KEY_HELP:
38199a2dd95SBruce Richardson cirbuf_align_left(&rdl->left);
38299a2dd95SBruce Richardson rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
38399a2dd95SBruce Richardson if (rdl->complete) {
38499a2dd95SBruce Richardson char tmp_buf[BUFSIZ];
38599a2dd95SBruce Richardson int complete_state;
38699a2dd95SBruce Richardson int ret;
38799a2dd95SBruce Richardson unsigned int tmp_size;
38899a2dd95SBruce Richardson
38999a2dd95SBruce Richardson if (cmd == CMDLINE_KEY_TAB)
39099a2dd95SBruce Richardson complete_state = 0;
39199a2dd95SBruce Richardson else
39299a2dd95SBruce Richardson complete_state = -1;
39399a2dd95SBruce Richardson
39499a2dd95SBruce Richardson /* see in parse.h for help on complete() */
39599a2dd95SBruce Richardson ret = rdl->complete(rdl, rdl->left_buf,
39699a2dd95SBruce Richardson tmp_buf, sizeof(tmp_buf),
39799a2dd95SBruce Richardson &complete_state);
39899a2dd95SBruce Richardson /* no completion or error */
39999a2dd95SBruce Richardson if (ret <= 0) {
40099a2dd95SBruce Richardson return RDLINE_RES_COMPLETE;
40199a2dd95SBruce Richardson }
40299a2dd95SBruce Richardson
40399a2dd95SBruce Richardson tmp_size = strnlen(tmp_buf, sizeof(tmp_buf));
40499a2dd95SBruce Richardson /* add chars */
40599a2dd95SBruce Richardson if (ret == RDLINE_RES_COMPLETE) {
40699a2dd95SBruce Richardson i=0;
40799a2dd95SBruce Richardson while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
40899a2dd95SBruce Richardson RDLINE_BUF_SIZE &&
40999a2dd95SBruce Richardson i < tmp_size) {
41099a2dd95SBruce Richardson cirbuf_add_tail(&rdl->left, tmp_buf[i]);
41199a2dd95SBruce Richardson rdl->write_char(rdl, tmp_buf[i]);
41299a2dd95SBruce Richardson i++;
41399a2dd95SBruce Richardson }
41499a2dd95SBruce Richardson display_right_buffer(rdl, 1);
41599a2dd95SBruce Richardson return RDLINE_RES_COMPLETE; /* ?? */
41699a2dd95SBruce Richardson }
41799a2dd95SBruce Richardson
41899a2dd95SBruce Richardson /* choice */
41999a2dd95SBruce Richardson rdline_puts(rdl, "\r\n");
42099a2dd95SBruce Richardson while (ret) {
42199a2dd95SBruce Richardson rdl->write_char(rdl, ' ');
42299a2dd95SBruce Richardson for (i=0 ; tmp_buf[i] ; i++)
42399a2dd95SBruce Richardson rdl->write_char(rdl, tmp_buf[i]);
42499a2dd95SBruce Richardson rdline_puts(rdl, "\r\n");
42599a2dd95SBruce Richardson ret = rdl->complete(rdl, rdl->left_buf,
42699a2dd95SBruce Richardson tmp_buf, sizeof(tmp_buf),
42799a2dd95SBruce Richardson &complete_state);
42899a2dd95SBruce Richardson }
42999a2dd95SBruce Richardson
43099a2dd95SBruce Richardson rdline_redisplay(rdl);
43199a2dd95SBruce Richardson }
43299a2dd95SBruce Richardson return RDLINE_RES_COMPLETE;
43399a2dd95SBruce Richardson
43499a2dd95SBruce Richardson /* complete buffer */
43599a2dd95SBruce Richardson case CMDLINE_KEY_RETURN:
43699a2dd95SBruce Richardson case CMDLINE_KEY_RETURN2:
43799a2dd95SBruce Richardson rdline_get_buffer(rdl);
43899a2dd95SBruce Richardson rdl->status = RDLINE_INIT;
43999a2dd95SBruce Richardson rdline_puts(rdl, "\r\n");
44099a2dd95SBruce Richardson if (rdl->history_cur_line != -1)
44199a2dd95SBruce Richardson rdline_remove_first_history_item(rdl);
44299a2dd95SBruce Richardson
44399a2dd95SBruce Richardson if (rdl->validate)
44499a2dd95SBruce Richardson rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
44599a2dd95SBruce Richardson /* user may have stopped rdline */
44699a2dd95SBruce Richardson if (rdl->status == RDLINE_EXITED)
44799a2dd95SBruce Richardson return RDLINE_RES_EXITED;
44899a2dd95SBruce Richardson return RDLINE_RES_VALIDATED;
44999a2dd95SBruce Richardson
45099a2dd95SBruce Richardson /* previous element in history */
45199a2dd95SBruce Richardson case CMDLINE_KEY_UP_ARR:
45299a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_P:
45399a2dd95SBruce Richardson if (rdl->history_cur_line == 0) {
45499a2dd95SBruce Richardson rdline_remove_first_history_item(rdl);
45599a2dd95SBruce Richardson }
45699a2dd95SBruce Richardson if (rdl->history_cur_line <= 0) {
45799a2dd95SBruce Richardson rdline_add_history(rdl, rdline_get_buffer(rdl));
45899a2dd95SBruce Richardson rdl->history_cur_line = 0;
45999a2dd95SBruce Richardson }
46099a2dd95SBruce Richardson
46199a2dd95SBruce Richardson buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
46299a2dd95SBruce Richardson if (!buf)
46399a2dd95SBruce Richardson break;
46499a2dd95SBruce Richardson
46599a2dd95SBruce Richardson rdl->history_cur_line ++;
46699a2dd95SBruce Richardson vt100_init(&rdl->vt100);
46799a2dd95SBruce Richardson cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
46899a2dd95SBruce Richardson cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
46999a2dd95SBruce Richardson cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
47099a2dd95SBruce Richardson rdline_redisplay(rdl);
47199a2dd95SBruce Richardson break;
47299a2dd95SBruce Richardson
47399a2dd95SBruce Richardson /* next element in history */
47499a2dd95SBruce Richardson case CMDLINE_KEY_DOWN_ARR:
47599a2dd95SBruce Richardson case CMDLINE_KEY_CTRL_N:
47699a2dd95SBruce Richardson if (rdl->history_cur_line - 1 < 0)
47799a2dd95SBruce Richardson break;
47899a2dd95SBruce Richardson
47999a2dd95SBruce Richardson rdl->history_cur_line --;
48099a2dd95SBruce Richardson buf = rdline_get_history_item(rdl, rdl->history_cur_line);
48199a2dd95SBruce Richardson if (!buf)
48299a2dd95SBruce Richardson break;
48399a2dd95SBruce Richardson vt100_init(&rdl->vt100);
48499a2dd95SBruce Richardson cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
48599a2dd95SBruce Richardson cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
48699a2dd95SBruce Richardson cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
48799a2dd95SBruce Richardson rdline_redisplay(rdl);
48899a2dd95SBruce Richardson
48999a2dd95SBruce Richardson break;
49099a2dd95SBruce Richardson
49199a2dd95SBruce Richardson
49299a2dd95SBruce Richardson default:
49399a2dd95SBruce Richardson break;
49499a2dd95SBruce Richardson }
49599a2dd95SBruce Richardson
49699a2dd95SBruce Richardson return RDLINE_RES_SUCCESS;
49799a2dd95SBruce Richardson }
49899a2dd95SBruce Richardson
49999a2dd95SBruce Richardson if (!isprint((int)c))
50099a2dd95SBruce Richardson return RDLINE_RES_SUCCESS;
50199a2dd95SBruce Richardson
50299a2dd95SBruce Richardson /* standard chars */
50399a2dd95SBruce Richardson if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
50499a2dd95SBruce Richardson return RDLINE_RES_SUCCESS;
50599a2dd95SBruce Richardson
50699a2dd95SBruce Richardson if (cirbuf_add_tail_safe(&rdl->left, c))
50799a2dd95SBruce Richardson return RDLINE_RES_SUCCESS;
50899a2dd95SBruce Richardson
50999a2dd95SBruce Richardson rdl->write_char(rdl, c);
51099a2dd95SBruce Richardson display_right_buffer(rdl, 0);
51199a2dd95SBruce Richardson
51299a2dd95SBruce Richardson return RDLINE_RES_SUCCESS;
51399a2dd95SBruce Richardson }
51499a2dd95SBruce Richardson
51599a2dd95SBruce Richardson
51699a2dd95SBruce Richardson /* HISTORY */
51799a2dd95SBruce Richardson
51899a2dd95SBruce Richardson static void
rdline_remove_old_history_item(struct rdline * rdl)51999a2dd95SBruce Richardson rdline_remove_old_history_item(struct rdline * rdl)
52099a2dd95SBruce Richardson {
52199a2dd95SBruce Richardson char tmp;
52299a2dd95SBruce Richardson
52399a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
52499a2dd95SBruce Richardson tmp = cirbuf_get_head(&rdl->history);
52599a2dd95SBruce Richardson cirbuf_del_head(&rdl->history);
52699a2dd95SBruce Richardson if (!tmp)
52799a2dd95SBruce Richardson break;
52899a2dd95SBruce Richardson }
52999a2dd95SBruce Richardson }
53099a2dd95SBruce Richardson
53199a2dd95SBruce Richardson static void
rdline_remove_first_history_item(struct rdline * rdl)53299a2dd95SBruce Richardson rdline_remove_first_history_item(struct rdline * rdl)
53399a2dd95SBruce Richardson {
53499a2dd95SBruce Richardson char tmp;
53599a2dd95SBruce Richardson
53699a2dd95SBruce Richardson if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
53799a2dd95SBruce Richardson return;
53899a2dd95SBruce Richardson }
53999a2dd95SBruce Richardson else {
54099a2dd95SBruce Richardson cirbuf_del_tail(&rdl->history);
54199a2dd95SBruce Richardson }
54299a2dd95SBruce Richardson
54399a2dd95SBruce Richardson while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
54499a2dd95SBruce Richardson tmp = cirbuf_get_tail(&rdl->history);
54599a2dd95SBruce Richardson if (!tmp)
54699a2dd95SBruce Richardson break;
54799a2dd95SBruce Richardson cirbuf_del_tail(&rdl->history);
54899a2dd95SBruce Richardson }
54999a2dd95SBruce Richardson }
55099a2dd95SBruce Richardson
55199a2dd95SBruce Richardson static unsigned int
rdline_get_history_size(struct rdline * rdl)55299a2dd95SBruce Richardson rdline_get_history_size(struct rdline * rdl)
55399a2dd95SBruce Richardson {
55499a2dd95SBruce Richardson unsigned int i, tmp, ret=0;
55599a2dd95SBruce Richardson
55699a2dd95SBruce Richardson CIRBUF_FOREACH(&rdl->history, i, tmp) {
55799a2dd95SBruce Richardson if (tmp == 0)
55899a2dd95SBruce Richardson ret ++;
55999a2dd95SBruce Richardson }
56099a2dd95SBruce Richardson
56199a2dd95SBruce Richardson return ret;
56299a2dd95SBruce Richardson }
56399a2dd95SBruce Richardson
56499a2dd95SBruce Richardson char *
rdline_get_history_item(struct rdline * rdl,unsigned int idx)56599a2dd95SBruce Richardson rdline_get_history_item(struct rdline * rdl, unsigned int idx)
56699a2dd95SBruce Richardson {
56799a2dd95SBruce Richardson unsigned int len, i, tmp;
56899a2dd95SBruce Richardson
56999a2dd95SBruce Richardson if (!rdl)
57099a2dd95SBruce Richardson return NULL;
57199a2dd95SBruce Richardson
57299a2dd95SBruce Richardson len = rdline_get_history_size(rdl);
57399a2dd95SBruce Richardson if ( idx >= len ) {
57499a2dd95SBruce Richardson return NULL;
57599a2dd95SBruce Richardson }
57699a2dd95SBruce Richardson
57799a2dd95SBruce Richardson cirbuf_align_left(&rdl->history);
57899a2dd95SBruce Richardson
57999a2dd95SBruce Richardson CIRBUF_FOREACH(&rdl->history, i, tmp) {
58099a2dd95SBruce Richardson if ( idx == len - 1) {
58199a2dd95SBruce Richardson return rdl->history_buf + i;
58299a2dd95SBruce Richardson }
58399a2dd95SBruce Richardson if (tmp == 0)
58499a2dd95SBruce Richardson len --;
58599a2dd95SBruce Richardson }
58699a2dd95SBruce Richardson
58799a2dd95SBruce Richardson return NULL;
58899a2dd95SBruce Richardson }
58999a2dd95SBruce Richardson
590*f8f8dc28SDmitry Kozlyuk size_t
rdline_get_history_buffer_size(struct rdline * rdl)591*f8f8dc28SDmitry Kozlyuk rdline_get_history_buffer_size(struct rdline *rdl)
592*f8f8dc28SDmitry Kozlyuk {
593*f8f8dc28SDmitry Kozlyuk return sizeof(rdl->history_buf);
594*f8f8dc28SDmitry Kozlyuk }
595*f8f8dc28SDmitry Kozlyuk
596*f8f8dc28SDmitry Kozlyuk void *
rdline_get_opaque(struct rdline * rdl)597*f8f8dc28SDmitry Kozlyuk rdline_get_opaque(struct rdline *rdl)
598*f8f8dc28SDmitry Kozlyuk {
599*f8f8dc28SDmitry Kozlyuk return rdl != NULL ? rdl->opaque : NULL;
600*f8f8dc28SDmitry Kozlyuk }
601*f8f8dc28SDmitry Kozlyuk
60299a2dd95SBruce Richardson int
rdline_add_history(struct rdline * rdl,const char * buf)60399a2dd95SBruce Richardson rdline_add_history(struct rdline * rdl, const char * buf)
60499a2dd95SBruce Richardson {
60599a2dd95SBruce Richardson unsigned int len, i;
60699a2dd95SBruce Richardson
60799a2dd95SBruce Richardson if (!rdl || !buf)
60899a2dd95SBruce Richardson return -EINVAL;
60999a2dd95SBruce Richardson
61099a2dd95SBruce Richardson len = strnlen(buf, RDLINE_BUF_SIZE);
61199a2dd95SBruce Richardson for (i=0; i<len ; i++) {
61299a2dd95SBruce Richardson if (buf[i] == '\n') {
61399a2dd95SBruce Richardson len = i;
61499a2dd95SBruce Richardson break;
61599a2dd95SBruce Richardson }
61699a2dd95SBruce Richardson }
61799a2dd95SBruce Richardson
61899a2dd95SBruce Richardson if ( len >= RDLINE_HISTORY_BUF_SIZE )
61999a2dd95SBruce Richardson return -1;
62099a2dd95SBruce Richardson
62199a2dd95SBruce Richardson while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
62299a2dd95SBruce Richardson rdline_remove_old_history_item(rdl);
62399a2dd95SBruce Richardson }
62499a2dd95SBruce Richardson
62599a2dd95SBruce Richardson cirbuf_add_buf_tail(&rdl->history, buf, len);
62699a2dd95SBruce Richardson cirbuf_add_tail(&rdl->history, 0);
62799a2dd95SBruce Richardson
62899a2dd95SBruce Richardson return 0;
62999a2dd95SBruce Richardson }
63099a2dd95SBruce Richardson
63199a2dd95SBruce Richardson void
rdline_clear_history(struct rdline * rdl)63299a2dd95SBruce Richardson rdline_clear_history(struct rdline * rdl)
63399a2dd95SBruce Richardson {
63499a2dd95SBruce Richardson if (!rdl)
63599a2dd95SBruce Richardson return;
63699a2dd95SBruce Richardson cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
63799a2dd95SBruce Richardson }
63899a2dd95SBruce Richardson
63999a2dd95SBruce Richardson
64099a2dd95SBruce Richardson /* STATIC USEFUL FUNCS */
64199a2dd95SBruce Richardson
64299a2dd95SBruce Richardson static void
rdline_puts(struct rdline * rdl,const char * buf)64399a2dd95SBruce Richardson rdline_puts(struct rdline * rdl, const char * buf)
64499a2dd95SBruce Richardson {
64599a2dd95SBruce Richardson char c;
64699a2dd95SBruce Richardson while ( (c = *(buf++)) != '\0' ) {
64799a2dd95SBruce Richardson rdl->write_char(rdl, c);
64899a2dd95SBruce Richardson }
64999a2dd95SBruce Richardson }
65099a2dd95SBruce Richardson
65199a2dd95SBruce Richardson /* a very very basic printf with one arg and one format 'u' */
65299a2dd95SBruce Richardson static void
rdline_miniprintf(struct rdline * rdl,const char * buf,unsigned int val)65399a2dd95SBruce Richardson rdline_miniprintf(struct rdline *rdl, const char * buf, unsigned int val)
65499a2dd95SBruce Richardson {
65599a2dd95SBruce Richardson char c, started=0, div=100;
65699a2dd95SBruce Richardson
65799a2dd95SBruce Richardson while ( (c=*(buf++)) ) {
65899a2dd95SBruce Richardson if (c != '%') {
65999a2dd95SBruce Richardson rdl->write_char(rdl, c);
66099a2dd95SBruce Richardson continue;
66199a2dd95SBruce Richardson }
66299a2dd95SBruce Richardson c = *(buf++);
66399a2dd95SBruce Richardson if (c != 'u') {
66499a2dd95SBruce Richardson rdl->write_char(rdl, '%');
66599a2dd95SBruce Richardson rdl->write_char(rdl, c);
66699a2dd95SBruce Richardson continue;
66799a2dd95SBruce Richardson }
66899a2dd95SBruce Richardson /* val is never more than 255 */
66999a2dd95SBruce Richardson while (div) {
67099a2dd95SBruce Richardson c = (char)(val / div);
67199a2dd95SBruce Richardson if (c || started) {
67299a2dd95SBruce Richardson rdl->write_char(rdl, (char)(c+'0'));
67399a2dd95SBruce Richardson started = 1;
67499a2dd95SBruce Richardson }
67599a2dd95SBruce Richardson val %= div;
67699a2dd95SBruce Richardson div /= 10;
67799a2dd95SBruce Richardson }
67899a2dd95SBruce Richardson }
67999a2dd95SBruce Richardson }
680