summaryrefslogtreecommitdiff
path: root/apps/nshlib
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-01-18 09:39:16 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-01-18 09:39:16 -0600
commitc9e72e0eed21a1c8c679bc094b0960dabf31c84d (patch)
tree9ef30c27fc3d15efa8db04cb1112d916316f3998 /apps/nshlib
parent1cc717520d36623c08f8b60f9cd7fede1bd8f1c1 (diff)
downloadnuttx-c9e72e0eed21a1c8c679bc094b0960dabf31c84d.tar.gz
nuttx-c9e72e0eed21a1c8c679bc094b0960dabf31c84d.tar.bz2
nuttx-c9e72e0eed21a1c8c679bc094b0960dabf31c84d.zip
NSH: Add a break command; if-then-else and looping behavior can not be configured out of the build for small systems that need minimal scripting capability
Diffstat (limited to 'apps/nshlib')
-rw-r--r--apps/nshlib/Kconfig21
-rw-r--r--apps/nshlib/README.txt21
-rw-r--r--apps/nshlib/nsh.h21
-rw-r--r--apps/nshlib/nsh_command.c8
-rw-r--r--apps/nshlib/nsh_parse.c86
-rw-r--r--apps/nshlib/nsh_script.c4
6 files changed, 143 insertions, 18 deletions
diff --git a/apps/nshlib/Kconfig b/apps/nshlib/Kconfig
index df1a9c518..7fb6a52b3 100644
--- a/apps/nshlib/Kconfig
+++ b/apps/nshlib/Kconfig
@@ -345,6 +345,27 @@ config NSH_DISABLESCRIPT
if-then[-else]-fi construct. This would only be set on systems
where a minimal footprint is a necessity and scripting is not.
+if !NSH_DISABLESCRIPT
+
+config NSH_DISABLE_ITEF
+ bool "Disable if-then-else-fi"
+ default n
+ ---help---
+ This can be set to 'y' to suppress support for if-then-else-fi
+ sequences in scripts. This would only be set on systems where
+ some minimal scripting is required but if-then-else-fi is not.
+
+config NSH_DISABLE_LOOPS
+ bool "Disable loops"
+ default n
+ ---help---
+ This can be set to 'y' to suppress support for while-do-done and
+ until-do-done sequences in scripts. This would only be set on
+ systems where some minimal scripting is required but looping
+ is not.
+
+endif # !NSH_DISABLESCRIPT
+
config NSH_DISABLEBG
bool "Disable background commands"
default n
diff --git a/apps/nshlib/README.txt b/apps/nshlib/README.txt
index 1e4731066..cdf7600bf 100644
--- a/apps/nshlib/README.txt
+++ b/apps/nshlib/README.txt
@@ -7,6 +7,7 @@ apps/nshlib
- Console/NSH Front End
- Command Overview
- Conditional Command Execution
+ - Looping
- Built-In Variables
- Current Working Directory
Environment Variables
@@ -121,6 +122,12 @@ Looping
Execute <cmd-sequence> as long as <test-cmd> has a non-zero exit
status.
+ A break command is also supported. The break command is only valid
+ within the body of the a while or until loop, between the do and done
+ tokens. If the break command is executed within the body of a loop, the
+ loop will immediately terminate and execution will continue with the
+ next command immediately following the done token.
+
Built-In Variables
^^^^^^^^^^^^^^^^^^
@@ -1094,6 +1101,20 @@ NSH-Specific Configuration Settings
if-then[-else]-fi construct. This would only be set on systems
where a minimal footprint is a necessity and scripting is not.
+ * CONFIG_NSH_DISABLE_ITEF
+
+ If scripting is enabled, then then this option can be selected to
+ suppress support for if-then-else-fi sequences in scripts. This would
+ only be set on systems where some minimal scripting is required but
+ if-then-else-fi is not.
+
+ * CONFIG_NSH_DISABLE_LOOPS
+
+ If scripting is enabled, then then this option can be selected
+ suppress support for while-do-done and until-do-done sequences in
+ scripts. This would only be set on systems where some minimal
+ scripting is required but looping is not.
+
* CONFIG_NSH_DISABLEBG
This can be set to 'y' to suppress support for background
commands. This setting disables the 'nice' command prefix and
diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h
index 4786692f7..2ea49706d 100644
--- a/apps/nshlib/nsh.h
+++ b/apps/nshlib/nsh.h
@@ -453,6 +453,8 @@
/****************************************************************************
* Public Types
****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_ITEF
/* State when parsing and if-then-else sequence */
enum nsh_itef_e
@@ -472,7 +474,9 @@ struct nsh_itef_s
uint8_t ie_unused : 4;
uint8_t ie_state : 2; /* If-then-else state (see enum nsh_itef_e) */
};
+#endif
+#ifndef CONFIG_NSH_DISABLE_LOOPS
/* State when parsing and while-do-done or until-do-done sequence */
enum nsh_lp_e
@@ -490,8 +494,12 @@ struct nsh_loop_s
uint8_t lp_enable : 1; /* Loop command processing is enabled */
uint8_t lp_unused : 5;
uint8_t lp_state : 2; /* Loop state (see enume nsh_lp_e) */
+#ifndef CONFIG_NSH_DISABLE_ITEF
+ uint8_t lp_iendx; /* Saved if-then-else-fi index */
+#endif
long lp_topoffs; /* Top of loop file offset */
};
+#endif
/* These structure provides the overall state of the parser */
@@ -510,19 +518,27 @@ struct nsh_parser_s
#ifndef CONFIG_NSH_DISABLESCRIPT
FILE *np_stream; /* Stream of current script */
+#ifndef CONFIG_NSH_DISABLE_LOOPS
long np_foffs; /* File offset to the beginning of a line */
#ifndef NSH_DISABLE_SEMICOLON
uint16_t np_loffs; /* Byte offset to the beginning of a command */
bool np_jump; /* "Jump" to the top of the loop */
#endif
- uint8_t np_iendx; /* Current index into np_iestate[] */
uint8_t np_lpndx; /* Current index into np_lpstate[] */
+#endif
+#ifndef CONFIG_NSH_DISABLE_ITEF
+ uint8_t np_iendx; /* Current index into np_iestate[] */
+#endif
/* This is a stack of parser state information. */
+#ifndef CONFIG_NSH_DISABLE_ITEF
struct nsh_itef_s np_iestate[CONFIG_NSH_NESTDEPTH];
+#endif
+#ifndef CONFIG_NSH_DISABLE_LOOPS
struct nsh_loop_s np_lpstate[CONFIG_NSH_NESTDEPTH];
#endif
+#endif
};
struct nsh_vtbl_s; /* Defined in nsh_console.h */
@@ -643,6 +659,9 @@ void nsh_usbtrace(void);
/* Shell command handlers */
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS)
+ int cmd_break(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
#ifndef CONFIG_NSH_DISABLE_ECHO
int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
#endif
diff --git a/apps/nshlib/nsh_command.c b/apps/nshlib/nsh_command.c
index 6ae3acfa7..ea028d463 100644
--- a/apps/nshlib/nsh_command.c
+++ b/apps/nshlib/nsh_command.c
@@ -119,6 +119,10 @@ static const struct cmdmap_s g_cmdmap[] =
# endif
#endif
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS)
+ { "break", cmd_break, 1, 1, NULL },
+#endif
+
#if CONFIG_NFILE_DESCRIPTORS > 0
# ifndef CONFIG_NSH_DISABLE_CAT
{ "cat", cmd_cat, 2, CONFIG_NSH_MAXARGUMENTS, "<path> [<path> [<path> ...]]" },
@@ -465,6 +469,7 @@ static inline void help_usage(FAR struct nsh_vtbl_s *vtbl)
nsh_output(vtbl, " <cmd> [> <file>|>> <file>]\n\n");
#endif
#ifndef CONFIG_NSH_DISABLESCRIPT
+#ifndef CONFIG_NSH_DISABLE_ITEF
nsh_output(vtbl, "OR\n");
nsh_output(vtbl, " if <cmd>\n");
nsh_output(vtbl, " then\n");
@@ -472,6 +477,8 @@ static inline void help_usage(FAR struct nsh_vtbl_s *vtbl)
nsh_output(vtbl, " else\n");
nsh_output(vtbl, " [sequence of <cmd>]\n");
nsh_output(vtbl, " fi\n\n");
+#endif
+#ifndef CONFIG_NSH_DISABLE_LOOPS
nsh_output(vtbl, "OR\n");
nsh_output(vtbl, " while <cmd>\n");
nsh_output(vtbl, " do\n");
@@ -483,6 +490,7 @@ static inline void help_usage(FAR struct nsh_vtbl_s *vtbl)
nsh_output(vtbl, " [sequence of <cmd>]\n");
nsh_output(vtbl, " done\n\n");
#endif
+#endif
}
#endif
diff --git a/apps/nshlib/nsh_parse.c b/apps/nshlib/nsh_parse.c
index c7505f34d..9641cd416 100644
--- a/apps/nshlib/nsh_parse.c
+++ b/apps/nshlib/nsh_parse.c
@@ -160,14 +160,22 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr,
FAR NSH_MEMLIST_TYPE *memlist);
#ifndef CONFIG_NSH_DISABLESCRIPT
+#ifndef CONFIG_NSH_DISABLE_LOOPS
static bool nsh_loop_enabled(FAR struct nsh_vtbl_s *vtbl);
+#endif
+#ifndef CONFIG_NSH_DISABLE_ITEF
static bool nsh_itef_enabled(FAR struct nsh_vtbl_s *vtbl);
+#endif
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);
+#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);
#endif
+#endif
#ifndef CONFIG_NSH_DISABLEBG
static int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
@@ -396,6 +404,7 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result)
struct nsh_parser_s *np = &vtbl->np;
#ifndef CONFIG_NSH_DISABLESCRIPT
+#ifndef CONFIG_NSH_DISABLE_LOOPS
/* Check if we are waiting for the condition associated with a while
* token.
*
@@ -421,16 +430,19 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result)
* status.
*/
- else if (np->np_lpstate[np->np_lpndx].lp_state == NSH_LOOP_UNTIL)
+ else if (np->np_lpstate[np->np_lpndx].lp_state == NSH_LOOP_UNTIL)
{
np->np_fail = false;
np->np_lpstate[np->np_lpndx].lp_enable = (result != OK);
return OK;
}
+ else
+#endif
+#ifndef CONFIG_NSH_DISABLE_ITEF
/* Check if we are waiting for the condition associated with an if token */
- else if (np->np_iestate[np->np_iendx].ie_state == NSH_ITEF_IF)
+ if (np->np_iestate[np->np_iendx].ie_state == NSH_ITEF_IF)
{
np->np_fail = false;
np->np_iestate[np->np_iendx].ie_ifcond = result;
@@ -438,6 +450,7 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result)
}
else
#endif
+#endif
{
np->np_fail = result;
return result ? ERROR : OK;
@@ -1369,7 +1382,7 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr,
* Name: nsh_loop_enabled
****************************************************************************/
-#ifndef CONFIG_NSH_DISABLESCRIPT
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS)
static bool nsh_loop_enabled(FAR struct nsh_vtbl_s *vtbl)
{
FAR struct nsh_parser_s *np = &vtbl->np;
@@ -1388,13 +1401,15 @@ static bool nsh_loop_enabled(FAR struct nsh_vtbl_s *vtbl)
return true;
}
+#else
+# define nsh_loop_enabled(vtbl) true
#endif
/****************************************************************************
* Name: nsh_itef_enabled
****************************************************************************/
-#ifndef CONFIG_NSH_DISABLESCRIPT
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_ITEF)
static bool nsh_itef_enabled(FAR struct nsh_vtbl_s *vtbl)
{
FAR struct nsh_parser_s *np = &vtbl->np;
@@ -1420,6 +1435,8 @@ static bool nsh_itef_enabled(FAR struct nsh_vtbl_s *vtbl)
return ret;
}
+#else
+# define nsh_itef_enabled(vtbl) true
#endif
/****************************************************************************
@@ -1442,7 +1459,7 @@ static bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl)
* Name: nsh_loop
****************************************************************************/
-#ifndef CONFIG_NSH_DISABLESCRIPT
+#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)
{
@@ -1476,7 +1493,10 @@ static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "while" or "until" is valid in this context */
- if (np->np_iestate[np->np_iendx].ie_state == NSH_ITEF_IF ||
+ if (
+#ifndef CONFIG_NSH_DISABLE_ITEF
+ np->np_iestate[np->np_iendx].ie_state == NSH_ITEF_IF ||
+#endif
np->np_lpstate[np->np_lpndx].lp_state == NSH_LOOP_WHILE ||
np->np_lpstate[np->np_lpndx].lp_state == NSH_LOOP_UNTIL ||
np->np_stream == NULL || np->np_foffs < 0)
@@ -1509,6 +1529,9 @@ static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
np->np_lpndx++;
np->np_lpstate[np->np_lpndx].lp_state = state;
np->np_lpstate[np->np_lpndx].lp_enable = enable;
+#ifndef CONFIG_NSH_DISABLE_ITEF
+ np->np_lpstate[np->np_lpndx].lp_iendx = np->np_iendx;
+#endif
np->np_lpstate[np->np_lpndx].lp_topoffs = offset;
}
@@ -1516,14 +1539,9 @@ static int nsh_loop(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
else if (strcmp(cmd, "do") == 0)
{
- /* Get the cmd following the "do" -- there shouldn't be one */
+ /* Get the cmd following the "do" -- there may or may not be one */
*ppcmd = nsh_argument(vtbl, saveptr, memlist);
- if (*ppcmd)
- {
- nsh_output(vtbl, g_fmtarginvalid, "do");
- goto errout;
- }
/* Verify that "do" is valid in this context */
@@ -1632,7 +1650,7 @@ errout:
* Name: nsh_itef
****************************************************************************/
-#ifndef CONFIG_NSH_DISABLESCRIPT
+#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)
{
@@ -1982,6 +2000,7 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
cmd = nsh_argument(vtbl, &saveptr, &memlist);
#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)
@@ -1989,7 +2008,9 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
NSH_MEMLIST_FREE(&memlist);
return nsh_saveresult(vtbl, true);
}
+#endif
+#ifndef CONFIG_NSH_DISABLE_ITEF
/* Handle if-then-else-fi */
if (nsh_itef(vtbl, &cmd, &saveptr, &memlist) != 0)
@@ -1997,6 +2018,8 @@ static int nsh_parse_command(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
NSH_MEMLIST_FREE(&memlist);
return nsh_saveresult(vtbl, true);
}
+
+#endif
#endif
/* Handle nice */
@@ -2137,7 +2160,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
return nsh_parse_command(vtbl, cmdline);
#else
-#ifndef CONFIG_NSH_DISABLESCRIPT
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS)
FAR struct nsh_parser_s *np = &vtbl->np;
#endif
FAR char *start = cmdline;
@@ -2151,13 +2174,13 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
* at the top of the loop.
*/
-#ifndef CONFIG_NSH_DISABLESCRIPT
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS)
for (np->np_jump = false; !np->np_jump; )
#else
for (;;)
#endif
{
-#ifndef CONFIG_NSH_DISABLESCRIPT
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS)
/* Save the offset on the line to the start of the command */
np->np_loffs = (uint16_t)(working - cmdline);
@@ -2241,3 +2264,34 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, FAR char *cmdline)
#endif
#endif
}
+
+/****************************************************************************
+ * Name: cmd_break
+ ****************************************************************************/
+
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_LOOPS)
+int cmd_break(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ FAR struct nsh_parser_s *np = &vtbl->np;
+
+ /* Break outside of a loop is ignored */
+
+ if (np->np_lpstate[np->np_lpndx].lp_state == NSH_LOOP_DO)
+ {
+#ifndef CONFIG_NSH_DISABLE_ITEF
+ /* Yes... pop the original if-then-else-if state */
+
+ np->np_iendx = np->np_lpstate[np->np_lpndx].lp_iendx;
+#endif
+ /* Disable all command processing until 'done' is encountered. */
+
+ np->np_lpstate[np->np_lpndx].lp_enable = false;
+ }
+
+ /* No syntax errors are detected(?). Break is a nop everywhere except
+ * the supported context.
+ */
+
+ return OK;
+}
+#endif
diff --git a/apps/nshlib/nsh_script.c b/apps/nshlib/nsh_script.c
index e5c1958a1..b115dc8fb 100644
--- a/apps/nshlib/nsh_script.c
+++ b/apps/nshlib/nsh_script.c
@@ -129,10 +129,11 @@ int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
do
{
- /* Get the next line of input from the file */
+ /* Flush any output generated by the previous line */
fflush(stdout);
+#ifndef CONFIG_NSH_DISABLE_LOOPS
/* Get the current file position. This is used to control
* looping. If a loop begins in the next line, then this file
* offset will be needed to locate the top of the loop in the
@@ -146,6 +147,7 @@ int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
{
nsh_output(vtbl, g_fmtcmdfailed, "loop", "ftell", NSH_ERRNO);
}
+#endif
/* Now read the next line from the script file */