OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [redboot/] [current/] [src/] [parse.c] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      parse.c
4
//
5
//      RedBoot command line parsing routine
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: gthomas, eCosCentric
44
// Date:         2000-07-14
45
// Purpose:      
46
// Description:  
47
//              
48
// This code is part of RedBoot (tm).
49
//
50
//####DESCRIPTIONEND####
51
//
52
//==========================================================================
53
 
54
#include <redboot.h>
55
#include <cyg/hal/hal_arch.h>
56
#include <cyg/hal/hal_intr.h>
57
#include <cyg/hal/hal_cache.h>
58
#include CYGHWR_MEMORY_LAYOUT_H
59
#include <cyg/hal/hal_tables.h>
60
 
61
// Define table boundaries
62
extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
63
 
64
//
65
// Scan through an input line and break it into "arguments".  These
66
// are space delimited strings.  Return a structure which points to
67
// the strings, similar to a Unix program. Multiple commands in the line
68
// are separated by ; similar to sh. If we find a semi we stop processing the 
69
// line, terminate the current command with a null and return the start 
70
// of the next command in *line. parse() can then be called again to 
71
// process the next command on the line.
72
// Note: original input is destroyed by replacing the delimiters with 
73
// null ('\0') characters for ease of use.
74
//
75
struct cmd *
76
parse(char **line, int *argc, char **argv)
77
{
78
    char *cp = *line;
79
    char *pp;
80
    int indx = 0;
81
    int semi = 0;
82
 
83
    while (*cp) {
84
        // Skip leading spaces
85
        while (*cp && *cp == ' ') cp++;
86
        if (!*cp) {
87
            break;  // Line ended with a string of spaces
88
        }
89
        if (*cp == ';') {
90
            *cp = '\0';
91
            semi=1;
92
            break;
93
        }
94
        if (indx < MAX_ARGV) {
95
            argv[indx++] = cp;
96
        } else {
97
            diag_printf("Too many arguments - stopped at: '%s'\n", cp);
98
        }
99
        while (*cp) {
100
            if (*cp == ' ') {
101
                *cp++ = '\0';
102
                break;
103
            } else if (*cp == ';') {
104
                break;
105
            } else if (*cp == '"') {
106
                // Swallow quote, scan till following one
107
                if (argv[indx-1] == cp) {
108
                    argv[indx-1] = ++cp;
109
                }
110
                pp = cp;
111
                while (*cp && *cp != '"') {
112
                    if (*cp == '\\') {
113
                        // Skip over escape - allows for escaped '"'
114
                        cp++;
115
                    }
116
                    // Move string to swallow escapes
117
                    *pp++ = *cp++;
118
                }
119
                if (!*cp) {
120
                    diag_printf("Unbalanced string!\n");
121
                } else {
122
                    if (pp != cp) *pp = '\0';
123
                    *cp++ = '\0';
124
                    break;
125
                }
126
            } else {
127
                cp++;
128
            }
129
        }
130
    }
131
    if (semi) {
132
        *line = cp + 1;
133
    } else {
134
        *line = cp;
135
    }
136
    *argc = indx;
137
    return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]);
138
}
139
 
140
//
141
// Search through a list of commands
142
//
143
struct cmd *
144
cmd_search(struct cmd *tab, struct cmd *tabend, char *arg)
145
{
146
    int cmd_len;
147
    struct cmd *cmd, *cmd2;
148
    // Search command table
149
    cmd_len = strlen(arg);
150
    cmd = tab;
151
    while (cmd != tabend) {
152
        if (strncasecmp(arg, cmd->str, cmd_len) == 0) {
153
            if (strlen(cmd->str) > cmd_len) {
154
                // Check for ambiguous commands here
155
                // Note: If there are commands which are not length-unique
156
                // then this check will be invalid.  E.g. "du" and "dump"
157
                bool first = true;
158
                cmd2 = tab;
159
                while (cmd2 != tabend) {
160
                    if ((cmd != cmd2) &&
161
                        (strncasecmp(arg, cmd2->str, cmd_len) == 0)) {
162
                        if (first) {
163
                            diag_printf("Ambiguous command '%s', choices are: %s",
164
                                        arg, cmd->str);
165
                            first = false;
166
                        }
167
                        diag_printf(" %s", cmd2->str);
168
                    }
169
                    cmd2++;
170
                }
171
                if (!first) {
172
                    // At least one ambiguity found - fail the lookup
173
                    diag_printf("\n");
174
                    return (struct cmd *)0;
175
                }
176
            }
177
            return cmd;
178
        }
179
        cmd++;
180
    }
181
    return (struct cmd *)0;
182
}
183
 
184
void
185
cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix)
186
{
187
    struct cmd *cmd;
188
 
189
    diag_printf("Usage:\n");
190
    for (cmd = tab;  cmd != tabend;  cmd++) {
191
        diag_printf("  %s%s %s\n", prefix, cmd->str, cmd->usage);
192
    }
193
}
194
 
195
//
196
// Handle illegal memory accesses (and other abort conditions)
197
//
198
static hal_jmp_buf error_jmpbuf;
199
static cyg_bool redboot_exec_call = false;
200
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
201
__externC void* volatile __mem_fault_handler;
202
 
203
static void error_handler(void)
204
{
205
    hal_longjmp(error_jmpbuf, 1);
206
}
207
#endif
208
 
209
// Routine to allow code to invoke RedBoot commands. This is useful
210
// during initialization and in platform specific code.
211
//
212
// Call it like this:
213
//
214
// result = redboot_exec( "load", "-m", "file", "foo", 0 );
215
//
216
// Note the terminating zero. The result will be zero if the command
217
// succeeded, and <0 if something went wrong.
218
 
219
#define ARGV_MAX        20
220
int redboot_exec( char *command, ... )
221
{
222
    int argc;
223
    char *argv[ARGV_MAX+1];
224
    va_list ap;
225
    struct cmd *cmd;
226
    int result = 0;
227
 
228
    va_start(ap, command);
229
 
230
    argv[0] = command;
231
    for( argc = 1; argc < ARGV_MAX; argc++ )
232
    {
233
        char *arg = va_arg(ap, char *);
234
        if( arg == 0 )
235
            break;
236
        argv[argc] = arg;
237
    }
238
    argv[argc] = NULL;
239
 
240
    if(( cmd = cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, command) ))
241
    {
242
        // Try to handle aborts - messy because of the stack unwinding...
243
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
244
        __mem_fault_handler = error_handler;
245
#endif
246
        redboot_exec_call = true;
247
        if (hal_setjmp(error_jmpbuf))
248
            result = -1;
249
        else
250
            (cmd->fun)(argc, argv);
251
 
252
        redboot_exec_call = false;
253
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
254
        __mem_fault_handler = 0;
255
#endif
256
    }
257
    else
258
        result = -1;
259
 
260
    va_end(ap);
261
 
262
    return result;
263
}
264
 
265
externC void err_printf( const char *fmt, ... )
266
{
267
    va_list ap;
268
 
269
    va_start(ap, fmt);
270
 
271
    diag_vprintf( fmt, ap );
272
 
273
    va_end(ap);
274
 
275
    // If we are not in redboot_exec() just return as usual. If we are
276
    // inside a call to redboot_exec(), longjump out to terminate the command.
277
 
278
    if( redboot_exec_call )
279
    {
280
        diag_printf("err_printf: aborting command\n");
281
        hal_longjmp(error_jmpbuf, 1);
282
    }
283
}
284
 
285
 
286
// Option processing
287
 
288
// Initialize option table entry (required because these entries
289
// may have dynamic contents, thus cannot be statically initialized)
290
//
291
void
292
init_opts(struct option_info *opts, char flag, bool takes_arg,
293
          int arg_type, void *arg, bool *arg_set, char *name)
294
{
295
    opts->flag = flag;
296
    opts->takes_arg = takes_arg;
297
    opts->arg_type = arg_type,
298
    opts->arg = arg;
299
    opts->arg_set = arg_set;
300
    opts->name = name;
301
}
302
 
303
//
304
// Scan command line arguments (argc/argv), processing options, etc.
305
//
306
bool
307
scan_opts(int argc, char *argv[], int first,
308
          struct option_info *opts, int num_opts,
309
          void *def_arg, int def_arg_type, char *def_descr)
310
{
311
    bool ret = true;
312
    bool flag_ok;
313
    bool def_arg_set = false;
314
    int i, j;
315
    char c, *s;
316
    struct option_info *opt;
317
 
318
    if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) {
319
        *(char **)def_arg = (char *)0;
320
    }
321
    opt = opts;
322
    for (j = 0;  j < num_opts;  j++, opt++) {
323
        if (opt->arg_set) {
324
            *opt->arg_set = false;
325
        }
326
        if (!opt->takes_arg) {
327
            switch (opt->arg_type) {
328
            case OPTION_ARG_TYPE_NUM:
329
                *(int *)opt->arg = 0;
330
                break;
331
            case OPTION_ARG_TYPE_FLG:
332
                *(bool *)opt->arg = false;
333
                break;
334
            }
335
        }
336
    }
337
    for (i = first;  i < argc;  i++) {
338
        if (argv[i][0] == '-') {
339
            c = argv[i][1];
340
            flag_ok = false;
341
            opt = opts;
342
            for (j = 0;  j < num_opts;  j++, opt++) {
343
                if (c == opt->flag) {
344
                    if (opt->arg_set && *opt->arg_set) {
345
                        diag_printf("** Error: %s already specified\n", opt->name);
346
                        ret = false;
347
                    }
348
                    if (opt->takes_arg) {
349
                        if (argv[i][2] == '=') {
350
                            s = &argv[i][3];
351
                        } else {
352
                            s = argv[i+1];
353
                            i++;
354
                        }
355
                        switch (opt->arg_type) {
356
                        case OPTION_ARG_TYPE_NUM:
357
                            if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) {
358
                                diag_printf("** Error: invalid number '%s' for %s\n",
359
                                            s, opt->name);
360
                                ret = false;
361
                            }
362
                            break;
363
                        case OPTION_ARG_TYPE_STR:
364
                            *(char **)opt->arg = s;
365
                            break;
366
                        }
367
                        *opt->arg_set = true;
368
                    } else {
369
                        switch (opt->arg_type) {
370
                        case OPTION_ARG_TYPE_NUM:
371
                            *(int *)opt->arg = *(int *)opt->arg + 1;
372
                            break;
373
                        case OPTION_ARG_TYPE_FLG:
374
                            *(bool *)opt->arg = true;
375
                            break;
376
                        }
377
                    }
378
                    flag_ok = true;
379
                    break;
380
                }
381
            }
382
            if (!flag_ok) {
383
                diag_printf("** Error: invalid flag '%c'\n", c);
384
                ret = false;
385
            }
386
        } else {
387
            if (def_arg) {
388
                if (def_arg_set) {
389
                    diag_printf("** Error: %s already specified\n", def_descr);
390
                    ret = false;
391
                }
392
                switch (def_arg_type) {
393
                case OPTION_ARG_TYPE_NUM:
394
                    if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) {
395
                        diag_printf("** Error: invalid number '%s' for %s\n",
396
                                    argv[i], def_descr);
397
                        ret = false;
398
                    }
399
                    break;
400
                case OPTION_ARG_TYPE_STR:
401
                    *(char **)def_arg = argv[i];
402
                    break;
403
                }
404
                def_arg_set = true;
405
            } else {
406
                diag_printf("** Error: no default/non-flag arguments supported\n");
407
                ret = false;
408
            }
409
        }
410
    }
411
    return ret;
412
}
413
 
414
//
415
// Parse (scan) a number
416
//
417
bool
418
parse_num(char *s, unsigned long *val, char **es, char *delim)
419
{
420
    bool first = true;
421
    int radix = 10;
422
    char c;
423
    unsigned long result = 0;
424
    int digit;
425
 
426
    while (*s == ' ') s++;
427
    while (*s) {
428
        if (first && (s[0] == '0') && (_tolower(s[1]) == 'x')) {
429
            radix = 16;
430
            s += 2;
431
        }
432
        first = false;
433
        c = *s++;
434
        if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
435
            // Valid digit
436
#ifdef CYGPKG_HAL_MIPS
437
            // FIXME: tx49 compiler generates 0x2539018 for MUL which
438
            // isn't any good.
439
            if (16 == radix)
440
                result = result << 4;
441
            else
442
                result = 10 * result;
443
            result += digit;
444
#else
445
            result = (result * radix) + digit;
446
#endif
447
        } else {
448
            if (delim != (char *)0) {
449
                // See if this character is one of the delimiters
450
                char *dp = delim;
451
                while (*dp && (c != *dp)) dp++;
452
                if (*dp) break;  // Found a good delimiter
453
            }
454
            return false;  // Malformatted number
455
        }
456
    }
457
    *val = result;
458
    if (es != (char **)0) {
459
        *es = s;
460
    }
461
    return true;
462
}
463
 
464
bool
465
parse_bool(char *s, bool *val)
466
{
467
    while (*s == ' ') s++;
468
    if ((*s == 't') || (*s == 'T')) {
469
        char *p = "rue";
470
        char *P = "RUE";
471
        // check for (partial) rest of the word and no extra including the
472
        // terminating zero.  "tru" will match; "truef" will not.
473
        while ( *++s ) {
474
            if ( *p != *s && *P != *s ) return false;
475
            p++; P++;
476
        }
477
        *val = true;
478
    } else
479
    if ((*s == 'f') || (*s == 'F')) {
480
        char *p = "alse";
481
        char *P = "ALSE";
482
        while ( *++s ) {
483
            if ( *p != *s && *P != *s ) return false;
484
            p++; P++;
485
        }
486
        *val = false;
487
    } else {
488
        return false;
489
    }
490
    return true;
491
}
492
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.