From 65b4921b23a4da4376e73a0edb07e189fcb93fe8 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 11 Jan 2014 09:50:54 -0600 Subject: [PATCH] Back quoted NSH arguments now functional --- ChangeLog.txt | 2 + nshlib/Kconfig | 27 +-- nshlib/README.txt | 60 +++++++ nshlib/nsh.h | 6 +- nshlib/nsh_ddcmd.c | 12 +- nshlib/nsh_parse.c | 438 ++++++++++++++++++++++++++++++++++++--------- 6 files changed, 445 insertions(+), 100 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0b377bf91..03dd38a3a 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -769,4 +769,6 @@ * apps/nshlib/nsh_parse.c: Add initial support of commands enclosed in back quotes as command arguments. Functionality still incomplete on initial commit (2014-1-10). + * Logic to support commands enclosed in back quotes is functional + but not thoroughly tested (2014-1-11). diff --git a/nshlib/Kconfig b/nshlib/Kconfig index 7d12d4d65..df1a9c518 100644 --- a/nshlib/Kconfig +++ b/nshlib/Kconfig @@ -277,11 +277,11 @@ config NSH_DISABLE_SEMICOLON command separated by a semicolon. You can disable this feature to save a little memory on FLASH challenged platforms. -config NSH_FUNCPARMS - bool "Enable function parameters" +config NSH_CMDPARMS + bool "Enable commands as parameters" default n ---help--- - If selected, then the output from cmds, from file applications, and + If selected, then the output from commands, from file applications, and from NSH built-in commands can be used as arguments to other commands. The entity to be executed is identified by enclosing the command line in back quotes. For example, @@ -292,14 +292,15 @@ config NSH_FUNCPARMS environment variable BAR. The value of the environment variable FOO is then set output of myprogram on stdout. - This feature is disabled by default. + Because this feature commits significant resourse, it is disabled by + default. config NSH_TMPDIR string "Temporary file directory" default "/tmp" - depends on NSH_FUNCPARMS + depends on NSH_CMDPARMS ---help--- - If NSH_FUNCPARMS is selected, then function output will be retained + If NSH_CMDPARMS is selected, then function output will be retained in a temporary file. In that case, this string must be provided to specify the full path to a directory where temporary files can be created. This would be a good application of RAM disk: To provide @@ -312,21 +313,21 @@ config NSH_MAXARGUMENTS The maximum number of NSH command arguments. Default: 6 -config NSH_ENVCAT - bool "Concatenation of environment variables" +config NSH_ARGCAT + bool "Concatenation of argument strings" default n ---help--- - Support concatenation of strings with environment variables. For - example: + Support concatenation of strings with environment variables or command + output. For example: set FOO XYZ set BAR 123 set FOOBAR ABC_${FOO}_${BAR} would set the environment variable FOO to XYZ, BAR to 123 and FOOBAR - to ABC_XYZ_123. If NSH_ENV, then a slightly small FLASH footprint - results but then also only simple environment variables like $FOO - can be used on the command line. + to ABC_XYZ_123. If NSH_ARGCAT is not selected, then a slightly small + FLASH footprint results but then also only simple environment + variables like $FOO can be used on the command line. config NSH_NESTDEPTH int "Maximum command nesting" diff --git a/nshlib/README.txt b/nshlib/README.txt index 683499c48..11d692dc1 100644 --- a/nshlib/README.txt +++ b/nshlib/README.txt @@ -65,6 +65,30 @@ Command Overview Multiple commands per line. NSH will accept multiple commands per command line with each command separated with the semi-colon character (;). + If CONFIG_NSH_CMDPARMS is selected, then the output from commands, from + file applications, and from NSH built-in commands can be used as arguments + to other commands. The entity to be executed is identified by enclosing + the command line in back quotes. For example, + + set FOO `myprogram $BAR` + + Will execute the program named myprogram passing it the value of the + environment variable BAR. The value of the environment variable FOO + is then set output of myprogram on stdout. Because this feature commits + significant resources, it is disabled by default. + + If CONFIG_NSH_ARGCAT is selected, the support concatenation of strings + with environment variables or command output. For example: + + set FOO XYZ + set BAR 123 + set FOOBAR ABC_${FOO}_${BAR} + + would set the environment variable FOO to XYZ, BAR to 123 and FOOBAR + to ABC_XYZ_123. If NSH_ARGCAT is not selected, then a slightly small + FLASH footprint results but then also only simple environment + variables like $FOO can be used on the command line. + Conditional Command Execution ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1007,6 +1031,42 @@ NSH-Specific Configuration Settings feature to save a little memory on FLASH challenged platforms. Default: n + * CONFIG_NSH_CMDPARMS + If selected, then the output from commands, from file applications, and + from NSH built-in commands can be used as arguments to other + commands. The entity to be executed is identified by enclosing the + command line in back quotes. For example, + + set FOO `myprogram $BAR` + + Will execute the program named myprogram passing it the value of the + environment variable BAR. The value of the environment variable FOO + is then set output of myprogram on stdout. Because this feature commits + significant resources, it is disabled by default. + + * CONFIG_NSH_TMPDIR + If CONFIG_NSH_CMDPARMS is selected, then function output will be retained + in a temporary file. In that case, this string must be provided to + specify the full path to a directory where temporary files can be + created. This would be a good application of RAM disk: To provide + temporary storage for function output. + + * CONFIG_NSH_MAXARGUMENTS + The maximum number of NSH command arguments. Default: 6 + + * CONFIG_NSH_ARGCAT + Support concatenation of strings with environment variables or command + output. For example: + + set FOO XYZ + set BAR 123 + set FOOBAR ABC_${FOO}_${BAR} + + would set the environment variable FOO to XYZ, BAR to 123 and FOOBAR + to ABC_XYZ_123. If NSH_ARGCAT is not selected, then a slightly small + FLASH footprint results but then also only simple environment + variables like $FOO can be used on the command line. + * CONFIG_NSH_NESTDEPTH The maximum number of nested if-then[-else]-fi sequences that are permissable. Default: 3 diff --git a/nshlib/nsh.h b/nshlib/nsh.h index 1466b7187..a38d04c4a 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -72,14 +72,14 @@ # undef CONFIG_NSH_TELNET # undef CONFIG_NSH_FILE_APPS # undef CONFIG_NSH_TELNET -# undef CONFIG_NSH_FUNCPARMS +# undef CONFIG_NSH_CMDPARMS #endif -/* If CONFIG_NSH_FUNCPARMS is selected, then the path to a directory to +/* If CONFIG_NSH_CMDPARMS is selected, then the path to a directory to * hold temporary files must be provided. */ -#if defined(CONFIG_NSH_FUNCPARMS) && !defined(CONFIG_NSH_TMPDIR) +#if defined(CONFIG_NSH_CMDPARMS) && !defined(CONFIG_NSH_TMPDIR) # define CONFIG_NSH_TMPDIR "/tmp" #endif diff --git a/nshlib/nsh_ddcmd.c b/nshlib/nsh_ddcmd.c index 5db3e42c3..ce6b47a47 100644 --- a/nshlib/nsh_ddcmd.c +++ b/nshlib/nsh_ddcmd.c @@ -173,7 +173,6 @@ static void dd_outfcloseblk(struct dd_s *dd) } #endif - /**************************************************************************** * Name: dd_outfclosech ****************************************************************************/ @@ -325,7 +324,7 @@ static int dd_readch(struct dd_s *dd) } /**************************************************************************** - * Name: dd_infopen + * Name: dd_filetype ****************************************************************************/ #ifndef CONFIG_DISABLE_MOUNTPOINT @@ -391,6 +390,7 @@ static inline int dd_infopen(const char *name, struct dd_s *dd) dd->infread = dd_readblk; dd->infclose = dd_infcloseblk; } + return OK; } #else @@ -403,6 +403,7 @@ static inline int dd_infopen(const char *name, struct dd_s *dd) nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO); return ERROR; } + return OK; } #endif @@ -450,6 +451,7 @@ static inline int dd_outfopen(const char *name, struct dd_s *dd) dd->outfwrite = dd_writech; /* Character oriented write */ dd->outfclose = dd_outfclosech; } + return OK; } #else @@ -461,6 +463,7 @@ static inline int dd_outfopen(const char *name, struct dd_s *dd) nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO); return ERROR; } + return OK; } #endif @@ -614,22 +617,27 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) dd.sector++; } } + ret = OK; errout_with_outf: DD_INCLOSE(&dd); + errout_with_inf: DD_OUTCLOSE(&dd); free(dd.buffer); + errout_with_paths: if (infile) { free(infile); } + if (outfile) { free(outfile); } + return ret; } diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index 10ac3a258..97c87a7a1 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -45,6 +45,10 @@ #include #include +#ifdef CONFIG_NSH_CMDPARMS +# include +#endif + #include #include "nsh.h" @@ -53,6 +57,37 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* If CONFIG_NSH_CMDPARMS or CONFIG_NSH_ARGCAT is enabled, then we will need + * retain a list of memory allocations to be freed at the completion of + * command processing. + */ + +#undef HAVE_MEMLIST +#if defined(CONFIG_NSH_CMDPARMS) || defined(CONFIG_NSH_ARGCAT) +# define HAVE_MEMLIST 1 +#endif + +#if defined(HAVE_MEMLIST) && !defined(CONFIG_NSH_MAXALLOCS) +# ifdef CONFIG_NSH_ARGCAT +# define CONFIG_NSH_MAXALLOCS (2*CONFIG_NSH_MAXARGUMENTS) +# else +# define CONFIG_NSH_MAXALLOCS CONFIG_NSH_MAXARGUMENTS +# endif +#endif + +/* Allocation list helper macros */ + +#ifdef HAVE_MEMLIST +# define NSH_MEMLIST_TYPE struct nsh_memlist_s +# define NSH_MEMLIST_INIT(m) memset(&(m), 0, sizeof(struct nsh_memlist_s)); +# define NSH_MEMLIST_ADD(m,a) nsh_memlist_add(m,a) +# define NSH_MEMLIST_FREE(m) nsh_memlist_free(m) +#else +# define NSH_MEMLIST_TYPE uint8_t +# define NSH_MEMLIST_INIT(m) do { (m) = 0; } while (0) +# define NSH_MEMLIST_ADD(m,a) +# define NSH_MEMLIST_FREE(m,a) +#endif /**************************************************************************** * Private Types @@ -70,10 +105,26 @@ struct cmdarg_s }; #endif +/* This structure describes the allocation list */ + +#ifdef HAVE_MEMLIST +struct nsh_memlist_s +{ + int nallocs; /* Number of allocations */ + FAR char *allocations[CONFIG_NSH_MAXALLOCS]; +}; +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ +#ifdef HAVE_MEMLIST +static void nsh_memlist_add(FAR struct nsh_memlist_s *memlist, + FAR char *address); +static void nsh_memlist_free(FAR struct nsh_memlist_s *memlist); +#endif + #ifndef CONFIG_NSH_DISABLEBG static void nsh_releaseargs(struct cmdarg_s *arg); static pthread_addr_t nsh_child(pthread_addr_t arg); @@ -85,20 +136,31 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result); static int nsh_execute(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char *argv[], FAR const char *redirfile, int oflags); -static char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr); + +#ifdef CONFIG_NSH_CMDPARMS +static FAR char *nsh_filecat(FAR struct nsh_vtbl_s *vtbl, FAR char *s1, + FAR const char *filename); +static FAR char *nsh_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, + FAR char **allocation); +#endif +#ifdef CONFIG_NSH_ARGCAT +static int nsh_strcat(FAR char *s1, FAR const char *s2); +#endif +static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr, + FAR NSH_MEMLIST_TYPE *memlist); #ifndef CONFIG_NSH_DISABLESCRIPT static bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl); -static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, - FAR char **ppcmd, FAR char **saveptr); +static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist); #endif #ifndef CONFIG_NSH_DISABLEBG static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr); + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist); #endif -#ifdef CONFIG_NSH_FUNCPARMS +#ifdef CONFIG_NSH_CMDPARMS static int nsh_parse_funcparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, FAR const char *redirfile); #endif @@ -172,6 +234,48 @@ const char g_fmtsignalrecvd[] = "nsh: %s: Interrupted by signal\n"; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nsh_memlist_add + ****************************************************************************/ + +#ifdef HAVE_MEMLIST +static void nsh_memlist_add(FAR struct nsh_memlist_s *memlist, + FAR char *address) +{ + if (memlist) + { + int index = memlist->nallocs; + if (index < CONFIG_NSH_MAXALLOCS) + { + memlist->allocations[index] = address; + memlist->nallocs = index + 1; + } + } +} +#endif + +/**************************************************************************** + * Name: nsh_memlist_free + ****************************************************************************/ + +#ifdef HAVE_MEMLIST +static void nsh_memlist_free(FAR struct nsh_memlist_s *memlist) +{ + if (memlist) + { + int index; + + for (index = 0; index < memlist->nallocs; index++) + { + free(memlist->allocations[index]); + memlist->allocations[index] = NULL; + } + + memlist->nallocs = 0; + } +} +#endif + /**************************************************************************** * Name: nsh_releaseargs ****************************************************************************/ @@ -204,6 +308,7 @@ static void nsh_releaseargs(struct cmdarg_s *arg) { free(arg->argv[i]); } + free(arg); } #endif @@ -558,15 +663,202 @@ errout: return nsh_saveresult(vtbl, true); } +/**************************************************************************** + * Name: nsh_filecat + ****************************************************************************/ + +#ifdef CONFIG_NSH_CMDPARMS +static FAR char *nsh_filecat(FAR struct nsh_vtbl_s *vtbl, FAR char *s1, + FAR const char *filename) +{ + struct stat buf; + size_t s1size = 0; + size_t allocsize; + ssize_t nbytesread; + FAR char *argument; + int index; + int fd; + int ret; + + /* Get the size of the string */ + + if (s1) + { + s1size = (size_t)strlen(s1); + } + + /* Get the size of file */ + + ret = stat(filename, &buf); + if (ret != 0) + { + nsh_output(vtbl, g_fmtcmdfailed, "``", "stat", NSH_ERRNO); + return NULL; + } + + /* Get the total allocation size */ + + allocsize = s1size + (size_t)buf.st_size + 1; + argument = (FAR char *)realloc(s1, allocsize); + if (!argument) + { + nsh_output(vtbl, g_fmtcmdoutofmemory, "``"); + return NULL; + } + + /* Open the source file for reading */ + + fd = open(filename, O_RDONLY); + if (fd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, "``", "open", NSH_ERRNO); + goto errout_with_alloc; + } + + /* Now copy the file. Loop until the entire file has been transferred to + * the allocated string (after the original contents of s1size bytes. + */ + + for (index = s1size; index < allocsize - 1; ) + { + /* Loop until we successfully read something , we encounter the + * end-of-file, or until a read error occurs + */ + + do + { + nbytesread = read(fd, &argument[index], IOBUFFERSIZE); + if (nbytesread == 0) + { + /* Unexpected end of file -- Break out of the loop */ + + break; + } + else if (nbytesread < 0) + { + /* EINTR is not an error (but will still stop the copy) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, "``"); + } + else +#endif + { + /* Read error */ + + nsh_output(vtbl, g_fmtcmdfailed, "``", "read", NSH_ERRNO); + } + + goto errout_with_fd; + } + } + while (nbytesread <= 0); + + /* Update the index based upon the number of bytes read */ + + index += nbytesread; + } + + /* Make sure that the new string is null terminated */ + + argument[index] = '\0'; + return argument; + +errout_with_fd: + close(fd); + +errout_with_alloc: + free(argument); + return NULL; +} +#endif + +/**************************************************************************** + * Name: nsh_cmdparm + ****************************************************************************/ + +#ifdef CONFIG_NSH_CMDPARMS +static FAR char *nsh_cmdparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, + FAR char **allocation) +{ + FAR char *tmpfile; + FAR char *argument; + int ret; + + /* We cannot process the command argument if there is no allocation pointer */ + + if (!allocation) + { + return NULL; + } + + /* Create a unique file name using the task ID */ + + tmpfile = NULL; + ret = asprintf(&tmpfile, "%s/TMP%d.dat", CONFIG_NSH_TMPDIR, getpid()); + if (ret < 0 || !tmpfile) + { + nsh_output(vtbl, g_fmtcmdoutofmemory, "``"); + return NULL; + } + + /* Execute the command that will re-direct the output of the command to + * the temporary file. This is a simple command that can't handle most + * options. + */ + + ret = nsh_parse_funcparm(vtbl, cmdline, tmpfile); + if (ret != OK) + { + /* Report the failure */ + + nsh_output(vtbl, g_fmtcmdfailed, "``", "exec", NSH_ERRNO); + free(tmpfile); + return NULL; + } + + /* Concatenate the file contents with the current allocation */ + + argument = nsh_filecat(vtbl, *allocation, tmpfile); + *allocation = argument; + + /* We can now unlink the tmpfile and free the tmpfile string */ + + ret = unlink(tmpfile); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, "``", "unlink", NSH_ERRNO); + } + + free(tmpfile); + return argument; +} +#endif + +/**************************************************************************** + * Name: nsh_strcat + ****************************************************************************/ + +#ifdef CONFIG_NSH_ARGCAT +static int nsh_strcat(FAR char *s1, FAR const char *s2) +{ +} +#endif + /**************************************************************************** * Name: nsh_argument ****************************************************************************/ -static char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr) +static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr, + FAR NSH_MEMLIST_TYPE *memlist) { - FAR char *pbegin = *saveptr; - FAR char *pend = NULL; - const char *term; + FAR char *pbegin = *saveptr; + FAR char *pend = NULL; + FAR char *allocation = NULL; + FAR char *argument = NULL; + FAR const char *term; #ifndef CONFIG_DISABLE_ENVIRON bool quoted = false; #endif @@ -614,17 +906,14 @@ static char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr) pbegin = NULL; } -#ifdef CONFIG_NSH_FUNCPARMS +#ifdef CONFIG_NSH_CMDPARMS /* Are we being asked to use the output from another command or program * as an input parameters for this command? */ else if (*pbegin == '`') { - FAR char *tmpfile; - int ret; - - /* Yes, find the terminated backquote */ + /* Yes, find the terminating backquote */ for (++pbegin, pend = pbegin; *pend && *pend != '`'; pend++); @@ -645,51 +934,9 @@ static char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr) *pend++ = '\0'; *saveptr = pend; - /* Create a unique file name using the task ID */ + /* Then execute the command to get the paramter value */ - tmpfile = NULL; - ret = asprintf(&tmpfile, "%s/TMP%d.dat", CONFIG_NSH_TMPDIR, getpid()); - if (ret < 0 || !tmpfile) - { - nsh_output(vtbl, g_fmtcmdoutofmemory, "``"); - return NULL; - } - - /* Execute the command that will re-direct the output of the command - * to the temporary file. This is a simple command that can't handle - * most options. - */ - - ret = nsh_parse_funcparm(vtbl, pbegin, tmpfile); - if (ret != OK) - { - /* Report the failure */ -#warning Logic Missing - - free(tmpfile); - return NULL; - } - - /* mmap() the file contain the output from the command so that - * we can refer to it like any string. - */ -#warning Logic Missing - - /* setup so that we can unmap the memory region and close the - * file after the command completes. - */ -#warning Logic Missing - - /* We can not unlink the tmpfile and free the tmpfile string */ - - ret = unlink(tmpfile); - if (ret < 0) - { - nsh_output(vtbl, g_fmtcmdfailed, "``", "unlink", NSH_ERRNO); - } - - free(tmpfile); - return "OH NO!"; + argument = nsh_cmdparm(vtbl, pbegin, &allocation); } #endif @@ -780,11 +1027,27 @@ static char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr) } } #endif + /* The argument to be returned is simply the beginning of the + * delimited string. + */ + + argument = pbegin; } - /* Return the beginning of the token. */ - return pbegin; + /* If any memory was allocated for this argument, make sure that it is + * added to the list of memory to be freed at the end of commend + * processing. + */ + + if (allocation) + { + NSH_MEMLIST_ADD(memlist, allocation); + } + + /* Return the parsed argument. */ + + return argument; } /**************************************************************************** @@ -825,7 +1088,7 @@ static bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl) #ifndef CONFIG_NSH_DISABLESCRIPT static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr) + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist) { struct nsh_parser_s *np = &vtbl->np; FAR char *cmd = *ppcmd; @@ -839,7 +1102,7 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the if */ - *ppcmd = nsh_argument(vtbl, saveptr); + *ppcmd = nsh_argument(vtbl, saveptr, memlist); if (!*ppcmd) { nsh_output(vtbl, g_fmtarginvalid, "if"); @@ -876,7 +1139,7 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the then -- there shouldn't be one */ - *ppcmd = nsh_argument(vtbl, saveptr); + *ppcmd = nsh_argument(vtbl, saveptr, memlist); if (*ppcmd) { nsh_output(vtbl, g_fmtarginvalid, "then"); @@ -896,7 +1159,7 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the else -- there shouldn't be one */ - *ppcmd = nsh_argument(vtbl, saveptr); + *ppcmd = nsh_argument(vtbl, saveptr, memlist); if (*ppcmd) { nsh_output(vtbl, g_fmtarginvalid, "else"); @@ -916,7 +1179,7 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, { /* Get the cmd following the fi -- there should be one */ - *ppcmd = nsh_argument(vtbl, saveptr); + *ppcmd = nsh_argument(vtbl, saveptr, memlist); if (*ppcmd) { nsh_output(vtbl, g_fmtarginvalid, "fi"); @@ -965,7 +1228,7 @@ errout: #ifndef CONFIG_NSH_DISABLEBG static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, - FAR char **saveptr) + FAR char **saveptr, FAR NSH_MEMLIST_TYPE *memlist) { FAR char *cmd = *ppcmd; @@ -984,10 +1247,10 @@ 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); + cmd = nsh_argument(vtbl, saveptr, memlist); if (cmd && strcmp(cmd, "-d") == 0) { - FAR char *val = nsh_argument(vtbl, saveptr); + FAR char *val = nsh_argument(vtbl, saveptr, memlist); if (val) { char *endptr; @@ -998,7 +1261,7 @@ static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, nsh_output(vtbl, g_fmtarginvalid, "nice"); return ERROR; } - cmd = nsh_argument(vtbl, saveptr); + cmd = nsh_argument(vtbl, saveptr, memlist); } } @@ -1017,7 +1280,7 @@ static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, * * Description: * This function parses and executes a simple NSH command. Output is - * always redirected. Function function supports function paramers like + * always redirected. This function supports command parameters like * * set FOO `hello` * @@ -1026,10 +1289,11 @@ static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, * ****************************************************************************/ -#ifdef CONFIG_NSH_FUNCPARMS +#ifdef CONFIG_NSH_CMDPARMS static int nsh_parse_funcparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, FAR const char *redirfile) { + NSH_MEMLIST_TYPE memlist; FAR char *argv[MAX_ARGV_ENTRIES]; FAR char *saveptr; FAR char *cmd; @@ -1041,6 +1305,7 @@ static int nsh_parse_funcparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, /* Initialize parser state */ memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *)); + NSH_MEMLIST_INIT(memlist); /* If any options like nice, redirection, or backgrounding are attempted, * these will not be recognized and will just be passed through as @@ -1048,7 +1313,7 @@ static int nsh_parse_funcparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, */ #ifndef CONFIG_NSH_DISABLEBG - /* The function is never backgrounded . Remember the current backgrouding + /* The command is never backgrounded . Remember the current backgrounding * state */ @@ -1064,7 +1329,7 @@ static int nsh_parse_funcparm(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); + cmd = nsh_argument(vtbl, &saveptr, &memlist); /* Check if any command was provided -OR- if command processing is * currently disabled. @@ -1077,10 +1342,11 @@ static int nsh_parse_funcparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, #endif { /* An empty line is not an error and an unprocessed command cannot - * generate an error, but neither should they change the last - * command status. + * generate an error, but neither should it change the last command + * status. */ + NSH_MEMLIST_FREE(&memlist); return OK; } @@ -1097,7 +1363,7 @@ static int nsh_parse_funcparm(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); + argv[argc] = nsh_argument(vtbl, &saveptr, &memlist); if (!argv[argc]) { break; @@ -1123,6 +1389,8 @@ static int nsh_parse_funcparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, vtbl->np.np_bg = bgsave; #endif vtbl->np.np_redirect = redirsave; + + NSH_MEMLIST_FREE(&memlist); return ret; } #endif @@ -1137,6 +1405,7 @@ static int nsh_parse_funcparm(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline, static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) { + NSH_MEMLIST_TYPE memlist; FAR char *argv[MAX_ARGV_ENTRIES]; FAR char *saveptr; FAR char *cmd; @@ -1150,6 +1419,7 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) /* Initialize parser state */ memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *)); + NSH_MEMLIST_INIT(memlist); #ifndef CONFIG_NSH_DISABLEBG vtbl->np.np_bg = false; @@ -1162,13 +1432,14 @@ 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); + cmd = nsh_argument(vtbl, &saveptr, &memlist); /* Handler if-then-else-fi */ #ifndef CONFIG_NSH_DISABLESCRIPT - if (nsh_ifthenelse(vtbl, &cmd, &saveptr) != 0) + if (nsh_ifthenelse(vtbl, &cmd, &saveptr, &memlist) != 0) { + NSH_MEMLIST_FREE(&memlist); return nsh_saveresult(vtbl, true); } #endif @@ -1176,8 +1447,9 @@ 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) != 0) + if (nsh_nice(vtbl, &cmd, &saveptr, &memlist) != 0) { + NSH_MEMLIST_FREE(&memlist); return nsh_saveresult(vtbl, true); } #endif @@ -1193,10 +1465,11 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) #endif { /* An empty line is not an error and an unprocessed command cannot - * generate an error, but neither should they change the last - * command status. + * generate an error, but neither should it change the last command + * status. */ + NSH_MEMLIST_FREE(&memlist); return OK; } @@ -1216,7 +1489,7 @@ static int nsh_parse_command(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); + argv[argc] = nsh_argument(vtbl, &saveptr, &memlist); if (!argv[argc]) { break; @@ -1285,6 +1558,7 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline) } #endif + NSH_MEMLIST_FREE(&memlist); return ret; }