diff --git a/include/system/cle.h b/include/system/cle.h index 82ec1c6e2..c09e9eeb8 100644 --- a/include/system/cle.h +++ b/include/system/cle.h @@ -76,7 +76,8 @@ extern "C" * ****************************************************************************/ -int cle(FAR char *line, uint16_t linelen, FILE *instream, FILE *outstream); +int cle(FAR char *line, FAR const char *prompt, uint16_t linelen, + FAR FILE *instream, FAR FILE *outstream); #undef EXTERN #ifdef __cplusplus diff --git a/nshlib/nsh_login.c b/nshlib/nsh_login.c index ffe4da30e..158a96804 100644 --- a/nshlib/nsh_login.c +++ b/nshlib/nsh_login.c @@ -127,7 +127,7 @@ static void nsh_token(FAR struct console_stdio_s *pstate, else if (isspace(*endp1)) { - /* Break out... endp1 points to first while space encountered */ + /* Break out... endp1 points to first while space encountered */ break; } @@ -168,24 +168,15 @@ int nsh_login(FAR struct console_stdio_s *pstate) { /* Ask for the login username */ + username[0] = '\0'; fputs(g_userprompt, pstate->cn_outstream); fflush(pstate->cn_outstream); - username[0] = '\0'; - -#ifdef CONFIG_NSH_CLE - /* cle() returns a negated errno value on failure */ - - ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, - INSTREAM(pstate), OUTSTREAM(pstate)); - if (ret >= 0) -#else /* readline() returns EOF on failure */ ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate), OUTSTREAM(pstate)); if (ret != EOF) -#endif { /* Parse out the username */ @@ -198,7 +189,8 @@ int nsh_login(FAR struct console_stdio_s *pstate) fflush(pstate->cn_outstream); password[0] = '\0'; - if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, + INSTREAM(pstate)) != NULL) { /* Parse out the password */ diff --git a/nshlib/nsh_session.c b/nshlib/nsh_session.c index f8c8088bd..6d11c4432 100644 --- a/nshlib/nsh_session.c +++ b/nshlib/nsh_session.c @@ -102,17 +102,17 @@ int nsh_session(FAR struct console_stdio_s *pstate) fputs(g_nshgreeting, pstate->cn_outstream); #ifdef CONFIG_NSH_MOTD -# ifdef CONFIG_NSH_PLATFORM_MOTD +#ifdef CONFIG_NSH_PLATFORM_MOTD /* Output the platform message of the day */ platform_motd(vtbl->iobuffer, IOBUFFERSIZE); fprintf(pstate->cn_outstream, "%s\n", vtbl->iobuffer); -# else +#else /* Output the fixed message of the day */ fprintf(pstate->cn_outstream, "%s\n", g_nshmotd); -# endif +#endif #endif fflush(pstate->cn_outstream); @@ -125,7 +125,7 @@ int nsh_session(FAR struct console_stdio_s *pstate) /* Then enter the command line parsing loop */ - for (;;) + for (; ; ) { /* For the case of debugging the USB console... dump collected USB trace data */ @@ -133,11 +133,6 @@ int nsh_session(FAR struct console_stdio_s *pstate) nsh_usbtrace(); #endif - /* Display the prompt string */ - - fputs(g_nshprompt, pstate->cn_outstream); - fflush(pstate->cn_outstream); - /* Get the next line of input. readline() returns EOF on end-of-file * or any read failure. */ @@ -148,7 +143,7 @@ int nsh_session(FAR struct console_stdio_s *pstate) * Either will cause the session to terminate. */ - ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, + ret = cle(pstate->cn_line, g_nshprompt, CONFIG_NSH_LINELEN, INSTREAM(pstate), OUTSTREAM(pstate)); if (ret < 0) { @@ -157,6 +152,11 @@ int nsh_session(FAR struct console_stdio_s *pstate) return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } #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. diff --git a/nshlib/nsh_stdlogin.c b/nshlib/nsh_stdlogin.c index ffc0460c6..d4067ba2c 100644 --- a/nshlib/nsh_stdlogin.c +++ b/nshlib/nsh_stdlogin.c @@ -127,7 +127,7 @@ static void nsh_stdtoken(FAR struct console_stdio_s *pstate, else if (isspace(*endp1)) { - /* Break out... endp1 points to first while space encountered */ + /* Break out... endp1 points to first while space encountered */ break; } @@ -166,10 +166,6 @@ int nsh_stdlogin(FAR struct console_stdio_s *pstate) for (i = 0; i < CONFIG_NSH_LOGIN_FAILCOUNT; i++) { - /* Ask for the login username */ - - printf("%s", g_userprompt); - /* Get the response, handling all possible cases */ username[0] = '\0'; @@ -177,10 +173,14 @@ int nsh_stdlogin(FAR struct console_stdio_s *pstate) #ifdef CONFIG_NSH_CLE /* cle() returns a negated errno value on failure */ - ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, + ret = cle(pstate->cn_line, g_userprompt, CONFIG_NSH_LINELEN, stdin, stdout); if (ret >= 0) #else + /* Ask for the login username */ + + printf("%s", g_userprompt); + /* readline() returns EOF on failure */ ret = std_readline(pstate->cn_line, CONFIG_NSH_LINELEN); diff --git a/nshlib/nsh_stdsession.c b/nshlib/nsh_stdsession.c index b14999bce..ed376a407 100644 --- a/nshlib/nsh_stdsession.c +++ b/nshlib/nsh_stdsession.c @@ -115,7 +115,7 @@ int nsh_session(FAR struct console_stdio_s *pstate) /* Then enter the command line parsing loop */ - for (;;) + for (; ; ) { /* For the case of debugging the USB console... dump collected USB trace data */ @@ -123,10 +123,6 @@ int nsh_session(FAR struct console_stdio_s *pstate) nsh_usbtrace(); #endif - /* Display the prompt string */ - - printf("%s", g_nshprompt); - /* Get the next line of input. */ #ifdef CONFIG_NSH_CLE @@ -135,15 +131,18 @@ int nsh_session(FAR struct console_stdio_s *pstate) * Either will cause the session to terminate. */ - ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, + 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)); 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. diff --git a/nshlib/nsh_telnetd.c b/nshlib/nsh_telnetd.c index 70aca88be..5311790de 100644 --- a/nshlib/nsh_telnetd.c +++ b/nshlib/nsh_telnetd.c @@ -144,20 +144,15 @@ static int nsh_telnetmain(int argc, char *argv[]) /* Then enter the command line parsing loop */ - for (;;) + for (; ; ) { - /* Display the prompt string */ - - fputs(g_nshprompt, pstate->cn_outstream); - fflush(pstate->cn_outstream); - /* Get the next line of input from the Telnet client */ #ifdef CONFIG_TELNET_CHARACTER_MODE #ifdef CONFIG_NSH_CLE /* cle() returns a negated errno value on failure (errno is not set) */ - ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, + ret = cle(pstate->cn_line, g_nshprompt, CONFIG_NSH_LINELEN, INSTREAM(pstate), OUTSTREAM(pstate)); if (ret < 0) { @@ -166,6 +161,11 @@ static int nsh_telnetmain(int argc, char *argv[]) nsh_exit(vtbl, 1); } #else + /* Display the prompt string */ + + fputs(g_nshprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + /* readline() returns EOF on failure (errno is not set) */ ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, @@ -182,6 +182,11 @@ static int nsh_telnetmain(int argc, char *argv[]) } #endif #else + /* Display the prompt string */ + + fputs(g_nshprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + /* fgets() returns NULL on failure (errno will be set) */ if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, @@ -278,7 +283,7 @@ int nsh_telnetstart(sa_family_t family) ret = telnetd_start(&config); if (ret < 0) { - _err("ERROR: Failed to tart the Telnet daemon: %d\n", ret); + _err("ERROR: Failed to start the Telnet daemon: %d\n", ret); state = TELNETD_NOTRUNNING; } else diff --git a/system/cle/Kconfig b/system/cle/Kconfig index 92054e8b2..12b89c516 100644 --- a/system/cle/Kconfig +++ b/system/cle/Kconfig @@ -21,6 +21,12 @@ menuconfig SYSTEM_CLE if SYSTEM_CLE +config SYSTEM_COLOR_CLE + bool "Simple color support in the CLE" + default n + ---help--- + Adds some simple color highlighting into the CLE. + config SYSTEM_CLE_CMD_HISTORY bool "Command line history" default n diff --git a/system/cle/cle.c b/system/cle/cle.c index e52306c49..d250b482d 100644 --- a/system/cle/cle.c +++ b/system/cle/cle.c @@ -161,6 +161,7 @@ static int g_cmd_history_len = 0; /**************************************************************************** * Private Types ****************************************************************************/ + /* VI Key Bindings */ enum cle_key_e @@ -172,6 +173,7 @@ enum cle_key_e KEY_RIGHT = CTRL('F'), /* Move right one character */ KEY_DELLEFT = CTRL('H'), /* Delete character, left (backspace) */ KEY_DELEOL = CTRL('K'), /* Delete to the end of the line */ + KEY_CLRSCR = CTRL('L'), /* Clear the screen */ KEY_DN = CTRL('N'), /* Cursor down */ KEY_UP = CTRL('P'), /* Cursor up */ KEY_DELLINE = CTRL('U'), /* Delete the entire line */ @@ -191,6 +193,7 @@ struct cle_s int infd; /* Input file descriptor */ int outfd; /* Output file descriptor */ FAR char *line; /* Line buffer */ + FAR const char *prompt; /* Prompt, in case we have to re-print it */ }; /**************************************************************************** @@ -218,7 +221,8 @@ static void cle_clrtoeol(FAR struct cle_s *priv); static bool cle_opentext(FAR struct cle_s *priv, uint16_t pos, uint16_t increment); -static void cle_closetext(FAR struct cle_s *priv, uint16_t pos, uint16_t size); +static void cle_closetext(FAR struct cle_s *priv, uint16_t pos, + uint16_t size); static void cle_showtext(FAR struct cle_s *priv); static void cle_insertch(FAR struct cle_s *priv, char ch); static int cle_editloop(FAR struct cle_s *priv); @@ -234,6 +238,15 @@ static const char g_cursoroff[] = VT100_CURSOROFF; static const char g_getcursor[] = VT100_GETCURSOR; static const char g_erasetoeol[] = VT100_CLEAREOL; static const char g_fmtcursorpos[] = VT100_FMT_CURSORPOS; +static const char g_clrscr[] = VT100_CLEARSCREEN; +static const char g_home[] = VT100_CURSORHOME; +static const char g_setcolor[] = VT100_FMT_FORE_COLOR; + +#ifdef CONFIG_SYSTEM_COLOR_CLE +# define COLOR_PROMPT VT100_YELLOW +# define COLOR_COMMAND VT100_CYAN +# define COLOR_OUTPUT VT100_GREEN +#endif /**************************************************************************** * Private Functions @@ -421,13 +434,70 @@ static void cle_setcursor(FAR struct cle_s *priv, uint16_t column) /* Format the cursor position command. The origin is (1,1). */ - len = snprintf(buffer, 16, g_fmtcursorpos, priv->row, column + priv->coloffs); + len = snprintf(buffer, 16, g_fmtcursorpos, + priv->row, column + priv->coloffs); /* Send the VT100 CURSORPOS command */ cle_write(priv, buffer, len); } +/**************************************************************************** + * Name: cle_setcolor + * + * Description: + * Set foreground color + * + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_COLOR_CLE +static void cle_setcolor(FAR struct cle_s *priv, uint8_t color) +{ + char buffer[16]; + int len; + + len = snprintf(buffer, 16, g_setcolor, color); + cle_write(priv, buffer, len); +} +#endif + +/**************************************************************************** + * Name: cle_outputprompt + * + * Description: + * Send the prompt to the screen + * + ****************************************************************************/ + +static void cle_outputprompt(FAR struct cle_s *priv) +{ +#ifdef CONFIG_SYSTEM_COLOR_CLE + cle_setcolor(priv, COLOR_PROMPT); +#endif + cle_write(priv, priv->prompt, strlen(priv->prompt)); +#ifdef CONFIG_SYSTEM_COLOR_CLE + cle_setcolor(priv, COLOR_OUTPUT); +#endif +} + +/**************************************************************************** + * Name: cle_clrscr + * + * Description: + * Clear the screen, and re-establish the prompt + * + ****************************************************************************/ + +static void cle_clrscr(FAR struct cle_s *priv) +{ + /* Send the VT100 CLEARSCREEN command */ + + cle_write(priv, g_clrscr, sizeof(g_clrscr)); + cle_write(priv, g_home, sizeof(g_home)); + priv->row = 1; + cle_outputprompt(priv); +} + /**************************************************************************** * Name: cle_getcursor * @@ -451,7 +521,7 @@ static int cle_getcursor(FAR struct cle_s *priv, FAR uint16_t *prow, /* We expect to get ESC[v;hR where v is the row and h is the column */ nbad = 0; - for (;;) + for (; ; ) { /* Get the next character from the input */ @@ -475,7 +545,7 @@ static int cle_getcursor(FAR struct cle_s *priv, FAR uint16_t *prow, /* Have ESC, now we expect '[' */ nbad = 0; - for (;;) + for (; ; ) { /* Get the next character from the input */ @@ -499,7 +569,7 @@ static int cle_getcursor(FAR struct cle_s *priv, FAR uint16_t *prow, /* Have ESC'['. Now we expect to see a numeric value terminated with ';' */ row = 0; - for (;;) + for (; ; ) { /* Get the next character from the input */ @@ -525,7 +595,7 @@ static int cle_getcursor(FAR struct cle_s *priv, FAR uint16_t *prow, /* Have ESC'['v';'. Now we expect to see another numeric value terminated with 'R' */ column = 0; - for (;;) + for (; ; ) { /* Get the next character from the input */ @@ -685,6 +755,9 @@ static void cle_showtext(FAR struct cle_s *priv) /* Set the cursor position to the beginning of this row */ +#ifdef CONFIG_SYSTEM_COLOR_CLE + cle_setcolor(priv, COLOR_COMMAND); +#endif cle_setcursor(priv, 0); cle_clrtoeol(priv); @@ -723,6 +796,10 @@ static void cle_showtext(FAR struct cle_s *priv) } } +#ifdef CONFIG_SYSTEM_COLOR_CLE + cle_setcolor(priv, COLOR_OUTPUT); +#endif + /* Turn the cursor back on */ cle_cursoron(priv); @@ -738,7 +815,8 @@ static void cle_showtext(FAR struct cle_s *priv) static void cle_insertch(FAR struct cle_s *priv, char ch) { - cleinfo("curpos=%ld ch=%c[%02x]\n", priv->curpos, isprint(ch) ? ch : '.', ch); + cleinfo("curpos=%ld ch=%c[%02x]\n", priv->curpos, + isprint(ch) ? ch : '.', ch); /* Make space in the buffer for the new character */ @@ -762,7 +840,7 @@ static int cle_editloop(FAR struct cle_s *priv) { /* Loop while we are in command mode */ - for (;;) + for (; ; ) { int ch; @@ -778,118 +856,115 @@ static int cle_editloop(FAR struct cle_s *priv) * home/end, del */ - { - char state = 0; + char state = 0; - /* loop till we have a ch */ + /* loop till we have a ch */ - for (; ; ) - { - ch = cle_getch(priv); - if (ch < 0) - { - return -EIO; - } - else if (state != 0) - { - if (state == (char)1) /* Got ESC */ - { - if (ch == '[' || ch == 'O') - { - state = ch; - } - else - { - break; /* break the for loop */ - } - } + for (; ; ) + { + ch = cle_getch(priv); + if (ch < 0) + { + return -EIO; + } + else if (state != 0) + { + if (state == (char)1) /* Got ESC */ + { + if (ch == '[' || ch == 'O') + { + state = ch; + } + else + { + break; /* break the for loop */ + } + } + else if (state == '[') + { + /* Got ESC[ */ - else if (state == '[') - { - /* Got ESC[ */ + switch (ch) + { + case '3': /* ESC[3~ = DEL */ + { + state = ch; + } + continue; - switch (ch) - { - case '3': /* ESC[3~ = DEL */ - { - state = ch; - } - continue; + case 'A': + { + ch = KEY_UP; + } + break; - case 'A': - { - ch = KEY_UP; - } - break; + case 'B': + { + ch = KEY_DN; + } + break; - case 'B': - { - ch = KEY_DN; - } - break; + case 'C': + { + ch = KEY_RIGHT; + } + break; - case 'C': - { - ch = KEY_RIGHT; - } - break; + case 'D': + { + ch = KEY_LEFT; + } + break; - case 'D': - { - ch = KEY_LEFT; - } - break; + case 'F': + { + ch = KEY_ENDLINE; + } + break; - case 'F': - { - ch = KEY_ENDLINE; - } - break; + case 'H': + { + ch = KEY_BEGINLINE; + } + break; - case 'H': - { - ch = KEY_BEGINLINE; - } - break; + default: + break; + } + break; /* Break the 'for' loop */ + } + else if (state == 'O') + { + /* got ESCO */ - default: - break; - } - break; /* Break the 'for' loop */ - } - else if (state == 'O') - { - /* got ESCO */ - - if (ch=='F') - { - ch = KEY_ENDLINE; - } - break; /* Break the 'for' loop */ - } - else if (state == '3') - { - if (ch == '~') - { - ch = KEY_DEL; - } - break; /* Break the 'for' loop */ - } - else - { - break; /* Break the 'for' loop */ - } - } - else if (ch == ASCII_ESC) - { - ++state; - } - else - { - break; /* Break the 'for' loop, use the char */ - } - } - } + if (ch == 'F') + { + ch = KEY_ENDLINE; + } + break; /* Break the 'for' loop */ + } + else if (state == '3') + { + if (ch == '~') + { + ch = KEY_DEL; + } + break; /* Break the 'for' loop */ + } + else + { + break; /* Break the 'for' loop */ + } + } + else if (ch == ASCII_ESC) + { + ++state; + } + else + { + break; /* Break the 'for' loop, use the char */ + } + } #else ch = cle_getch(priv); @@ -910,6 +985,7 @@ static int cle_editloop(FAR struct cle_s *priv) switch (ch) { case KEY_UP: + /* Go to the past command in history */ g_cmd_history_steps_from_head--; @@ -921,6 +997,7 @@ static int cle_editloop(FAR struct cle_s *priv) break; case KEY_DN: + /* Go to the recent command in history */ g_cmd_history_steps_from_head++; @@ -1023,8 +1100,7 @@ static int cle_editloop(FAR struct cle_s *priv) break; case ASCII_DEL: - case KEY_DELLEFT: /* Delete 1 character before the cursor */ - //case ASCII_BS: + case KEY_DELLEFT: /* Delete 1 character before the cursor */ { if (priv->curpos > 0) { @@ -1050,6 +1126,10 @@ static int cle_editloop(FAR struct cle_s *priv) } break; + case KEY_CLRSCR: /* Clear the screen & return cursor to top */ + cle_clrscr(priv); + break; + case KEY_QUOTE: /* Quoted character follows */ { ch = cle_getch(priv); @@ -1130,7 +1210,8 @@ static int cle_editloop(FAR struct cle_s *priv) * ****************************************************************************/ -int cle(FAR char *line, uint16_t linelen, FILE *instream, FILE *outstream) +int cle(FAR char *line, const char *prompt, uint16_t linelen, + FILE *instream, FILE *outstream) { FAR struct cle_s priv; uint16_t column; @@ -1148,6 +1229,11 @@ int cle(FAR char *line, uint16_t linelen, FILE *instream, FILE *outstream) priv.infd = instream->fs_fd; priv.outfd = outstream->fs_fd; + /* Store the prompt in case we need to re-print it */ + + priv.prompt = prompt; + cle_outputprompt(&priv); + /* Get the current cursor position */ ret = cle_getcursor(&priv, &priv.row, &column); @@ -1188,7 +1274,8 @@ int cle(FAR char *line, uint16_t linelen, FILE *instream, FILE *outstream) (g_cmd_history_head + 1) % CONFIG_SYSTEM_CLE_CMD_HISTORY_LEN; for (i = 0; - (i < priv.nchars - 1) && i < (CONFIG_SYSTEM_CLE_CMD_HISTORY_LINELEN - 1); + (i < priv.nchars - 1) && + i < (CONFIG_SYSTEM_CLE_CMD_HISTORY_LINELEN - 1); i++) { g_cmd_history[g_cmd_history_head][i] = line[i];