Add true and false commands; repartition some logic to better support forthcoming looping
This commit is contained in:
parent
626dc7d6e4
commit
97e1d8b535
@ -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).
|
||||
|
39
nshlib/nsh.h
39
nshlib/nsh.h
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
****************************************************************************/
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user