Support nested if-then[-else]-fi

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@832 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2008-08-19 23:16:45 +00:00
parent cab9dbe225
commit 07c715e09c
3 changed files with 109 additions and 39 deletions

View File

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

View File

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

View File

@ -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
@ -433,13 +435,45 @@ char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr)
return pbegin;
}
/****************************************************************************
* 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;
}
}