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

Subversion Repositories de1_olpcl2294_system

[/] [de1_olpcl2294_system/] [trunk/] [sw/] [ecos/] [shell/] [parse.c] - Blame information for rev 2

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

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

powered by: WebSVN 2.1.0

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