MINI2440:Fixes for gcc 4.x
[u-boot-openmoko/mini2440.git] / common / main.c
blob15d52aa392f015ed59ee9e6bb89d8a04fdb3716e
1 /*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * Add to readline cmdline-editing by
6 * (C) Copyright 2005
7 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
9 * See file CREDITS for list of people who contributed to this
10 * project.
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
28 /* #define DEBUG */
30 #include <common.h>
31 #include <watchdog.h>
32 #include <command.h>
33 #ifdef CONFIG_MODEM_SUPPORT
34 #include <malloc.h> /* for free() prototype */
35 #endif
37 #ifdef CFG_HUSH_PARSER
38 #include <hush.h>
39 #endif
41 #include <post.h>
43 #if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST)
44 DECLARE_GLOBAL_DATA_PTR;
45 #endif
48 * Board-specific Platform code can reimplement show_boot_progress () if needed
50 #ifndef CONFIG_MINI2440
51 void inline __show_boot_progress (int val) {}
52 void inline show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
53 #else
54 void inline show_boot_progress (int val) {}
55 #endif
57 #if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
58 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); /* for do_reset() prototype */
59 #endif
61 extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
64 #define MAX_DELAY_STOP_STR 32
66 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
67 static int abortboot(int);
68 #endif
70 #undef DEBUG_PARSER
72 char console_buffer[CFG_CBSIZE]; /* console I/O buffer */
73 int nobootdelay;
75 #ifndef CONFIG_CMDLINE_EDITING
76 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
77 static char erase_seq[] = "\b \b"; /* erase sequence */
78 static char tab_seq[] = " "; /* used to expand TABs */
79 #endif /* CONFIG_CMDLINE_EDITING */
81 #ifdef CONFIG_BOOT_RETRY_TIME
82 static uint64_t endtime = 0; /* must be set, default is instant timeout */
83 static int retry_time = -1; /* -1 so can call readline before main_loop */
84 #endif
86 #define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
88 #ifndef CONFIG_BOOT_RETRY_MIN
89 #define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
90 #endif
92 #ifdef CONFIG_MODEM_SUPPORT
93 int do_mdm_init = 0;
94 extern void mdm_init(void); /* defined in board.c */
95 #endif
97 #ifdef CFG_PREBOOT_OVERRIDE
98 extern char *preboot_override;
99 #endif
102 /***************************************************************************
103 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
104 * returns: 0 - no key string, allow autoboot
105 * 1 - got key string, abort
107 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
108 # if defined(CONFIG_AUTOBOOT_KEYED)
109 static __inline__ int abortboot(int bootdelay)
111 int abort = 0;
112 uint64_t etime = endtick(bootdelay);
113 struct {
114 char* str;
115 u_int len;
116 int retry;
118 delaykey [] = {
119 { str: getenv ("bootdelaykey"), retry: 1 },
120 { str: getenv ("bootdelaykey2"), retry: 1 },
121 { str: getenv ("bootstopkey"), retry: 0 },
122 { str: getenv ("bootstopkey2"), retry: 0 },
125 char presskey [MAX_DELAY_STOP_STR];
126 u_int presskey_len = 0;
127 u_int presskey_max = 0;
128 u_int i;
130 # ifdef CONFIG_AUTOBOOT_PROMPT
131 printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
132 # endif
134 # ifdef CONFIG_AUTOBOOT_DELAY_STR
135 if (delaykey[0].str == NULL)
136 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
137 # endif
138 # ifdef CONFIG_AUTOBOOT_DELAY_STR2
139 if (delaykey[1].str == NULL)
140 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
141 # endif
142 # ifdef CONFIG_AUTOBOOT_STOP_STR
143 if (delaykey[2].str == NULL)
144 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
145 # endif
146 # ifdef CONFIG_AUTOBOOT_STOP_STR2
147 if (delaykey[3].str == NULL)
148 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
149 # endif
151 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
152 delaykey[i].len = delaykey[i].str == NULL ?
153 0 : strlen (delaykey[i].str);
154 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
155 MAX_DELAY_STOP_STR : delaykey[i].len;
157 presskey_max = presskey_max > delaykey[i].len ?
158 presskey_max : delaykey[i].len;
160 # if DEBUG_BOOTKEYS
161 printf("%s key:<%s>\n",
162 delaykey[i].retry ? "delay" : "stop",
163 delaykey[i].str ? delaykey[i].str : "NULL");
164 # endif
167 /* In order to keep up with incoming data, check timeout only
168 * when catch up.
170 while (!abort && get_ticks() <= etime) {
171 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
172 if (delaykey[i].len > 0 &&
173 presskey_len >= delaykey[i].len &&
174 memcmp (presskey + presskey_len - delaykey[i].len,
175 delaykey[i].str,
176 delaykey[i].len) == 0) {
177 # if DEBUG_BOOTKEYS
178 printf("got %skey\n",
179 delaykey[i].retry ? "delay" : "stop");
180 # endif
182 # ifdef CONFIG_BOOT_RETRY_TIME
183 /* don't retry auto boot */
184 if (! delaykey[i].retry)
185 retry_time = -1;
186 # endif
187 abort = 1;
191 if (tstc()) {
192 if (presskey_len < presskey_max) {
193 presskey [presskey_len ++] = getc();
195 else {
196 for (i = 0; i < presskey_max - 1; i ++)
197 presskey [i] = presskey [i + 1];
199 presskey [i] = getc();
203 # if DEBUG_BOOTKEYS
204 if (!abort)
205 puts("key timeout\n");
206 # endif
208 #ifdef CONFIG_SILENT_CONSOLE
209 if (abort)
210 gd->flags &= ~GD_FLG_SILENT;
211 #endif
213 return abort;
216 # else /* !defined(CONFIG_AUTOBOOT_KEYED) */
218 #ifdef CONFIG_MENUKEY
219 static int menukey = 0;
220 #endif
222 static __inline__ int abortboot(int bootdelay)
224 int abort = 0;
226 #ifdef CONFIG_MENUPROMPT
227 printf(CONFIG_MENUPROMPT, bootdelay);
228 #else
229 printf("Hit any key to stop autoboot: %2d ", bootdelay);
230 #endif
232 #if defined CONFIG_ZERO_BOOTDELAY_CHECK
234 * Check if key already pressed
235 * Don't check if bootdelay < 0
237 if (bootdelay >= 0) {
238 if (tstc()) { /* we got a key press */
239 (void) getc(); /* consume input */
240 puts ("\b\b\b 0");
241 abort = 1; /* don't auto boot */
244 #endif
246 while ((bootdelay > 0) && (!abort)) {
247 int i;
249 --bootdelay;
250 /* delay 100 * 10ms */
251 for (i=0; !abort && i<100; ++i) {
252 if (tstc()) { /* we got a key press */
253 abort = 1; /* don't auto boot */
254 bootdelay = 0; /* no more delay */
255 # ifdef CONFIG_MENUKEY
256 menukey = getc();
257 # else
258 (void) getc(); /* consume input */
259 # endif
260 break;
262 udelay(10000);
265 printf("\b\b\b%2d ", bootdelay);
268 putc('\n');
270 #ifdef CONFIG_SILENT_CONSOLE
271 if (abort)
272 gd->flags &= ~GD_FLG_SILENT;
273 #endif
275 return abort;
277 # endif /* CONFIG_AUTOBOOT_KEYED */
278 #endif /* CONFIG_BOOTDELAY >= 0 */
280 /****************************************************************************/
282 void main_loop (void)
284 #ifndef CFG_HUSH_PARSER
285 static char lastcommand[CFG_CBSIZE] = { 0, };
286 int len;
287 int rc = 1;
288 int flag;
289 #endif
291 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
292 char *s;
293 int bootdelay;
294 #endif
295 #if defined(CONFIG_PREBOOT) || defined(CFG_PREBOOT_OVERRIDE)
296 char *p = NULL;
297 #endif
298 #ifdef CONFIG_BOOTCOUNT_LIMIT
299 unsigned long bootcount = 0;
300 unsigned long bootlimit = 0;
301 char *bcs;
302 char bcs_set[16];
303 #endif /* CONFIG_BOOTCOUNT_LIMIT */
305 #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
306 ulong bmp = 0; /* default bitmap */
307 extern int trab_vfd (ulong bitmap);
309 #ifdef CONFIG_MODEM_SUPPORT
310 if (do_mdm_init)
311 bmp = 1; /* alternate bitmap */
312 #endif
313 trab_vfd (bmp);
314 #endif /* CONFIG_VFD && VFD_TEST_LOGO */
316 #ifdef CONFIG_BOOTCOUNT_LIMIT
317 bootcount = bootcount_load();
318 bootcount++;
319 bootcount_store (bootcount);
320 sprintf (bcs_set, "%lu", bootcount);
321 setenv ("bootcount", bcs_set);
322 bcs = getenv ("bootlimit");
323 bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
324 #endif /* CONFIG_BOOTCOUNT_LIMIT */
326 #ifdef CONFIG_MODEM_SUPPORT
327 debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
328 if (do_mdm_init) {
329 char *str = strdup(getenv("mdm_cmd"));
330 setenv ("preboot", str); /* set or delete definition */
331 if (str != NULL)
332 free (str);
333 mdm_init(); /* wait for modem connection */
335 #endif /* CONFIG_MODEM_SUPPORT */
337 #ifdef CONFIG_VERSION_VARIABLE
339 extern char version_string[];
341 setenv ("ver", version_string); /* set version variable */
343 #endif /* CONFIG_VERSION_VARIABLE */
345 #ifdef CFG_HUSH_PARSER
346 u_boot_hush_start ();
347 #endif
349 #ifdef CONFIG_AUTO_COMPLETE
350 install_auto_complete();
351 #endif
353 #if defined(CONFIG_PREBOOT) || defined(CFG_PREBOOT_OVERRIDE)
354 #ifdef CONFIG_PREBOOT
355 p = getenv ("preboot");
356 #endif
357 #ifdef CFG_PREBOOT_OVERRIDE
358 if (preboot_override) {
359 /* for convenience, preboot_override may end in \n, not \0 */
360 p = strchr(preboot_override, '\n');
361 if (p)
362 *p = 0;
363 /* make sure we can overwrite the load area if we want to */
364 p = strdup(preboot_override);
365 /* clean the image in case we want to flash it */
366 preboot_override = NULL;
368 #endif /* CFG_PREBOOT_OVERRIDE */
369 if (p) {
370 # ifdef CONFIG_AUTOBOOT_KEYED
371 int prev = disable_ctrlc(1); /* disable Control C checking */
372 # endif
374 # ifndef CFG_HUSH_PARSER
375 run_command (p, 0);
376 # else
377 parse_string_outer(p, FLAG_PARSE_SEMICOLON |
378 FLAG_EXIT_FROM_LOOP);
379 # endif
381 # ifdef CONFIG_AUTOBOOT_KEYED
382 disable_ctrlc(prev); /* restore Control C checking */
383 # endif
385 #endif /* CONFIG_PREBOOT || CFG_PREBOOT_OVERRIDE */
387 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
388 s = getenv ("bootdelay");
389 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
391 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
393 # ifdef CONFIG_BOOT_RETRY_TIME
394 init_cmd_timeout ();
395 # endif /* CONFIG_BOOT_RETRY_TIME */
397 #ifdef CONFIG_POST
398 if (gd->flags & GD_FLG_POSTFAIL) {
399 s = getenv("failbootcmd");
401 else
402 #endif /* CONFIG_POST */
403 #ifdef CONFIG_BOOTCOUNT_LIMIT
404 if (bootlimit && (bootcount > bootlimit)) {
405 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
406 (unsigned)bootlimit);
407 s = getenv ("altbootcmd");
409 else
410 #endif /* CONFIG_BOOTCOUNT_LIMIT */
411 s = getenv ("bootcmd");
413 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
415 if (!nobootdelay && bootdelay >= 0 && s && !abortboot (bootdelay)) {
416 # ifdef CONFIG_AUTOBOOT_KEYED
417 int prev = disable_ctrlc(1); /* disable Control C checking */
418 # endif
420 # ifndef CFG_HUSH_PARSER
421 run_command (s, 0);
422 # else
423 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
424 FLAG_EXIT_FROM_LOOP);
425 # endif
427 # ifdef CONFIG_AUTOBOOT_KEYED
428 disable_ctrlc(prev); /* restore Control C checking */
429 # endif
432 # ifdef CONFIG_MENUKEY
433 if (menukey == CONFIG_MENUKEY) {
434 s = getenv("menucmd");
435 if (s) {
436 # ifndef CFG_HUSH_PARSER
437 run_command (s, 0);
438 # else
439 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
440 FLAG_EXIT_FROM_LOOP);
441 # endif
444 #endif /* CONFIG_MENUKEY */
445 #endif /* CONFIG_BOOTDELAY */
447 #ifdef CONFIG_AMIGAONEG3SE
449 extern void video_banner(void);
450 video_banner();
452 #endif
455 * Main Loop for Monitor Command Processing
457 #ifdef CFG_HUSH_PARSER
458 parse_file_outer();
459 /* This point is never reached */
460 for (;;);
461 #else
462 for (;;) {
463 #ifdef CONFIG_BOOT_RETRY_TIME
464 if (rc >= 0) {
465 /* Saw enough of a valid command to
466 * restart the timeout.
468 reset_cmd_timeout();
470 #endif
471 len = readline (CFG_PROMPT);
473 flag = 0; /* assume no special flags for now */
474 if (len > 0)
475 strcpy (lastcommand, console_buffer);
476 else if (len == 0)
477 flag |= CMD_FLAG_REPEAT;
478 #ifdef CONFIG_BOOT_RETRY_TIME
479 else if (len == -2) {
480 /* -2 means timed out, retry autoboot
482 puts ("\nTimed out waiting for command\n");
483 # ifdef CONFIG_RESET_TO_RETRY
484 /* Reinit board to run initialization code again */
485 do_reset (NULL, 0, 0, NULL);
486 # else
487 return; /* retry autoboot */
488 # endif
490 #endif
492 if (len == -1)
493 puts ("<INTERRUPT>\n");
494 else
495 rc = run_command (lastcommand, flag);
497 if (rc <= 0) {
498 /* invalid command or not repeatable, forget it */
499 lastcommand[0] = 0;
502 #endif /*CFG_HUSH_PARSER*/
505 #ifdef CONFIG_BOOT_RETRY_TIME
506 /***************************************************************************
507 * initialize command line timeout
509 void init_cmd_timeout(void)
511 char *s = getenv ("bootretry");
513 if (s != NULL)
514 retry_time = (int)simple_strtol(s, NULL, 10);
515 else
516 retry_time = CONFIG_BOOT_RETRY_TIME;
518 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
519 retry_time = CONFIG_BOOT_RETRY_MIN;
522 /***************************************************************************
523 * reset command line timeout to retry_time seconds
525 void reset_cmd_timeout(void)
527 endtime = endtick(retry_time);
529 #endif
531 #ifdef CONFIG_CMDLINE_EDITING
534 * cmdline-editing related codes from vivi.
535 * Author: Janghoon Lyu <nandy@mizi.com>
538 #define putnstr(str,n) do { \
539 printf ("%.*s", n, str); \
540 } while (0)
542 #define CTL_CH(c) ((c) - 'a' + 1)
544 #define MAX_CMDBUF_SIZE 256
546 #define CTL_BACKSPACE ('\b')
547 #define DEL ((char)255)
548 #define DEL7 ((char)127)
549 #define CREAD_HIST_CHAR ('!')
551 #define getcmd_putch(ch) putc(ch)
552 #define getcmd_getch() getc()
553 #define getcmd_cbeep() getcmd_putch('\a')
555 #define HIST_MAX 20
556 #define HIST_SIZE MAX_CMDBUF_SIZE
558 static int hist_max = 0;
559 static int hist_add_idx = 0;
560 static int hist_cur = -1;
561 unsigned hist_num = 0;
563 char* hist_list[HIST_MAX];
564 char hist_lines[HIST_MAX][HIST_SIZE];
566 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
568 static void hist_init(void)
570 int i;
572 hist_max = 0;
573 hist_add_idx = 0;
574 hist_cur = -1;
575 hist_num = 0;
577 for (i = 0; i < HIST_MAX; i++) {
578 hist_list[i] = hist_lines[i];
579 hist_list[i][0] = '\0';
583 static void cread_add_to_hist(char *line)
585 strcpy(hist_list[hist_add_idx], line);
587 if (++hist_add_idx >= HIST_MAX)
588 hist_add_idx = 0;
590 if (hist_add_idx > hist_max)
591 hist_max = hist_add_idx;
593 hist_num++;
596 static char* hist_prev(void)
598 char *ret;
599 int old_cur;
601 if (hist_cur < 0)
602 return NULL;
604 old_cur = hist_cur;
605 if (--hist_cur < 0)
606 hist_cur = hist_max;
608 if (hist_cur == hist_add_idx) {
609 hist_cur = old_cur;
610 ret = NULL;
611 } else
612 ret = hist_list[hist_cur];
614 return (ret);
617 static char* hist_next(void)
619 char *ret;
621 if (hist_cur < 0)
622 return NULL;
624 if (hist_cur == hist_add_idx)
625 return NULL;
627 if (++hist_cur > hist_max)
628 hist_cur = 0;
630 if (hist_cur == hist_add_idx) {
631 ret = "";
632 } else
633 ret = hist_list[hist_cur];
635 return (ret);
638 #ifndef CONFIG_CMDLINE_EDITING
639 static void cread_print_hist_list(void)
641 int i;
642 unsigned long n;
644 n = hist_num - hist_max;
646 i = hist_add_idx + 1;
647 while (1) {
648 if (i > hist_max)
649 i = 0;
650 if (i == hist_add_idx)
651 break;
652 printf("%s\n", hist_list[i]);
653 n++;
654 i++;
657 #endif /* CONFIG_CMDLINE_EDITING */
659 #define BEGINNING_OF_LINE() { \
660 while (num) { \
661 getcmd_putch(CTL_BACKSPACE); \
662 num--; \
666 #define ERASE_TO_EOL() { \
667 if (num < eol_num) { \
668 int tmp; \
669 for (tmp = num; tmp < eol_num; tmp++) \
670 getcmd_putch(' '); \
671 while (tmp-- > num) \
672 getcmd_putch(CTL_BACKSPACE); \
673 eol_num = num; \
677 #define REFRESH_TO_EOL() { \
678 if (num < eol_num) { \
679 wlen = eol_num - num; \
680 putnstr(buf + num, wlen); \
681 num = eol_num; \
685 static void cread_add_char(char ichar, int insert, unsigned long *num,
686 unsigned long *eol_num, char *buf, unsigned long len)
688 unsigned long wlen;
690 /* room ??? */
691 if (insert || *num == *eol_num) {
692 if (*eol_num > len - 1) {
693 getcmd_cbeep();
694 return;
696 (*eol_num)++;
699 if (insert) {
700 wlen = *eol_num - *num;
701 if (wlen > 1) {
702 memmove(&buf[*num+1], &buf[*num], wlen-1);
705 buf[*num] = ichar;
706 putnstr(buf + *num, wlen);
707 (*num)++;
708 while (--wlen) {
709 getcmd_putch(CTL_BACKSPACE);
711 } else {
712 /* echo the character */
713 wlen = 1;
714 buf[*num] = ichar;
715 putnstr(buf + *num, wlen);
716 (*num)++;
720 static void cread_add_str(char *str, int strsize, int insert, unsigned long *num,
721 unsigned long *eol_num, char *buf, unsigned long len)
723 while (strsize--) {
724 cread_add_char(*str, insert, num, eol_num, buf, len);
725 str++;
729 static int cread_line(const char *const prompt, char *buf, unsigned int *len)
731 unsigned long num = 0;
732 unsigned long eol_num = 0;
733 unsigned long rlen;
734 unsigned long wlen;
735 char ichar;
736 int insert = 1;
737 int esc_len = 0;
738 int rc = 0;
739 char esc_save[8];
741 while (1) {
742 rlen = 1;
743 #ifdef CONFIG_BOOT_RETRY_TIME
744 while (!tstc()) { /* while no incoming data */
745 if (retry_time >= 0 && get_ticks() > endtime)
746 return (-2); /* timed out */
748 #endif
750 ichar = getcmd_getch();
752 if ((ichar == '\n') || (ichar == '\r')) {
753 putc('\n');
754 break;
758 * handle standard linux xterm esc sequences for arrow key, etc.
760 if (esc_len != 0) {
761 if (esc_len == 1) {
762 if (ichar == '[') {
763 esc_save[esc_len] = ichar;
764 esc_len = 2;
765 } else {
766 cread_add_str(esc_save, esc_len, insert,
767 &num, &eol_num, buf, *len);
768 esc_len = 0;
770 continue;
773 switch (ichar) {
775 case 'D': /* <- key */
776 ichar = CTL_CH('b');
777 esc_len = 0;
778 break;
779 case 'C': /* -> key */
780 ichar = CTL_CH('f');
781 esc_len = 0;
782 break; /* pass off to ^F handler */
783 case 'H': /* Home key */
784 ichar = CTL_CH('a');
785 esc_len = 0;
786 break; /* pass off to ^A handler */
787 case 'A': /* up arrow */
788 ichar = CTL_CH('p');
789 esc_len = 0;
790 break; /* pass off to ^P handler */
791 case 'B': /* down arrow */
792 ichar = CTL_CH('n');
793 esc_len = 0;
794 break; /* pass off to ^N handler */
795 default:
796 esc_save[esc_len++] = ichar;
797 cread_add_str(esc_save, esc_len, insert,
798 &num, &eol_num, buf, *len);
799 esc_len = 0;
800 continue;
804 switch (ichar) {
805 case 0x1b:
806 if (esc_len == 0) {
807 esc_save[esc_len] = ichar;
808 esc_len = 1;
809 } else {
810 puts("impossible condition #876\n");
811 esc_len = 0;
813 break;
815 case CTL_CH('a'):
816 BEGINNING_OF_LINE();
817 break;
818 case CTL_CH('c'): /* ^C - break */
819 *buf = '\0'; /* discard input */
820 return (-1);
821 case CTL_CH('f'):
822 if (num < eol_num) {
823 getcmd_putch(buf[num]);
824 num++;
826 break;
827 case CTL_CH('b'):
828 if (num) {
829 getcmd_putch(CTL_BACKSPACE);
830 num--;
832 break;
833 case CTL_CH('d'):
834 if (num < eol_num) {
835 wlen = eol_num - num - 1;
836 if (wlen) {
837 memmove(&buf[num], &buf[num+1], wlen);
838 putnstr(buf + num, wlen);
841 getcmd_putch(' ');
842 do {
843 getcmd_putch(CTL_BACKSPACE);
844 } while (wlen--);
845 eol_num--;
847 break;
848 case CTL_CH('k'):
849 ERASE_TO_EOL();
850 break;
851 case CTL_CH('e'):
852 REFRESH_TO_EOL();
853 break;
854 case CTL_CH('o'):
855 insert = !insert;
856 break;
857 case CTL_CH('x'):
858 case CTL_CH('u'):
859 BEGINNING_OF_LINE();
860 ERASE_TO_EOL();
861 break;
862 case DEL:
863 case DEL7:
864 case 8:
865 if (num) {
866 wlen = eol_num - num;
867 num--;
868 memmove(&buf[num], &buf[num+1], wlen);
869 getcmd_putch(CTL_BACKSPACE);
870 putnstr(buf + num, wlen);
871 getcmd_putch(' ');
872 do {
873 getcmd_putch(CTL_BACKSPACE);
874 } while (wlen--);
875 eol_num--;
877 break;
878 case CTL_CH('p'):
879 case CTL_CH('n'):
881 char * hline;
883 esc_len = 0;
885 if (ichar == CTL_CH('p'))
886 hline = hist_prev();
887 else
888 hline = hist_next();
890 if (!hline) {
891 getcmd_cbeep();
892 continue;
895 /* nuke the current line */
896 /* first, go home */
897 BEGINNING_OF_LINE();
899 /* erase to end of line */
900 ERASE_TO_EOL();
902 /* copy new line into place and display */
903 strcpy(buf, hline);
904 eol_num = strlen(buf);
905 REFRESH_TO_EOL();
906 continue;
908 #ifdef CONFIG_AUTO_COMPLETE
909 case '\t': {
910 int num2, col;
912 /* do not autocomplete when in the middle */
913 if (num < eol_num) {
914 getcmd_cbeep();
915 break;
918 buf[num] = '\0';
919 col = strlen(prompt) + eol_num;
920 num2 = num;
921 if (cmd_auto_complete(prompt, buf, &num2, &col)) {
922 col = num2 - num;
923 num += col;
924 eol_num += col;
926 break;
928 #endif
929 default:
930 cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
931 break;
934 *len = eol_num;
935 buf[eol_num] = '\0'; /* lose the newline */
937 if (buf[0] && buf[0] != CREAD_HIST_CHAR)
938 cread_add_to_hist(buf);
939 hist_cur = hist_add_idx;
941 return (rc);
944 #endif /* CONFIG_CMDLINE_EDITING */
946 /****************************************************************************/
949 * Prompt for input and read a line.
950 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
951 * time out when time goes past endtime (timebase time in ticks).
952 * Return: number of read characters
953 * -1 if break
954 * -2 if timed out
956 int readline (const char *const prompt)
958 return readline_into_buffer(prompt, console_buffer);
962 int readline_into_buffer (const char *const prompt, char * buffer)
964 char *p = buffer;
965 #ifdef CONFIG_CMDLINE_EDITING
966 unsigned int len=MAX_CMDBUF_SIZE;
967 int rc;
968 static int initted = 0;
970 if (!initted) {
971 hist_init();
972 initted = 1;
975 puts (prompt);
977 rc = cread_line(prompt, p, &len);
978 return rc < 0 ? rc : len;
979 #else
980 char * p_buf = p;
981 int n = 0; /* buffer index */
982 int plen = 0; /* prompt length */
983 int col; /* output column cnt */
984 char c;
986 /* print prompt */
987 if (prompt) {
988 plen = strlen (prompt);
989 puts (prompt);
991 col = plen;
993 for (;;) {
994 #ifdef CONFIG_BOOT_RETRY_TIME
995 while (!tstc()) { /* while no incoming data */
996 if (retry_time >= 0 && get_ticks() > endtime)
997 return (-2); /* timed out */
999 #endif
1000 WATCHDOG_RESET(); /* Trigger watchdog, if needed */
1002 #ifdef CONFIG_SHOW_ACTIVITY
1003 while (!tstc()) {
1004 extern void show_activity(int arg);
1005 show_activity(0);
1007 #endif
1008 c = getc();
1011 * Special character handling
1013 switch (c) {
1014 case '\r': /* Enter */
1015 case '\n':
1016 *p = '\0';
1017 puts ("\r\n");
1018 return (p - p_buf);
1020 case '\0': /* nul */
1021 continue;
1023 case 0x03: /* ^C - break */
1024 p_buf[0] = '\0'; /* discard input */
1025 return (-1);
1027 case 0x15: /* ^U - erase line */
1028 while (col > plen) {
1029 puts (erase_seq);
1030 --col;
1032 p = p_buf;
1033 n = 0;
1034 continue;
1036 case 0x17: /* ^W - erase word */
1037 p=delete_char(p_buf, p, &col, &n, plen);
1038 while ((n > 0) && (*p != ' ')) {
1039 p=delete_char(p_buf, p, &col, &n, plen);
1041 continue;
1043 case 0x08: /* ^H - backspace */
1044 case 0x7F: /* DEL - backspace */
1045 p=delete_char(p_buf, p, &col, &n, plen);
1046 continue;
1048 default:
1050 * Must be a normal character then
1052 if (n < CFG_CBSIZE-2) {
1053 if (c == '\t') { /* expand TABs */
1054 #ifdef CONFIG_AUTO_COMPLETE
1055 /* if auto completion triggered just continue */
1056 *p = '\0';
1057 if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
1058 p = p_buf + n; /* reset */
1059 continue;
1061 #endif
1062 puts (tab_seq+(col&07));
1063 col += 8 - (col&07);
1064 } else {
1065 ++col; /* echo input */
1066 putc (c);
1068 *p++ = c;
1069 ++n;
1070 } else { /* Buffer full */
1071 putc ('\a');
1075 #endif /* CONFIG_CMDLINE_EDITING */
1078 /****************************************************************************/
1080 #ifndef CONFIG_CMDLINE_EDITING
1081 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
1083 char *s;
1085 if (*np == 0) {
1086 return (p);
1089 if (*(--p) == '\t') { /* will retype the whole line */
1090 while (*colp > plen) {
1091 puts (erase_seq);
1092 (*colp)--;
1094 for (s=buffer; s<p; ++s) {
1095 if (*s == '\t') {
1096 puts (tab_seq+((*colp) & 07));
1097 *colp += 8 - ((*colp) & 07);
1098 } else {
1099 ++(*colp);
1100 putc (*s);
1103 } else {
1104 puts (erase_seq);
1105 (*colp)--;
1107 (*np)--;
1108 return (p);
1110 #endif /* CONFIG_CMDLINE_EDITING */
1112 /****************************************************************************/
1114 int parse_line (char *line, char *argv[])
1116 int nargs = 0;
1118 #ifdef DEBUG_PARSER
1119 printf ("parse_line: \"%s\"\n", line);
1120 #endif
1121 while (nargs < CFG_MAXARGS) {
1123 /* skip any white space */
1124 while ((*line == ' ') || (*line == '\t')) {
1125 ++line;
1128 if (*line == '\0') { /* end of line, no more args */
1129 argv[nargs] = NULL;
1130 #ifdef DEBUG_PARSER
1131 printf ("parse_line: nargs=%d\n", nargs);
1132 #endif
1133 return (nargs);
1136 argv[nargs++] = line; /* begin of argument string */
1138 /* find end of string */
1139 while (*line && (*line != ' ') && (*line != '\t')) {
1140 ++line;
1143 if (*line == '\0') { /* end of line, no more args */
1144 argv[nargs] = NULL;
1145 #ifdef DEBUG_PARSER
1146 printf ("parse_line: nargs=%d\n", nargs);
1147 #endif
1148 return (nargs);
1151 *line++ = '\0'; /* terminate current arg */
1154 printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
1156 #ifdef DEBUG_PARSER
1157 printf ("parse_line: nargs=%d\n", nargs);
1158 #endif
1159 return (nargs);
1162 /****************************************************************************/
1164 static void process_macros (const char *input, char *output)
1166 char c, prev;
1167 const char *varname_start = NULL;
1168 int inputcnt = strlen (input);
1169 int outputcnt = CFG_CBSIZE;
1170 int state = 0; /* 0 = waiting for '$' */
1172 /* 1 = waiting for '(' or '{' */
1173 /* 2 = waiting for ')' or '}' */
1174 /* 3 = waiting for ''' */
1175 #ifdef DEBUG_PARSER
1176 char *output_start = output;
1178 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
1179 input);
1180 #endif
1182 prev = '\0'; /* previous character */
1184 while (inputcnt && outputcnt) {
1185 c = *input++;
1186 inputcnt--;
1188 if (state != 3) {
1189 /* remove one level of escape characters */
1190 if ((c == '\\') && (prev != '\\')) {
1191 if (inputcnt-- == 0)
1192 break;
1193 prev = c;
1194 c = *input++;
1198 switch (state) {
1199 case 0: /* Waiting for (unescaped) $ */
1200 if ((c == '\'') && (prev != '\\')) {
1201 state = 3;
1202 break;
1204 if ((c == '$') && (prev != '\\')) {
1205 state++;
1206 } else {
1207 *(output++) = c;
1208 outputcnt--;
1210 break;
1211 case 1: /* Waiting for ( */
1212 if (c == '(' || c == '{') {
1213 state++;
1214 varname_start = input;
1215 } else {
1216 state = 0;
1217 *(output++) = '$';
1218 outputcnt--;
1220 if (outputcnt) {
1221 *(output++) = c;
1222 outputcnt--;
1225 break;
1226 case 2: /* Waiting for ) */
1227 if (c == ')' || c == '}') {
1228 int i;
1229 char envname[CFG_CBSIZE], *envval;
1230 int envcnt = input - varname_start - 1; /* Varname # of chars */
1232 /* Get the varname */
1233 for (i = 0; i < envcnt; i++) {
1234 envname[i] = varname_start[i];
1236 envname[i] = 0;
1238 /* Get its value */
1239 envval = getenv (envname);
1241 /* Copy into the line if it exists */
1242 if (envval != NULL)
1243 while ((*envval) && outputcnt) {
1244 *(output++) = *(envval++);
1245 outputcnt--;
1247 /* Look for another '$' */
1248 state = 0;
1250 break;
1251 case 3: /* Waiting for ' */
1252 if ((c == '\'') && (prev != '\\')) {
1253 state = 0;
1254 } else {
1255 *(output++) = c;
1256 outputcnt--;
1258 break;
1260 prev = c;
1263 if (outputcnt)
1264 *output = 0;
1265 else
1266 *(output - 1) = 0;
1268 #ifdef DEBUG_PARSER
1269 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
1270 strlen (output_start), output_start);
1271 #endif
1274 /****************************************************************************
1275 * returns:
1276 * 1 - command executed, repeatable
1277 * 0 - command executed but not repeatable, interrupted commands are
1278 * always considered not repeatable
1279 * -1 - not executed (unrecognized, bootd recursion or too many args)
1280 * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
1281 * considered unrecognized)
1283 * WARNING:
1285 * We must create a temporary copy of the command since the command we get
1286 * may be the result from getenv(), which returns a pointer directly to
1287 * the environment data, which may change magicly when the command we run
1288 * creates or modifies environment variables (like "bootp" does).
1291 int run_command (const char *cmd, int flag)
1293 cmd_tbl_t *cmdtp;
1294 char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */
1295 char *token; /* start of token in cmdbuf */
1296 char *sep; /* end of token (separator) in cmdbuf */
1297 char finaltoken[CFG_CBSIZE];
1298 char *str = cmdbuf;
1299 char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
1300 int argc, inquotes;
1301 int repeatable = 1;
1302 int rc = 0;
1304 #ifdef DEBUG_PARSER
1305 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
1306 puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
1307 puts ("\"\n");
1308 #endif
1310 clear_ctrlc(); /* forget any previous Control C */
1312 if (!cmd || !*cmd) {
1313 return -1; /* empty command */
1316 if (strlen(cmd) >= CFG_CBSIZE) {
1317 puts ("## Command too long!\n");
1318 return -1;
1321 strcpy (cmdbuf, cmd);
1323 /* Process separators and check for invalid
1324 * repeatable commands
1327 #ifdef DEBUG_PARSER
1328 printf ("[PROCESS_SEPARATORS] %s\n", cmd);
1329 #endif
1330 while (*str) {
1333 * Find separator, or string end
1334 * Allow simple escape of ';' by writing "\;"
1336 for (inquotes = 0, sep = str; *sep; sep++) {
1337 if ((*sep=='\'') &&
1338 (*(sep-1) != '\\'))
1339 inquotes=!inquotes;
1341 if (!inquotes &&
1342 (*sep == ';') && /* separator */
1343 ( sep != str) && /* past string start */
1344 (*(sep-1) != '\\')) /* and NOT escaped */
1345 break;
1349 * Limit the token to data between separators
1351 token = str;
1352 if (*sep) {
1353 str = sep + 1; /* start of command for next pass */
1354 *sep = '\0';
1356 else
1357 str = sep; /* no more commands for next pass */
1358 #ifdef DEBUG_PARSER
1359 printf ("token: \"%s\"\n", token);
1360 #endif
1362 /* find macros in this token and replace them */
1363 process_macros (token, finaltoken);
1365 /* Extract arguments */
1366 if ((argc = parse_line (finaltoken, argv)) == 0) {
1367 rc = -1; /* no command at all */
1368 continue;
1371 /* Look up command in command table */
1372 if ((cmdtp = find_cmd(argv[0])) == NULL) {
1373 printf ("Unknown command '%s' - try 'help'\n", argv[0]);
1374 rc = -1; /* give up after bad command */
1375 continue;
1378 /* found - check max args */
1379 if (argc > cmdtp->maxargs) {
1380 printf ("Usage:\n%s\n", cmdtp->usage);
1381 rc = -1;
1382 continue;
1385 #if defined(CONFIG_CMD_BOOTD)
1386 /* avoid "bootd" recursion */
1387 if (cmdtp->cmd == do_bootd) {
1388 #ifdef DEBUG_PARSER
1389 printf ("[%s]\n", finaltoken);
1390 #endif
1391 if (flag & CMD_FLAG_BOOTD) {
1392 puts ("'bootd' recursion detected\n");
1393 rc = -1;
1394 continue;
1395 } else {
1396 flag |= CMD_FLAG_BOOTD;
1399 #endif
1401 /* OK - call function to do the command */
1402 if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
1403 rc = -1;
1406 repeatable &= cmdtp->repeatable;
1408 /* Did the user stop this? */
1409 if (had_ctrlc ())
1410 return -1; /* if stopped then not repeatable */
1413 return rc ? rc : repeatable;
1416 /****************************************************************************/
1418 #if defined(CONFIG_CMD_RUN)
1419 int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
1421 int i;
1423 if (argc < 2) {
1424 printf ("Usage:\n%s\n", cmdtp->usage);
1425 return 1;
1428 for (i=1; i<argc; ++i) {
1429 char *arg;
1431 if ((arg = getenv (argv[i])) == NULL) {
1432 printf ("## Error: \"%s\" not defined\n", argv[i]);
1433 return 1;
1435 #ifndef CFG_HUSH_PARSER
1436 if (run_command (arg, flag) == -1)
1437 return 1;
1438 #else
1439 if (parse_string_outer(arg,
1440 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
1441 return 1;
1442 #endif
1444 return 0;
1446 #endif