diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index 75c7876a1..800daf08c 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -59,11 +59,29 @@ # define HAVE_MEMLIST 1 #endif +/* If CONFIG_NSH_ALIAS is enabled, the alias strings might need dynamic + * memory, in case the alias has arguments and is set like: + * + * $ alias ls='ls -l' + * + * In this case the command verb and the arguments need to be separated, much + * like the argument separation is done with environment variable expansion. + * + * This needs a new working buffer in order to keep the original alias string + * intact. + */ + +#ifdef CONFIG_NSH_ALIAS +# define ALIAS_ALLOCS 2 +#else +# define ALIAS_ALLOCS 0 +#endif + #if defined(HAVE_MEMLIST) && !defined(CONFIG_NSH_MAXALLOCS) # ifdef CONFIG_NSH_ARGCAT -# define CONFIG_NSH_MAXALLOCS (2*CONFIG_NSH_MAXARGUMENTS) +# define CONFIG_NSH_MAXALLOCS ((2*CONFIG_NSH_MAXARGUMENTS) + ALIAS_ALLOCS) # else -# define CONFIG_NSH_MAXALLOCS CONFIG_NSH_MAXARGUMENTS +# define CONFIG_NSH_MAXALLOCS (CONFIG_NSH_MAXARGUMENTS + ALIAS_ALLOCS) # endif #endif @@ -173,7 +191,7 @@ static FAR char *nsh_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, FAR char **allocation); #endif -#ifdef CONFIG_NSH_ARGCAT +#if defined(CONFIG_NSH_ARGCAT) || defined(CONFIG_NSH_ALIAS) static FAR char *nsh_strcat(FAR struct nsh_vtbl_s *vtbl, FAR char *s1, FAR const char *s2); #endif @@ -186,7 +204,9 @@ static FAR char *nsh_strchr(FAR const char *str, int ch); #ifdef CONFIG_NSH_ALIAS static FAR char *nsh_aliasexpand(FAR struct nsh_vtbl_s *vtbl, - FAR char *cmdline, FAR NSH_ALIASLIST_TYPE *alist); + FAR char *cmdline, FAR char **saveptr, + FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist); #endif #ifdef NSH_HAVE_VARS @@ -1057,7 +1077,7 @@ static FAR char *nsh_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, * Name: nsh_strcat ****************************************************************************/ -#ifdef CONFIG_NSH_ARGCAT +#if defined(CONFIG_NSH_ARGCAT) || defined(CONFIG_NSH_ALIAS) static FAR char *nsh_strcat(FAR struct nsh_vtbl_s *vtbl, FAR char *s1, FAR const char *s2) { @@ -1131,7 +1151,9 @@ static FAR char *nsh_strchr(FAR const char *str, int ch) #ifdef CONFIG_NSH_ALIAS static FAR char *nsh_aliasexpand(FAR struct nsh_vtbl_s *vtbl, - FAR char *cmdline, FAR NSH_ALIASLIST_TYPE *alist) + FAR char *cmdline, FAR char **saveptr, + FAR NSH_MEMLIST_TYPE *memlist, + FAR NSH_ALIASLIST_TYPE *alist) { FAR struct nsh_alias_s *alias; @@ -1140,10 +1162,45 @@ static FAR char *nsh_aliasexpand(FAR struct nsh_vtbl_s *vtbl, alias = nsh_aliasfind(vtbl, cmdline); if (alias) { - /* Yes, expand and mark it as already expanded */ + FAR char *ptr; + size_t len; + /* Yes, expand the alias and mark it as already expanded */ + + cmdline = alias->value; NSH_ALIASLIST_ADD(alist, alias); - return alias->value; + + /* Check if alias expands to more words on the command line */ + + len = strcspn(cmdline, g_token_separator); + ptr = cmdline + len; + + if (*ptr != '\0') + { + /* It does, make a copy so the alias string is not modified */ + + if ((ptr = strdup(alias->value)) != NULL) + { + /* Set the new command line (expanded alias) */ + + cmdline = ptr; + + /* Then concatenate the old command line with the new */ + + ptr = nsh_strcat(vtbl, ptr, " "); + ptr = nsh_strcat(vtbl, ptr, *saveptr); + NSH_MEMLIST_ADD(memlist, ptr); + + /* NULL terminate the new command */ + + ptr = cmdline + len; + *ptr++ = '\0'; + + /* Mark where we left off in the new command line string */ + + *saveptr = ptr; + } + } } return cmdline; @@ -1811,7 +1868,7 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, if (alist && !quoted) { - pbegin = nsh_aliasexpand(vtbl, pbegin, alist); + pbegin = nsh_aliasexpand(vtbl, pbegin, saveptr, memlist, alist); } #endif