]> Git Repo - J-u-boot.git/blobdiff - common/cli_readline.c
bloblist: check bloblist with specified buffer size
[J-u-boot.git] / common / cli_readline.c
index 61f9ba99068a1171b342e1b6331351a7ab04d06b..2507be2295269a64b9eefe50ba4572c5e4111337 100644 (file)
@@ -12,6 +12,8 @@
 #include <bootretry.h>
 #include <cli.h>
 #include <command.h>
+#include <hang.h>
+#include <malloc.h>
 #include <time.h>
 #include <watchdog.h>
 #include <asm/global_data.h>
@@ -85,23 +87,35 @@ static int hist_cur = -1;
 static unsigned hist_num;
 
 static char *hist_list[HIST_MAX];
-static char hist_lines[HIST_MAX][HIST_SIZE + 1];       /* Save room for NULL */
 
 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
 
-static void hist_init(void)
+static void getcmd_putchars(int count, int ch)
 {
        int i;
 
+       for (i = 0; i < count; i++)
+               getcmd_putch(ch);
+}
+
+static int hist_init(void)
+{
+       unsigned char *hist;
+       int i;
+
        hist_max = 0;
        hist_add_idx = 0;
        hist_cur = -1;
        hist_num = 0;
 
-       for (i = 0; i < HIST_MAX; i++) {
-               hist_list[i] = hist_lines[i];
-               hist_list[i][0] = '\0';
-       }
+       hist = calloc(HIST_MAX, HIST_SIZE + 1);
+       if (!hist)
+               return -ENOMEM;
+
+       for (i = 0; i < HIST_MAX; i++)
+               hist_list[i] = hist + (i * (HIST_SIZE + 1));
+
+       return 0;
 }
 
 static void cread_add_to_hist(char *line)
@@ -163,7 +177,7 @@ static char *hist_next(void)
 void cread_print_hist_list(void)
 {
        int i;
-       unsigned long n;
+       uint n;
 
        n = hist_num - hist_max;
 
@@ -180,33 +194,33 @@ void cread_print_hist_list(void)
 }
 
 #define BEGINNING_OF_LINE() {                  \
-       while (num) {                           \
+       while (cls->num) {                      \
                getcmd_putch(CTL_BACKSPACE);    \
-               num--;                          \
+               cls->num--;                     \
        }                                       \
 }
 
 #define ERASE_TO_EOL() {                               \
-       if (num < eol_num) {                            \
-               printf("%*s", (int)(eol_num - num), ""); \
+       if (cls->num < cls->eol_num) {          \
+               printf("%*s", (int)(cls->eol_num - cls->num), ""); \
                do {                                    \
                        getcmd_putch(CTL_BACKSPACE);    \
-               } while (--eol_num > num);              \
+               } while (--cls->eol_num > cls->num);    \
        }                                               \
 }
 
-#define REFRESH_TO_EOL() {                     \
-       if (num < eol_num) {                    \
-               wlen = eol_num - num;           \
-               putnstr(buf + num, wlen);       \
-               num = eol_num;                  \
-       }                                       \
+#define REFRESH_TO_EOL() {                             \
+       if (cls->num < cls->eol_num) {                  \
+               uint wlen = cls->eol_num - cls->num;    \
+               putnstr(buf + cls->num, wlen);          \
+               cls->num = cls->eol_num;                \
+       }                                               \
 }
 
-static void cread_add_char(char ichar, int insert, unsigned long *num,
-              unsigned long *eol_num, char *buf, unsigned long len)
+static void cread_add_char(char ichar, int insert, uint *num,
+                          uint *eol_num, char *buf, uint len)
 {
-       unsigned long wlen;
+       uint wlen;
 
        /* room ??? */
        if (insert || *num == *eol_num) {
@@ -237,8 +251,7 @@ static void cread_add_char(char ichar, int insert, unsigned long *num,
 }
 
 static void cread_add_str(char *str, int strsize, int insert,
-                         unsigned long *num, unsigned long *eol_num,
-                         char *buf, unsigned long len)
+                         uint *num, uint *eol_num, char *buf, uint len)
 {
        while (strsize--) {
                cread_add_char(*str, insert, num, eol_num, buf, len);
@@ -246,121 +259,115 @@ static void cread_add_str(char *str, int strsize, int insert,
        }
 }
 
-static int cread_line(const char *const prompt, char *buf, unsigned int *len,
-               int timeout)
+int cread_line_process_ch(struct cli_line_state *cls, char ichar)
 {
-       struct cli_ch_state s_cch, *cch = &s_cch;
-       unsigned long num = 0;
-       unsigned long eol_num = 0;
-       unsigned long wlen;
-       char ichar;
-       int insert = 1;
-       int init_len = strlen(buf);
-       int first = 1;
-
-       cli_ch_init(cch);
+       char *buf = cls->buf;
 
-       if (init_len)
-               cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
+       /* ichar=0x0 when error occurs in U-Boot getc */
+       if (!ichar)
+               return -EAGAIN;
 
-       while (1) {
-               /* Check for saved characters */
-               ichar = cli_ch_process(cch, 0);
-
-               if (!ichar) {
-                       if (bootretry_tstc_timeout())
-                               return -2;      /* timed out */
-                       if (first && timeout) {
-                               u64 etime = endtick(timeout);
-
-                               while (!tstc()) {       /* while no incoming data */
-                                       if (get_ticks() >= etime)
-                                               return -2;      /* timed out */
-                                       schedule();
-                               }
-                               first = 0;
-                       }
+       if (ichar == '\n') {
+               putc('\n');
+               buf[cls->eol_num] = '\0';       /* terminate the string */
+               return 0;
+       }
 
-                       ichar = getcmd_getch();
-                       ichar = cli_ch_process(cch, ichar);
+       switch (ichar) {
+       case CTL_CH('a'):
+               BEGINNING_OF_LINE();
+               break;
+       case CTL_CH('c'):       /* ^C - break */
+               *buf = '\0';    /* discard input */
+               return -EINTR;
+       case CTL_CH('f'):
+               if (cls->num < cls->eol_num) {
+                       getcmd_putch(buf[cls->num]);
+                       cls->num++;
                }
-
-               /* ichar=0x0 when error occurs in U-Boot getc */
-               if (!ichar)
-                       continue;
-
-               if (ichar == '\n') {
-                       putc('\n');
-                       break;
+               break;
+       case CTL_CH('b'):
+               if (cls->num) {
+                       getcmd_putch(CTL_BACKSPACE);
+                       cls->num--;
                }
-
-               switch (ichar) {
-               case CTL_CH('a'):
-                       BEGINNING_OF_LINE();
-                       break;
-               case CTL_CH('c'):       /* ^C - break */
-                       *buf = '\0';    /* discard input */
-                       return -1;
-               case CTL_CH('f'):
-                       if (num < eol_num) {
-                               getcmd_putch(buf[num]);
-                               num++;
-                       }
-                       break;
-               case CTL_CH('b'):
-                       if (num) {
-                               getcmd_putch(CTL_BACKSPACE);
-                               num--;
+               break;
+       case CTL_CH('d'):
+               if (cls->num < cls->eol_num) {
+                       uint wlen;
+
+                       wlen = cls->eol_num - cls->num - 1;
+                       if (wlen) {
+                               memmove(&buf[cls->num], &buf[cls->num + 1],
+                                       wlen);
+                               putnstr(buf + cls->num, wlen);
                        }
-                       break;
-               case CTL_CH('d'):
-                       if (num < eol_num) {
-                               wlen = eol_num - num - 1;
-                               if (wlen) {
-                                       memmove(&buf[num], &buf[num+1], wlen);
-                                       putnstr(buf + num, wlen);
-                               }
 
-                               getcmd_putch(' ');
-                               do {
-                                       getcmd_putch(CTL_BACKSPACE);
-                               } while (wlen--);
-                               eol_num--;
-                       }
-                       break;
-               case CTL_CH('k'):
-                       ERASE_TO_EOL();
-                       break;
-               case CTL_CH('e'):
-                       REFRESH_TO_EOL();
-                       break;
-               case CTL_CH('o'):
-                       insert = !insert;
-                       break;
-               case CTL_CH('x'):
-               case CTL_CH('u'):
-                       BEGINNING_OF_LINE();
-                       ERASE_TO_EOL();
-                       break;
-               case DEL:
-               case DEL7:
-               case 8:
-                       if (num) {
-                               wlen = eol_num - num;
-                               num--;
-                               memmove(&buf[num], &buf[num+1], wlen);
+                       getcmd_putch(' ');
+                       do {
                                getcmd_putch(CTL_BACKSPACE);
-                               putnstr(buf + num, wlen);
-                               getcmd_putch(' ');
-                               do {
-                                       getcmd_putch(CTL_BACKSPACE);
-                               } while (wlen--);
-                               eol_num--;
-                       }
-                       break;
-               case CTL_CH('p'):
-               case CTL_CH('n'):
-               {
+                       } while (wlen--);
+                       cls->eol_num--;
+               }
+               break;
+       case CTL_CH('k'):
+               ERASE_TO_EOL();
+               break;
+       case CTL_CH('e'):
+               REFRESH_TO_EOL();
+               break;
+       case CTL_CH('o'):
+               cls->insert = !cls->insert;
+               break;
+       case CTL_CH('w'):
+               if (cls->num) {
+                       uint base, wlen;
+
+                       for (base = cls->num - 1;
+                            base >= 0 && buf[base] == ' ';)
+                               base--;
+                       for (; base > 0 && buf[base - 1] != ' ';)
+                               base--;
+
+                       /* now delete chars from base to cls->num */
+                       wlen = cls->num - base;
+                       cls->eol_num -= wlen;
+                       memmove(&buf[base], &buf[cls->num],
+                               cls->eol_num - base + 1);
+                       cls->num = base;
+                       getcmd_putchars(wlen, CTL_BACKSPACE);
+                       puts(buf + base);
+                       getcmd_putchars(wlen, ' ');
+                       getcmd_putchars(wlen + cls->eol_num - cls->num,
+                                       CTL_BACKSPACE);
+               }
+               break;
+       case CTL_CH('x'):
+       case CTL_CH('u'):
+               BEGINNING_OF_LINE();
+               ERASE_TO_EOL();
+               break;
+       case DEL:
+       case DEL7:
+       case 8:
+               if (cls->num) {
+                       uint wlen;
+
+                       wlen = cls->eol_num - cls->num;
+                       cls->num--;
+                       memmove(&buf[cls->num], &buf[cls->num + 1], wlen);
+                       getcmd_putch(CTL_BACKSPACE);
+                       putnstr(buf + cls->num, wlen);
+                       getcmd_putch(' ');
+                       do {
+                               getcmd_putch(CTL_BACKSPACE);
+                       } while (wlen--);
+                       cls->eol_num--;
+               }
+               break;
+       case CTL_CH('p'):
+       case CTL_CH('n'):
+               if (cls->history) {
                        char *hline;
 
                        if (ichar == CTL_CH('p'))
@@ -370,7 +377,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len,
 
                        if (!hline) {
                                getcmd_cbeep();
-                               continue;
+                               break;
                        }
 
                        /* nuke the current line */
@@ -382,39 +389,106 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len,
 
                        /* copy new line into place and display */
                        strcpy(buf, hline);
-                       eol_num = strlen(buf);
+                       cls->eol_num = strlen(buf);
                        REFRESH_TO_EOL();
-                       continue;
+                       break;
                }
-#ifdef CONFIG_AUTO_COMPLETE
-               case '\t': {
+               break;
+       case '\t':
+               if (IS_ENABLED(CONFIG_AUTO_COMPLETE) && cls->cmd_complete) {
                        int num2, col;
 
                        /* do not autocomplete when in the middle */
-                       if (num < eol_num) {
+                       if (cls->num < cls->eol_num) {
                                getcmd_cbeep();
                                break;
                        }
 
-                       buf[num] = '\0';
-                       col = strlen(prompt) + eol_num;
-                       num2 = num;
-                       if (cmd_auto_complete(prompt, buf, &num2, &col)) {
-                               col = num2 - num;
-                               num += col;
-                               eol_num += col;
+                       buf[cls->num] = '\0';
+                       col = strlen(cls->prompt) + cls->eol_num;
+                       num2 = cls->num;
+                       if (cmd_auto_complete(cls->prompt, buf, &num2, &col)) {
+                               col = num2 - cls->num;
+                               cls->num += col;
+                               cls->eol_num += col;
                        }
                        break;
                }
-#endif
-               default:
-                       cread_add_char(ichar, insert, &num, &eol_num, buf,
-                                      *len);
-                       break;
+               fallthrough;
+       default:
+               cread_add_char(ichar, cls->insert, &cls->num, &cls->eol_num,
+                              buf, cls->len);
+               break;
+       }
+
+       /*
+        * keep the string terminated...if we added a char at the end then we
+        * want a \0 after it
+        */
+       buf[cls->eol_num] = '\0';
+
+       return -EAGAIN;
+}
+
+void cli_cread_init(struct cli_line_state *cls, char *buf, uint buf_size)
+{
+       int init_len = strlen(buf);
+
+       memset(cls, '\0', sizeof(struct cli_line_state));
+       cls->insert = true;
+       cls->buf = buf;
+       cls->len = buf_size;
+
+       if (init_len)
+               cread_add_str(buf, init_len, 0, &cls->num, &cls->eol_num, buf,
+                             buf_size);
+}
+
+static int cread_line(const char *const prompt, char *buf, unsigned int *len,
+                     int timeout)
+{
+       struct cli_ch_state s_cch, *cch = &s_cch;
+       struct cli_line_state s_cls, *cls = &s_cls;
+       char ichar;
+       int first = 1;
+
+       cli_ch_init(cch);
+       cli_cread_init(cls, buf, *len);
+       cls->prompt = prompt;
+       cls->history = true;
+       cls->cmd_complete = true;
+
+       while (1) {
+               int ret;
+
+               /* Check for saved characters */
+               ichar = cli_ch_process(cch, 0);
+
+               if (!ichar) {
+                       if (bootretry_tstc_timeout())
+                               return -2;      /* timed out */
+                       if (first && timeout) {
+                               u64 etime = endtick(timeout);
+
+                               while (!tstc()) {       /* while no incoming data */
+                                       if (get_ticks() >= etime)
+                                               return -2;      /* timed out */
+                                       schedule();
+                               }
+                               first = 0;
+                       }
+
+                       ichar = getcmd_getch();
+                       ichar = cli_ch_process(cch, ichar);
                }
+
+               ret = cread_line_process_ch(cls, ichar);
+               if (ret == -EINTR)
+                       return -1;
+               else if (!ret)
+                       break;
        }
-       *len = eol_num;
-       buf[eol_num] = '\0';    /* lose the newline */
+       *len = cls->eol_num;
 
        if (buf[0] && buf[0] != CREAD_HIST_CHAR)
                cread_add_to_hist(buf);
@@ -425,8 +499,9 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len,
 
 #else /* !CONFIG_CMDLINE_EDITING */
 
-static inline void hist_init(void)
+static inline int hist_init(void)
 {
+       return 0;
 }
 
 static int cread_line(const char *const prompt, char *buf, unsigned int *len,
@@ -465,7 +540,7 @@ static int cread_line_simple(const char *const prompt, char *p)
        int n = 0;              /* buffer index */
        int plen = 0;           /* prompt length */
        int col;                /* output column cnt */
-       char c;
+       int c;
 
        /* print prompt */
        if (prompt) {
@@ -519,14 +594,15 @@ static int cread_line_simple(const char *const prompt, char *p)
                        continue;
 
                default:
-                       /*
-                        * Must be a normal character then
-                        */
-                       if (n < CONFIG_SYS_CBSIZE-2) {
-                               if (c == '\t') {        /* expand TABs */
-#ifdef CONFIG_AUTO_COMPLETE
+                       /* Must be a normal character then */
+                       if (n >= CONFIG_SYS_CBSIZE - 2) { /* Buffer full */
+                               putc('\a');
+                               break;
+                       }
+                       if (c == '\t') {        /* expand TABs */
+                               if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) {
                                        /*
-                                        * if auto completion triggered just
+                                        * if auto-completion triggered just
                                         * continue
                                         */
                                        *p = '\0';
@@ -536,26 +612,24 @@ static int cread_line_simple(const char *const prompt, char *p)
                                                p = p_buf + n;  /* reset */
                                                continue;
                                        }
-#endif
-                                       puts(tab_seq + (col & 07));
-                                       col += 8 - (col & 07);
-                               } else {
-                                       char __maybe_unused buf[2];
-
-                                       /*
-                                        * Echo input using puts() to force an
-                                        * LCD flush if we are using an LCD
-                                        */
-                                       ++col;
-                                       buf[0] = c;
-                                       buf[1] = '\0';
-                                       puts(buf);
                                }
-                               *p++ = c;
-                               ++n;
-                       } else {                        /* Buffer full */
-                               putc('\a');
+                               puts(tab_seq + (col & 07));
+                               col += 8 - (col & 07);
+                       } else {
+                               char __maybe_unused buf[2];
+
+                               /*
+                                * Echo input using puts() to force an LCD
+                                * flush if we are using an LCD
+                                */
+                               ++col;
+                               buf[0] = c;
+                               buf[1] = '\0';
+                               puts(buf);
                        }
+                       *p++ = c;
+                       ++n;
+                       break;
                }
        }
 }
@@ -576,8 +650,9 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer,
         */
        if (IS_ENABLED(CONFIG_CMDLINE_EDITING) && (gd->flags & GD_FLG_RELOC)) {
                if (!initted) {
-                       hist_init();
-                       initted = 1;
+                       rc = hist_init();
+                       if (rc == 0)
+                               initted = 1;
                }
 
                if (prompt)
This page took 0.048157 seconds and 4 git commands to generate.