From 9d80399bd512257d6dc92aba0a520b488423baea Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Mon, 17 Aug 2020 18:28:50 +0800 Subject: [PATCH] nsh: Accept the command line arguments like sh Usage: nsh [|-c ] Signed-off-by: Xiang Xiao Change-Id: Ifb76b27e7fd09d26b1f6e48c391fed0972018041 --- examples/nxterm/nxterm_main.c | 2 +- examples/pty_test/pty_test.c | 2 +- include/system/readline.h | 1 + nshlib/nsh.h | 3 +- nshlib/nsh_altconsole.c | 2 +- nshlib/nsh_console.c | 21 +++--- nshlib/nsh_console.h | 11 ++- nshlib/nsh_consolemain.c | 2 +- nshlib/nsh_session.c | 136 ++++++++++++++++++++-------------- nshlib/nsh_stdsession.c | 128 +++++++++++++++++++------------- nshlib/nsh_system.c | 33 +-------- nshlib/nsh_timcmds.c | 40 +++++----- nshlib/nsh_usbconsole.c | 2 +- system/nsh/nsh_main.c | 2 +- 14 files changed, 203 insertions(+), 182 deletions(-) diff --git a/examples/nxterm/nxterm_main.c b/examples/nxterm/nxterm_main.c index 9f608489f..d41add838 100644 --- a/examples/nxterm/nxterm_main.c +++ b/examples/nxterm/nxterm_main.c @@ -191,7 +191,7 @@ static int nxterm_task(int argc, char **argv) /* If the console front end is selected, then run it on this thread */ #ifdef CONFIG_NSH_CONSOLE - nsh_consolemain(0, NULL); + nsh_consolemain(argc, argv); #endif printf("nxterm_task: Unlinking the NX console device\n"); diff --git a/examples/pty_test/pty_test.c b/examples/pty_test/pty_test.c index 5d17e37e6..4955213c5 100644 --- a/examples/pty_test/pty_test.c +++ b/examples/pty_test/pty_test.c @@ -384,7 +384,7 @@ int main(int argc, FAR char *argv[]) pid = task_create("NSH Console", CONFIG_EXAMPLES_PTYTEST_DAEMONPRIO, CONFIG_EXAMPLES_PTYTEST_STACKSIZE, nsh_consolemain, - NULL); + argv); if (pid < 0) { /* Can't do output because stdout and stderr are redirected */ diff --git a/include/system/readline.h b/include/system/readline.h index f9b8bc18e..5651cd2e1 100644 --- a/include/system/readline.h +++ b/include/system/readline.h @@ -48,6 +48,7 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* Tab completion cannot be supported if there is no console echo */ #ifndef CONFIG_READLINE_ECHO diff --git a/nshlib/nsh.h b/nshlib/nsh.h index e21950241..8ebdbab15 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -850,7 +850,8 @@ int nsh_loginscript(FAR struct nsh_vtbl_s *vtbl); /* Basic session and message handling */ struct console_stdio_s; -int nsh_session(FAR struct console_stdio_s *pstate, bool login); +int nsh_session(FAR struct console_stdio_s *pstate, + bool login, int argc, FAR char *argv[]); int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline); /**************************************************************************** diff --git a/nshlib/nsh_altconsole.c b/nshlib/nsh_altconsole.c index b2c4a4c11..88bf54098 100644 --- a/nshlib/nsh_altconsole.c +++ b/nshlib/nsh_altconsole.c @@ -325,7 +325,7 @@ int nsh_consolemain(int argc, FAR char *argv[]) /* Execute the session */ - nsh_session(pstate, true); + nsh_session(pstate, true, argc, argv); /* We lost the connection. Wait for the keyboard to * be re-connected. diff --git a/nshlib/nsh_console.c b/nshlib/nsh_console.c index ec9f5f912..7cd0a4d56 100644 --- a/nshlib/nsh_console.c +++ b/nshlib/nsh_console.c @@ -1,7 +1,8 @@ /**************************************************************************** * apps/nshlib/nsh_console.c * - * Copyright (C) 2007-2009, 2011-2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2013, 2015 Gregory Nutt. + * All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -180,9 +181,9 @@ static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, */ if (nsh_openifnotopen(pstate) != 0) - { - return (ssize_t)ERROR; - } + { + return ERROR; + } /* Write the data to the output stream */ @@ -221,9 +222,9 @@ static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, */ if (nsh_openifnotopen(pstate) != 0) - { - return ERROR; - } + { + return ERROR; + } va_start(ap, fmt); ret = vfprintf(pstate->cn_outstream, fmt, ap); @@ -253,9 +254,9 @@ static int nsh_erroroutput(FAR struct nsh_vtbl_s *vtbl, */ if (nsh_openifnotopen(pstate) != 0) - { - return ERROR; - } + { + return ERROR; + } va_start(ap, fmt); ret = vfprintf(pstate->cn_errstream, fmt, ap); diff --git a/nshlib/nsh_console.h b/nshlib/nsh_console.h index 0d12b4b51..c71d14533 100644 --- a/nshlib/nsh_console.h +++ b/nshlib/nsh_console.h @@ -52,6 +52,7 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* Method access macros */ #define nsh_clone(v) (v)->clone(v) @@ -70,8 +71,9 @@ # define nsh_output vtbl->output #endif -/* Size of info to be saved in call to nsh_redirect */ -/* See struct serialsave_s in nsh_console.c */ +/* Size of info to be saved in call to nsh_redirect + * See struct serialsave_s in nsh_console.c + */ #define SAVE_SIZE (2 * sizeof(int) + 2 * sizeof(FILE*)) @@ -107,6 +109,7 @@ /**************************************************************************** * Public Types ****************************************************************************/ + /* This describes a generic console front-end */ struct nsh_vtbl_s @@ -129,10 +132,10 @@ struct nsh_vtbl_s FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl); void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save); void (*undirect)(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save); - void (*exit)(FAR struct nsh_vtbl_s *vtbl, int exitstatus) noreturn_function; + void (*exit)(FAR struct nsh_vtbl_s *vtbl, int status) noreturn_function; #ifdef NSH_HAVE_IOBUFFER -/* Common buffer for file I/O. */ + /* Common buffer for file I/O. */ char iobuffer[IOBUFFERSIZE]; #endif diff --git a/nshlib/nsh_consolemain.c b/nshlib/nsh_consolemain.c index 3c27581cf..a222f49ee 100644 --- a/nshlib/nsh_consolemain.c +++ b/nshlib/nsh_consolemain.c @@ -112,7 +112,7 @@ int nsh_consolemain(int argc, FAR char *argv[]) /* Execute the session */ - ret = nsh_session(pstate, true); + ret = nsh_session(pstate, true, argc, argv); /* Exit upon return */ diff --git a/nshlib/nsh_session.c b/nshlib/nsh_session.c index 329e3a7fc..fc4382224 100644 --- a/nshlib/nsh_session.c +++ b/nshlib/nsh_session.c @@ -42,6 +42,7 @@ #include #include +#include #ifdef CONFIG_NSH_CLE # include "system/cle.h" @@ -79,10 +80,11 @@ * ****************************************************************************/ -int nsh_session(FAR struct console_stdio_s *pstate, bool login) +int nsh_session(FAR struct console_stdio_s *pstate, + bool login, int argc, FAR char *argv[]) { FAR struct nsh_vtbl_s *vtbl; - int ret; + int ret = EXIT_FAILURE; DEBUGASSERT(pstate); vtbl = &pstate->cn_vtbl; @@ -126,70 +128,92 @@ int nsh_session(FAR struct console_stdio_s *pstate, bool login) #endif } - /* Then enter the command line parsing loop */ - - for (; ; ) + if (argc < 2) { - /* For the case of debugging the USB console... - * dump collected USB trace data - */ + /* Then enter the command line parsing loop */ -#ifdef CONFIG_NSH_USBDEV_TRACE - nsh_usbtrace(); -#endif - - /* Get the next line of input. readline() returns EOF on end-of-file - * or any read failure. - */ - -#ifdef CONFIG_NSH_CLE - /* cle() normally returns the number of characters read, but will - * return a negated errno value on end of file or if an error occurs. - * Either will cause the session to terminate. - */ - - ret = cle(pstate->cn_line, g_nshprompt, CONFIG_NSH_LINELEN, - INSTREAM(pstate), OUTSTREAM(pstate)); - if (ret < 0) + for (; ; ) { - fprintf(pstate->cn_errstream, g_fmtcmdfailed, "nsh_session", - "cle", NSH_ERRNO_OF(-ret)); - continue; - } -#else - /* Display the prompt string */ - - fputs(g_nshprompt, pstate->cn_outstream); - fflush(pstate->cn_outstream); - - /* readline() normally returns the number of characters read, but will - * return EOF on end of file or if an error occurs. EOF - * will cause the session to terminate. - */ - - ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, - INSTREAM(pstate), OUTSTREAM(pstate)); - if (ret == EOF) - { - /* NOTE: readline() does not set the errno variable, but perhaps we - * will be lucky and it will still be valid. + /* For the case of debugging the USB console... + * dump collected USB trace data */ - fprintf(pstate->cn_errstream, g_fmtcmdfailed, "nsh_session", - "readline", NSH_ERRNO); - return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; - } +#ifdef CONFIG_NSH_USBDEV_TRACE + nsh_usbtrace(); #endif + /* Get the next line of input. readline() returns EOF + * on end-of-file or any read failure. + */ + +#ifdef CONFIG_NSH_CLE + /* cle() normally returns the number of characters read, but will + * return a negated errno value on end of file or if an error + * occurs. Either will cause the session to terminate. + */ + + ret = cle(pstate->cn_line, g_nshprompt, CONFIG_NSH_LINELEN, + INSTREAM(pstate), OUTSTREAM(pstate)); + if (ret < 0) + { + fprintf(pstate->cn_errstream, g_fmtcmdfailed, "nsh_session", + "cle", NSH_ERRNO_OF(-ret)); + continue; + } +#else + /* Display the prompt string */ + + fputs(g_nshprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + /* readline() normally returns the number of characters read, but + * will return EOF on end of file or if an error occurs. EOF + * will cause the session to terminate. + */ + + ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, + INSTREAM(pstate), OUTSTREAM(pstate)); + if (ret == EOF) + { + /* NOTE: readline() does not set the errno variable, but + * perhaps we will be lucky and it will still be valid. + */ + + fprintf(pstate->cn_errstream, g_fmtcmdfailed, "nsh_session", + "readline", NSH_ERRNO); + ret = EXIT_SUCCESS; + break; + } +#endif + + /* Parse process the command */ + + nsh_parse(vtbl, pstate->cn_line); + fflush(pstate->cn_outstream); + } + } + else if (strcmp(argv[1], "-h") == 0) + { + ret = nsh_output(vtbl, "Usage: %s [|-c ]\n", + argv[0]); + } + else if (strcmp(argv[1], "-c") != 0) + { +#if defined(CONFIG_NFILE_STREAMS) && !defined(CONFIG_NSH_DISABLESCRIPT) + /* Execute the shell script */ + + ret = nsh_script(vtbl, argv[0], argv[1]); +#endif + } + else if (argc >= 3) + { /* Parse process the command */ - nsh_parse(vtbl, pstate->cn_line); + ret = nsh_parse(vtbl, argv[2]); +#ifdef CONFIG_NFILE_STREAMS fflush(pstate->cn_outstream); +#endif } - /* We do not get here, but this is necessary to keep some compilers happy. - * But others will complain that this code is not reachable. - */ - - return EXIT_SUCCESS; + return ret; } diff --git a/nshlib/nsh_stdsession.c b/nshlib/nsh_stdsession.c index 1a2c6c391..a9da4e5e3 100644 --- a/nshlib/nsh_stdsession.c +++ b/nshlib/nsh_stdsession.c @@ -41,6 +41,7 @@ #include #include +#include #ifdef CONFIG_NSH_CLE # include "system/cle.h" @@ -71,15 +72,13 @@ * Input Parameters: * pstate - Abstracts the underlying session. * - * Returned Values: - * EXIT_SUCCESS only - * ****************************************************************************/ -int nsh_session(FAR struct console_stdio_s *pstate, bool login) +int nsh_session(FAR struct console_stdio_s *pstate, + bool login, int argc, FAR char *argv[]) { FAR struct nsh_vtbl_s *vtbl; - int ret; + int ret = EXIT_FAILURE; DEBUGASSERT(pstate); vtbl = &pstate->cn_vtbl; @@ -116,63 +115,86 @@ int nsh_session(FAR struct console_stdio_s *pstate, bool login) #endif } - /* Then enter the command line parsing loop */ - - for (; ; ) + if (argc < 2) { - /* For the case of debugging the USB console... - * dump collected USB trace data - */ + /* Then enter the command line parsing loop */ -#ifdef CONFIG_NSH_USBDEV_TRACE - nsh_usbtrace(); -#endif - - /* Get the next line of input. */ - -#ifdef CONFIG_NSH_CLE - /* cle() normally returns the number of characters read, but will - * return a negated errno value on end of file or if an error occurs. - * Either will cause the session to terminate. - */ - - ret = cle(pstate->cn_line, g_nshprompt, CONFIG_NSH_LINELEN, - stdin, stdout); - if (ret < 0) + for (; ; ) { - printf(g_fmtcmdfailed, "nsh_session", "cle", NSH_ERRNO_OF(-ret)); - return EXIT_SUCCESS; - } -#else - /* Display the prompt string */ - - printf("%s", g_nshprompt); - - /* readline () normally returns the number of characters read, but will - * return EOF on end of file or if an error occurs. Either will cause - * the session to terminate. - */ - - ret = std_readline(pstate->cn_line, CONFIG_NSH_LINELEN); - if (ret == EOF) - { - /* NOTE: readline() does not set the errno variable, but perhaps we - * will be lucky and it will still be valid. + /* For the case of debugging the USB console... + * dump collected USB trace data */ - printf(g_fmtcmdfailed, "nsh_session", "readline", NSH_ERRNO); - return EXIT_SUCCESS; - } +#ifdef CONFIG_NSH_USBDEV_TRACE + nsh_usbtrace(); #endif + /* Get the next line of input. */ + +#ifdef CONFIG_NSH_CLE + /* cle() normally returns the number of characters read, but will + * return a negated errno value on end of file or if an error + * occurs. Either will cause the session to terminate. + */ + + ret = cle(pstate->cn_line, g_nshprompt, CONFIG_NSH_LINELEN, + stdin, stdout); + if (ret < 0) + { + printf(g_fmtcmdfailed, + "nsh_session", "cle", NSH_ERRNO_OF(-ret)); + continue; + } +#else + /* Display the prompt string */ + + printf("%s", g_nshprompt); + + /* readline () normally returns the number of characters read, but + * will return EOF on end of file or if an error occurs. Either + * will cause the session to terminate. + */ + + ret = std_readline(pstate->cn_line, CONFIG_NSH_LINELEN); + if (ret == EOF) + { + /* NOTE: readline() does not set the errno variable, but + * perhaps we will be lucky and it will still be valid. + */ + + printf(g_fmtcmdfailed, "nsh_session", "readline", NSH_ERRNO); + ret = EXIT_SUCCESS; + break; + } +#endif + + /* Parse process the command */ + + nsh_parse(vtbl, pstate->cn_line); + } + } + else if (strcmp(argv[1], "-h") == 0) + { + ret = nsh_output(vtbl, "Usage: %s [|-c ]\n", + argv[0]); + } + else if (strcmp(argv[1], "-c") != 0) + { +#if defined(CONFIG_NFILE_STREAMS) && !defined(CONFIG_NSH_DISABLESCRIPT) + /* Execute the shell script */ + + ret = nsh_script(vtbl, argv[0], argv[1]); +#endif + } + else if (argc >= 3) + { /* Parse process the command */ - nsh_parse(vtbl, pstate->cn_line); + ret = nsh_parse(vtbl, argv[2]); +#ifdef CONFIG_NFILE_STREAMS + fflush(pstate->cn_outstream); +#endif } - /* We do not get here, but this is necessary to keep some compilers happy. - * But others will complain that this code is not reachable. - */ - - return EXIT_SUCCESS; + return ret; } diff --git a/nshlib/nsh_system.c b/nshlib/nsh_system.c index 83fa347b3..f597e86c8 100644 --- a/nshlib/nsh_system.c +++ b/nshlib/nsh_system.c @@ -73,40 +73,13 @@ int nsh_system(int argc, FAR char *argv[]) { FAR struct console_stdio_s *pstate = nsh_newconsole(); - FAR struct nsh_vtbl_s *vtbl; - int ret = EXIT_FAILURE; + int ret; DEBUGASSERT(pstate != NULL); - vtbl = &pstate->cn_vtbl; - if (argc < 2) - { - /* Execute the interactive shell */ + /* Execute the session */ - ret = nsh_session(pstate, false); - } - else if (strcmp(argv[1], "-h") == 0) - { - ret = nsh_output(vtbl, "Usage: %s [|-c ]\n", - argv[0]); - } - else if (strcmp(argv[1], "-c") != 0) - { -#if CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) - /* Execute the shell script */ - - ret = nsh_script(vtbl, argv[0], argv[1]); -#endif - } - else if (argc >= 3) - { - /* Parse process the command */ - - ret = nsh_parse(vtbl, argv[2]); -#if CONFIG_NFILE_STREAMS > 0 - fflush(pstate->cn_outstream); -#endif - } + ret = nsh_session(pstate, false, argc, argv); /* Exit upon return */ diff --git a/nshlib/nsh_timcmds.c b/nshlib/nsh_timcmds.c index 88f044f8e..940c343a8 100644 --- a/nshlib/nsh_timcmds.c +++ b/nshlib/nsh_timcmds.c @@ -99,6 +99,7 @@ static inline int date_month(FAR const char *abbrev) return i; } } + return ERROR; } #endif @@ -108,7 +109,8 @@ static inline int date_month(FAR const char *abbrev) ****************************************************************************/ #ifndef CONFIG_NSH_DISABLE_DATE -static inline int date_showtime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name) +static inline int date_showtime(FAR struct nsh_vtbl_s *vtbl, + FAR const char *name) { static const char format[] = "%a, %b %d %H:%M:%S %Y"; struct timespec ts; @@ -127,7 +129,7 @@ static inline int date_showtime(FAR struct nsh_vtbl_s *vtbl, FAR const char *nam /* Break the current time up into the format needed by strftime */ - if (gmtime_r((FAR const time_t*)&ts.tv_sec, &tm) == NULL) + if (gmtime_r((FAR const time_t *)&ts.tv_sec, &tm) == NULL) { nsh_error(vtbl, g_fmtcmdfailed, name, "gmtime_r", NSH_ERRNO); return ERROR; @@ -152,8 +154,8 @@ static inline int date_showtime(FAR struct nsh_vtbl_s *vtbl, FAR const char *nam ****************************************************************************/ #ifndef CONFIG_NSH_DISABLE_DATE -static inline int date_settime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name, - FAR char *newtime) +static inline int date_settime(FAR struct nsh_vtbl_s *vtbl, + FAR const char *name, FAR char *newtime) { struct timespec ts; struct tm tm; @@ -165,9 +167,10 @@ static inline int date_settime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name memset(&tm, 0, sizeof(tm)); /* Only this date format is supported: MMM DD HH:MM:SS YYYY */ + /* Get the month abbreviation */ - token = strtok_r(newtime, " \t",&saveptr); + token = strtok_r(newtime, " \t", &saveptr); if (token == NULL) { goto errout_bad_parm; @@ -179,9 +182,11 @@ static inline int date_settime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name goto errout_bad_parm; } - /* Get the day of the month. NOTE: Accepts day-of-month up to 31 for all months */ + /* Get the day of the month. + * NOTE: Accepts day-of-month up to 31 for all months + */ - token = strtok_r(NULL, " \t",&saveptr); + token = strtok_r(NULL, " \t", &saveptr); if (token == NULL) { goto errout_bad_parm; @@ -304,8 +309,8 @@ int cmd_time(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) ret = clock_gettime(TIME_CLOCK, &start); if (ret < 0) { - nsh_error(vtbl, g_fmtcmdfailed, argv[0], "clock_gettime", NSH_ERRNO); - return ERROR; + nsh_error(vtbl, g_fmtcmdfailed, argv[0], "clock_gettime", NSH_ERRNO); + return ERROR; } /* Save state */ @@ -330,7 +335,8 @@ int cmd_time(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) ret = clock_gettime(TIME_CLOCK, &end); if (ret < 0) { - nsh_error(vtbl, g_fmtcmdfailed, argv[0], "clock_gettime", NSH_ERRNO); + nsh_error(vtbl, g_fmtcmdfailed, + argv[0], "clock_gettime", NSH_ERRNO); ret = ERROR; } else @@ -370,7 +376,6 @@ int cmd_date(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { FAR char *newtime = NULL; FAR const char *errfmt; - bool badarg = false; int option; int ret; @@ -386,18 +391,9 @@ int cmd_date(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) } else /* option = '?' */ { - /* We need to parse to the end anyway so that getopt stays healthy */ - - badarg = true; + errfmt = g_fmtarginvalid; + goto errout; } - } - - /* If a bad argument was encountered then exit with an error */ - - if (badarg) - { - errfmt = g_fmtarginvalid; - goto errout; } /* optind < argc-1 means that there are additional, unexpected arguments on diff --git a/nshlib/nsh_usbconsole.c b/nshlib/nsh_usbconsole.c index 700a10fa9..d7069ddf7 100644 --- a/nshlib/nsh_usbconsole.c +++ b/nshlib/nsh_usbconsole.c @@ -346,7 +346,7 @@ int nsh_consolemain(int argc, FAR char *argv[]) /* Execute the session */ - nsh_session(pstate, true); + nsh_session(pstate, true, argc, argv); /* Switch to /dev/null because we probably no longer have a * valid console device. diff --git a/system/nsh/nsh_main.c b/system/nsh/nsh_main.c index 8aaf0a218..6b939be8b 100644 --- a/system/nsh/nsh_main.c +++ b/system/nsh/nsh_main.c @@ -165,7 +165,7 @@ int main(int argc, FAR char *argv[]) #ifdef CONFIG_NSH_CONSOLE /* If the serial console front end is selected, run it on this thread */ - ret = nsh_consolemain(0, NULL); + ret = nsh_consolemain(argc, argv); /* nsh_consolemain() should not return. So if we get here, something * is wrong.