summaryrefslogtreecommitdiff
path: root/lib/console/split_argv.c
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-06-27 16:12:18 +1000
committerjacqueline <me@jacqueline.id.au>2024-06-27 16:12:18 +1000
commit1036f1b00efe2bbd2467cbfa3a4a97ab7f56591e (patch)
treecc3aa8683daa30e36f3777699e32aaf93e211f95 /lib/console/split_argv.c
parent1daa1e9b0fe737ea5dac99f42fdf3c217873443f (diff)
downloadtangara-fw-1036f1b00efe2bbd2467cbfa3a4a97ab7f56591e.tar.gz
fork esp-idf's dev console, in order to add some hooks
Diffstat (limited to 'lib/console/split_argv.c')
-rw-r--r--lib/console/split_argv.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/lib/console/split_argv.c b/lib/console/split_argv.c
new file mode 100644
index 00000000..d2e3bd08
--- /dev/null
+++ b/lib/console/split_argv.c
@@ -0,0 +1,112 @@
+/*
+ * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#define SS_FLAG_ESCAPE 0x8
+
+typedef enum {
+ /* parsing the space between arguments */
+ SS_SPACE = 0x0,
+ /* parsing an argument which isn't quoted */
+ SS_ARG = 0x1,
+ /* parsing a quoted argument */
+ SS_QUOTED_ARG = 0x2,
+ /* parsing an escape sequence within unquoted argument */
+ SS_ARG_ESCAPED = SS_ARG | SS_FLAG_ESCAPE,
+ /* parsing an escape sequence within a quoted argument */
+ SS_QUOTED_ARG_ESCAPED = SS_QUOTED_ARG | SS_FLAG_ESCAPE,
+} split_state_t;
+
+/* helper macro, called when done with an argument */
+#define END_ARG() do { \
+ char_out = 0; \
+ argv[argc++] = next_arg_start; \
+ state = SS_SPACE; \
+} while(0)
+
+size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
+{
+ const int QUOTE = '"';
+ const int ESCAPE = '\\';
+ const int SPACE = ' ';
+ split_state_t state = SS_SPACE;
+ size_t argc = 0;
+ char *next_arg_start = line;
+ char *out_ptr = line;
+ for (char *in_ptr = line; argc < argv_size - 1; ++in_ptr) {
+ int char_in = (unsigned char) *in_ptr;
+ if (char_in == 0) {
+ break;
+ }
+ int char_out = -1;
+
+ switch (state) {
+ case SS_SPACE:
+ if (char_in == SPACE) {
+ /* skip space */
+ } else if (char_in == QUOTE) {
+ next_arg_start = out_ptr;
+ state = SS_QUOTED_ARG;
+ } else if (char_in == ESCAPE) {
+ next_arg_start = out_ptr;
+ state = SS_ARG_ESCAPED;
+ } else {
+ next_arg_start = out_ptr;
+ state = SS_ARG;
+ char_out = char_in;
+ }
+ break;
+
+ case SS_QUOTED_ARG:
+ if (char_in == QUOTE) {
+ END_ARG();
+ } else if (char_in == ESCAPE) {
+ state = SS_QUOTED_ARG_ESCAPED;
+ } else {
+ char_out = char_in;
+ }
+ break;
+
+ case SS_ARG_ESCAPED:
+ case SS_QUOTED_ARG_ESCAPED:
+ if (char_in == ESCAPE || char_in == QUOTE || char_in == SPACE) {
+ char_out = char_in;
+ } else {
+ /* unrecognized escape character, skip */
+ }
+ state = (split_state_t) (state & (~SS_FLAG_ESCAPE));
+ break;
+
+ case SS_ARG:
+ if (char_in == SPACE) {
+ END_ARG();
+ } else if (char_in == ESCAPE) {
+ state = SS_ARG_ESCAPED;
+ } else {
+ char_out = char_in;
+ }
+ break;
+ }
+ /* need to output anything? */
+ if (char_out >= 0) {
+ *out_ptr = char_out;
+ ++out_ptr;
+ }
+ }
+ /* make sure the final argument is terminated */
+ *out_ptr = 0;
+ /* finalize the last argument */
+ if (state != SS_SPACE && argc < argv_size - 1) {
+ argv[argc++] = next_arg_start;
+ }
+ /* add a NULL at the end of argv */
+ argv[argc] = NULL;
+
+ return argc;
+}