numam-dpdk/lib/cmdline/cmdline_rdline.c
Bruce Richardson 99a2dd955f lib: remove librte_ prefix from directory names
There is no reason for the DPDK libraries to all have 'librte_' prefix on
the directory names. This prefix makes the directory names longer and also
makes it awkward to add features referring to individual libraries in the
build - should the lib names be specified with or without the prefix.
Therefore, we can just remove the library prefix and use the library's
unique name as the directory name, i.e. 'eal' rather than 'librte_eal'

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
2021-04-21 14:04:09 +02:00

645 lines
14 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2014 Intel Corporation.
* Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
* All rights reserved.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <ctype.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);
static void rdline_remove_old_history_item(struct rdline *rdl);
static void rdline_remove_first_history_item(struct rdline *rdl);
static unsigned int rdline_get_history_size(struct rdline *rdl);
/* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
* own. */
static int
isblank2(char c)
{
if (c == ' ' ||
c == '\t' )
return 1;
return 0;
}
int
rdline_init(struct rdline *rdl,
rdline_write_char_t *write_char,
rdline_validate_t *validate,
rdline_complete_t *complete)
{
if (!rdl || !write_char || !validate || !complete)
return -EINVAL;
memset(rdl, 0, sizeof(*rdl));
rdl->validate = validate;
rdl->complete = complete;
rdl->write_char = write_char;
rdl->status = RDLINE_INIT;
return cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
}
void
rdline_newline(struct rdline *rdl, const char *prompt)
{
unsigned int i;
if (!rdl || !prompt)
return;
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);
rdl->prompt_size = strnlen(prompt, RDLINE_PROMPT_SIZE-1);
if (prompt != rdl->prompt)
memcpy(rdl->prompt, prompt, rdl->prompt_size);
rdl->prompt[RDLINE_PROMPT_SIZE-1] = '\0';
for (i=0 ; i<rdl->prompt_size ; i++)
rdl->write_char(rdl, rdl->prompt[i]);
rdl->status = RDLINE_RUNNING;
rdl->history_cur_line = -1;
}
void
rdline_stop(struct rdline *rdl)
{
if (!rdl)
return;
rdl->status = RDLINE_INIT;
}
void
rdline_quit(struct rdline *rdl)
{
if (!rdl)
return;
rdl->status = RDLINE_EXITED;
}
void
rdline_restart(struct rdline *rdl)
{
if (!rdl)
return;
rdl->status = RDLINE_RUNNING;
}
void
rdline_reset(struct rdline *rdl)
{
if (!rdl)
return;
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);
rdl->status = RDLINE_RUNNING;
rdl->history_cur_line = -1;
}
const char *
rdline_get_buffer(struct rdline *rdl)
{
if (!rdl)
return NULL;
unsigned int len_l, len_r;
cirbuf_align_left(&rdl->left);
cirbuf_align_left(&rdl->right);
len_l = CIRBUF_GET_LEN(&rdl->left);
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';
return rdl->left_buf;
}
static void
display_right_buffer(struct rdline *rdl, int force)
{
unsigned int i;
char tmp;
if (!force && CIRBUF_IS_EMPTY(&rdl->right))
return;
rdline_puts(rdl, vt100_clear_right);
CIRBUF_FOREACH(&rdl->right, i, tmp) {
rdl->write_char(rdl, tmp);
}
if (!CIRBUF_IS_EMPTY(&rdl->right))
rdline_miniprintf(rdl, vt100_multi_left,
CIRBUF_GET_LEN(&rdl->right));
}
void
rdline_redisplay(struct rdline *rdl)
{
unsigned int i;
char tmp;
if (!rdl)
return;
rdline_puts(rdl, vt100_home);
for (i=0 ; i<rdl->prompt_size ; i++)
rdl->write_char(rdl, rdl->prompt[i]);
CIRBUF_FOREACH(&rdl->left, i, tmp) {
rdl->write_char(rdl, tmp);
}
display_right_buffer(rdl, 1);
}
int
rdline_char_in(struct rdline *rdl, char c)
{
unsigned int i;
int cmd;
char tmp;
char *buf;
if (!rdl)
return -EINVAL;
if (rdl->status == RDLINE_EXITED)
return RDLINE_RES_EXITED;
if (rdl->status != RDLINE_RUNNING)
return RDLINE_RES_NOT_RUNNING;
cmd = vt100_parser(&rdl->vt100, c);
if (cmd == -2)
return RDLINE_RES_SUCCESS;
if (cmd >= 0) {
switch (cmd) {
/* move caret 1 char to the left */
case CMDLINE_KEY_CTRL_B:
case CMDLINE_KEY_LEFT_ARR:
if (CIRBUF_IS_EMPTY(&rdl->left))
break;
tmp = cirbuf_get_tail(&rdl->left);
cirbuf_del_tail(&rdl->left);
cirbuf_add_head(&rdl->right, tmp);
rdline_puts(rdl, vt100_left_arr);
break;
/* move caret 1 char to the right */
case CMDLINE_KEY_CTRL_F:
case CMDLINE_KEY_RIGHT_ARR:
if (CIRBUF_IS_EMPTY(&rdl->right))
break;
tmp = cirbuf_get_head(&rdl->right);
cirbuf_del_head(&rdl->right);
cirbuf_add_tail(&rdl->left, tmp);
rdline_puts(rdl, vt100_right_arr);
break;
/* move caret 1 word to the left */
/* keyboard equivalent: Alt+B */
case CMDLINE_KEY_WLEFT:
while (! CIRBUF_IS_EMPTY(&rdl->left) &&
(tmp = cirbuf_get_tail(&rdl->left)) &&
isblank2(tmp)) {
rdline_puts(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);
cirbuf_del_tail(&rdl->left);
cirbuf_add_head(&rdl->right, tmp);
}
break;
/* move caret 1 word to the right */
/* keyboard equivalent: Alt+F */
case CMDLINE_KEY_WRIGHT:
while (! CIRBUF_IS_EMPTY(&rdl->right) &&
(tmp = cirbuf_get_head(&rdl->right)) &&
isblank2(tmp)) {
rdline_puts(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);
cirbuf_del_head(&rdl->right);
cirbuf_add_tail(&rdl->left, tmp);
}
break;
/* move caret to the left */
case CMDLINE_KEY_CTRL_A:
if (CIRBUF_IS_EMPTY(&rdl->left))
break;
rdline_miniprintf(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);
cirbuf_add_head(&rdl->right, tmp);
}
break;
/* move caret to the right */
case CMDLINE_KEY_CTRL_E:
if (CIRBUF_IS_EMPTY(&rdl->right))
break;
rdline_miniprintf(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_add_tail(&rdl->left, tmp);
}
break;
/* delete 1 char from the left */
case CMDLINE_KEY_BKSPACE:
case CMDLINE_KEY_BKSPACE2:
if(!cirbuf_del_tail_safe(&rdl->left)) {
rdline_puts(rdl, vt100_bs);
display_right_buffer(rdl, 1);
}
break;
/* delete 1 char from the right */
case CMDLINE_KEY_SUPPR:
case CMDLINE_KEY_CTRL_D:
if (cmd == CMDLINE_KEY_CTRL_D &&
CIRBUF_IS_EMPTY(&rdl->left) &&
CIRBUF_IS_EMPTY(&rdl->right)) {
return RDLINE_RES_EOF;
}
if (!cirbuf_del_head_safe(&rdl->right)) {
display_right_buffer(rdl, 1);
}
break;
/* delete 1 word from the left */
case CMDLINE_KEY_META_BKSPACE:
case CMDLINE_KEY_CTRL_W:
while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
rdline_puts(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);
cirbuf_del_tail(&rdl->left);
}
display_right_buffer(rdl, 1);
break;
/* delete 1 word from the right */
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;
/* set kill buffer to contents on the right side of caret */
case CMDLINE_KEY_CTRL_K:
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);
break;
/* paste contents of kill buffer to the left side of caret */
case CMDLINE_KEY_CTRL_Y:
i=0;
while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
RDLINE_BUF_SIZE &&
i < rdl->kill_size) {
cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
rdl->write_char(rdl, rdl->kill_buf[i]);
i++;
}
display_right_buffer(rdl, 0);
break;
/* clear and newline */
case CMDLINE_KEY_CTRL_C:
rdline_puts(rdl, "\r\n");
rdline_newline(rdl, rdl->prompt);
break;
/* redisplay (helps when prompt is lost in other output) */
case CMDLINE_KEY_CTRL_L:
rdline_redisplay(rdl);
break;
/* autocomplete */
case CMDLINE_KEY_TAB:
case CMDLINE_KEY_HELP:
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 RDLINE_RES_COMPLETE;
}
tmp_size = strnlen(tmp_buf, sizeof(tmp_buf));
/* add chars */
if (ret == RDLINE_RES_COMPLETE) {
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, 1);
return RDLINE_RES_COMPLETE; /* ?? */
}
/* 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);
}
rdline_redisplay(rdl);
}
return RDLINE_RES_COMPLETE;
/* complete buffer */
case CMDLINE_KEY_RETURN:
case CMDLINE_KEY_RETURN2:
rdline_get_buffer(rdl);
rdl->status = RDLINE_INIT;
rdline_puts(rdl, "\r\n");
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);
/* user may have stopped rdline */
if (rdl->status == RDLINE_EXITED)
return RDLINE_RES_EXITED;
return RDLINE_RES_VALIDATED;
/* previous element in history */
case CMDLINE_KEY_UP_ARR:
case CMDLINE_KEY_CTRL_P:
if (rdl->history_cur_line == 0) {
rdline_remove_first_history_item(rdl);
}
if (rdl->history_cur_line <= 0) {
rdline_add_history(rdl, rdline_get_buffer(rdl));
rdl->history_cur_line = 0;
}
buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
if (!buf)
break;
rdl->history_cur_line ++;
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);
cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
rdline_redisplay(rdl);
break;
/* next element in history */
case CMDLINE_KEY_DOWN_ARR:
case CMDLINE_KEY_CTRL_N:
if (rdl->history_cur_line - 1 < 0)
break;
rdl->history_cur_line --;
buf = rdline_get_history_item(rdl, rdl->history_cur_line);
if (!buf)
break;
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);
cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
rdline_redisplay(rdl);
break;
default:
break;
}
return RDLINE_RES_SUCCESS;
}
if (!isprint((int)c))
return RDLINE_RES_SUCCESS;
/* standard chars */
if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
return RDLINE_RES_SUCCESS;
if (cirbuf_add_tail_safe(&rdl->left, c))
return RDLINE_RES_SUCCESS;
rdl->write_char(rdl, c);
display_right_buffer(rdl, 0);
return RDLINE_RES_SUCCESS;
}
/* HISTORY */
static void
rdline_remove_old_history_item(struct rdline * rdl)
{
char tmp;
while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
tmp = cirbuf_get_head(&rdl->history);
cirbuf_del_head(&rdl->history);
if (!tmp)
break;
}
}
static void
rdline_remove_first_history_item(struct rdline * rdl)
{
char tmp;
if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
return;
}
else {
cirbuf_del_tail(&rdl->history);
}
while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
tmp = cirbuf_get_tail(&rdl->history);
if (!tmp)
break;
cirbuf_del_tail(&rdl->history);
}
}
static unsigned int
rdline_get_history_size(struct rdline * rdl)
{
unsigned int i, tmp, ret=0;
CIRBUF_FOREACH(&rdl->history, i, tmp) {
if (tmp == 0)
ret ++;
}
return ret;
}
char *
rdline_get_history_item(struct rdline * rdl, unsigned int idx)
{
unsigned int len, i, tmp;
if (!rdl)
return NULL;
len = rdline_get_history_size(rdl);
if ( idx >= len ) {
return NULL;
}
cirbuf_align_left(&rdl->history);
CIRBUF_FOREACH(&rdl->history, i, tmp) {
if ( idx == len - 1) {
return rdl->history_buf + i;
}
if (tmp == 0)
len --;
}
return NULL;
}
int
rdline_add_history(struct rdline * rdl, const char * buf)
{
unsigned int len, i;
if (!rdl || !buf)
return -EINVAL;
len = strnlen(buf, RDLINE_BUF_SIZE);
for (i=0; i<len ; i++) {
if (buf[i] == '\n') {
len = i;
break;
}
}
if ( len >= RDLINE_HISTORY_BUF_SIZE )
return -1;
while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
rdline_remove_old_history_item(rdl);
}
cirbuf_add_buf_tail(&rdl->history, buf, len);
cirbuf_add_tail(&rdl->history, 0);
return 0;
}
void
rdline_clear_history(struct rdline * rdl)
{
if (!rdl)
return;
cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
}
/* STATIC USEFUL FUNCS */
static void
rdline_puts(struct rdline * rdl, const char * buf)
{
char c;
while ( (c = *(buf++)) != '\0' ) {
rdl->write_char(rdl, c);
}
}
/* 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)
{
char c, started=0, div=100;
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 = (char)(val / div);
if (c || started) {
rdl->write_char(rdl, (char)(c+'0'));
started = 1;
}
val %= div;
div /= 10;
}
}
}