1 //==========================================================================
5 // RedBoot command line parsing routine
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2004, 2005, 2006 eCosCentric Limited
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
42 // Contributors: gthomas, eCosCentric
47 // This code is part of RedBoot (tm).
49 //####DESCRIPTIONEND####
51 //==========================================================================
54 #include <cyg/hal/hal_arch.h>
55 #include <cyg/hal/hal_intr.h>
56 #include <cyg/hal/hal_cache.h>
57 #include CYGHWR_MEMORY_LAYOUT_H
58 #include <cyg/hal/hal_tables.h>
60 // Define table boundaries
61 extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
64 // Scan through an input line and break it into "arguments". These
65 // are space delimited strings. Return a structure which points to
66 // the strings, similar to a Unix program. Multiple commands in the line
67 // are separated by ; similar to sh. If we find a semi we stop processing the
68 // line, terminate the current command with a null and return the start
69 // of the next command in *line. parse() can then be called again to
70 // process the next command on the line.
71 // Note: original input is destroyed by replacing the delimiters with
72 // null ('\0') characters for ease of use.
75 parse(char **line, int *argc, char **argv)
83 // Skip leading spaces
84 while (*cp && *cp == ' ') cp++;
86 break; // Line ended with a string of spaces
93 if (indx < MAX_ARGV) {
96 diag_printf("Too many arguments - stopped at: '%s'\n", cp);
102 } else if (*cp == ';') {
104 } else if (*cp == '"') {
105 // Swallow quote, scan till following one
106 if (argv[indx-1] == cp) {
110 while (*cp && *cp != '"') {
112 // Skip over escape - allows for escaped '"'
115 // Move string to swallow escapes
119 diag_printf("Unbalanced string!\n");
121 if (pp != cp) *pp = '\0';
136 return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]);
140 // Search through a list of commands
143 cmd_search(struct cmd *tab, struct cmd *tabend, char *arg)
146 struct cmd *cmd, *cmd2;
147 // Search command table
148 cmd_len = strlen(arg);
150 while (cmd != tabend) {
151 if (strncasecmp(arg, cmd->str, cmd_len) == 0) {
152 if (strlen(cmd->str) > cmd_len) {
153 // Check for ambiguous commands here
154 // Note: If there are commands which are not length-unique
155 // then this check will be invalid. E.g. "du" and "dump"
158 while (cmd2 != tabend) {
160 (strncasecmp(arg, cmd2->str, cmd_len) == 0)) {
162 diag_printf("Ambiguous command '%s', choices are: %s",
166 diag_printf(" %s", cmd2->str);
171 // At least one ambiguity found - fail the lookup
173 return (struct cmd *)0;
180 return (struct cmd *)0;
184 cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix)
188 diag_printf("Usage:\n");
189 for (cmd = tab; cmd != tabend; cmd++) {
190 diag_printf(" %s%s %s\n", prefix, cmd->str, cmd->usage);
195 // Handle illegal memory accesses (and other abort conditions)
197 static hal_jmp_buf error_jmpbuf;
198 static cyg_bool redboot_exec_call = false;
199 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
200 __externC void* volatile __mem_fault_handler;
202 static void error_handler(void)
204 hal_longjmp(error_jmpbuf, 1);
208 // Routine to allow code to invoke RedBoot commands. This is useful
209 // during initialization and in platform specific code.
211 // Call it like this:
213 // result = redboot_exec( "load", "-m", "file", "foo", 0 );
215 // Note the terminating zero. The result will be zero if the command
216 // succeeded, and <0 if something went wrong.
219 int redboot_exec( char *command, ... )
222 char *argv[ARGV_MAX+1];
227 va_start(ap, command);
230 for( argc = 1; argc < ARGV_MAX; argc++ )
232 char *arg = va_arg(ap, char *);
239 if(( cmd = cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, command) ))
241 // Try to handle aborts - messy because of the stack unwinding...
242 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
243 __mem_fault_handler = error_handler;
245 redboot_exec_call = true;
246 if (hal_setjmp(error_jmpbuf))
249 (cmd->fun)(argc, argv);
251 redboot_exec_call = false;
252 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
253 __mem_fault_handler = 0;
264 externC void err_printf(const char *fmt, ... )
270 diag_vprintf( fmt, ap );
274 // If we are not in redboot_exec() just return as usual. If we are
275 // inside a call to redboot_exec(), longjump out to terminate the command.
277 if( redboot_exec_call )
279 diag_printf("err_printf: aborting command\n");
280 hal_longjmp(error_jmpbuf, 1);
287 // Initialize option table entry (required because these entries
288 // may have dynamic contents, thus cannot be statically initialized)
291 init_opts(struct option_info *opts, char flag, bool takes_arg,
292 int arg_type, void *arg, bool *arg_set, char *name)
295 opts->takes_arg = takes_arg;
296 opts->arg_type = arg_type,
298 opts->arg_set = arg_set;
303 // Scan command line arguments (argc/argv), processing options, etc.
306 // argc+1 if no default argument was specified,
307 // (index of first non-option argument)+1 otherwise
310 scan_opts(int argc, char *argv[], int first,
311 struct option_info *opts, int num_opts,
312 void *def_arg, int def_arg_type, char *def_descr)
317 bool def_arg_set = false;
320 struct option_info *opt;
322 if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) {
323 *(char **)def_arg = NULL;
326 for (j = 0; j < num_opts; j++, opt++) {
328 *opt->arg_set = false;
330 if (!opt->takes_arg) {
331 switch (opt->arg_type) {
332 case OPTION_ARG_TYPE_NUM:
333 *(int *)opt->arg = 0;
335 case OPTION_ARG_TYPE_FLG:
336 *(bool *)opt->arg = false;
341 for (i = first; i < argc; i++) {
342 if (argv[i][0] == '-') {
346 for (j = 0; j < num_opts; j++, opt++) {
347 if (c == opt->flag) {
348 if (opt->arg_set && *opt->arg_set) {
349 diag_printf("** Error: option '-%c' already specified\n", opt->flag);
352 if (opt->takes_arg) {
353 if (argv[i][2] == '=') {
360 diag_printf("** Error: option '%c' [%s] requires an argument\n",
367 switch (opt->arg_type) {
368 case OPTION_ARG_TYPE_NUM:
369 if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) {
370 diag_printf("** Error: invalid number '%s' for %s\n",
375 case OPTION_ARG_TYPE_STR:
376 *(char **)opt->arg = s;
379 *opt->arg_set = true;
381 switch (opt->arg_type) {
382 case OPTION_ARG_TYPE_NUM:
383 *(int *)opt->arg = *(int *)opt->arg + 1;
385 case OPTION_ARG_TYPE_FLG:
386 *(bool *)opt->arg = true;
395 diag_printf("** Error: invalid flag '%c'\n", c);
402 diag_printf("** Error: %s already specified\n", def_descr);
405 switch (def_arg_type) {
406 case OPTION_ARG_TYPE_NUM:
407 if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) {
408 diag_printf("** Error: invalid number '%s' for %s\n",
413 case OPTION_ARG_TYPE_STR:
414 *(char **)def_arg = argv[i];
419 diag_printf("** Error: no default/non-flag arguments supported\n");
428 // Parse (scan) a number
431 parse_num(char *s, unsigned long *val, char **es, char *delim)
436 unsigned long result = 0;
439 while (*s == ' ') s++;
441 if (first && (s[0] == '0') && (_tolower(s[1]) == 'x')) {
447 if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
449 #ifdef CYGPKG_HAL_MIPS
450 // FIXME: tx49 compiler generates 0x2539018 for MUL which
453 result = result << 4;
455 result = 10 * result;
458 result = (result * radix) + digit;
461 if (delim != (char *)0) {
462 // See if this character is one of the delimiters
464 while (*dp && (c != *dp)) dp++;
465 if (*dp) break; // Found a good delimiter
467 return false; // Malformatted number
471 if (es != (char **)0) {
478 parse_bool(char *s, bool *val)
480 while (*s == ' ') s++;
481 if ((*s == 't') || (*s == 'T')) {
484 // check for (partial) rest of the word and no extra including the
485 // terminating zero. "tru" will match; "truef" will not.
487 if ( *p != *s && *P != *s ) return false;
492 if ((*s == 'f') || (*s == 'F')) {
496 if ( *p != *s && *P != *s ) return false;