summaryrefslogtreecommitdiff
path: root/nuttx/examples/nsh/nsh_main.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2008-08-16 18:39:46 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2008-08-16 18:39:46 +0000
commit07656e5f84288c96e871a522bb48e050ceec8551 (patch)
tree9ee3ba0a23a3c660076204af8b2a7fbf399c5ff2 /nuttx/examples/nsh/nsh_main.c
parent4764ba54f9306b0e39ccf5e3a0dd2f40604ea848 (diff)
downloadpx4-nuttx-07656e5f84288c96e871a522bb48e050ceec8551.tar.gz
px4-nuttx-07656e5f84288c96e871a522bb48e050ceec8551.tar.bz2
px4-nuttx-07656e5f84288c96e871a522bb48e050ceec8551.zip
NSH redirected output
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@823 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/examples/nsh/nsh_main.c')
-rw-r--r--nuttx/examples/nsh/nsh_main.c505
1 files changed, 353 insertions, 152 deletions
diff --git a/nuttx/examples/nsh/nsh_main.c b/nuttx/examples/nsh/nsh_main.c
index cf20141cb..c2754ae3f 100644
--- a/nuttx/examples/nsh/nsh_main.c
+++ b/nuttx/examples/nsh/nsh_main.c
@@ -39,11 +39,14 @@
#include <nuttx/config.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
#include <sched.h>
+#include <fcntl.h>
#include <errno.h>
#include "nsh.h"
@@ -69,14 +72,16 @@ struct cmdmap_s
* Private Function Prototypes
****************************************************************************/
-static void cmd_help(FAR void *handle, int argc, char **argv);
-static void cmd_unrecognized(FAR void *handle, int argc, char **argv);
+static void cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+static void cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
/****************************************************************************
* Private Data
****************************************************************************/
-static const char delim[] = " \t\n";
+static const char g_delim[] = " \t\n";
+static const char g_redirect1[] = ">";
+static const char g_redirect2[] = ">>";
static const struct cmdmap_s g_cmdmap[] =
{
@@ -162,21 +167,22 @@ const char g_fmtcmdoutofmemory[] = "nsh: %s: out of memory\n";
* Name: cmd_help
****************************************************************************/
-static void cmd_help(FAR void *handle, int argc, char **argv)
+static void cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
{
const struct cmdmap_s *ptr;
- nsh_output(handle, "NSH commands:\n");
- nsh_output(handle, " nice [-d] <cmd> &\n");
+ nsh_output(vtbl, "NSH command form:\n");
+ nsh_output(vtbl, " [nice [-d <niceness>>]] <cmd> [[> <file>|>> <file>] &]\n");
+ nsh_output(vtbl, "Where <cmd> is one of:\n");
for (ptr = g_cmdmap; ptr->cmd; ptr++)
{
if (ptr->usage)
{
- nsh_output(handle, " %s %s\n", ptr->cmd, ptr->usage);
+ nsh_output(vtbl, " %s %s\n", ptr->cmd, ptr->usage);
}
else
{
- nsh_output(handle, " %s\n", ptr->cmd);
+ nsh_output(vtbl, " %s\n", ptr->cmd);
}
}
}
@@ -185,9 +191,9 @@ static void cmd_help(FAR void *handle, int argc, char **argv)
* Name: cmd_unrecognized
****************************************************************************/
-static void cmd_unrecognized(FAR void *handle, int argc, char **argv)
+static void cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
{
- nsh_output(handle, g_fmtcmdnotfound, argv[0]);
+ nsh_output(vtbl, g_fmtcmdnotfound, argv[0]);
}
/****************************************************************************
@@ -198,23 +204,25 @@ static int nsh_execute(int argc, char *argv[])
{
const struct cmdmap_s *cmdmap;
const char *cmd;
- void *handle;
+ struct nsh_vtbl_s *vtbl;
cmd_t handler = cmd_unrecognized;
/* Parse all of the arguments following the command name. The form
* of argv is:
*
- * argv[0]: Task name "nsh_execute"
- * argv[1]: This is string version of the handle needed to execute
- * the command (under telnetd). It is a string because
- * binary values cannot be provided via char *argv[]
- * argv[2]: The command name. This is argv[0] when the arguments
- * are, finally, received by the command handler
- * argv[3]: The beginning of argument (up to NSH_MAX_ARGUMENTS)
- * argv[argc]: NULL terminating pointer
+ * argv[0]: Task name "nsh_execute"
+ * argv[1]: This is string version of the vtbl needed to execute
+ * the command (under telnetd). It is a string because
+ * binary values cannot be provided via char *argv[]
+ * argv[2]: The command name. This is argv[0] when the arguments
+ * are, finally, received by the command vtblr
+ * argv[3]: The beginning of argument (up to NSH_MAX_ARGUMENTS)
+ * argv[argc]: NULL terminating pointer
+ *
+ * Maximum size is NSH_MAX_ARGUMENTS+4
*/
- handle = (void*)strtol(argv[1], NULL, 16);
+ vtbl = (struct nsh_vtbl_s*)strtol(argv[1], NULL, 16);
cmd = argv[2];
argc -= 2;
@@ -233,14 +241,14 @@ static int nsh_execute(int argc, char *argv[])
{
/* Fewer than the minimum number were provided */
- nsh_output(handle, g_fmtargrequired, cmd);
+ nsh_output(vtbl, g_fmtargrequired, cmd);
return ERROR;
}
else if (argc > cmdmap->maxargs)
{
/* More than the maximum number were provided */
- nsh_output(handle, g_fmttoomanyargs, cmd);
+ nsh_output(vtbl, g_fmttoomanyargs, cmd);
return ERROR;
}
else
@@ -255,23 +263,93 @@ static int nsh_execute(int argc, char *argv[])
}
}
- handler(handle, argc, &argv[2]);
- nsh_release(handle);
+ handler(vtbl, argc, &argv[2]);
+ nsh_release(vtbl);
return OK;
}
/****************************************************************************
- * Name: nsh_setprio
+ * Name: nsh_argument
****************************************************************************/
-static inline void nsh_setprio(void)
+char *nsh_argument(char **saveptr)
{
- int max_priority = sched_get_priority_max(SCHED_RR);
- int min_priority = sched_get_priority_min(SCHED_RR);
- struct sched_param param;
+ char *pbegin = *saveptr;
+ char *pend = NULL;
+ const char *term;
+
+ /* Find the beginning of the next token */
+
+ for (;
+ *pbegin && strchr(g_delim, *pbegin) != NULL;
+ pbegin++);
+
+ /* If we are at the end of the string with nothing
+ * but delimiters found, then return NULL.
+ */
+
+ if (!*pbegin)
+ {
+ return NULL;
+ }
+
+ /* Does the token begin with '>' */
- param.sched_priority = (max_priority + min_priority) >> 1;
- (void)sched_setscheduler(0, SCHED_RR, &param);
+ if (*pbegin == '>')
+ {
+ /* Yes.. does it begin with ">>"? */
+
+ if (*(pbegin + 1) == '>')
+ {
+ *saveptr = pbegin + 2;
+ return (char*)g_redirect2;
+ }
+ else
+ {
+ *saveptr = pbegin + 1;
+ return (char*)g_redirect1;
+ }
+ }
+
+ /* Does the token begin with '"'? */
+
+ else if (*pbegin == '"')
+ {
+ /* Yes.. then only another '"' can terminate the string */
+
+ pbegin++;
+ term = "\"";
+ }
+ else
+ {
+ /* No, then any of the usual terminators will terminate the argument */
+
+ term = g_delim;
+ }
+
+ /* Find the end of the string */
+
+ for (pend = pbegin + 1;
+ *pend && strchr(term, *pend) == NULL;
+ pend++);
+
+ /* pend either points to the end of the string or to
+ * the first delimiter after the string.
+ */
+
+ if (*pend)
+ {
+ /* Turn the delimiter into a null terminator */
+
+ *pend++ = '\0';
+ }
+
+ /* Save the pointer where we left off and return the
+ * beginning of the token.
+ */
+
+ *saveptr = pend;
+ return pbegin;
}
/****************************************************************************
@@ -293,22 +371,66 @@ void user_initialize(void)
int user_start(int argc, char *argv[])
{
- nsh_setprio();
- return nsh_main();
+ int mid_priority;
+ int ret;
+
+ /* Set the priority of this task to something in the middle so that 'nice'
+ * can both raise and lower the priority.
+ */
+
+ mid_priority = (sched_get_priority_max(SCHED_RR) + sched_get_priority_min(SCHED_RR)) >> 1;
+ {
+ struct sched_param param;
+
+ param.sched_priority = mid_priority;
+ (void)sched_setscheduler(0, SCHED_RR, &param);
+ }
+
+ /* If both the console and telnet are selected as front-ends, then run
+ * the telnet front end on another thread.
+ */
+
+#if defined(CONFIG_EXAMPLES_NSH_CONSOLE) && defined(CONFIG_EXAMPLES_NSH_TELNET)
+# ifndef CONFIG_CUSTOM_STACK
+ ret = task_create("nsh_telnetmain", mid_priority, CONFIG_EXAMPLES_NSH_STACKSIZE,
+ nsh_telnetmain, NULL);
+# else
+ ret = task_create("nsh_telnetmain", mid_priority, nsh_telnetmain, NULL);
+# endif
+ if (ret < 0)
+ {
+ fprintf(stderr, g_fmtcmdfailed, "user_start", "task_create", NSH_ERRNO);
+ }
+
+ /* If only the telnet front-end is selected, run it on this thread */
+
+#elif defined(CONFIG_EXAMPLES_NSH_TELNET)
+ return nsh_telnetmain(0, NULL);
+#endif
+
+/* If the serial console front end is selected, then run it on this thread */
+
+#ifdef CONFIG_EXAMPLES_NSH_CONSOLE
+ return nsh_consolemain(0, NULL);
+#endif
}
/****************************************************************************
* Name: nsh_parse
****************************************************************************/
-int nsh_parse(FAR void *handle, char *cmdline)
+int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline)
{
- FAR char *argv[NSH_MAX_ARGUMENTS+4];
- FAR char strhandle[2*sizeof(FAR char*)+3];
+ FAR char *argv[NSH_MAX_ARGUMENTS+7];
+ FAR char strvtbl[2*sizeof(FAR char*)+3];
FAR char *saveptr;
FAR char *cmd;
- boolean bg;
+ FAR char *redirfile;
+ boolean bg = FALSE;
+ boolean redirect = FALSE;
+ int fd = -1;
int nice = 0;
+ int oflags;
int argc;
int ret;
@@ -316,7 +438,8 @@ int nsh_parse(FAR void *handle, char *cmdline)
/* Parse out the command at the beginning of the line */
- cmd = strtok_r(cmdline, " \t\n", &saveptr);
+ saveptr = cmdline;
+ cmd = nsh_argument(&saveptr);
if (cmd)
{
/* Check if the command is preceded by "nice" */
@@ -331,20 +454,20 @@ int nsh_parse(FAR void *handle, char *cmdline)
/* Get the cmd (or -d option of nice command) */
- cmd = strtok_r(NULL, " \t\n", &saveptr);
+ cmd = nsh_argument(&saveptr);
if (cmd && strcmp(cmd, "-d") == 0)
{
- FAR char *val = strtok_r(NULL, " \t\n", &saveptr);
+ FAR char *val = nsh_argument(&saveptr);
if (val)
{
char *endptr;
nice = (int)strtol(val, &endptr, 0);
if (nice > 19 || nice < -20 || endptr == val || *endptr != '\0')
{
- nsh_output(handle, g_fmtarginvalid, "nice");
+ nsh_output(vtbl, g_fmtarginvalid, "nice");
return ERROR;
}
- cmd = strtok_r(NULL, " \t\n", &saveptr);
+ cmd = nsh_argument(&saveptr);
}
}
}
@@ -352,164 +475,242 @@ int nsh_parse(FAR void *handle, char *cmdline)
/* Check if any command was provided */
- if (cmd)
+ if (!cmd)
{
- /* Parse all of the arguments following the command name. The form
- * of argv is:
- *
- * argv[0]: Not really used. It is just a place hold for where the
- * task name would be if the same command were executed
- * in the "background"
- * argv[1]: This is string version of the handle needed to execute
- * the command (under telnetd). It is a string because
- * binary values cannot be provided via char *argv[]. NOTE
- * that this value is filled in later.
- * argv[2]: The command name. This is argv[0] when the arguments
- * are, finally, received by the command handler
- * argv[3]: The beginning of argument (up to NSH_MAX_ARGUMENTS)
- * argv[argc]: NULL terminating pointer
- */
+ return OK; /* Newline only is not an error */
+ }
- argv[0] = "nsh_execute";
- argv[2] = cmd;
- for (argc = 3; argc < NSH_MAX_ARGUMENTS+4; argc++)
+ /* Parse all of the arguments following the command name. The form
+ * of argv is:
+ *
+ * argv[0]: Not really used. It is just a place hold for where the
+ * task name would be if the same command were executed
+ * in the "background"
+ * argv[1]: This is string version of the vtbl needed to execute
+ * the command (under telnetd). It is a string because
+ * binary values cannot be provided via char *argv[]. NOTE
+ * that this value is filled in later.
+ * argv[2]: The command name. This is argv[0] when the arguments
+ * are, finally, received by the command vtblr
+ * argv[3]: The beginning of argument (up to NSH_MAX_ARGUMENTS)
+ * argv[argc-3]: Possibly '>' or '>>'
+ * argv[argc-2]: Possibly <file>
+ * argv[argc-1]: Possibly '&'
+ * argv[argc]: NULL terminating pointer
+ *
+ * Maximum size is NSH_MAX_ARGUMENTS+7
+ */
+
+ argv[0] = "nsh_execute";
+ argv[2] = cmd;
+ for (argc = 3; argc < NSH_MAX_ARGUMENTS+6; argc++)
+ {
+ argv[argc] = nsh_argument(&saveptr);
+ if (!argv[argc])
{
- argv[argc] = strtok_r(NULL, " \t\n", &saveptr);
- if (!argv[argc])
- {
- break;
- }
+ break;
}
+ }
+ argv[argc] = NULL;
- /* Check if the command should run in background */
+ /* Check if the command should run in background */
- bg = FALSE;
- if (strcmp(argv[argc-1], "&") == 0)
+ if (argc > 3 && strcmp(argv[argc-1], "&") == 0)
+ {
+ bg = TRUE;
+ argv[argc-1] = NULL;
+ argc--;
+ }
+
+ /* Check if the output was re-directed using > or >> */
+
+ if (argc > 5)
+ {
+ /* Check for redirection to a new file */
+
+ if (strcmp(argv[argc-2], g_redirect1) == 0)
{
- bg = TRUE;
- argv[argc-1] = NULL;
- argc--;
+ redirect = TRUE;
+ oflags = O_WRONLY|O_CREAT|O_TRUNC;
+ redirfile = argv[argc-1];
+ argc -= 2;
}
- if (argc > NSH_MAX_ARGUMENTS+3)
+ /* Check for redirection by appending to an existing file */
+
+ else if (strcmp(argv[argc-2], g_redirect2) == 0)
{
- nsh_output(handle, g_fmttoomanyargs, cmd);
+ redirect = TRUE;
+ oflags = O_WRONLY|O_CREAT|O_APPEND;
+ redirfile = argv[argc-1];
+ argc -= 2;
}
+ }
+
+ /* Redirected output? */
+
+ if (redirect)
+ {
+ /* Open the redirection file. This file will eventually
+ * be closed by a call to either nsh_release (if the command
+ * is executed in the background) or by nsh_undirect if the
+ * command is executed in the foreground.
+ */
- if (bg)
+ fd = open(redirfile, oflags, 0666);
+ if (fd < 0)
{
- struct sched_param param;
- int priority;
- void *bkghandle;
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO);
+ return ERROR;
+ }
+ }
- /* Get a cloned copy of the handle with reference count=1.
- * after the command has been processed, the nsh_release() call
- * at the end of nsh_execute() will destroy the clone.
- */
+ /* Check if the maximum number of arguments was exceeded */
- bkghandle = nsh_clone(handle);
+ if (argc > NSH_MAX_ARGUMENTS+3)
+ {
+ nsh_output(vtbl, g_fmttoomanyargs, cmd);
+ }
- /* Place a string copy of the cloned handle in the argument list */
+ /* Handle the case where the command is executed in background */
- sprintf(strhandle, "%p\n", bkghandle);
- argv[1] = strhandle;
+ if (bg)
+ {
+ struct sched_param param;
+ int priority;
+ struct nsh_vtbl_s *bkgvtbl;
- /* Handle redirection of output via a file descriptor */
+ /* Get a cloned copy of the vtbl with reference count=1.
+ * after the command has been processed, the nsh_release() call
+ * at the end of nsh_execute() will destroy the clone.
+ */
- /* (void)nsh_redirect(bkghandle); */
+ bkgvtbl = nsh_clone(vtbl);
- /* Get the execution priority of this task */
+ /* Place a string copy of the cloned vtbl in the argument list */
- ret = sched_getparam(0, &param);
- if (ret != 0)
- {
- nsh_output(handle, g_fmtcmdfailed, cmd, "sched_getparm", NSH_ERRNO);
- return ERROR;
- }
+ sprintf(strvtbl, "%p\n", bkgvtbl);
+ argv[1] = strvtbl;
- /* Determine the priority to execute the command */
+ /* Handle redirection of output via a file descriptor */
- priority = param.sched_priority;
- if (nice != 0)
+ if (redirect)
+ {
+ (void)nsh_redirect(bkgvtbl, fd);
+ }
+
+ /* Get the execution priority of this task */
+
+ ret = sched_getparam(0, &param);
+ if (ret != 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "sched_getparm", NSH_ERRNO);
+ goto errout;
+ }
+
+ /* Determine the priority to execute the command */
+
+ priority = param.sched_priority;
+ if (nice != 0)
+ {
+ priority -= nice;
+ if (nice < 0)
{
- priority -= nice;
- if (nice < 0)
+ int max_priority = sched_get_priority_max(SCHED_RR);
+ if (priority > max_priority)
{
- int max_priority = sched_get_priority_max(SCHED_RR);
- if (priority > max_priority)
- {
- priority = max_priority;
- }
+ priority = max_priority;
}
- else
+ }
+ else
+ {
+ int min_priority = sched_get_priority_min(SCHED_RR);
+ if (priority < min_priority)
{
- int min_priority = sched_get_priority_min(SCHED_RR);
- if (priority < min_priority)
- {
- priority = min_priority;
- }
+ priority = min_priority;
}
}
+ }
- /* Execute the command as a separate task at the appropriate priority */
+ /* Execute the command as a separate task at the appropriate priority */
#ifndef CONFIG_CUSTOM_STACK
- ret = task_create("nsh_execute", priority, CONFIG_EXAMPLES_NSH_STACKSIZE,
- nsh_execute, &argv[1]);
+ ret = task_create("nsh_execute", priority, CONFIG_EXAMPLES_NSH_STACKSIZE,
+ nsh_execute, &argv[1]);
#else
- ret = task_create("nsh_execute", priority, nsh_execute, &argv[1]);
+ ret = task_create("nsh_execute", priority, nsh_execute, &argv[1]);
#endif
- if (ret < 0)
- {
- nsh_output(handle, g_fmtcmdfailed, cmd, "task_create", NSH_ERRNO);
- return ERROR;
- }
-#ifdef CONFIG_DEBUG
- nsh_output(handle, "%s [%d:%d:%d]\n", cmd, ret, priority, param.sched_priority);
-#else
- nsh_output(handle, "%s [%d]\n", cmd, ret);
-#endif
- }
- else
+ if (ret < 0)
{
- /* void *save; */
-
- /* Increment the reference count on the handle. This reference count will
- * be decremented at the end of nsh_execute() and exists only for compatibility
- * with the background command logic.
- */
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "task_create", NSH_ERRNO);
+ goto errout;
+ }
+ nsh_output(vtbl, "%s [%d:%d:%d]\n", cmd, ret, priority, param.sched_priority);
- nsh_addref(handle);
+ /* If the output was redirected, then file descriptor should
+ * be closed. The created task has its one, independent copy of
+ * the file descriptor
+ */
- /* Place a string copy of the original handle in the argument list */
+ if (redirect)
+ {
+ (void)close(fd);
+ }
+ }
+ else
+ {
+ void *save;
- sprintf(strhandle, "%p\n", handle);
- argv[1] = strhandle;
+ /* Increment the reference count on the vtbl. This reference count will
+ * be decremented at the end of nsh_execute() and exists only for compatibility
+ * with the background command logic.
+ */
- /* Handle redirection of output via a file descriptor */
- /* save = nsh_redirect(fd); */
+ nsh_addref(vtbl);
- /* Then execute the command in "foreground" -- i.e., while the user waits
- * for the next prompt.
- */
+ /* Place a string copy of the original vtbl in the argument list */
- ret = nsh_execute(argc, argv);
- if (ret < 0)
- {
- return ERROR;
- }
+ sprintf(strvtbl, "%p\n", vtbl);
+ argv[1] = strvtbl;
- /* Restore the original output */
+ /* Handle redirection of output via a file descriptor */
- /* nsh_undirect(save); */
+ if (redirect)
+ {
+ save = nsh_redirect(vtbl, fd);
}
- /* Return success if the command succeeded (or at least, starting of the
- * command task succeeded).
+ /* Then execute the command in "foreground" -- i.e., while the user waits
+ * for the next prompt.
+ */
+
+ ret = nsh_execute(argc, argv);
+
+ /* Restore the original output. Undirect will close the redirection
+ * file descriptor.
*/
- return OK;
+ if (redirect)
+ {
+ nsh_undirect(vtbl, save);
+ }
+
+ if (ret < 0)
+ {
+ return ERROR;
+ }
}
+ /* Return success if the command succeeded (or at least, starting of the
+ * command task succeeded).
+ */
+
+ return OK;
+
+errout:
+ if (redirect)
+ {
+ close(fd);
+ }
return ERROR;
}