From dbd4e672417d915304a1216e3ea2edab93bad0da Mon Sep 17 00:00:00 2001 From: Dave Marples <dave@marples.net> Date: Mon, 4 Nov 2019 11:35:18 -0600 Subject: [PATCH] apps/system/cle/cle.c: This commit modifies the cle to use the streams file interface more consistently and has removed the observed race conditions. It was previously a mix of streams and fileio. It also simplifies the VT100 cursor position handling. --- nshlib/nsh_session.c | 2 +- system/cle/cle.c | 166 ++++++++++++++++--------------------------- 2 files changed, 63 insertions(+), 105 deletions(-) diff --git a/nshlib/nsh_session.c b/nshlib/nsh_session.c index 6d11c4432..d06a1c28c 100644 --- a/nshlib/nsh_session.c +++ b/nshlib/nsh_session.c @@ -149,7 +149,7 @@ int nsh_session(FAR struct console_stdio_s *pstate) { fprintf(pstate->cn_errstream, g_fmtcmdfailed, "nsh_session", "cle", NSH_ERRNO_OF(-ret)); - return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + continue; } #else /* Display the prompt string */ diff --git a/system/cle/cle.c b/system/cle/cle.c index b8a6a3632..548ce98d8 100644 --- a/system/cle/cle.c +++ b/system/cle/cle.c @@ -172,8 +172,8 @@ struct cle_s uint16_t coloffs; /* Left cursor offset */ uint16_t linelen; /* Size of the line buffer */ uint16_t nchars; /* Size of data in the line buffer */ - int infd; /* Input file descriptor */ - int outfd; /* Output file descriptor */ + FAR FILE *ins; /* Input file stream */ + FAR FILE *outs; /* Output file stream */ FAR char *line; /* Line buffer */ FAR const char *prompt; /* Prompt, in case we have to re-print it */ }; @@ -297,9 +297,9 @@ static void cle_write(FAR struct cle_s *priv, FAR const char *buffer, do { - /* Take the next gulp */ + /* Put the next gulp */ - nwritten = write(priv->outfd, buffer, buflen); + nwritten = fwrite(buffer, sizeof(char), buflen, priv->outs); /* Handle write errors. write() should neve return 0. */ @@ -327,6 +327,8 @@ static void cle_write(FAR struct cle_s *priv, FAR const char *buffer, } } while (nremaining > 0); + + fflush(priv->outs); } /**************************************************************************** @@ -363,7 +365,7 @@ static int cle_getch(FAR struct cle_s *priv) { /* Read one character from the incoming stream */ - nread = read(priv->infd, &buffer, 1); + nread = fread (&buffer, sizeof(char), 1, priv->ins); /* Check for error or end-of-file. */ @@ -520,118 +522,70 @@ static int cle_getcursor(FAR struct cle_s *priv, FAR uint16_t *prow, cle_write(priv, g_getcursor, sizeof(g_getcursor)); - /* We expect to get ESC[v;hR where v is the row and h is the column */ + /* We expect to get back ESC[v;hR where v is the row and h is the column. + * once the sequence has started we don't expect any characters + * interspersed. + */ - nbad = 0; - for (; ; ) + for (nbad = 0; nbad < 10; nbad++) { - /* Get the next character from the input */ + /* Look for initial ESC */ ch = cle_getch(priv); - if (ch == ASCII_ESC) + if (ch != ASCII_ESC) { - break; + continue; } - else if (ch < 0) - { - return -EIO; - } - else if (++nbad > 3) - { - /* We are probably talking to a non-VT100 terminal! */ - return -EINVAL; - } - } - - /* Have ESC, now we expect '[' */ - - nbad = 0; - for (; ; ) - { - /* Get the next character from the input */ + /* Have ESC, now we expect '[' */ ch = cle_getch(priv); - if (ch == '[') + if (ch != '[') { - break; + continue; } - else if (ch < 0) + + /* ...now we expect to see a numeric value terminated with ';' */ + + row = 0; + + while (isdigit(ch = cle_getch(priv))) { - return -EIO; + row = row * 10 + (ch - '0'); + } + + if (ch != ';') + { + continue; + } + + /* ...now we expect to see another numeric value terminated with 'R' */ + + column = 0; + while (isdigit(ch = cle_getch(priv))) + { + column = 10 * column + (ch - '0'); + } + + /* ...we are done */ + + cleinfo("row=%ld column=%ld\n", row, column); + + /* Make sure that the values are within range */ + + if (row <= UINT16_MAX && column <= UINT16_MAX) + { + *prow = row; + *pcolumn = column; + return OK; } else { - /* We are probably talking to a non-VT100 terminal! */ - - return -EINVAL; + return -ERANGE; } } - /* Have ESC'['. Now we expect to see a numeric value terminated with ';' */ - - row = 0; - for (; ; ) - { - /* Get the next character from the input */ - - ch = cle_getch(priv); - if (isdigit(ch)) - { - row = 10*row + (ch - '0'); - } - else if (ch == ';') - { - break; - } - else if (ch < 0) - { - return -EIO; - } - else - { - return -EINVAL; - } - } - - /* Have ESC'['v';'. Now we expect to see another numeric value terminated with 'R' */ - - column = 0; - for (; ; ) - { - /* Get the next character from the input */ - - ch = cle_getch(priv); - if (isdigit(ch)) - { - column = 10*column + (ch - '0'); - } - else if (ch == 'R') - { - break; - } - else if (ch < 0) - { - return -EIO; - } - else - { - return -EINVAL; - } - } - - cleinfo("row=%ld column=%ld\n", row, column); - - /* Make sure that the values are within range */ - - if (row <= UINT16_MAX && column <= UINT16_MAX) - { - *prow = row; - *pcolumn = column; - return OK; - } - - return -ERANGE; + return -EINVAL; } /**************************************************************************** @@ -891,8 +845,8 @@ static int cle_editloop(FAR struct cle_s *priv) case '3': /* ESC[3~ = DEL */ { state = ch; + continue; } - continue; case 'A': { @@ -943,6 +897,7 @@ static int cle_editloop(FAR struct cle_s *priv) { ch = KEY_ENDLINE; } + break; /* Break the 'for' loop */ } else if (state == '3') @@ -951,6 +906,7 @@ static int cle_editloop(FAR struct cle_s *priv) { ch = KEY_DEL; } + break; /* Break the 'for' loop */ } else @@ -996,6 +952,7 @@ static int cle_editloop(FAR struct cle_s *priv) { g_cmd_history_steps_from_head = -(g_cmd_history_len - 1); } + break; case KEY_DN: @@ -1008,6 +965,7 @@ static int cle_editloop(FAR struct cle_s *priv) { g_cmd_history_steps_from_head = 1; } + break; default: @@ -1043,6 +1001,7 @@ static int cle_editloop(FAR struct cle_s *priv) priv->curpos = priv->nchars; } + continue; } } @@ -1226,10 +1185,8 @@ int cle(FAR char *line, const char *prompt, uint16_t linelen, priv.linelen = linelen; priv.line = line; - /* REVISIT: Non-standard, non-portable */ - - priv.infd = instream->fs_fd; - priv.outfd = outstream->fs_fd; + priv.ins = instream; + priv.outs = outstream; /* Store the prompt in case we need to re-print it */ @@ -1239,6 +1196,7 @@ int cle(FAR char *line, const char *prompt, uint16_t linelen, /* Get the current cursor position */ ret = cle_getcursor(&priv, &priv.row, &column); + if (ret < 0) { return ret;