feat(console): Add max_cmdline_args to esp_console_repl_config_t

This commit is contained in:
Guillaume Souchere
2026-04-27 09:08:42 +02:00
parent a413aabf9c
commit 96d13b63e9
7 changed files with 82 additions and 8 deletions

View File

@@ -55,6 +55,7 @@ typedef struct {
BaseType_t task_core_id; //!< repl task affinity, i.e. which core the task is pinned to
const char *prompt; //!< prompt (NULL represents default: "esp> ")
size_t max_cmdline_length; //!< maximum length of a command line. If 0, default value will be used
size_t max_cmdline_args; //!< maximum number of command line arguments to parse. If 0, default value will be used
} esp_console_repl_config_t;
/**
@@ -70,6 +71,7 @@ typedef struct {
.task_core_id = tskNO_AFFINITY, \
.prompt = NULL, \
.max_cmdline_length = 0, \
.max_cmdline_args = 0, \
}
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM

View File

@@ -59,17 +59,23 @@ _exit:
return ret;
}
esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com)
esp_err_t esp_console_common_init(size_t max_cmdline_length, size_t max_cmdline_args, esp_console_repl_com_t *repl_com)
{
esp_err_t ret = ESP_OK;
/* Initialize the console */
esp_console_config_t console_config = ESP_CONSOLE_CONFIG_DEFAULT();
repl_com->max_cmdline_length = console_config.max_cmdline_length;
repl_com->max_cmdline_args = console_config.max_cmdline_args;
/* Replace the default command line length if passed as a parameter */
if (max_cmdline_length != 0) {
console_config.max_cmdline_length = max_cmdline_length;
repl_com->max_cmdline_length = max_cmdline_length;
}
/* Replace the default command line args if passed as a parameter */
if (max_cmdline_args != 0) {
console_config.max_cmdline_args = max_cmdline_args;
repl_com->max_cmdline_args = max_cmdline_args;
}
#if CONFIG_LOG_COLORS
console_config.hint_color = atoi(LOG_COLOR_CYAN);

View File

@@ -62,7 +62,7 @@ esp_err_t esp_console_new_repl_usb_cdc(const esp_console_dev_usb_cdc_config_t *d
fcntl(fileno(stdin), F_SETFL, 0);
// initialize console, common part
ret = esp_console_common_init(repl_config->max_cmdline_length, &cdc_repl->repl_com);
ret = esp_console_common_init(repl_config->max_cmdline_length, repl_config->max_cmdline_args, &cdc_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
@@ -136,7 +136,7 @@ esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_
}
// initialize console, common part
ret = esp_console_common_init(repl_config->max_cmdline_length, &usb_serial_jtag_repl->repl_com);
ret = esp_console_common_init(repl_config->max_cmdline_length, repl_config->max_cmdline_args, &usb_serial_jtag_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}
@@ -240,7 +240,9 @@ esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_con
uart_vfs_dev_use_driver(dev_config->channel);
// initialize console, common part
ret = esp_console_common_init(repl_config->max_cmdline_length, &uart_repl->repl_com);
ret = esp_console_common_init(repl_config->max_cmdline_length,
repl_config->max_cmdline_args,
&uart_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}

View File

@@ -101,7 +101,7 @@ static esp_err_t esp_console_new_repl_linux(const esp_console_repl_config_t *rep
fcntl(fileno(stdin), F_SETFL, 0);
// initialize console , common part
ret = esp_console_common_init(repl_config->max_cmdline_length, &linux_repl->repl_com);
ret = esp_console_common_init(repl_config->max_cmdline_length, repl_config->max_cmdline_args, &linux_repl->repl_com);
if (ret != ESP_OK) {
goto _exit;
}

View File

@@ -35,6 +35,7 @@ typedef struct {
const char *history_save_path;
TaskHandle_t task_hdl; // REPL task handle
size_t max_cmdline_length; // Maximum length of a command line. If 0, default value will be used.
size_t max_cmdline_args; // Maximum number of command line arguments to parse. If 0, default value will be used.
} esp_console_repl_com_t;
typedef struct {
@@ -44,7 +45,7 @@ typedef struct {
void esp_console_repl_task(void *args);
esp_err_t esp_console_common_init(size_t max_cmdline_length, esp_console_repl_com_t *repl_com);
esp_err_t esp_console_common_init(size_t max_cmdline_length, size_t max_cmdline_args, esp_console_repl_com_t *repl_com);
esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com);
esp_err_t esp_console_setup_history(const char *history_path,
uint32_t max_history_len,

View File

@@ -10,7 +10,7 @@
#include <sys/time.h>
// Some resources are lazy allocated (newlib locks) in the console code, the threshold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (150)
#define TEST_MEMORY_LEAK_THRESHOLD (250)
void setUp(void)
{

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -31,6 +31,26 @@ typedef struct {
static esp_console_repl_t *s_repl = NULL;
/* Shared state for the repl config limits test */
static int s_cmd_captured_argc;
static char s_cmd_captured_last_arg[32];
static int do_capture_args_cmd(int argc, char **argv)
{
s_cmd_captured_argc = argc;
if (argc > 1) {
strncpy(s_cmd_captured_last_arg, argv[argc - 1], sizeof(s_cmd_captured_last_arg) - 1);
s_cmd_captured_last_arg[sizeof(s_cmd_captured_last_arg) - 1] = '\0';
}
return 0;
}
static const esp_console_cmd_t s_capture_args_cmd = {
.command = "capture",
.help = "Capture argc and last arg for testing",
.func = do_capture_args_cmd,
};
static int do_hello_cmd_with_context(void *context, int argc, char **argv)
{
cmd_context_t *cmd_context = (cmd_context_t *)context;
@@ -348,3 +368,46 @@ TEST_CASE("esp console re-register commands", "[console][ignore]")
TEST_ESP_OK(esp_console_start_repl(s_repl));
vTaskDelay(pdMS_TO_TICKS(5000));
}
TEST_CASE("esp console repl config respects max_cmdline_args and max_cmdline_length", "[console][ignore]")
{
/*
* Use small limits to make truncation observable:
* - max_cmdline_args = 4: split_argv stops when argc reaches argv_size-1 = 3,
* so "capture arg1 arg2 arg3" drops "arg3" and the command receives argc == 3.
* - max_cmdline_length = 20: strlcpy copies at most 19 chars, so the 20-char
* input "capture longarg12345" is truncated to "capture longarg1234" and the
* last argument received by the command is "longarg1234".
*/
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
repl_config.max_cmdline_args = 4;
repl_config.max_cmdline_length = 20;
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
TEST_ASSERT_EQUAL(ESP_OK, esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
TEST_ESP_OK(esp_console_cmd_register(&s_capture_args_cmd));
/* --- Verify max_cmdline_args ---
* Input has 4 tokens (command + 3 args). The limit allows at most
* argv_size-1 = 3 tokens, so the last token ("arg3") is dropped.
*/
s_cmd_captured_argc = -1;
int ret;
TEST_ESP_OK(esp_console_run("capture arg1 arg2 arg3", &ret));
TEST_ASSERT_EQUAL(0, ret);
TEST_ASSERT_EQUAL(3, s_cmd_captured_argc);
/* --- Verify max_cmdline_length ---
* "capture longarg12345" is exactly 20 chars. strlcpy(buf, input, 20)
* retains at most 19 chars, yielding "capture longarg1234".
* The command therefore receives "longarg1234" as its only argument.
*/
s_cmd_captured_argc = -1;
memset(s_cmd_captured_last_arg, 0, sizeof(s_cmd_captured_last_arg));
TEST_ESP_OK(esp_console_run("capture longarg12345", &ret));
TEST_ASSERT_EQUAL(0, ret);
TEST_ASSERT_EQUAL(2, s_cmd_captured_argc);
TEST_ASSERT_EQUAL_STRING("longarg1234", s_cmd_captured_last_arg);
TEST_ESP_OK(esp_console_deinit());
}