]> git.ipfire.org Git - people/ms/u-boot.git/blame - common/main.c
cmd_bmp.c: message about compressed formats is debug info only.
[people/ms/u-boot.git] / common / main.c
CommitLineData
c609719b
WD
1/*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
501090aa
WD
5 * Add to readline cmdline-editing by
6 * (C) Copyright 2005
7 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
8 *
c609719b
WD
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
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.
16 *
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.
21 *
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
26 */
27
a6c7ad2f
WD
28/* #define DEBUG */
29
c609719b
WD
30#include <common.h>
31#include <watchdog.h>
32#include <command.h>
d9631ecf
WD
33#ifdef CONFIG_MODEM_SUPPORT
34#include <malloc.h> /* for free() prototype */
35#endif
c609719b 36
6d0f6bcf 37#ifdef CONFIG_SYS_HUSH_PARSER
c609719b
WD
38#include <hush.h>
39#endif
40
bdccc4fe
WD
41#include <post.h>
42
597f6c26 43#if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING)
d87080b7
WD
44DECLARE_GLOBAL_DATA_PTR;
45#endif
46
fad63407
HS
47/*
48 * Board-specific Platform code can reimplement show_boot_progress () if needed
49 */
50void inline __show_boot_progress (int val) {}
5e2c08c3 51void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
fad63407 52
4bae9090
BS
53#if defined(CONFIG_UPDATE_TFTP)
54void update_tftp (void);
55#endif /* CONFIG_UPDATE_TFTP */
8bde7f77 56
c609719b
WD
57#define MAX_DELAY_STOP_STR 32
58
c609719b
WD
59#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
60static int abortboot(int);
61#endif
62
63#undef DEBUG_PARSER
64
6475b9f9 65char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
c609719b 66
3ca9122f 67static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
82359aec
MF
68static const char erase_seq[] = "\b \b"; /* erase sequence */
69static const char tab_seq[] = " "; /* used to expand TABs */
c609719b
WD
70
71#ifdef CONFIG_BOOT_RETRY_TIME
72static uint64_t endtime = 0; /* must be set, default is instant timeout */
73static int retry_time = -1; /* -1 so can call readline before main_loop */
74#endif
75
76#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
77
78#ifndef CONFIG_BOOT_RETRY_MIN
79#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
80#endif
81
82#ifdef CONFIG_MODEM_SUPPORT
83int do_mdm_init = 0;
84extern void mdm_init(void); /* defined in board.c */
85#endif
86
87/***************************************************************************
88 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
89 * returns: 0 - no key string, allow autoboot
90 * 1 - got key string, abort
91 */
92#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
93# if defined(CONFIG_AUTOBOOT_KEYED)
94static __inline__ int abortboot(int bootdelay)
95{
96 int abort = 0;
97 uint64_t etime = endtick(bootdelay);
19973b6a 98 struct {
c609719b
WD
99 char* str;
100 u_int len;
101 int retry;
102 }
19973b6a 103 delaykey [] = {
c609719b
WD
104 { str: getenv ("bootdelaykey"), retry: 1 },
105 { str: getenv ("bootdelaykey2"), retry: 1 },
106 { str: getenv ("bootstopkey"), retry: 0 },
107 { str: getenv ("bootstopkey2"), retry: 0 },
108 };
109
110 char presskey [MAX_DELAY_STOP_STR];
111 u_int presskey_len = 0;
112 u_int presskey_max = 0;
113 u_int i;
114
115# ifdef CONFIG_AUTOBOOT_PROMPT
f2302d44 116 printf(CONFIG_AUTOBOOT_PROMPT);
c609719b
WD
117# endif
118
119# ifdef CONFIG_AUTOBOOT_DELAY_STR
120 if (delaykey[0].str == NULL)
121 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
122# endif
123# ifdef CONFIG_AUTOBOOT_DELAY_STR2
124 if (delaykey[1].str == NULL)
125 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
126# endif
127# ifdef CONFIG_AUTOBOOT_STOP_STR
128 if (delaykey[2].str == NULL)
129 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
130# endif
131# ifdef CONFIG_AUTOBOOT_STOP_STR2
132 if (delaykey[3].str == NULL)
133 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
134# endif
135
136 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
137 delaykey[i].len = delaykey[i].str == NULL ?
138 0 : strlen (delaykey[i].str);
139 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
140 MAX_DELAY_STOP_STR : delaykey[i].len;
141
142 presskey_max = presskey_max > delaykey[i].len ?
143 presskey_max : delaykey[i].len;
144
145# if DEBUG_BOOTKEYS
146 printf("%s key:<%s>\n",
147 delaykey[i].retry ? "delay" : "stop",
148 delaykey[i].str ? delaykey[i].str : "NULL");
149# endif
150 }
151
152 /* In order to keep up with incoming data, check timeout only
153 * when catch up.
154 */
c3284b03
PK
155 do {
156 if (tstc()) {
157 if (presskey_len < presskey_max) {
158 presskey [presskey_len ++] = getc();
159 }
160 else {
161 for (i = 0; i < presskey_max - 1; i ++)
162 presskey [i] = presskey [i + 1];
163
164 presskey [i] = getc();
165 }
166 }
167
c609719b
WD
168 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
169 if (delaykey[i].len > 0 &&
170 presskey_len >= delaykey[i].len &&
171 memcmp (presskey + presskey_len - delaykey[i].len,
8bde7f77 172 delaykey[i].str,
c609719b
WD
173 delaykey[i].len) == 0) {
174# if DEBUG_BOOTKEYS
175 printf("got %skey\n",
176 delaykey[i].retry ? "delay" : "stop");
177# endif
178
179# ifdef CONFIG_BOOT_RETRY_TIME
180 /* don't retry auto boot */
181 if (! delaykey[i].retry)
182 retry_time = -1;
183# endif
184 abort = 1;
185 }
186 }
c3284b03 187 } while (!abort && get_ticks() <= etime);
c609719b 188
c609719b
WD
189# if DEBUG_BOOTKEYS
190 if (!abort)
ada4d400 191 puts("key timeout\n");
c609719b
WD
192# endif
193
8cb8143e 194#ifdef CONFIG_SILENT_CONSOLE
4ec5bd55
LM
195 if (abort)
196 gd->flags &= ~GD_FLG_SILENT;
8cb8143e 197#endif
198
c609719b
WD
199 return abort;
200}
201
202# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
203
c7de829c
WD
204#ifdef CONFIG_MENUKEY
205static int menukey = 0;
206#endif
207
c609719b
WD
208static __inline__ int abortboot(int bootdelay)
209{
210 int abort = 0;
211
c7de829c 212#ifdef CONFIG_MENUPROMPT
f2302d44 213 printf(CONFIG_MENUPROMPT);
c7de829c 214#else
c609719b 215 printf("Hit any key to stop autoboot: %2d ", bootdelay);
c7de829c 216#endif
c609719b
WD
217
218#if defined CONFIG_ZERO_BOOTDELAY_CHECK
8bde7f77
WD
219 /*
220 * Check if key already pressed
221 * Don't check if bootdelay < 0
222 */
c609719b
WD
223 if (bootdelay >= 0) {
224 if (tstc()) { /* we got a key press */
225 (void) getc(); /* consume input */
4b9206ed 226 puts ("\b\b\b 0");
4ec5bd55 227 abort = 1; /* don't auto boot */
c609719b 228 }
8bde7f77 229 }
c609719b
WD
230#endif
231
f72da340 232 while ((bootdelay > 0) && (!abort)) {
c609719b
WD
233 int i;
234
235 --bootdelay;
236 /* delay 100 * 10ms */
237 for (i=0; !abort && i<100; ++i) {
238 if (tstc()) { /* we got a key press */
239 abort = 1; /* don't auto boot */
240 bootdelay = 0; /* no more delay */
c7de829c
WD
241# ifdef CONFIG_MENUKEY
242 menukey = getc();
243# else
c609719b 244 (void) getc(); /* consume input */
c7de829c 245# endif
c609719b
WD
246 break;
247 }
ada4d400 248 udelay(10000);
c609719b
WD
249 }
250
ada4d400 251 printf("\b\b\b%2d ", bootdelay);
c609719b
WD
252 }
253
ada4d400 254 putc('\n');
c609719b 255
f72da340 256#ifdef CONFIG_SILENT_CONSOLE
4ec5bd55
LM
257 if (abort)
258 gd->flags &= ~GD_FLG_SILENT;
f72da340
WD
259#endif
260
c609719b
WD
261 return abort;
262}
263# endif /* CONFIG_AUTOBOOT_KEYED */
264#endif /* CONFIG_BOOTDELAY >= 0 */
265
266/****************************************************************************/
267
268void main_loop (void)
269{
6d0f6bcf
JCPV
270#ifndef CONFIG_SYS_HUSH_PARSER
271 static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
c609719b
WD
272 int len;
273 int rc = 1;
274 int flag;
275#endif
276
277#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
278 char *s;
279 int bootdelay;
280#endif
281#ifdef CONFIG_PREBOOT
282 char *p;
283#endif
bdccc4fe
WD
284#ifdef CONFIG_BOOTCOUNT_LIMIT
285 unsigned long bootcount = 0;
286 unsigned long bootlimit = 0;
287 char *bcs;
288 char bcs_set[16];
289#endif /* CONFIG_BOOTCOUNT_LIMIT */
c609719b
WD
290
291#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
292 ulong bmp = 0; /* default bitmap */
293 extern int trab_vfd (ulong bitmap);
294
295#ifdef CONFIG_MODEM_SUPPORT
296 if (do_mdm_init)
297 bmp = 1; /* alternate bitmap */
298#endif
299 trab_vfd (bmp);
300#endif /* CONFIG_VFD && VFD_TEST_LOGO */
301
bdccc4fe
WD
302#ifdef CONFIG_BOOTCOUNT_LIMIT
303 bootcount = bootcount_load();
304 bootcount++;
305 bootcount_store (bootcount);
306 sprintf (bcs_set, "%lu", bootcount);
307 setenv ("bootcount", bcs_set);
308 bcs = getenv ("bootlimit");
309 bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
310#endif /* CONFIG_BOOTCOUNT_LIMIT */
311
c609719b
WD
312#ifdef CONFIG_MODEM_SUPPORT
313 debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
314 if (do_mdm_init) {
77ddac94 315 char *str = strdup(getenv("mdm_cmd"));
c609719b
WD
316 setenv ("preboot", str); /* set or delete definition */
317 if (str != NULL)
318 free (str);
319 mdm_init(); /* wait for modem connection */
320 }
321#endif /* CONFIG_MODEM_SUPPORT */
322
0587597c
SR
323#ifdef CONFIG_VERSION_VARIABLE
324 {
325 extern char version_string[];
0587597c 326
155cb010 327 setenv ("ver", version_string); /* set version variable */
0587597c
SR
328 }
329#endif /* CONFIG_VERSION_VARIABLE */
330
6d0f6bcf 331#ifdef CONFIG_SYS_HUSH_PARSER
c609719b
WD
332 u_boot_hush_start ();
333#endif
334
81473f67
HS
335#if defined(CONFIG_HUSH_INIT_VAR)
336 hush_init_var ();
337#endif
338
c609719b
WD
339#ifdef CONFIG_PREBOOT
340 if ((p = getenv ("preboot")) != NULL) {
341# ifdef CONFIG_AUTOBOOT_KEYED
342 int prev = disable_ctrlc(1); /* disable Control C checking */
343# endif
344
6d0f6bcf 345# ifndef CONFIG_SYS_HUSH_PARSER
c609719b
WD
346 run_command (p, 0);
347# else
348 parse_string_outer(p, FLAG_PARSE_SEMICOLON |
349 FLAG_EXIT_FROM_LOOP);
350# endif
351
352# ifdef CONFIG_AUTOBOOT_KEYED
353 disable_ctrlc(prev); /* restore Control C checking */
354# endif
355 }
356#endif /* CONFIG_PREBOOT */
357
143cd21f
WD
358#if defined(CONFIG_UPDATE_TFTP)
359 update_tftp ();
360#endif /* CONFIG_UPDATE_TFTP */
361
c609719b
WD
362#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
363 s = getenv ("bootdelay");
364 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
365
a6c7ad2f 366 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
c609719b
WD
367
368# ifdef CONFIG_BOOT_RETRY_TIME
6dd652fa 369 init_cmd_timeout ();
c609719b
WD
370# endif /* CONFIG_BOOT_RETRY_TIME */
371
b428f6a8
YT
372#ifdef CONFIG_POST
373 if (gd->flags & GD_FLG_POSTFAIL) {
374 s = getenv("failbootcmd");
375 }
376 else
377#endif /* CONFIG_POST */
bdccc4fe
WD
378#ifdef CONFIG_BOOTCOUNT_LIMIT
379 if (bootlimit && (bootcount > bootlimit)) {
380 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
381 (unsigned)bootlimit);
382 s = getenv ("altbootcmd");
383 }
384 else
385#endif /* CONFIG_BOOTCOUNT_LIMIT */
386 s = getenv ("bootcmd");
a6c7ad2f
WD
387
388 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
389
c609719b
WD
390 if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
391# ifdef CONFIG_AUTOBOOT_KEYED
392 int prev = disable_ctrlc(1); /* disable Control C checking */
393# endif
394
6d0f6bcf 395# ifndef CONFIG_SYS_HUSH_PARSER
c609719b
WD
396 run_command (s, 0);
397# else
398 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
399 FLAG_EXIT_FROM_LOOP);
400# endif
401
402# ifdef CONFIG_AUTOBOOT_KEYED
403 disable_ctrlc(prev); /* restore Control C checking */
404# endif
405 }
c7de829c
WD
406
407# ifdef CONFIG_MENUKEY
a6c7ad2f 408 if (menukey == CONFIG_MENUKEY) {
c7de829c 409 s = getenv("menucmd");
a6c7ad2f 410 if (s) {
6d0f6bcf 411# ifndef CONFIG_SYS_HUSH_PARSER
6225c5db 412 run_command (s, 0);
c7de829c
WD
413# else
414 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
415 FLAG_EXIT_FROM_LOOP);
416# endif
417 }
418 }
419#endif /* CONFIG_MENUKEY */
953b7e62 420#endif /* CONFIG_BOOTDELAY */
c7de829c 421
c609719b
WD
422 /*
423 * Main Loop for Monitor Command Processing
424 */
6d0f6bcf 425#ifdef CONFIG_SYS_HUSH_PARSER
c609719b
WD
426 parse_file_outer();
427 /* This point is never reached */
428 for (;;);
429#else
430 for (;;) {
431#ifdef CONFIG_BOOT_RETRY_TIME
432 if (rc >= 0) {
433 /* Saw enough of a valid command to
434 * restart the timeout.
435 */
436 reset_cmd_timeout();
437 }
438#endif
6d0f6bcf 439 len = readline (CONFIG_SYS_PROMPT);
c609719b
WD
440
441 flag = 0; /* assume no special flags for now */
442 if (len > 0)
443 strcpy (lastcommand, console_buffer);
444 else if (len == 0)
445 flag |= CMD_FLAG_REPEAT;
446#ifdef CONFIG_BOOT_RETRY_TIME
447 else if (len == -2) {
448 /* -2 means timed out, retry autoboot
449 */
4b9206ed 450 puts ("\nTimed out waiting for command\n");
c609719b
WD
451# ifdef CONFIG_RESET_TO_RETRY
452 /* Reinit board to run initialization code again */
453 do_reset (NULL, 0, 0, NULL);
454# else
455 return; /* retry autoboot */
456# endif
457 }
458#endif
459
460 if (len == -1)
4b9206ed 461 puts ("<INTERRUPT>\n");
c609719b
WD
462 else
463 rc = run_command (lastcommand, flag);
464
465 if (rc <= 0) {
466 /* invalid command or not repeatable, forget it */
467 lastcommand[0] = 0;
468 }
469 }
6d0f6bcf 470#endif /*CONFIG_SYS_HUSH_PARSER*/
c609719b
WD
471}
472
6dd652fa
WD
473#ifdef CONFIG_BOOT_RETRY_TIME
474/***************************************************************************
19973b6a 475 * initialize command line timeout
6dd652fa
WD
476 */
477void init_cmd_timeout(void)
478{
479 char *s = getenv ("bootretry");
480
481 if (s != NULL)
b028f715 482 retry_time = (int)simple_strtol(s, NULL, 10);
6dd652fa
WD
483 else
484 retry_time = CONFIG_BOOT_RETRY_TIME;
485
486 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
487 retry_time = CONFIG_BOOT_RETRY_MIN;
488}
489
c609719b
WD
490/***************************************************************************
491 * reset command line timeout to retry_time seconds
492 */
c609719b
WD
493void reset_cmd_timeout(void)
494{
495 endtime = endtick(retry_time);
496}
497#endif
498
501090aa
WD
499#ifdef CONFIG_CMDLINE_EDITING
500
501/*
502 * cmdline-editing related codes from vivi.
503 * Author: Janghoon Lyu <nandy@mizi.com>
504 */
505
501090aa 506#define putnstr(str,n) do { \
dc4b0b38 507 printf ("%.*s", (int)n, str); \
501090aa 508 } while (0)
501090aa
WD
509
510#define CTL_CH(c) ((c) - 'a' + 1)
501090aa
WD
511#define CTL_BACKSPACE ('\b')
512#define DEL ((char)255)
513#define DEL7 ((char)127)
514#define CREAD_HIST_CHAR ('!')
515
516#define getcmd_putch(ch) putc(ch)
517#define getcmd_getch() getc()
518#define getcmd_cbeep() getcmd_putch('\a')
519
520#define HIST_MAX 20
8804ae3b 521#define HIST_SIZE CONFIG_SYS_CBSIZE
501090aa
WD
522
523static int hist_max = 0;
524static int hist_add_idx = 0;
525static int hist_cur = -1;
526unsigned hist_num = 0;
527
528char* hist_list[HIST_MAX];
6475b9f9 529char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
501090aa
WD
530
531#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
532
533static void hist_init(void)
534{
535 int i;
536
537 hist_max = 0;
538 hist_add_idx = 0;
539 hist_cur = -1;
540 hist_num = 0;
541
542 for (i = 0; i < HIST_MAX; i++) {
543 hist_list[i] = hist_lines[i];
544 hist_list[i][0] = '\0';
545 }
546}
547
548static void cread_add_to_hist(char *line)
549{
550 strcpy(hist_list[hist_add_idx], line);
551
552 if (++hist_add_idx >= HIST_MAX)
553 hist_add_idx = 0;
554
555 if (hist_add_idx > hist_max)
556 hist_max = hist_add_idx;
557
558 hist_num++;
559}
560
561static char* hist_prev(void)
562{
563 char *ret;
564 int old_cur;
565
566 if (hist_cur < 0)
567 return NULL;
568
569 old_cur = hist_cur;
570 if (--hist_cur < 0)
571 hist_cur = hist_max;
572
573 if (hist_cur == hist_add_idx) {
574 hist_cur = old_cur;
575 ret = NULL;
576 } else
577 ret = hist_list[hist_cur];
578
579 return (ret);
580}
581
582static char* hist_next(void)
583{
584 char *ret;
585
586 if (hist_cur < 0)
587 return NULL;
588
589 if (hist_cur == hist_add_idx)
590 return NULL;
591
592 if (++hist_cur > hist_max)
593 hist_cur = 0;
594
595 if (hist_cur == hist_add_idx) {
596 ret = "";
597 } else
598 ret = hist_list[hist_cur];
599
600 return (ret);
601}
602
3ca9122f 603#ifndef CONFIG_CMDLINE_EDITING
501090aa
WD
604static void cread_print_hist_list(void)
605{
606 int i;
607 unsigned long n;
608
609 n = hist_num - hist_max;
610
611 i = hist_add_idx + 1;
612 while (1) {
613 if (i > hist_max)
614 i = 0;
615 if (i == hist_add_idx)
616 break;
617 printf("%s\n", hist_list[i]);
618 n++;
619 i++;
620 }
621}
3ca9122f 622#endif /* CONFIG_CMDLINE_EDITING */
501090aa
WD
623
624#define BEGINNING_OF_LINE() { \
625 while (num) { \
626 getcmd_putch(CTL_BACKSPACE); \
627 num--; \
628 } \
629}
630
631#define ERASE_TO_EOL() { \
632 if (num < eol_num) { \
8faba489
MF
633 printf("%*s", (int)(eol_num - num), ""); \
634 do { \
501090aa 635 getcmd_putch(CTL_BACKSPACE); \
8faba489 636 } while (--eol_num > num); \
501090aa
WD
637 } \
638}
639
640#define REFRESH_TO_EOL() { \
641 if (num < eol_num) { \
642 wlen = eol_num - num; \
643 putnstr(buf + num, wlen); \
644 num = eol_num; \
645 } \
646}
647
648static void cread_add_char(char ichar, int insert, unsigned long *num,
649 unsigned long *eol_num, char *buf, unsigned long len)
650{
651 unsigned long wlen;
652
653 /* room ??? */
654 if (insert || *num == *eol_num) {
655 if (*eol_num > len - 1) {
656 getcmd_cbeep();
657 return;
658 }
659 (*eol_num)++;
660 }
661
662 if (insert) {
663 wlen = *eol_num - *num;
664 if (wlen > 1) {
665 memmove(&buf[*num+1], &buf[*num], wlen-1);
666 }
667
668 buf[*num] = ichar;
669 putnstr(buf + *num, wlen);
670 (*num)++;
671 while (--wlen) {
672 getcmd_putch(CTL_BACKSPACE);
673 }
674 } else {
675 /* echo the character */
676 wlen = 1;
677 buf[*num] = ichar;
678 putnstr(buf + *num, wlen);
679 (*num)++;
680 }
681}
682
683static void cread_add_str(char *str, int strsize, int insert, unsigned long *num,
684 unsigned long *eol_num, char *buf, unsigned long len)
685{
686 while (strsize--) {
687 cread_add_char(*str, insert, num, eol_num, buf, len);
688 str++;
689 }
690}
691
23d0baf9 692static int cread_line(const char *const prompt, char *buf, unsigned int *len)
501090aa
WD
693{
694 unsigned long num = 0;
695 unsigned long eol_num = 0;
501090aa
WD
696 unsigned long wlen;
697 char ichar;
698 int insert = 1;
699 int esc_len = 0;
501090aa 700 char esc_save[8];
ecc5500e
PT
701 int init_len = strlen(buf);
702
703 if (init_len)
704 cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
501090aa
WD
705
706 while (1) {
00ac50e3
AE
707#ifdef CONFIG_BOOT_RETRY_TIME
708 while (!tstc()) { /* while no incoming data */
709 if (retry_time >= 0 && get_ticks() > endtime)
710 return (-2); /* timed out */
30dc165a 711 WATCHDOG_RESET();
00ac50e3
AE
712 }
713#endif
714
501090aa
WD
715 ichar = getcmd_getch();
716
717 if ((ichar == '\n') || (ichar == '\r')) {
dd9f06f0 718 putc('\n');
501090aa
WD
719 break;
720 }
721
722 /*
723 * handle standard linux xterm esc sequences for arrow key, etc.
724 */
725 if (esc_len != 0) {
726 if (esc_len == 1) {
727 if (ichar == '[') {
728 esc_save[esc_len] = ichar;
729 esc_len = 2;
730 } else {
731 cread_add_str(esc_save, esc_len, insert,
732 &num, &eol_num, buf, *len);
733 esc_len = 0;
734 }
735 continue;
736 }
737
738 switch (ichar) {
739
740 case 'D': /* <- key */
741 ichar = CTL_CH('b');
742 esc_len = 0;
743 break;
744 case 'C': /* -> key */
745 ichar = CTL_CH('f');
746 esc_len = 0;
747 break; /* pass off to ^F handler */
748 case 'H': /* Home key */
749 ichar = CTL_CH('a');
750 esc_len = 0;
751 break; /* pass off to ^A handler */
752 case 'A': /* up arrow */
753 ichar = CTL_CH('p');
754 esc_len = 0;
755 break; /* pass off to ^P handler */
756 case 'B': /* down arrow */
757 ichar = CTL_CH('n');
758 esc_len = 0;
759 break; /* pass off to ^N handler */
760 default:
761 esc_save[esc_len++] = ichar;
762 cread_add_str(esc_save, esc_len, insert,
763 &num, &eol_num, buf, *len);
764 esc_len = 0;
765 continue;
766 }
767 }
768
769 switch (ichar) {
770 case 0x1b:
771 if (esc_len == 0) {
772 esc_save[esc_len] = ichar;
773 esc_len = 1;
774 } else {
dd9f06f0 775 puts("impossible condition #876\n");
501090aa
WD
776 esc_len = 0;
777 }
778 break;
779
780 case CTL_CH('a'):
781 BEGINNING_OF_LINE();
782 break;
783 case CTL_CH('c'): /* ^C - break */
784 *buf = '\0'; /* discard input */
785 return (-1);
786 case CTL_CH('f'):
787 if (num < eol_num) {
788 getcmd_putch(buf[num]);
789 num++;
790 }
791 break;
792 case CTL_CH('b'):
793 if (num) {
794 getcmd_putch(CTL_BACKSPACE);
795 num--;
796 }
797 break;
798 case CTL_CH('d'):
799 if (num < eol_num) {
800 wlen = eol_num - num - 1;
801 if (wlen) {
802 memmove(&buf[num], &buf[num+1], wlen);
803 putnstr(buf + num, wlen);
804 }
805
806 getcmd_putch(' ');
807 do {
808 getcmd_putch(CTL_BACKSPACE);
809 } while (wlen--);
810 eol_num--;
811 }
812 break;
813 case CTL_CH('k'):
814 ERASE_TO_EOL();
815 break;
816 case CTL_CH('e'):
817 REFRESH_TO_EOL();
818 break;
819 case CTL_CH('o'):
820 insert = !insert;
821 break;
822 case CTL_CH('x'):
23d0baf9 823 case CTL_CH('u'):
501090aa
WD
824 BEGINNING_OF_LINE();
825 ERASE_TO_EOL();
826 break;
827 case DEL:
828 case DEL7:
829 case 8:
830 if (num) {
831 wlen = eol_num - num;
832 num--;
833 memmove(&buf[num], &buf[num+1], wlen);
834 getcmd_putch(CTL_BACKSPACE);
835 putnstr(buf + num, wlen);
836 getcmd_putch(' ');
837 do {
838 getcmd_putch(CTL_BACKSPACE);
839 } while (wlen--);
840 eol_num--;
841 }
842 break;
843 case CTL_CH('p'):
844 case CTL_CH('n'):
845 {
846 char * hline;
847
848 esc_len = 0;
849
850 if (ichar == CTL_CH('p'))
851 hline = hist_prev();
852 else
853 hline = hist_next();
854
855 if (!hline) {
856 getcmd_cbeep();
857 continue;
858 }
859
860 /* nuke the current line */
861 /* first, go home */
862 BEGINNING_OF_LINE();
863
864 /* erase to end of line */
865 ERASE_TO_EOL();
866
867 /* copy new line into place and display */
868 strcpy(buf, hline);
869 eol_num = strlen(buf);
870 REFRESH_TO_EOL();
871 continue;
872 }
23d0baf9
JCPV
873#ifdef CONFIG_AUTO_COMPLETE
874 case '\t': {
875 int num2, col;
876
877 /* do not autocomplete when in the middle */
878 if (num < eol_num) {
879 getcmd_cbeep();
880 break;
881 }
882
883 buf[num] = '\0';
884 col = strlen(prompt) + eol_num;
885 num2 = num;
886 if (cmd_auto_complete(prompt, buf, &num2, &col)) {
887 col = num2 - num;
888 num += col;
889 eol_num += col;
890 }
891 break;
892 }
893#endif
501090aa
WD
894 default:
895 cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
896 break;
897 }
898 }
899 *len = eol_num;
900 buf[eol_num] = '\0'; /* lose the newline */
901
902 if (buf[0] && buf[0] != CREAD_HIST_CHAR)
903 cread_add_to_hist(buf);
904 hist_cur = hist_add_idx;
905
f9239438 906 return 0;
501090aa
WD
907}
908
909#endif /* CONFIG_CMDLINE_EDITING */
910
c609719b
WD
911/****************************************************************************/
912
913/*
914 * Prompt for input and read a line.
915 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
916 * time out when time goes past endtime (timebase time in ticks).
917 * Return: number of read characters
918 * -1 if break
919 * -2 if timed out
920 */
921int readline (const char *const prompt)
922{
ecc5500e
PT
923 /*
924 * If console_buffer isn't 0-length the user will be prompted to modify
925 * it instead of entering it from scratch as desired.
926 */
927 console_buffer[0] = '\0';
928
6636b62a
JY
929 return readline_into_buffer(prompt, console_buffer);
930}
931
932
933int readline_into_buffer (const char *const prompt, char * buffer)
934{
935 char *p = buffer;
501090aa 936#ifdef CONFIG_CMDLINE_EDITING
8804ae3b 937 unsigned int len = CONFIG_SYS_CBSIZE;
d8f961bb 938 int rc;
501090aa
WD
939 static int initted = 0;
940
597f6c26
JY
941 /*
942 * History uses a global array which is not
943 * writable until after relocation to RAM.
944 * Revert to non-history version if still
945 * running from flash.
946 */
947 if (gd->flags & GD_FLG_RELOC) {
948 if (!initted) {
949 hist_init();
950 initted = 1;
951 }
952
e491a71e
PT
953 if (prompt)
954 puts (prompt);
597f6c26
JY
955
956 rc = cread_line(prompt, p, &len);
957 return rc < 0 ? rc : len;
958
959 } else {
960#endif /* CONFIG_CMDLINE_EDITING */
0ec59524 961 char * p_buf = p;
c609719b
WD
962 int n = 0; /* buffer index */
963 int plen = 0; /* prompt length */
964 int col; /* output column cnt */
965 char c;
966
967 /* print prompt */
968 if (prompt) {
969 plen = strlen (prompt);
970 puts (prompt);
971 }
972 col = plen;
973
974 for (;;) {
975#ifdef CONFIG_BOOT_RETRY_TIME
976 while (!tstc()) { /* while no incoming data */
977 if (retry_time >= 0 && get_ticks() > endtime)
978 return (-2); /* timed out */
30dc165a 979 WATCHDOG_RESET();
c609719b
WD
980 }
981#endif
982 WATCHDOG_RESET(); /* Trigger watchdog, if needed */
983
984#ifdef CONFIG_SHOW_ACTIVITY
985 while (!tstc()) {
986 extern void show_activity(int arg);
987 show_activity(0);
30dc165a 988 WATCHDOG_RESET();
c609719b
WD
989 }
990#endif
991 c = getc();
992
993 /*
994 * Special character handling
995 */
996 switch (c) {
997 case '\r': /* Enter */
998 case '\n':
999 *p = '\0';
1000 puts ("\r\n");
6636b62a 1001 return (p - p_buf);
c609719b 1002
27aa8186
WD
1003 case '\0': /* nul */
1004 continue;
1005
c609719b 1006 case 0x03: /* ^C - break */
6636b62a 1007 p_buf[0] = '\0'; /* discard input */
c609719b
WD
1008 return (-1);
1009
1010 case 0x15: /* ^U - erase line */
1011 while (col > plen) {
1012 puts (erase_seq);
1013 --col;
1014 }
6636b62a 1015 p = p_buf;
c609719b
WD
1016 n = 0;
1017 continue;
1018
1636d1c8 1019 case 0x17: /* ^W - erase word */
6636b62a 1020 p=delete_char(p_buf, p, &col, &n, plen);
c609719b 1021 while ((n > 0) && (*p != ' ')) {
6636b62a 1022 p=delete_char(p_buf, p, &col, &n, plen);
c609719b
WD
1023 }
1024 continue;
1025
1026 case 0x08: /* ^H - backspace */
1027 case 0x7F: /* DEL - backspace */
6636b62a 1028 p=delete_char(p_buf, p, &col, &n, plen);
c609719b
WD
1029 continue;
1030
1031 default:
1032 /*
1033 * Must be a normal character then
1034 */
6d0f6bcf 1035 if (n < CONFIG_SYS_CBSIZE-2) {
c609719b 1036 if (c == '\t') { /* expand TABs */
04a85b3b
WD
1037#ifdef CONFIG_AUTO_COMPLETE
1038 /* if auto completion triggered just continue */
1039 *p = '\0';
1040 if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
6636b62a 1041 p = p_buf + n; /* reset */
04a85b3b
WD
1042 continue;
1043 }
1044#endif
c609719b
WD
1045 puts (tab_seq+(col&07));
1046 col += 8 - (col&07);
1047 } else {
1048 ++col; /* echo input */
1049 putc (c);
1050 }
1051 *p++ = c;
1052 ++n;
1053 } else { /* Buffer full */
1054 putc ('\a');
1055 }
1056 }
1057 }
597f6c26
JY
1058#ifdef CONFIG_CMDLINE_EDITING
1059 }
1060#endif
c609719b
WD
1061}
1062
1063/****************************************************************************/
1064
1065static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
1066{
1067 char *s;
1068
1069 if (*np == 0) {
1070 return (p);
1071 }
1072
1073 if (*(--p) == '\t') { /* will retype the whole line */
1074 while (*colp > plen) {
1075 puts (erase_seq);
1076 (*colp)--;
1077 }
1078 for (s=buffer; s<p; ++s) {
1079 if (*s == '\t') {
1080 puts (tab_seq+((*colp) & 07));
1081 *colp += 8 - ((*colp) & 07);
1082 } else {
1083 ++(*colp);
1084 putc (*s);
1085 }
1086 }
1087 } else {
1088 puts (erase_seq);
1089 (*colp)--;
1090 }
1091 (*np)--;
1092 return (p);
1093}
1094
1095/****************************************************************************/
1096
1097int parse_line (char *line, char *argv[])
1098{
1099 int nargs = 0;
1100
1101#ifdef DEBUG_PARSER
1102 printf ("parse_line: \"%s\"\n", line);
1103#endif
6d0f6bcf 1104 while (nargs < CONFIG_SYS_MAXARGS) {
c609719b
WD
1105
1106 /* skip any white space */
1107 while ((*line == ' ') || (*line == '\t')) {
1108 ++line;
1109 }
1110
1111 if (*line == '\0') { /* end of line, no more args */
1112 argv[nargs] = NULL;
1113#ifdef DEBUG_PARSER
1114 printf ("parse_line: nargs=%d\n", nargs);
1115#endif
1116 return (nargs);
1117 }
1118
1119 argv[nargs++] = line; /* begin of argument string */
1120
1121 /* find end of string */
1122 while (*line && (*line != ' ') && (*line != '\t')) {
1123 ++line;
1124 }
1125
1126 if (*line == '\0') { /* end of line, no more args */
1127 argv[nargs] = NULL;
1128#ifdef DEBUG_PARSER
1129 printf ("parse_line: nargs=%d\n", nargs);
1130#endif
1131 return (nargs);
1132 }
1133
1134 *line++ = '\0'; /* terminate current arg */
1135 }
1136
6d0f6bcf 1137 printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
c609719b
WD
1138
1139#ifdef DEBUG_PARSER
1140 printf ("parse_line: nargs=%d\n", nargs);
1141#endif
1142 return (nargs);
1143}
1144
1145/****************************************************************************/
1146
1147static void process_macros (const char *input, char *output)
1148{
1149 char c, prev;
1150 const char *varname_start = NULL;
19973b6a 1151 int inputcnt = strlen (input);
6d0f6bcf 1152 int outputcnt = CONFIG_SYS_CBSIZE;
19973b6a
WD
1153 int state = 0; /* 0 = waiting for '$' */
1154
1155 /* 1 = waiting for '(' or '{' */
1156 /* 2 = waiting for ')' or '}' */
1157 /* 3 = waiting for ''' */
c609719b
WD
1158#ifdef DEBUG_PARSER
1159 char *output_start = output;
1160
19973b6a
WD
1161 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
1162 input);
c609719b
WD
1163#endif
1164
19973b6a 1165 prev = '\0'; /* previous character */
c609719b
WD
1166
1167 while (inputcnt && outputcnt) {
8bde7f77 1168 c = *input++;
19973b6a
WD
1169 inputcnt--;
1170
1171 if (state != 3) {
1172 /* remove one level of escape characters */
1173 if ((c == '\\') && (prev != '\\')) {
1174 if (inputcnt-- == 0)
1175 break;
1176 prev = c;
1177 c = *input++;
1178 }
c609719b 1179 }
19973b6a
WD
1180
1181 switch (state) {
1182 case 0: /* Waiting for (unescaped) $ */
1183 if ((c == '\'') && (prev != '\\')) {
1184 state = 3;
1185 break;
1186 }
1187 if ((c == '$') && (prev != '\\')) {
1188 state++;
1189 } else {
c609719b
WD
1190 *(output++) = c;
1191 outputcnt--;
1192 }
19973b6a
WD
1193 break;
1194 case 1: /* Waiting for ( */
1195 if (c == '(' || c == '{') {
1196 state++;
1197 varname_start = input;
1198 } else {
1199 state = 0;
1200 *(output++) = '$';
1201 outputcnt--;
c609719b 1202
19973b6a
WD
1203 if (outputcnt) {
1204 *(output++) = c;
c609719b
WD
1205 outputcnt--;
1206 }
19973b6a
WD
1207 }
1208 break;
1209 case 2: /* Waiting for ) */
1210 if (c == ')' || c == '}') {
1211 int i;
6d0f6bcf 1212 char envname[CONFIG_SYS_CBSIZE], *envval;
19973b6a
WD
1213 int envcnt = input - varname_start - 1; /* Varname # of chars */
1214
1215 /* Get the varname */
1216 for (i = 0; i < envcnt; i++) {
1217 envname[i] = varname_start[i];
1218 }
1219 envname[i] = 0;
1220
1221 /* Get its value */
1222 envval = getenv (envname);
1223
1224 /* Copy into the line if it exists */
1225 if (envval != NULL)
1226 while ((*envval) && outputcnt) {
1227 *(output++) = *(envval++);
1228 outputcnt--;
1229 }
1230 /* Look for another '$' */
1231 state = 0;
1232 }
1233 break;
1234 case 3: /* Waiting for ' */
1235 if ((c == '\'') && (prev != '\\')) {
1236 state = 0;
1237 } else {
1238 *(output++) = c;
1239 outputcnt--;
1240 }
1241 break;
a25f862b 1242 }
19973b6a 1243 prev = c;
c609719b
WD
1244 }
1245
1246 if (outputcnt)
1247 *output = 0;
9160b96f
BS
1248 else
1249 *(output - 1) = 0;
c609719b
WD
1250
1251#ifdef DEBUG_PARSER
1252 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
19973b6a 1253 strlen (output_start), output_start);
c609719b
WD
1254#endif
1255}
1256
1257/****************************************************************************
1258 * returns:
1259 * 1 - command executed, repeatable
1260 * 0 - command executed but not repeatable, interrupted commands are
1261 * always considered not repeatable
1262 * -1 - not executed (unrecognized, bootd recursion or too many args)
6d0f6bcf 1263 * (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
c609719b
WD
1264 * considered unrecognized)
1265 *
1266 * WARNING:
1267 *
1268 * We must create a temporary copy of the command since the command we get
1269 * may be the result from getenv(), which returns a pointer directly to
1270 * the environment data, which may change magicly when the command we run
1271 * creates or modifies environment variables (like "bootp" does).
1272 */
1273
1274int run_command (const char *cmd, int flag)
1275{
1276 cmd_tbl_t *cmdtp;
6d0f6bcf 1277 char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
c609719b
WD
1278 char *token; /* start of token in cmdbuf */
1279 char *sep; /* end of token (separator) in cmdbuf */
6d0f6bcf 1280 char finaltoken[CONFIG_SYS_CBSIZE];
c609719b 1281 char *str = cmdbuf;
6d0f6bcf 1282 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
f07771cc 1283 int argc, inquotes;
c609719b 1284 int repeatable = 1;
f07771cc 1285 int rc = 0;
c609719b
WD
1286
1287#ifdef DEBUG_PARSER
1288 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
1289 puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
1290 puts ("\"\n");
1291#endif
1292
1293 clear_ctrlc(); /* forget any previous Control C */
1294
1295 if (!cmd || !*cmd) {
1296 return -1; /* empty command */
1297 }
1298
6d0f6bcf 1299 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
c609719b
WD
1300 puts ("## Command too long!\n");
1301 return -1;
1302 }
1303
1304 strcpy (cmdbuf, cmd);
1305
1306 /* Process separators and check for invalid
1307 * repeatable commands
1308 */
1309
1310#ifdef DEBUG_PARSER
1311 printf ("[PROCESS_SEPARATORS] %s\n", cmd);
1312#endif
1313 while (*str) {
1314
1315 /*
1316 * Find separator, or string end
1317 * Allow simple escape of ';' by writing "\;"
1318 */
a25f862b
WD
1319 for (inquotes = 0, sep = str; *sep; sep++) {
1320 if ((*sep=='\'') &&
1321 (*(sep-1) != '\\'))
1322 inquotes=!inquotes;
1323
1324 if (!inquotes &&
1325 (*sep == ';') && /* separator */
c609719b
WD
1326 ( sep != str) && /* past string start */
1327 (*(sep-1) != '\\')) /* and NOT escaped */
1328 break;
1329 }
1330
1331 /*
1332 * Limit the token to data between separators
1333 */
1334 token = str;
1335 if (*sep) {
1336 str = sep + 1; /* start of command for next pass */
1337 *sep = '\0';
1338 }
1339 else
1340 str = sep; /* no more commands for next pass */
1341#ifdef DEBUG_PARSER
1342 printf ("token: \"%s\"\n", token);
1343#endif
1344
1345 /* find macros in this token and replace them */
1346 process_macros (token, finaltoken);
1347
1348 /* Extract arguments */
1264b405
WD
1349 if ((argc = parse_line (finaltoken, argv)) == 0) {
1350 rc = -1; /* no command at all */
1351 continue;
1352 }
c609719b
WD
1353
1354 /* Look up command in command table */
1355 if ((cmdtp = find_cmd(argv[0])) == NULL) {
1356 printf ("Unknown command '%s' - try 'help'\n", argv[0]);
f07771cc
WD
1357 rc = -1; /* give up after bad command */
1358 continue;
c609719b
WD
1359 }
1360
1361 /* found - check max args */
1362 if (argc > cmdtp->maxargs) {
62c3ae7c 1363 cmd_usage(cmdtp);
f07771cc
WD
1364 rc = -1;
1365 continue;
c609719b
WD
1366 }
1367
c3517f91 1368#if defined(CONFIG_CMD_BOOTD)
c609719b
WD
1369 /* avoid "bootd" recursion */
1370 if (cmdtp->cmd == do_bootd) {
1371#ifdef DEBUG_PARSER
1372 printf ("[%s]\n", finaltoken);
1373#endif
1374 if (flag & CMD_FLAG_BOOTD) {
4b9206ed 1375 puts ("'bootd' recursion detected\n");
f07771cc
WD
1376 rc = -1;
1377 continue;
1264b405 1378 } else {
c609719b 1379 flag |= CMD_FLAG_BOOTD;
1264b405 1380 }
c609719b 1381 }
90253178 1382#endif
c609719b
WD
1383
1384 /* OK - call function to do the command */
1385 if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
f07771cc 1386 rc = -1;
c609719b
WD
1387 }
1388
1389 repeatable &= cmdtp->repeatable;
1390
1391 /* Did the user stop this? */
1392 if (had_ctrlc ())
5afb2020 1393 return -1; /* if stopped then not repeatable */
c609719b
WD
1394 }
1395
f07771cc 1396 return rc ? rc : repeatable;
c609719b
WD
1397}
1398
1399/****************************************************************************/
1400
c3517f91 1401#if defined(CONFIG_CMD_RUN)
54841ab5 1402int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
c609719b
WD
1403{
1404 int i;
c609719b 1405
47e26b1b
WD
1406 if (argc < 2)
1407 return cmd_usage(cmdtp);
c609719b
WD
1408
1409 for (i=1; i<argc; ++i) {
3e38691e
WD
1410 char *arg;
1411
1412 if ((arg = getenv (argv[i])) == NULL) {
1413 printf ("## Error: \"%s\" not defined\n", argv[i]);
1414 return 1;
1415 }
6d0f6bcf 1416#ifndef CONFIG_SYS_HUSH_PARSER
3e38691e
WD
1417 if (run_command (arg, flag) == -1)
1418 return 1;
c609719b 1419#else
3e38691e 1420 if (parse_string_outer(arg,
7aa78614 1421 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
3e38691e 1422 return 1;
c609719b
WD
1423#endif
1424 }
3e38691e 1425 return 0;
c609719b 1426}
90253178 1427#endif