This is an automated email from the ASF dual-hosted git repository. pkarashchenko pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit bf40833d2e3a3e4c8906fbad4973c4973109b108 Author: Ville Juven <[email protected]> AuthorDate: Fri Mar 10 12:39:00 2023 +0200 nsh/nsh_parse.c: Add support for single ('') and double ("") quotes The parser is modified to detect, handle and remove quotes from the command string. Whatever is inside the quotes is treated as a string literal. If no matching end quote is found, the terminal prints out and error. --- nshlib/nsh_parse.c | 221 +++++++++++++++++++++-------------------------------- 1 file changed, 85 insertions(+), 136 deletions(-) diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index 0aabe5dbf..87bf50c1a 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -166,6 +166,8 @@ static void nsh_dequote(FAR char *cmdline); # define nsh_dequote(c) #endif +static FAR char *nsh_rmquotes(FAR char *qbegin, FAR char *qend); + static FAR char *nsh_argexpand(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, FAR char **allocation, FAR int *isenvvar); static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, @@ -208,8 +210,9 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline); ****************************************************************************/ static const char g_token_separator[] = " \t\n"; +static const char g_quote_separator[] = "'\"`"; #ifndef NSH_DISABLE_SEMICOLON -static const char g_line_separator[] = "\"#;\n"; +static const char g_line_separator[] = "\"'#;\n"; #endif #ifdef CONFIG_NSH_ARGCAT static const char g_arg_separator[] = "`$"; @@ -1141,6 +1144,38 @@ static void nsh_dequote(FAR char *cmdline) } #endif +/**************************************************************************** + * Name: nsh_rmquotes + ****************************************************************************/ + +static FAR char *nsh_rmquotes(FAR char *qbegin, FAR char *qend) +{ + FAR char *dst; + FAR char *ptr; + char ch; + + /* Remove the starting quote */ + + dst = qbegin; + ptr = qbegin + 1; + + do + { + /* Remove the ending quote */ + + if (ptr == qend) + { + ptr++; + } + + ch = *ptr++; + *dst++ = ch; + } + while(ch != '\0'); + + return qend - 2; +} + /**************************************************************************** * Name: nsh_argexpand ****************************************************************************/ @@ -1484,13 +1519,9 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char *pend = NULL; FAR char *allocation = NULL; FAR char *argument = NULL; - FAR const char *term; #ifdef CONFIG_NSH_QUOTE FAR char *prev; - bool quoted; -#endif -#ifdef CONFIG_NSH_CMDPARMS - bool backquote; + bool escaped; #endif /* Find the beginning of the next token */ @@ -1543,111 +1574,77 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, else { - /* However, the rules are a little different if the next argument is - * a quoted string. - */ - - if (*pbegin == '"') - { - /* A quoted string can only be terminated with another quotation - * mark. Set pbegin to point at the character after the opening - * quote mark. - */ - - pbegin++; - term = "\""; - - /* If this is an environment variable in double quotes, we don't - * want it split into multiple arguments. So just invalidate the - * flag pointer which would otherwise communicate such back up - * the call tree. - */ - - isenvvar = NULL; - } - else - { - /* No, then any of the usual separators will terminate the - * argument. In this case, pbegin points for the first character - * of the token following the previous separator. - */ - - term = g_token_separator; - } - - /* Find the end of the string */ - -#ifdef CONFIG_NSH_CMDPARMS - /* Some special care must be exercised to make sure that we do not - * break up any back-quote delimited substrings. NOTE that the - * absence of a closing back-quote is not detected; That case should - * be detected later. + /* Find the end of the string. Some special care must be exercised to + * make sure that we do not break up any quoted substrings. */ #ifdef CONFIG_NSH_QUOTE - quoted = false; - backquote = false; + escaped = false; for (prev = NULL, pend = pbegin; *pend != '\0'; prev = pend, pend++) +#else + for (pend = pbegin; *pend != '\0'; pend++) +#endif { - /* Check if the current character is quoted */ +#ifdef CONFIG_NSH_QUOTE + /* Check if the current character is escaped */ - if (prev != NULL && *prev == '\\' && !quoted) + if (prev != NULL && *prev == '\\' && !escaped) { /* Do no special checks on the quoted character */ - quoted = true; + escaped = true; continue; } - quoted = false; + escaped = false; - /* Check if the current character is an (unquoted) back-quote */ + /* Check if the current character is an (unescaped) back-slash */ - if (*pend == '\\' && !quoted) + if (*pend == '\\' && !escaped) { /* Yes.. Do no special processing on the backspace character */ continue; } +#endif - /* Toggle the back-quote flag when one is encountered? */ + /* Are we entering a quoted string ? */ - if (*pend == '`') + if (nsh_strchr(g_quote_separator, *pend)) { - backquote = !backquote; - } + /* Yes, find the terminator and continue from there */ - /* Check for a delimiting character only if we are not in a - * back-quoted sub-string. - */ + FAR char *qend = nsh_strchr(pend + 1, *pend); + if (!qend) + { + /* No terminator found, get out */ - else if (!backquote && nsh_strchr(term, *pend) != NULL) - { - /* We found a delimiter outside of any back-quoted substring. - * Now we can break out of the loop. - */ + char qterm[2]; - break; - } - } -#else - backquote = false; + qterm[0] = ptr; + qterm[1] = '\0'; - for (pend = pbegin; *pend != '\0'; pend++) - { - /* Toggle the back-quote flag when one is encountered? */ + nsh_error(vtbl, g_fmtnomatching, qterm, qterm); - if (*pend == '`') - { - backquote = !backquote; + return NULL; + } + + /* Is it a back-quote ? These are not removed here */ + + if (*pend != '`') + { + /* No, get rid of the single / double quotes here */ + + pend = nsh_rmquotes(pend, qend); + } } - /* Check for a delimiting character only if we are not in a - * back-quoted sub-string. + /* Check for a delimiting character only if we are not in a quoted + * sub-string. */ - else if (!backquote && nsh_strchr(term, *pend) != NULL) + else if (nsh_strchr(g_token_separator, *pend) != NULL) { /* We found a delimiter outside of any back-quoted substring. * Now we can break out of the loop. @@ -1657,60 +1654,6 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, } } -#endif /* CONFIG_NSH_QUOTE */ -#else /* CONFIG_NSH_CMDPARMS */ - - /* Search the next occurrence of a terminating character (or the end - * of the line). - */ - -#ifdef CONFIG_NSH_QUOTE - quoted = false; - - for (prev = NULL, pend = pbegin; *pend != '\0'; prev = pend, pend++) - { - /* Check if the current character is quoted */ - - if (prev != NULL && *prev == '\\' && !quoted) - { - /* Do no special checks on the quoted character */ - - quoted = true; - continue; - } - - quoted = false; - - /* Check if the current character is an (unquoted) back-quote */ - - if (*pend == '\\' && !quoted) - { - /* Yes.. Do no special processing on the backspace character */ - - continue; - } - - /* Check for a delimiting character */ - - if (nsh_strchr(term, *pend) != NULL) - { - /* We found a delimiter. Now we can break out of the loop. */ - - break; - } - } - -#else - - for (pend = pbegin; - *pend != '\0' && nsh_strchr(term, *pend) == NULL; - pend++) - { - } - -#endif /* CONFIG_NSH_QUOTE */ -#endif /* CONFIG_NSH_CMDPARMS */ - /* pend either points to the end of the string or to the first * delimiter after the string. */ @@ -2688,16 +2631,22 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) /* Check if we encountered a quoted string */ - else /* if (*ptr == '"') */ + else /* if (*ptr == '"' || *ptr == '\'') */ { /* Find the closing quotation mark */ - FAR char *tmp = nsh_strchr(ptr + 1, '"'); + FAR char *tmp = nsh_strchr(ptr + 1, *ptr); if (!tmp) { /* No closing quotation mark! */ - nsh_error(vtbl, g_fmtnomatching, "\"", "\""); + char qterm[2]; + + qterm[0] = *ptr; + qterm[1] = '\0'; + + nsh_error(vtbl, g_fmtnomatching, qterm, qterm); + return ERROR; }
