Add true and false commands; repartition some logic to better support forthcoming looping

This commit is contained in:
Gregory Nutt 2014-01-17 13:24:44 -06:00
parent 626dc7d6e4
commit 97e1d8b535
5 changed files with 140 additions and 57 deletions

View File

@ -781,3 +781,10 @@
is untested in its current incarnation (2014-1-15).
* aps/nshlib/nsh_parse.c: Recent changes broke redirection of output
(2014-1-14).
* apps/nshlib/nsh_parse.c: Add true and false commands (2014-1-17)
* apps/nshlib/nsh.h and nsh_parse.c: Re-name and re-organize some
if-then-else related structures to better support forthcoming until
and while loops (2014-1-17).
* apps/nshlib/nsh_script.c: Now saves the FILE stream for the script
file in the vtbl structure so that it can be accessed by forthcoming
while and until logic (2014-1-17).

View File

@ -1,7 +1,7 @@
/****************************************************************************
* apps/nshlib/nsh.h
*
* Copyright (C) 2007-2013 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -453,23 +453,28 @@
/****************************************************************************
* Public Types
****************************************************************************/
/* State when parsing and if-then-else sequence */
enum nsh_parser_e
{
NSH_PARSER_NORMAL = 0,
NSH_PARSER_IF,
NSH_PARSER_THEN,
NSH_PARSER_ELSE
NSH_PARSER_NORMAL = 0, /* Not in any special sequence */
NSH_PARSER_IF, /* Just parsed 'if', expect condition */
NSH_PARSER_THEN, /* Just parsed 'then', looking for 'else' or 'fi' */
NSH_PARSER_ELSE /* Just parsed 'else', look for 'fi' */
};
struct nsh_state_s
/* All state data for parsing one if-then-else sequence */
struct nsh_ifthenelse_s
{
uint8_t ns_ifcond : 1; /* Value of command in 'if' statement */
uint8_t ns_disabled : 1; /* TRUE: Unconditionally disabled */
uint8_t ns_unused : 4;
uint8_t ns_state : 2; /* Parser state (see enum nsh_parser_e) */
uint8_t ie_ifcond : 1; /* Value of command in 'if' statement */
uint8_t ie_disabled : 1; /* TRUE: Unconditionally disabled */
uint8_t ie_unused : 4;
uint8_t ie_state : 2; /* Parser state (see enum nsh_parser_e) */
};
/* These structure provides the overall state of the parser */
struct nsh_parser_s
{
#ifndef CONFIG_NSH_DISABLEBG
@ -479,19 +484,17 @@ struct nsh_parser_s
bool np_redirect; /* true: Output from the last command was re-directed */
#endif
bool np_fail; /* true: The last command failed */
#ifndef CONFIG_NSH_DISABLESCRIPT
uint8_t np_ndx; /* Current index into np_st[] */
#endif
#ifndef CONFIG_NSH_DISABLEBG
int np_nice; /* "nice" value applied to last background cmd */
#endif
/* This is a stack of parser state information. It supports nested
* execution of commands that span multiple lines (like if-then-else-fi)
*/
#ifndef CONFIG_NSH_DISABLESCRIPT
struct nsh_state_s np_st[CONFIG_NSH_NESTDEPTH];
FILE *np_stream; /* Stream of current script */
uint8_t np_iendx; /* Current index into np_iestate[] */
/* This is a stack of if-then-else state information. */
struct nsh_ifthenelse_s np_iestate[CONFIG_NSH_NESTDEPTH];
#endif
};

View File

@ -81,9 +81,15 @@ struct cmdmap_s
static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
#endif
#ifndef CONFIG_NSH_DISABLESCRIPT
static int cmd_true(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
static int cmd_false(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
#endif
#ifndef CONFIG_NSH_DISABLE_EXIT
static int cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
#endif
static int cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
/****************************************************************************
@ -167,10 +173,15 @@ static const struct cmdmap_s g_cmdmap[] =
#ifndef CONFIG_NSH_DISABLE_EXEC
{ "exec", cmd_exec, 2, 3, "<hex-address>" },
#endif
#ifndef CONFIG_NSH_DISABLE_EXIT
{ "exit", cmd_exit, 1, 1, NULL },
#endif
#ifndef CONFIG_NSH_DISABLESCRIPT
{ "false", cmd_false, 1, 1, NULL },
#endif
#ifndef CONFIG_NSH_DISABLE_FREE
{ "free", cmd_free, 1, 1, NULL },
#endif
@ -356,6 +367,10 @@ static const struct cmdmap_s g_cmdmap[] =
{ "test", cmd_test, 3, CONFIG_NSH_MAXARGUMENTS, "<expression>" },
#endif
#ifndef CONFIG_NSH_DISABLESCRIPT
{ "true", cmd_true, 1, 1, NULL },
#endif
#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE)
# ifndef CONFIG_NSH_DISABLE_UMOUNT
{ "umount", cmd_umount, 2, 2, "<dir-path>" },
@ -644,6 +659,29 @@ static int cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
return ERROR;
}
/****************************************************************************
* Name: cmd_true
****************************************************************************/
#ifndef CONFIG_NSH_DISABLESCRIPT
static int cmd_true(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
{
return OK;
}
#endif
/****************************************************************************
* Name: cmd_false
****************************************************************************/
#ifndef CONFIG_NSH_DISABLESCRIPT
static int cmd_false(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
{
return ERROR;
}
#endif
/****************************************************************************
* Name: cmd_exit
****************************************************************************/

View File

@ -392,10 +392,10 @@ static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result)
struct nsh_parser_s *np = &vtbl->np;
#ifndef CONFIG_NSH_DISABLESCRIPT
if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF)
if (np->np_iestate[np->np_iendx].ie_state == NSH_PARSER_IF)
{
np->np_fail = false;
np->np_st[np->np_ndx].ns_ifcond = result;
np->np_iestate[np->np_iendx].ie_ifcond = result;
return OK;
}
else
@ -1335,10 +1335,10 @@ static FAR char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, FAR char **saveptr,
static bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl)
{
struct nsh_parser_s *np = &vtbl->np;
bool ret = !np->np_st[np->np_ndx].ns_disabled;
bool ret = !np->np_iestate[np->np_iendx].ie_disabled;
if (ret)
{
switch (np->np_st[np->np_ndx].ns_state)
switch (np->np_iestate[np->np_iendx].ie_state)
{
case NSH_PARSER_NORMAL :
case NSH_PARSER_IF:
@ -1346,11 +1346,11 @@ static bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl)
break;
case NSH_PARSER_THEN:
ret = !np->np_st[np->np_ndx].ns_ifcond;
ret = !np->np_iestate[np->np_iendx].ie_ifcond;
break;
case NSH_PARSER_ELSE:
ret = np->np_st[np->np_ndx].ns_ifcond;
ret = np->np_iestate[np->np_iendx].ie_ifcond;
break;
}
}
@ -1367,13 +1367,13 @@ 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, FAR NSH_MEMLIST_TYPE *memlist)
{
struct nsh_parser_s *np = &vtbl->np;
FAR struct nsh_parser_s *np = &vtbl->np;
FAR char *cmd = *ppcmd;
bool disabled;
if (cmd)
{
/* Check if the command is preceeded by "if" */
/* Check if the command is preceded by "if" */
if (strcmp(cmd, "if") == 0)
{
@ -1388,9 +1388,9 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "if" is valid in this context */
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)
if (np->np_iestate[np->np_iendx].ie_state != NSH_PARSER_NORMAL &&
np->np_iestate[np->np_iendx].ie_state != NSH_PARSER_THEN &&
np->np_iestate[np->np_iendx].ie_state != NSH_PARSER_ELSE)
{
nsh_output(vtbl, g_fmtcontext, "if");
goto errout;
@ -1398,7 +1398,7 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Check if we have exceeded the maximum depth of nesting */
if (np->np_ndx >= CONFIG_NSH_NESTDEPTH-1)
if (np->np_iendx >= CONFIG_NSH_NESTDEPTH-1)
{
nsh_output(vtbl, g_fmtdeepnesting, "if");
goto errout;
@ -1406,12 +1406,15 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* "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;
disabled = !nsh_cmdenabled(vtbl);
np->np_iendx++;
np->np_iestate[np->np_iendx].ie_state = NSH_PARSER_IF;
np->np_iestate[np->np_iendx].ie_disabled = disabled;
np->np_iestate[np->np_iendx].ie_ifcond = false;
}
/* Check if the command is "then" */
else if (strcmp(cmd, "then") == 0)
{
/* Get the cmd following the then -- there shouldn't be one */
@ -1425,13 +1428,17 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "then" is valid in this context */
if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_IF)
if (np->np_iestate[np->np_iendx].ie_state != NSH_PARSER_IF)
{
nsh_output(vtbl, g_fmtcontext, "then");
goto errout;
}
np->np_st[np->np_ndx].ns_state = NSH_PARSER_THEN;
np->np_iestate[np->np_iendx].ie_state = NSH_PARSER_THEN;
}
/* Check if the command is "else" */
else if (strcmp(cmd, "else") == 0)
{
/* Get the cmd following the else -- there shouldn't be one */
@ -1443,15 +1450,19 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
goto errout;
}
/* Verify that "then" is valid in this context */
/* Verify that "else" is valid in this context */
if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN)
if (np->np_iestate[np->np_iendx].ie_state != NSH_PARSER_THEN)
{
nsh_output(vtbl, g_fmtcontext, "else");
goto errout;
}
np->np_st[np->np_ndx].ns_state = NSH_PARSER_ELSE;
np->np_iestate[np->np_iendx].ie_state = NSH_PARSER_ELSE;
}
/* Check if the command is "fi" */
else if (strcmp(cmd, "fi") == 0)
{
/* Get the cmd following the fi -- there should be one */
@ -1465,14 +1476,14 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* Verify that "fi" is valid in this context */
if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN &&
np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE)
if (np->np_iestate[np->np_iendx].ie_state != NSH_PARSER_THEN &&
np->np_iestate[np->np_iendx].ie_state != NSH_PARSER_ELSE)
{
nsh_output(vtbl, g_fmtcontext, "fi");
goto errout;
}
if (np->np_ndx < 1) /* Shouldn't happen */
if (np->np_iendx < 1) /* Shouldn't happen */
{
nsh_output(vtbl, g_fmtinternalerror, "if");
goto errout;
@ -1480,21 +1491,25 @@ static int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd,
/* "Pop" the previous state */
np->np_ndx--;
np->np_iendx--;
}
else if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF)
/* If we just parsed 'if', then nothing is acceptable other than 'then' */
else if (np->np_iestate[np->np_iendx].ie_state == NSH_PARSER_IF)
{
nsh_output(vtbl, g_fmtcontext, cmd);
goto errout;
}
}
return OK;
errout:
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;
np->np_iendx = 0;
np->np_iestate[0].ie_state = NSH_PARSER_NORMAL;
np->np_iestate[0].ie_disabled = false;
np->np_iestate[0].ie_ifcond = false;
return ERROR;
}
#endif

View File

@ -83,10 +83,10 @@
int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
FAR const char *path)
{
char *fullpath;
FILE *stream;
char *buffer;
char *pret;
FAR char *fullpath;
FAR FILE *savestream;
FAR char *buffer;
FAR char *pret;
int ret = ERROR;
/* The path to the script may be relative to the current working directory */
@ -102,13 +102,24 @@ int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
buffer = nsh_linebuffer(vtbl);
if (buffer)
{
/* Save the parent stream in case of nested script processing */
savestream = vtbl->np.np_stream;
/* Open the file containing the script */
stream = fopen(fullpath, "r");
if (!stream)
vtbl->np.np_stream = fopen(fullpath, "r");
if (!vtbl->np.np_stream)
{
nsh_output(vtbl, g_fmtcmdfailed, cmd, "fopen", NSH_ERRNO);
/* Free the allocated path */
nsh_freefullpath(fullpath);
/* Restore the parent script stream */
vtbl->np.np_stream = savestream;
return ERROR;
}
@ -121,7 +132,7 @@ int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
/* Get the next line of input from the file */
fflush(stdout);
pret = fgets(buffer, CONFIG_NSH_LINELEN, stream);
pret = fgets(buffer, CONFIG_NSH_LINELEN, vtbl->np.np_stream);
if (pret)
{
/* Parse process the command. NOTE: this is recursive...
@ -133,9 +144,18 @@ int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
}
}
while (pret && ret == OK);
fclose(stream);
/* Close the script file */
fclose(vtbl->np.np_stream);
/* Restore the parent script stream */
vtbl->np.np_stream = savestream;
}
/* Free the allocated path */
nsh_freefullpath(fullpath);
return ret;
}