nsh/alias: Add support for alias arguments

This adds support for more complex alias handling, such as:

$ alias ls='ls -l'

Previously such an alias was not split into the command verb and the
argument correctly, instead the full alias string was handled as the
verb, which obviously fails.

This commit fixes this by expanding the alias, checking whether it has
arguments and if so, it merges the expanded alias + the old command line
together, resulting in a completely new command line.

Example (assuming the alias above has been created):

$ ls /bin

Results in a new command line: "ls -l /bin" which is then parsed and
executed.
This commit is contained in:
Ville Juven 2023-04-05 10:36:49 +03:00 committed by Masayuki Ishikawa
parent 90c963677c
commit 0914c20c0d

View File

@ -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