summaryrefslogtreecommitdiff
path: root/nuttx
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx')
-rw-r--r--nuttx/examples/README.txt4
-rw-r--r--nuttx/examples/nsh/nsh.h27
-rw-r--r--nuttx/examples/nsh/nsh_main.c117
3 files changed, 109 insertions, 39 deletions
diff --git a/nuttx/examples/README.txt b/nuttx/examples/README.txt
index a3cf60a45..130ab5cb5 100644
--- a/nuttx/examples/README.txt
+++ b/nuttx/examples/README.txt
@@ -79,6 +79,10 @@ examples/nsh
new threads are generated when a command is executed in background
or as new TELNET connections are established.
+ * CONFIG_EXAMPLES_NSH_NESTDEPTH
+ The maximum number of nested if-then[-else]-fi sequences that
+ are permissable. Default: 3
+
* CONFIG_EXAMPLES_NSH_CONSOLE
If CONFIG_EXAMPLES_NSH_CONSOLE is set to 'y', then a serial
console front-end is selected.
diff --git a/nuttx/examples/nsh/nsh.h b/nuttx/examples/nsh/nsh.h
index 574e03221..57c75e1bc 100644
--- a/nuttx/examples/nsh/nsh.h
+++ b/nuttx/examples/nsh/nsh.h
@@ -87,6 +87,14 @@
# define CONFIG_EXAMPLES_NSH_STACKSIZE 4096
#endif
+/* The maximum number of nested if-then[-else]-fi sequences that
+ * are permissable.
+ */
+
+#ifndef CONFIG_EXAMPLES_NSH_NESTDEPTH
+# define CONFIG_EXAMPLES_NSH_NESTDEPTH 3
+#endif
+
/* Define to enable dumping of all input/output buffers */
#undef CONFIG_EXAMPLES_NSH_TELNETD_DUMPBUFFER
@@ -120,14 +128,27 @@ enum nsh_parser_e
NSH_PARSER_ELSE
};
+struct nsh_state_s
+{
+ ubyte ns_ifcond : 1; /* Value of command in 'if' statement */
+ ubyte ns_disabled : 1; /* TRUE: Unconditionally disabled */
+ ubyte ns_unused : 4;
+ ubyte ns_state : 2; /* Parser state (see enum nsh_parser_e) */
+};
+
struct nsh_parser_s
{
boolean np_bg; /* TRUE: The last command executed in background */
boolean np_redirect; /* TRUE: Output from the last command was re-directed */
boolean np_fail; /* TRUE: The last command failed */
- boolean np_ifcond; /* Value of command in 'if' statement */
- ubyte np_state; /* Parser state (see enum nsh_parser_e) */
+ ubyte np_ndx; /* Current index into np_st[] */
int np_nice; /* "nice" value applied to last background cmd */
+
+ /* This is a stack of parser state information. It supports nested
+ * execution of commands that span multiple lines (like if-then-else-fi)
+ */
+
+ struct nsh_state_s np_st[CONFIG_EXAMPLES_NSH_NESTDEPTH];
};
struct nsh_vtbl_s
@@ -165,9 +186,11 @@ extern const char g_fmtcmdnotfound[];
extern const char g_fmtcmdnotimpl[];
extern const char g_fmtnosuch[];
extern const char g_fmttoomanyargs[];
+extern const char g_fmtdeepnesting[];
extern const char g_fmtcontext[];
extern const char g_fmtcmdfailed[];
extern const char g_fmtcmdoutofmemory[];
+extern const char g_fmtinternalerror[];
/****************************************************************************
* Public Function Prototypes
diff --git a/nuttx/examples/nsh/nsh_main.c b/nuttx/examples/nsh/nsh_main.c
index 8c2999cf7..ff3398ea1 100644
--- a/nuttx/examples/nsh/nsh_main.c
+++ b/nuttx/examples/nsh/nsh_main.c
@@ -156,6 +156,7 @@ const char g_fmtcmdnotfound[] = "nsh: %s: command not found\n";
const char g_fmtcmdnotimpl[] = "nsh: %s: command not implemented\n";
const char g_fmtnosuch[] = "nsh: %s: no such %s: %s\n";
const char g_fmttoomanyargs[] = "nsh: %s: too many arguments\n";
+const char g_fmtdeepnesting[] = "nsh: %s: nesting too deep\n";
const char g_fmtcontext[] = "nsh: %s: not valid in this context\n";
#ifdef CONFIG_EXAMPLES_NSH_STRERROR
const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %s\n";
@@ -163,6 +164,7 @@ const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %s\n";
const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %d\n";
#endif
const char g_fmtcmdoutofmemory[] = "nsh: %s: out of memory\n";
+const char g_fmtinternalerror[] = "nsh: %s: Internal error\n";
/****************************************************************************
* Private Functions
@@ -434,12 +436,44 @@ char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr)
}
/****************************************************************************
+ * Name: nsh_cmdenabled
+ ****************************************************************************/
+
+static inline boolean nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl)
+{
+ struct nsh_parser_s *np = &vtbl->np;
+ boolean ret = !np->np_st[np->np_ndx].ns_disabled;
+ if (ret)
+ {
+ switch (np->np_st[np->np_ndx].ns_state)
+ {
+ case NSH_PARSER_NORMAL :
+ case NSH_PARSER_IF:
+ default:
+ break;
+
+ case NSH_PARSER_THEN:
+ ret = !np->np_st[np->np_ndx].ns_ifcond;
+ break;
+
+ case NSH_PARSER_ELSE:
+ ret = np->np_st[np->np_ndx].ns_ifcond;
+ break;
+ }
+ }
+ return ret;
+}
+
+/****************************************************************************
* Name: nsh_ifthenelse
****************************************************************************/
static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, FAR char **saveptr)
{
+ struct nsh_parser_s *np = &vtbl->np;
FAR char *cmd = *ppcmd;
+ boolean disabled;
+
if (cmd)
{
/* Check if the command is preceeded by "if" */
@@ -457,12 +491,29 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "if" is valid in this context */
- if (vtbl->np.np_state != NSH_PARSER_NORMAL)
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_NORMAL &&
+ np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN &&
+ np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE)
{
nsh_output(vtbl, g_fmtcontext, "if");
goto errout;
}
- vtbl->np.np_state = NSH_PARSER_IF;
+
+ /* Check if we have exceeded the maximum depth of nesting */
+
+ if (np->np_ndx >= CONFIG_EXAMPLES_NSH_NESTDEPTH-1)
+ {
+ nsh_output(vtbl, g_fmtdeepnesting, "if");
+ goto errout;
+ }
+
+ /* "Push" the old state and set the new state */
+
+ disabled = !nsh_cmdenabled(vtbl);
+ np->np_ndx++;
+ np->np_st[np->np_ndx].ns_state = NSH_PARSER_IF;
+ np->np_st[np->np_ndx].ns_disabled = disabled;
+ np->np_st[np->np_ndx].ns_ifcond = FALSE;
}
else if (strcmp(cmd, "then") == 0)
{
@@ -477,12 +528,12 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "then" is valid in this context */
- if (vtbl->np.np_state != NSH_PARSER_IF)
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_IF)
{
nsh_output(vtbl, g_fmtcontext, "then");
goto errout;
}
- vtbl->np.np_state = NSH_PARSER_THEN;
+ np->np_st[np->np_ndx].ns_state = NSH_PARSER_THEN;
}
else if (strcmp(cmd, "else") == 0)
{
@@ -497,12 +548,12 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "then" is valid in this context */
- if (vtbl->np.np_state != NSH_PARSER_THEN)
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN)
{
nsh_output(vtbl, g_fmtcontext, "else");
goto errout;
}
- vtbl->np.np_state = NSH_PARSER_ELSE;
+ np->np_st[np->np_ndx].ns_state = NSH_PARSER_ELSE;
}
else if (strcmp(cmd, "fi") == 0)
{
@@ -517,14 +568,24 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "fi" is valid in this context */
- if (vtbl->np.np_state != NSH_PARSER_THEN && vtbl->np.np_state != NSH_PARSER_ELSE)
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN &&
+ np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE)
{
nsh_output(vtbl, g_fmtcontext, "fi");
goto errout;
}
- vtbl->np.np_state = NSH_PARSER_NORMAL;
+
+ if (np->np_ndx < 1) /* Shouldn't happen */
+ {
+ nsh_output(vtbl, g_fmtinternalerror, "if");
+ goto errout;
+ }
+
+ /* "Pop" the previous state */
+
+ np->np_ndx--;
}
- else if (vtbl->np.np_state == NSH_PARSER_IF)
+ else if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF)
{
nsh_output(vtbl, g_fmtcontext, cmd);
goto errout;
@@ -533,48 +594,30 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
return OK;
errout:
- vtbl->np.np_state = NSH_PARSER_NORMAL;
+ np->np_ndx = 0;
+ np->np_st[0].ns_state = NSH_PARSER_NORMAL;
+ np->np_st[0].ns_disabled = FALSE;
+ np->np_st[0].ns_ifcond = FALSE;
return ERROR;
}
/****************************************************************************
- * Name: nsh_cmdenabled
- ****************************************************************************/
-
-static inline boolean nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl)
-{
- switch (vtbl->np.np_state)
- {
- case NSH_PARSER_NORMAL :
- case NSH_PARSER_IF:
- default:
- break;
-
- case NSH_PARSER_THEN:
- return !vtbl->np.np_ifcond;
-
- case NSH_PARSER_ELSE:
- return vtbl->np.np_ifcond;
- }
- return TRUE;
-}
-
-/****************************************************************************
* Name: nsh_saveresult
****************************************************************************/
static inline int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, boolean result)
{
- vtbl->np.np_fail = result;
- if (vtbl->np.np_state == NSH_PARSER_IF)
+ struct nsh_parser_s *np = &vtbl->np;
+
+ if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF)
{
- vtbl->np.np_fail = FALSE;
- vtbl->np.np_ifcond = result;
+ np->np_fail = FALSE;
+ np->np_st[np->np_ndx].ns_ifcond = result;
return OK;
}
else
{
- vtbl->np.np_fail = result;
+ np->np_fail = result;
return result ? ERROR : OK;
}
}