mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-23 14:55:21 +00:00
This patch increases the amount of slab memory per item for the shell history to match the maximum command input buffer size plus the accounting information for the dnode list item. Signed-off-by: Andy Gross <andy.gross@linaro.org>
121 lines
2.7 KiB
C
121 lines
2.7 KiB
C
/*
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <shell/shell_history.h>
|
|
#include <string.h>
|
|
|
|
void shell_history_mode_exit(struct shell_history *history)
|
|
{
|
|
history->current = NULL;
|
|
}
|
|
|
|
bool shell_history_get(struct shell_history *history, bool up,
|
|
u8_t *dst, u16_t *len)
|
|
{
|
|
struct shell_history_item *h_item; /* history item */
|
|
sys_dnode_t *l_item; /* list item */
|
|
|
|
if (sys_dlist_is_empty(&history->list)) {
|
|
*len = 0;
|
|
return false;
|
|
}
|
|
|
|
if (!up) { /* button down */
|
|
if (history->current == NULL) {
|
|
/* Not in history mode. It is started by up button. */
|
|
*len = 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
l_item = sys_dlist_peek_prev_no_check(&history->list,
|
|
history->current);
|
|
} else { /* button up */
|
|
l_item = (history->current == NULL) ?
|
|
sys_dlist_peek_head_not_empty(&history->list) :
|
|
sys_dlist_peek_next_no_check(&history->list, history->current);
|
|
|
|
}
|
|
|
|
history->current = l_item;
|
|
h_item = CONTAINER_OF(l_item, struct shell_history_item, dnode);
|
|
|
|
if (h_item) {
|
|
memcpy(dst, h_item->data, h_item->len);
|
|
*len = h_item->len;
|
|
dst[*len] = '\0';
|
|
return true;
|
|
}
|
|
|
|
*len = 0;
|
|
return false;
|
|
}
|
|
|
|
static void add_to_head(struct shell_history *history,
|
|
struct shell_history_item *item,
|
|
u8_t *src, size_t len)
|
|
{
|
|
item->len = len;
|
|
memcpy(item->data, src, len);
|
|
item->data[len] = '\0';
|
|
sys_dlist_prepend(&history->list, &item->dnode);
|
|
}
|
|
|
|
static void remove_from_tail(struct shell_history *history)
|
|
{
|
|
sys_dnode_t *l_item; /* list item */
|
|
struct shell_history_item *h_item;
|
|
|
|
l_item = sys_dlist_peek_tail(&history->list);
|
|
sys_dlist_remove(l_item);
|
|
|
|
h_item = CONTAINER_OF(l_item, struct shell_history_item, dnode);
|
|
k_mem_slab_free(history->mem_slab, (void **)&l_item);
|
|
}
|
|
|
|
void shell_history_purge(struct shell_history *history)
|
|
{
|
|
while (!sys_dlist_is_empty(&history->list)) {
|
|
remove_from_tail(history);
|
|
}
|
|
}
|
|
|
|
void shell_history_put(struct shell_history *history, u8_t *line, size_t len)
|
|
{
|
|
sys_dnode_t *l_item; /* list item */
|
|
struct shell_history_item *h_item;
|
|
|
|
shell_history_mode_exit(history);
|
|
|
|
if (len == 0) {
|
|
return;
|
|
}
|
|
|
|
l_item = sys_dlist_peek_head(&history->list);
|
|
h_item = CONTAINER_OF(l_item, struct shell_history_item, dnode);
|
|
|
|
if (h_item &&
|
|
(h_item->len == len) &&
|
|
(strncmp(h_item->data, line, CONFIG_SHELL_CMD_BUFF_SIZE) == 0)) {
|
|
/* Same command as before, do not store */
|
|
return;
|
|
}
|
|
|
|
while (k_mem_slab_alloc(history->mem_slab, (void **)&h_item, K_NO_WAIT)
|
|
!= 0) {
|
|
/* if no space remove the oldest entry. */
|
|
remove_from_tail(history);
|
|
}
|
|
|
|
add_to_head(history, h_item, line, len);
|
|
}
|
|
|
|
void shell_history_init(struct shell_history *history)
|
|
{
|
|
sys_dlist_init(&history->list);
|
|
history->current = NULL;
|
|
}
|