From f9dfb51001254f2f50ba081be791e45c7f5965a5 Mon Sep 17 00:00:00 2001 From: Ville Juven <ville.juven@unikie.com> Date: Wed, 22 Feb 2023 18:19:59 +0200 Subject: [PATCH] nsh/nshlib: Add alias support for nsh This adds support for string aliases into nsh. There are some nuances that are not handled correctly yet: - Reserved words can be overloaded, which is a clear POSIX violation --- nshlib/Kconfig | 18 ++ nshlib/Makefile | 4 + nshlib/nsh.h | 31 +++ nshlib/nsh_alias.c | 440 +++++++++++++++++++++++++++++++++++++++++++ nshlib/nsh_command.c | 7 + nshlib/nsh_console.h | 10 + nshlib/nsh_parse.c | 209 ++++++++++++++++---- 7 files changed, 683 insertions(+), 36 deletions(-) create mode 100644 nshlib/nsh_alias.c diff --git a/nshlib/Kconfig b/nshlib/Kconfig index 9607facb7..2123c1bf3 100644 --- a/nshlib/Kconfig +++ b/nshlib/Kconfig @@ -185,6 +185,24 @@ config NSH_DISABLEBG where a minimal footprint is a necessity and background command execution is not. +config NSH_ALIAS + bool "Enable alias support" + default !DEFAULT_SMALL + ---help--- + Enable alias support for nsh. This enables command substitution from + a table of alias strings for individual commands. The maximum amount + of alias strings is configurable with NSH_ALIAS_MAX_AMOUNT. + +if NSH_ALIAS + +config NSH_ALIAS_MAX_AMOUNT + int "Maximum amount of aliases" + default 1 + ---help--- + Set the maximum amount of alias entries. + +endif # NSH_ALIAS + endmenu # Command Line Configuration config NSH_BUILTIN_APPS diff --git a/nshlib/Makefile b/nshlib/Makefile index 3987a3a7d..351002dc9 100644 --- a/nshlib/Makefile +++ b/nshlib/Makefile @@ -106,4 +106,8 @@ ifeq ($(CONFIG_NSH_LOGIN_PASSWD),y) CSRCS += nsh_passwdcmds.c endif +ifeq ($(CONFIG_NSH_ALIAS),y) +CSRCS += nsh_alias.c +endif + include $(APPDIR)/Application.mk diff --git a/nshlib/nsh.h b/nshlib/nsh.h index 50205c8cc..ddf294672 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -715,6 +715,25 @@ struct nsh_parser_s #endif }; +#ifdef CONFIG_NSH_ALIAS +struct nsh_alias_s +{ + FAR struct nsh_alias_s *next; /* Single link list for traversing */ + FAR char *name; /* Name of the alias */ + FAR char *value; /* Value behind the name */ + union + { + struct + { + uint8_t exp : 1; /* Already expanded ? */ + uint8_t rem : 1; /* Marked for deletion */ + }; + + uint8_t flags; /* Raw value */ + }; +}; +#endif + /* This is the general form of a command handler */ struct nsh_vtbl_s; /* Defined in nsh_console.h */ @@ -793,6 +812,13 @@ int nsh_usbconsole(void); # define nsh_usbconsole() (-ENOSYS) #endif +#ifdef CONFIG_NSH_ALIAS +FAR struct nsh_alias_s *nsh_aliasfind(FAR struct nsh_vtbl_s *vtbl, + FAR const char *token); +void nsh_aliasfree(FAR struct nsh_vtbl_s *vtbl, + FAR struct nsh_alias_s *alias); +#endif + #ifndef CONFIG_NSH_DISABLESCRIPT int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, FAR const char *path, bool log); @@ -1193,6 +1219,11 @@ int cmd_pmconfig(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv); # endif #endif +#ifdef CONFIG_NSH_ALIAS +int cmd_alias(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv); +int cmd_unalias(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv); +#endif + /**************************************************************************** * Name: nsh_extmatch_count * diff --git a/nshlib/nsh_alias.c b/nshlib/nsh_alias.c new file mode 100644 index 000000000..3a819dd02 --- /dev/null +++ b/nshlib/nsh_alias.c @@ -0,0 +1,440 @@ +/**************************************************************************** + * apps/nshlib/nsh_alias.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include <nuttx/queue.h> + +#include "nsh.h" +#include "nsh_console.h" + +#ifdef CONFIG_NSH_ALIAS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Macro to get head of alias list */ + +#define alias_head(list) (FAR struct nsh_alias_s *)sq_peek(list) +#define alias_remfirst(list) (FAR struct nsh_alias_s *)sq_remfirst(list) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Alias message format */ + +static const char g_aliasfmt[] = "alias %s='%s'\n"; +static const char g_savefailfmt[] = "alias %s='%s' failed\n"; + +/* Common for both alias / unalias */ + +static const char g_noaliasfmt[] = "%s: %s not found\n"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: alias_init + ****************************************************************************/ + +void alias_init(FAR struct nsh_vtbl_s *vtbl) +{ + int i; + + if (!sq_empty(&vtbl->alist) || !sq_empty(&vtbl->afreelist)) + { + /* If either list is non-empty, we are initialized already */ + + return; + } + + sq_init(&vtbl->alist); + sq_init(&vtbl->afreelist); + + for (i = 0; i < CONFIG_NSH_ALIAS_MAX_AMOUNT; i++) + { + sq_addlast((FAR struct sq_entry_s *)&vtbl->atab[i], &vtbl->afreelist); + } + + return; +} + +/**************************************************************************** + * Name: alias_find + ****************************************************************************/ + +static FAR struct nsh_alias_s *alias_find(FAR struct nsh_vtbl_s *vtbl, + FAR const char *name) +{ + FAR struct nsh_alias_s *alias; + + for (alias = alias_head(&vtbl->alist); alias; alias = alias->next) + { + if (strcmp(alias->name, name) == 0) + { + return alias; + } + } + + return NULL; +} + +/**************************************************************************** + * Name: alias_delete + ****************************************************************************/ + +static void alias_delete(FAR struct nsh_vtbl_s *vtbl, + FAR struct nsh_alias_s *alias) +{ + if (alias) + { + if (alias->exp) + { + /* Mark it for removal, but keep the data intact */ + + alias->rem = 1; + return; + } + + if (alias->name) + { + free(alias->name); + } + + if (alias->value) + { + free(alias->value); + } + + alias->name = NULL; + alias->value = NULL; + alias->flags = 0; + + sq_rem((FAR sq_entry_t *)alias, &vtbl->alist); + sq_addfirst((FAR sq_entry_t *)alias, &vtbl->afreelist); + } +} + +/**************************************************************************** + * Name: alias_save + ****************************************************************************/ + +static int alias_save(FAR struct nsh_vtbl_s *vtbl, FAR const char *name, + FAR const char *value) +{ + FAR struct nsh_alias_s *alias; + int ret = OK; + + if (!name || *name == '\0' || !value) + { + return -EINVAL; + } + + if ((alias = alias_find(vtbl, name)) != NULL) + { + /* Update the value */ + + free(alias->value); + alias->value = strdup(value); + } + else if ((alias = alias_remfirst(&vtbl->afreelist)) != NULL) + { + /* Create new value */ + + alias->name = strdup(name); + alias->value = strdup(value); + sq_addlast((FAR sq_entry_t *)alias, &vtbl->alist); + } + + if (!alias || !alias->name || !alias->value) + { + /* Something went wrong, clean up after ourselves */ + + alias_delete(vtbl, alias); + ret = -ENOMEM; + } + + return ret; +} + +/**************************************************************************** + * Name: alias_printall + ****************************************************************************/ + +static void alias_printall(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct nsh_alias_s *alias; + + for (alias = alias_head(&vtbl->alist); alias; alias = alias->next) + { + nsh_output(vtbl, g_aliasfmt, alias->name, alias->value); + } +} + +/**************************************************************************** + * Name: alias_removeall + ****************************************************************************/ + +static void alias_removeall(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct nsh_alias_s *alias; + FAR struct nsh_alias_s *next; + + alias = alias_head(&vtbl->alist); + + while (alias) + { + next = alias->next; + alias_delete(vtbl, alias); + alias = next; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_aliasfind + * + * Description: + * Find alias for token. Returns the alias structure or NULL if not found. + * + * Input Parameters: + * vtbl - NSH session data. + * token - The argument string to find. + * + * Returned Value: + * The alias is returned, if one found, otherwise NULL. + * + ****************************************************************************/ + +FAR struct nsh_alias_s *nsh_aliasfind(FAR struct nsh_vtbl_s *vtbl, + FAR const char *token) +{ + FAR struct nsh_alias_s *alias; + + /* Init, if necessary */ + + alias_init(vtbl); + + if (token) + { + /* See if such an alias exists ? */ + + alias = alias_find(vtbl, token); + if (alias && !alias->exp && alias->value) + { + /* Yes, return the alias */ + + return alias; + } + } + + return NULL; +} + +/**************************************************************************** + * Name: nsh_aliasfree + * + * Description: + * Free memory for any deleted alias, aliases are kept in memory until all + * references to it have been freed. + * + * Input Parameters: + * vtbl - NSH session data. + * alias - Pointer to alias data that is freed. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void nsh_aliasfree(FAR struct nsh_vtbl_s *vtbl, + FAR struct nsh_alias_s *alias) +{ + alias_delete(vtbl, alias); +} + +/**************************************************************************** + * Name: cmd_alias + * + * Description: + * Handle 'alias' command from terminal. Multiple alias values can be given + * by a single command. + * + * Command does one of three things: + * 1) If no arguments are given, every alias is printed to terminal. + * 2) If a known alias name is given, the value is printed to terminal. + * 3) If a "name=value" pair is given, a new alias is created, if there is + * room. + * + * Input Parameters: + * vtbl - The NSH console. + * argc - Amount of argument strings in command. + * argv - The argument strings. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int cmd_alias(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv) +{ + FAR struct nsh_alias_s *alias; + FAR char **arg; + FAR char *value; + int ret = OK; + + /* Init, if necessary */ + + alias_init(vtbl); + + if (argc < 2) + { + /* Print the alias list */ + + alias_printall(vtbl); + return ret; + } + + /* Traverse through the argument vector */ + + for (arg = argv + 1; *arg; arg++) + { + /* Look for name=value */ + + if ((value = strchr(*arg, '=')) != NULL) + { + /* Save new / modify existing alias */ + + *value++ = '\0'; + + ret = alias_save(vtbl, *arg, value); + if (ret < 0) + { + nsh_error(vtbl, g_savefailfmt, *arg, value); + } + } + else if ((alias = alias_find(vtbl, *arg)) != NULL) + { + /* Found it */ + + nsh_output(vtbl, g_aliasfmt, alias->name, alias->value); + } + else + { + /* Nothing found */ + + nsh_error(vtbl, g_noaliasfmt, "alias", *arg); + ret = -ENOENT; + } + } + + return ret; +} + +/**************************************************************************** + * Name: cmd_unalias + * + * Description: + * Handle 'cmd_unalias' command from terminal. + * + * Command does one of two things: + * 1) If the '-a' argument is given, all aliases are destroyed. + * 2) If a known alias name is given, the name=value pair is destroyed. + * + * Input Parameters: + * vtbl - The NSH console. + * argc - Amount of argument strings in command. + * argv - The argument strings. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int cmd_unalias(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv) +{ + FAR struct nsh_alias_s *alias; + FAR char **arg; + int option; + int ret = OK; + + /* Init, if necessary */ + + alias_init(vtbl); + + if (argc < 2) + { + /* No arguments given, this is an error */ + + return -EINVAL; + } + + /* If '-a' is provided, then just wipe them all */ + + if ((option = getopt(argc, argv, "a")) != ERROR) + { + alias_removeall(vtbl); + return ret; + } + + /* Traverse through the argument vector */ + + for (arg = argv + 1; *arg; arg++) + { + if ((alias = alias_find(vtbl, *arg)) != NULL) + { + /* Found it */ + + alias_delete(vtbl, alias); + } + else + { + /* Nothing found */ + + nsh_error(vtbl, g_noaliasfmt, "unalias", *arg); + ret = -ENOENT; + } + } + + return ret; +} + +#endif /* CONFIG_NSH_ALIAS */ diff --git a/nshlib/nsh_command.c b/nshlib/nsh_command.c index e5ff25289..79da9341d 100644 --- a/nshlib/nsh_command.c +++ b/nshlib/nsh_command.c @@ -104,6 +104,13 @@ static const struct cmdmap_s g_cmdmap[] = { "addroute", cmd_addroute, 3, 4, "<target> [<netmask>] <router>" }, #endif +#ifdef CONFIG_NSH_ALIAS + { "alias", cmd_alias, 1, CONFIG_NSH_MAXARGUMENTS, + "[name[=value] ... ]" }, + { "unalias", cmd_unalias, 1, CONFIG_NSH_MAXARGUMENTS, + "[-a] name [name ... ]" }, +#endif + #if defined(CONFIG_NET) && defined(CONFIG_NET_ARP) && !defined(CONFIG_NSH_DISABLE_ARP) { "arp", cmd_arp, 1, 6, "[-i <ifname>] [-a <ipaddr>|-d <ipaddr>|-s <ipaddr> <hwaddr>]" }, diff --git a/nshlib/nsh_console.h b/nshlib/nsh_console.h index cf5e75a89..176f9bdba 100644 --- a/nshlib/nsh_console.h +++ b/nshlib/nsh_console.h @@ -33,6 +33,8 @@ #include <stdbool.h> #include <errno.h> +#include <nuttx/queue.h> + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -119,6 +121,14 @@ struct nsh_vtbl_s char iobuffer[IOBUFFERSIZE]; #endif +#ifdef CONFIG_NSH_ALIAS + /* Shell alias support */ + + struct nsh_alias_s atab[CONFIG_NSH_ALIAS_MAX_AMOUNT]; + struct sq_queue_s alist; + struct sq_queue_s afreelist; +#endif + /* Parser state data */ struct nsh_parser_s np; diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index 87bf50c1a..f2cc78cd0 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -54,7 +54,8 @@ */ #undef HAVE_MEMLIST -#if defined(CONFIG_NSH_CMDPARMS) || defined(CONFIG_NSH_ARGCAT) +#if defined(CONFIG_NSH_CMDPARMS) || defined(CONFIG_NSH_ALIAS) || \ + defined(CONFIG_NSH_ARGCAT) # define HAVE_MEMLIST 1 #endif @@ -89,6 +90,19 @@ # define NEED_NULLSTRING 1 #endif +/* Mark already expanded aliases into a list, to prevent recursion */ + +#ifdef CONFIG_NSH_ALIAS +# define NSH_ALIASLIST_TYPE struct nsh_alist_s +# define NSH_ALIASLIST_INIT(l) memset(&(l), 0, sizeof(struct nsh_alist_s)) +# define NSH_ALIASLIST_ADD(l, a) nsh_alist_add((l), (a)) +# define NSH_ALIASLIST_FREE(v, l) nsh_alist_free((v), (l)) +#else +# define NSH_ALIASLIST_TYPE uint8_t +# define NSH_ALIASLIST_INIT(l) do { (l) = 0; } while (0) +# define NSH_ALIASLIST_FREE(v, l) +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -115,6 +129,14 @@ struct nsh_memlist_s }; #endif +#ifdef CONFIG_NSH_ALIAS +struct nsh_alist_s +{ + int nallocs; + FAR struct nsh_alias_s *allocs[CONFIG_NSH_ALIAS_MAX_AMOUNT]; +}; +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -125,6 +147,13 @@ static void nsh_memlist_add(FAR struct nsh_memlist_s *memlist, static void nsh_memlist_free(FAR struct nsh_memlist_s *memlist); #endif +#ifdef CONFIG_NSH_ALIAS +static void nsh_alist_add(FAR struct nsh_alist_s *alist, + FAR struct nsh_alias_s *alias); +static void nsh_alist_free(FAR struct nsh_vtbl_s *vtbl, + FAR struct nsh_alist_s *alist); +#endif + #ifndef CONFIG_NSH_DISABLEBG static void nsh_releaseargs(struct cmdarg_s *arg); static pthread_addr_t nsh_child(pthread_addr_t arg); @@ -155,6 +184,11 @@ static FAR char *nsh_strchr(FAR const char *str, int ch); # define nsh_strchr(s,c) strchr(s,c) #endif +#ifdef CONFIG_NSH_ALIAS +static FAR char *nsh_aliasexpand(FAR struct nsh_vtbl_s *vtbl, + FAR char *cmdline, FAR NSH_ALIASLIST_TYPE *alist); +#endif + #ifdef NSH_HAVE_VARS static FAR char *nsh_envexpand(FAR struct nsh_vtbl_s *vtbl, FAR char *varname); @@ -173,6 +207,7 @@ static FAR char *nsh_argexpand(FAR struct nsh_vtbl_s *vtbl, static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist, FAR int *isenvvar); #ifndef CONFIG_NSH_DISABLESCRIPT @@ -185,17 +220,20 @@ static bool nsh_itef_enabled(FAR struct nsh_vtbl_s *vtbl); static bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl); #ifndef CONFIG_NSH_DISABLE_LOOPS static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist); + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist); #endif #ifndef CONFIG_NSH_DISABLE_ITEF static int nsh_itef(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist); + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist); #endif #endif #ifndef CONFIG_NSH_DISABLEBG static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist); + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist); #endif #ifdef CONFIG_NSH_CMDPARMS @@ -334,6 +372,57 @@ static void nsh_memlist_free(FAR struct nsh_memlist_s *memlist) } #endif +/**************************************************************************** + * Name: nsh_alist_add + ****************************************************************************/ + +#ifdef CONFIG_NSH_ALIAS +static void nsh_alist_add(FAR struct nsh_alist_s *alist, + FAR struct nsh_alias_s *alias) +{ + if (alist && alias) + { + int index = alist->nallocs; + if (index < CONFIG_NSH_ALIAS_MAX_AMOUNT) + { + alias->exp = 1; + alist->allocs[index] = alias; + alist->nallocs = index + 1; + } + } +} +#endif + +/**************************************************************************** + * Name: nsh_alist_free + ****************************************************************************/ + +#ifdef CONFIG_NSH_ALIAS +static void nsh_alist_free(FAR struct nsh_vtbl_s *vtbl, + FAR struct nsh_alist_s *alist) +{ + if (vtbl && alist) + { + FAR struct nsh_alias_s *alias; + int index; + + for (index = 0; index < alist->nallocs; index++) + { + alias = alist->allocs[index]; + alias->exp = 0; + if (alias->rem == 1) + { + nsh_aliasfree(vtbl, alias); + } + + alist->allocs[index] = NULL; + } + + alist->nallocs = 0; + } +} +#endif + /**************************************************************************** * Name: nsh_releaseargs ****************************************************************************/ @@ -1036,6 +1125,31 @@ static FAR char *nsh_strchr(FAR const char *str, int ch) } #endif +/**************************************************************************** + * Name: nsh_aliasexpand + ****************************************************************************/ + +#ifdef CONFIG_NSH_ALIAS +static FAR char *nsh_aliasexpand(FAR struct nsh_vtbl_s *vtbl, + FAR char *cmdline, FAR NSH_ALIASLIST_TYPE *alist) +{ + FAR struct nsh_alias_s *alias; + + /* Does such an alias exist ? */ + + alias = nsh_aliasfind(vtbl, cmdline); + if (alias) + { + /* Yes, expand and mark it as already expanded */ + + NSH_ALIASLIST_ADD(alist, alias); + return alias->value; + } + + return cmdline; +} +#endif + /**************************************************************************** * Name: nsh_envexpand ****************************************************************************/ @@ -1171,7 +1285,7 @@ static FAR char *nsh_rmquotes(FAR char *qbegin, FAR char *qend) ch = *ptr++; *dst++ = ch; } - while(ch != '\0'); + while (ch != '\0'); return qend - 2; } @@ -1513,6 +1627,7 @@ static FAR char *nsh_argexpand(FAR struct nsh_vtbl_s *vtbl, static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist, FAR int *isenvvar) { FAR char *pbegin = *saveptr; @@ -1523,6 +1638,7 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char *prev; bool escaped; #endif + bool quoted; /* Find the beginning of the next token */ @@ -1578,6 +1694,7 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, * make sure that we do not break up any quoted substrings. */ + quoted = false; #ifdef CONFIG_NSH_QUOTE escaped = false; @@ -1611,7 +1728,7 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, /* Are we entering a quoted string ? */ - if (nsh_strchr(g_quote_separator, *pend)) + if ((quoted = (nsh_strchr(g_quote_separator, *pend) != NULL))) { /* Yes, find the terminator and continue from there */ @@ -1622,7 +1739,7 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char qterm[2]; - qterm[0] = ptr; + qterm[0] = *pend; qterm[1] = '\0'; nsh_error(vtbl, g_fmtnomatching, qterm, qterm); @@ -1669,6 +1786,15 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, *saveptr = pend; +#ifdef CONFIG_NSH_ALIAS + /* Expand aliases (if applicable) first, quoting prevents this */ + + if (!quoted) + { + pbegin = nsh_aliasexpand(vtbl, pbegin, alist); + } +#endif + /* Perform expansions as necessary for the argument */ argument = nsh_argexpand(vtbl, pbegin, &allocation, isenvvar); @@ -1769,7 +1895,8 @@ static bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl) #if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS) static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist) + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist) { FAR struct nsh_parser_s *np = &vtbl->np; FAR char *cmd = *ppcmd; @@ -1792,7 +1919,7 @@ static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, /* Get the cmd following the "while" or "until" */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, 0); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, 0); if (*ppcmd == NULL || **ppcmd == '\0') { nsh_error(vtbl, g_fmtarginvalid, cmd); @@ -1849,7 +1976,7 @@ static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the "do" -- there may or may not be one */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, NULL); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); /* Verify that "do" is valid in this context */ @@ -1869,7 +1996,7 @@ static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the "done" -- there should be one */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, NULL); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); if (*ppcmd) { nsh_error(vtbl, g_fmtarginvalid, "done"); @@ -1961,7 +2088,8 @@ errout: #if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_ITEF) static int nsh_itef(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist) + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist) { FAR struct nsh_parser_s *np = &vtbl->np; FAR char *cmd = *ppcmd; @@ -1976,7 +2104,7 @@ static int nsh_itef(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the if */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, NULL); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); if (*ppcmd == NULL || **ppcmd == '\0') { nsh_error(vtbl, g_fmtarginvalid, "if"); @@ -1991,7 +2119,7 @@ static int nsh_itef(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, /* Get the next cmd */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, 0); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, 0); if (*ppcmd == NULL || **ppcmd == '\0') { nsh_error(vtbl, g_fmtarginvalid, "if"); @@ -2033,7 +2161,7 @@ static int nsh_itef(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, * one. */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, NULL); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); /* Verify that "then" is valid in this context */ @@ -2054,7 +2182,7 @@ static int nsh_itef(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, * one. */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, NULL); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); /* Verify that "else" is valid in this context */ @@ -2073,7 +2201,7 @@ static int nsh_itef(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the fi -- there should be one */ - *ppcmd = nsh_argument(vtbl, saveptr, memlist, NULL); + *ppcmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); if (*ppcmd) { nsh_error(vtbl, g_fmtarginvalid, "fi"); @@ -2129,7 +2257,8 @@ errout: #ifndef CONFIG_NSH_DISABLEBG static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist) + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist) { FAR char *cmd = *ppcmd; @@ -2148,10 +2277,11 @@ static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, /* Get the cmd (or -d option of nice command) */ - cmd = nsh_argument(vtbl, saveptr, memlist, NULL); + cmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); if (cmd && strcmp(cmd, "-d") == 0) { - FAR char *val = nsh_argument(vtbl, saveptr, memlist, NULL); + FAR char *val = nsh_argument(vtbl, saveptr, memlist, alist, + NULL); if (val) { FAR char *endptr; @@ -2163,7 +2293,7 @@ static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, return ERROR; } - cmd = nsh_argument(vtbl, saveptr, memlist, NULL); + cmd = nsh_argument(vtbl, saveptr, memlist, alist, NULL); } } @@ -2196,6 +2326,7 @@ static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, FAR const char *redirfile) { NSH_MEMLIST_TYPE memlist; + NSH_ALIASLIST_TYPE alist; FAR char *argv[MAX_ARGV_ENTRIES]; FAR char *saveptr; FAR char *cmd; @@ -2210,6 +2341,7 @@ static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *)); NSH_MEMLIST_INIT(memlist); + NSH_ALIASLIST_INIT(alist); /* If any options like nice, redirection, or backgrounding are attempted, * these will not be recognized and will just be passed through as @@ -2233,7 +2365,7 @@ static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, /* Parse out the command at the beginning of the line */ saveptr = cmdline; - cmd = nsh_argument(vtbl, &saveptr, &memlist, NULL); + cmd = nsh_argument(vtbl, &saveptr, &memlist, &alist, NULL); /* Check if any command was provided -OR- if command processing is * currently disabled. @@ -2268,7 +2400,7 @@ static int nsh_parse_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, argv[0] = cmd; for (argc = 1; argc < MAX_ARGV_ENTRIES - 1; argc++) { - argv[argc] = nsh_argument(vtbl, &saveptr, &memlist, NULL); + argv[argc] = nsh_argument(vtbl, &saveptr, &memlist, &alist, NULL); if (!argv[argc]) { break; @@ -2297,6 +2429,7 @@ exit: #endif vtbl->np.np_redirect = redirsave; + NSH_ALIASLIST_FREE(vtbl, &alist); NSH_MEMLIST_FREE(&memlist); return ret; } @@ -2313,6 +2446,7 @@ exit: static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) { NSH_MEMLIST_TYPE memlist; + NSH_ALIASLIST_TYPE alist; FAR char *argv[MAX_ARGV_ENTRIES]; FAR char *saveptr; FAR char *cmd; @@ -2326,6 +2460,7 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *)); NSH_MEMLIST_INIT(memlist); + NSH_ALIASLIST_INIT(alist); #ifndef CONFIG_NSH_DISABLEBG vtbl->np.np_bg = false; @@ -2336,26 +2471,26 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) /* Parse out the command at the beginning of the line */ saveptr = cmdline; - cmd = nsh_argument(vtbl, &saveptr, &memlist, NULL); + cmd = nsh_argument(vtbl, &saveptr, &memlist, &alist, NULL); #ifndef CONFIG_NSH_DISABLESCRIPT #ifndef CONFIG_NSH_DISABLE_LOOPS /* Handle while-do-done and until-do-done loops */ - if (nsh_loop(vtbl, &cmd, &saveptr, &memlist) != 0) + if (nsh_loop(vtbl, &cmd, &saveptr, &memlist, &alist) != 0) { - NSH_MEMLIST_FREE(&memlist); - return nsh_saveresult(vtbl, true); + ret = nsh_saveresult(vtbl, true); + goto dynlist_free; } #endif #ifndef CONFIG_NSH_DISABLE_ITEF /* Handle if-then-else-fi */ - if (nsh_itef(vtbl, &cmd, &saveptr, &memlist) != 0) + if (nsh_itef(vtbl, &cmd, &saveptr, &memlist, &alist) != 0) { - NSH_MEMLIST_FREE(&memlist); - return nsh_saveresult(vtbl, true); + ret = nsh_saveresult(vtbl, true); + goto dynlist_free; } #endif @@ -2364,10 +2499,10 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) /* Handle nice */ #ifndef CONFIG_NSH_DISABLEBG - if (nsh_nice(vtbl, &cmd, &saveptr, &memlist) != 0) + if (nsh_nice(vtbl, &cmd, &saveptr, &memlist, &alist) != 0) { - NSH_MEMLIST_FREE(&memlist); - return nsh_saveresult(vtbl, true); + ret = nsh_saveresult(vtbl, true); + goto dynlist_free; } #endif @@ -2386,8 +2521,8 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) * status. */ - NSH_MEMLIST_FREE(&memlist); - return OK; + ret = OK; + goto dynlist_free; } /* Parse all of the arguments following the command name. The form @@ -2409,7 +2544,7 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) { int isenvvar = 0; /* flag for if an environment variable gets expanded */ - argv[argc] = nsh_argument(vtbl, &saveptr, &memlist, &isenvvar); + argv[argc] = nsh_argument(vtbl, &saveptr, &memlist, &alist, &isenvvar); if (!argv[argc]) { @@ -2526,6 +2661,8 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) vtbl->np.np_redirect = redirect_save; } +dynlist_free: + NSH_ALIASLIST_FREE(vtbl, &alist); NSH_MEMLIST_FREE(&memlist); return ret; }