From 3895a010a5c8d971ec04802ae569f44a06bd572b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 17 Jan 2014 13:24:44 -0600 Subject: Add true and false commands; repartition some logic to better support forthcoming looping --- apps/ChangeLog.txt | 7 +++++ apps/nshlib/nsh.h | 39 +++++++++++++----------- apps/nshlib/nsh_command.c | 38 +++++++++++++++++++++++ apps/nshlib/nsh_parse.c | 77 ++++++++++++++++++++++++++++------------------- apps/nshlib/nsh_script.c | 36 +++++++++++++++++----- 5 files changed, 140 insertions(+), 57 deletions(-) (limited to 'apps') diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index b5b343e37..e34781464 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -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). diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h index a38d04c4a..a9db6e5d2 100644 --- a/apps/nshlib/nsh.h +++ b/apps/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 * * 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 }; diff --git a/apps/nshlib/nsh_command.c b/apps/nshlib/nsh_command.c index faf64bbe5..8321ad876 100644 --- a/apps/nshlib/nsh_command.c +++ b/apps/nshlib/nsh_command.c @@ -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, "" }, #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, "" }, #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, "" }, @@ -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 ****************************************************************************/ diff --git a/apps/nshlib/nsh_parse.c b/apps/nshlib/nsh_parse.c index c7ef521a1..a83b9e999 100644 --- a/apps/nshlib/nsh_parse.c +++ b/apps/nshlib/nsh_parse.c @@ -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 diff --git a/apps/nshlib/nsh_script.c b/apps/nshlib/nsh_script.c index 3aa698b31..088df6878 100644 --- a/apps/nshlib/nsh_script.c +++ b/apps/nshlib/nsh_script.c @@ -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; } -- cgit v1.2.3