3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * Add to readline cmdline-editing by
7 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
9 * SPDX-License-Identifier: GPL-2.0+
16 DECLARE_GLOBAL_DATA_PTR;
18 static const char erase_seq[] = "\b \b"; /* erase sequence */
19 static const char tab_seq[] = " "; /* used to expand TABs */
21 #ifdef CONFIG_BOOT_RETRY_TIME
22 static uint64_t endtime; /* must be set, default is instant timeout */
23 static int retry_time = -1; /* -1 so can call readline before main_loop */
26 char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
28 #ifndef CONFIG_BOOT_RETRY_MIN
29 #define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
32 static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen)
39 if (*(--p) == '\t') { /* will retype the whole line */
40 while (*colp > plen) {
44 for (s = buffer; s < p; ++s) {
46 puts(tab_seq + ((*colp) & 07));
47 *colp += 8 - ((*colp) & 07);
62 #ifdef CONFIG_CMDLINE_EDITING
65 * cmdline-editing related codes from vivi.
66 * Author: Janghoon Lyu <nandy@mizi.com>
69 #define putnstr(str, n) printf("%.*s", (int)n, str)
71 #define CTL_CH(c) ((c) - 'a' + 1)
72 #define CTL_BACKSPACE ('\b')
73 #define DEL ((char)255)
74 #define DEL7 ((char)127)
75 #define CREAD_HIST_CHAR ('!')
77 #define getcmd_putch(ch) putc(ch)
78 #define getcmd_getch() getc()
79 #define getcmd_cbeep() getcmd_putch('\a')
82 #define HIST_SIZE CONFIG_SYS_CBSIZE
85 static int hist_add_idx;
86 static int hist_cur = -1;
87 static unsigned hist_num;
89 static char *hist_list[HIST_MAX];
90 static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
92 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
94 static void hist_init(void)
103 for (i = 0; i < HIST_MAX; i++) {
104 hist_list[i] = hist_lines[i];
105 hist_list[i][0] = '\0';
109 static void cread_add_to_hist(char *line)
111 strcpy(hist_list[hist_add_idx], line);
113 if (++hist_add_idx >= HIST_MAX)
116 if (hist_add_idx > hist_max)
117 hist_max = hist_add_idx;
122 static char *hist_prev(void)
134 if (hist_cur == hist_add_idx) {
138 ret = hist_list[hist_cur];
144 static char *hist_next(void)
151 if (hist_cur == hist_add_idx)
154 if (++hist_cur > hist_max)
157 if (hist_cur == hist_add_idx)
160 ret = hist_list[hist_cur];
165 #ifndef CONFIG_CMDLINE_EDITING
166 static void cread_print_hist_list(void)
171 n = hist_num - hist_max;
173 i = hist_add_idx + 1;
177 if (i == hist_add_idx)
179 printf("%s\n", hist_list[i]);
184 #endif /* CONFIG_CMDLINE_EDITING */
186 #define BEGINNING_OF_LINE() { \
188 getcmd_putch(CTL_BACKSPACE); \
193 #define ERASE_TO_EOL() { \
194 if (num < eol_num) { \
195 printf("%*s", (int)(eol_num - num), ""); \
197 getcmd_putch(CTL_BACKSPACE); \
198 } while (--eol_num > num); \
202 #define REFRESH_TO_EOL() { \
203 if (num < eol_num) { \
204 wlen = eol_num - num; \
205 putnstr(buf + num, wlen); \
210 static void cread_add_char(char ichar, int insert, unsigned long *num,
211 unsigned long *eol_num, char *buf, unsigned long len)
216 if (insert || *num == *eol_num) {
217 if (*eol_num > len - 1) {
225 wlen = *eol_num - *num;
227 memmove(&buf[*num+1], &buf[*num], wlen-1);
230 putnstr(buf + *num, wlen);
233 getcmd_putch(CTL_BACKSPACE);
235 /* echo the character */
238 putnstr(buf + *num, wlen);
243 static void cread_add_str(char *str, int strsize, int insert,
244 unsigned long *num, unsigned long *eol_num,
245 char *buf, unsigned long len)
248 cread_add_char(*str, insert, num, eol_num, buf, len);
253 static int cread_line(const char *const prompt, char *buf, unsigned int *len,
256 unsigned long num = 0;
257 unsigned long eol_num = 0;
263 int init_len = strlen(buf);
267 cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
270 #ifdef CONFIG_BOOT_RETRY_TIME
271 while (!tstc()) { /* while no incoming data */
272 if (retry_time >= 0 && get_ticks() > endtime)
273 return -2; /* timed out */
277 if (first && timeout) {
278 uint64_t etime = endtick(timeout);
280 while (!tstc()) { /* while no incoming data */
281 if (get_ticks() >= etime)
282 return -2; /* timed out */
288 ichar = getcmd_getch();
290 if ((ichar == '\n') || (ichar == '\r')) {
296 * handle standard linux xterm esc sequences for arrow key, etc.
301 esc_save[esc_len] = ichar;
304 cread_add_str(esc_save, esc_len,
305 insert, &num, &eol_num,
313 case 'D': /* <- key */
317 case 'C': /* -> key */
320 break; /* pass off to ^F handler */
321 case 'H': /* Home key */
324 break; /* pass off to ^A handler */
325 case 'A': /* up arrow */
328 break; /* pass off to ^P handler */
329 case 'B': /* down arrow */
332 break; /* pass off to ^N handler */
334 esc_save[esc_len++] = ichar;
335 cread_add_str(esc_save, esc_len, insert,
336 &num, &eol_num, buf, *len);
345 esc_save[esc_len] = ichar;
348 puts("impossible condition #876\n");
356 case CTL_CH('c'): /* ^C - break */
357 *buf = '\0'; /* discard input */
361 getcmd_putch(buf[num]);
367 getcmd_putch(CTL_BACKSPACE);
373 wlen = eol_num - num - 1;
375 memmove(&buf[num], &buf[num+1], wlen);
376 putnstr(buf + num, wlen);
381 getcmd_putch(CTL_BACKSPACE);
404 wlen = eol_num - num;
406 memmove(&buf[num], &buf[num+1], wlen);
407 getcmd_putch(CTL_BACKSPACE);
408 putnstr(buf + num, wlen);
411 getcmd_putch(CTL_BACKSPACE);
423 if (ichar == CTL_CH('p'))
433 /* nuke the current line */
437 /* erase to end of line */
440 /* copy new line into place and display */
442 eol_num = strlen(buf);
446 #ifdef CONFIG_AUTO_COMPLETE
450 /* do not autocomplete when in the middle */
457 col = strlen(prompt) + eol_num;
459 if (cmd_auto_complete(prompt, buf, &num2, &col)) {
468 cread_add_char(ichar, insert, &num, &eol_num, buf,
474 buf[eol_num] = '\0'; /* lose the newline */
476 if (buf[0] && buf[0] != CREAD_HIST_CHAR)
477 cread_add_to_hist(buf);
478 hist_cur = hist_add_idx;
483 #endif /* CONFIG_CMDLINE_EDITING */
485 /****************************************************************************/
487 int readline(const char *const prompt)
490 * If console_buffer isn't 0-length the user will be prompted to modify
491 * it instead of entering it from scratch as desired.
493 console_buffer[0] = '\0';
495 return readline_into_buffer(prompt, console_buffer, 0);
499 int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
502 #ifdef CONFIG_CMDLINE_EDITING
503 unsigned int len = CONFIG_SYS_CBSIZE;
508 * History uses a global array which is not
509 * writable until after relocation to RAM.
510 * Revert to non-history version if still
511 * running from flash.
513 if (gd->flags & GD_FLG_RELOC) {
522 rc = cread_line(prompt, p, &len, timeout);
523 return rc < 0 ? rc : len;
526 #endif /* CONFIG_CMDLINE_EDITING */
528 int n = 0; /* buffer index */
529 int plen = 0; /* prompt length */
530 int col; /* output column cnt */
535 plen = strlen(prompt);
541 #ifdef CONFIG_BOOT_RETRY_TIME
542 while (!tstc()) { /* while no incoming data */
543 if (retry_time >= 0 && get_ticks() > endtime)
544 return -2; /* timed out */
548 WATCHDOG_RESET(); /* Trigger watchdog, if needed */
550 #ifdef CONFIG_SHOW_ACTIVITY
559 * Special character handling
562 case '\r': /* Enter */
571 case 0x03: /* ^C - break */
572 p_buf[0] = '\0'; /* discard input */
575 case 0x15: /* ^U - erase line */
584 case 0x17: /* ^W - erase word */
585 p = delete_char(p_buf, p, &col, &n, plen);
586 while ((n > 0) && (*p != ' '))
587 p = delete_char(p_buf, p, &col, &n, plen);
590 case 0x08: /* ^H - backspace */
591 case 0x7F: /* DEL - backspace */
592 p = delete_char(p_buf, p, &col, &n, plen);
597 * Must be a normal character then
599 if (n < CONFIG_SYS_CBSIZE-2) {
600 if (c == '\t') { /* expand TABs */
601 #ifdef CONFIG_AUTO_COMPLETE
603 * if auto completion triggered just
607 if (cmd_auto_complete(prompt,
610 p = p_buf + n; /* reset */
614 puts(tab_seq + (col & 07));
615 col += 8 - (col & 07);
620 * Echo input using puts() to force an
621 * LCD flush if we are using an LCD
630 } else { /* Buffer full */
635 #ifdef CONFIG_CMDLINE_EDITING
640 #ifdef CONFIG_BOOT_RETRY_TIME
641 /***************************************************************************
642 * initialize command line timeout
644 void init_cmd_timeout(void)
646 char *s = getenv("bootretry");
649 retry_time = (int)simple_strtol(s, NULL, 10);
651 retry_time = CONFIG_BOOT_RETRY_TIME;
653 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
654 retry_time = CONFIG_BOOT_RETRY_MIN;
657 /***************************************************************************
658 * reset command line timeout to retry_time seconds
660 void reset_cmd_timeout(void)
662 endtime = endtick(retry_time);
665 void bootretry_dont_retry(void)