]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/parse.c
Initial revision
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / parse.c
1 //==========================================================================
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 Red Hat, 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 version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    gthomas
44 // Contributors: gthomas
45 // Date:         2000-07-14
46 // Purpose:      
47 // Description:  
48 //              
49 // This code is part of RedBoot (tm).
50 //
51 //####DESCRIPTIONEND####
52 //
53 //==========================================================================
54
55 #include <redboot.h>
56 #include <cyg/hal/hal_arch.h>
57 #include <cyg/hal/hal_intr.h>
58 #include <cyg/hal/hal_cache.h>
59 #include CYGHWR_MEMORY_LAYOUT_H
60 #include <cyg/hal/hal_tables.h>
61
62 // Define table boundaries
63 extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
64
65 //
66 // Scan through an input line and break it into "arguments".  These
67 // are space delimited strings.  Return a structure which points to
68 // the strings, similar to a Unix program. Multiple commands in the line
69 // are separated by ; similar to sh. If we find a semi we stop processing the 
70 // line, terminate the current command with a null and return the start 
71 // of the next command in *line. parse() can then be called again to 
72 // process the next command on the line.
73 // Note: original input is destroyed by replacing the delimiters with 
74 // null ('\0') characters for ease of use.
75 //
76 struct cmd *
77 parse(char **line, int *argc, char **argv)
78 {
79     char *cp = *line;
80     char *pp;
81     int indx = 0;
82     int semi = 0;
83
84     while (*cp) {
85         // Skip leading spaces
86         while (*cp && *cp == ' ') cp++;
87         if (!*cp) {
88             break;  // Line ended with a string of spaces
89         }
90         if (*cp == ';') {
91             *cp = '\0';
92             semi=1;
93             break;
94         }
95         if (indx < MAX_ARGV) {
96             argv[indx++] = cp;
97         } else {
98             diag_printf("Too many arguments - stopped at: '%s'\n", cp);
99         }
100         while (*cp) {
101             if (*cp == ' ') {
102                 *cp++ = '\0';
103                 break;
104             } else if (*cp == ';') {
105                 break;
106             } else if (*cp == '"') {
107                 // Swallow quote, scan till following one
108                 if (argv[indx-1] == cp) {
109                     argv[indx-1] = ++cp;
110                 }
111                 pp = cp;
112                 while (*cp && *cp != '"') {
113                     if (*cp == '\\') {
114                         // Skip over escape - allows for escaped '"'
115                         cp++;
116                     }
117                     // Move string to swallow escapes
118                     *pp++ = *cp++;
119                 }
120                 if (!*cp) {
121                     diag_printf("Unbalanced string!\n");
122                 } else {
123                     if (pp != cp) *pp = '\0';
124                     *cp++ = '\0';
125                     break;
126                 }
127             } else {
128                 cp++;
129             }
130         }
131     }
132     if (semi) {
133         *line = cp + 1;
134     } else {
135         *line = cp;
136     }
137     *argc = indx;
138     return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]);
139 }
140
141 //
142 // Search through a list of commands
143 //
144 struct cmd *
145 cmd_search(struct cmd *tab, struct cmd *tabend, char *arg)
146 {
147     int cmd_len;
148     struct cmd *cmd, *cmd2;
149     // Search command table
150     cmd_len = strlen(arg);
151     cmd = tab;
152     while (cmd != tabend) {
153         if (strncasecmp(arg, cmd->str, cmd_len) == 0) {
154             if (strlen(cmd->str) > cmd_len) {
155                 // Check for ambiguous commands here
156                 // Note: If there are commands which are not length-unique
157                 // then this check will be invalid.  E.g. "du" and "dump"
158                 bool first = true;
159                 cmd2 = tab;
160                 while (cmd2 != tabend) {
161                     if ((cmd != cmd2) && 
162                         (strncasecmp(arg, cmd2->str, cmd_len) == 0)) {
163                         if (first) {
164                             diag_printf("Ambiguous command '%s', choices are: %s", 
165                                         arg, cmd->str);
166                             first = false;
167                         }
168                         diag_printf(" %s", cmd2->str);
169                     }
170                     cmd2++;
171                 }
172                 if (!first) {
173                     // At least one ambiguity found - fail the lookup
174                     diag_printf("\n");
175                     return (struct cmd *)0;
176                 }
177             }
178             return cmd;
179         }
180         cmd++;
181     }
182     return (struct cmd *)0;
183 }
184
185 void
186 cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix)
187 {
188     struct cmd *cmd;
189
190     diag_printf("Usage:\n"); 
191     for (cmd = tab;  cmd != tabend;  cmd++) {
192         diag_printf("  %s%s %s\n", prefix, cmd->str, cmd->usage);
193     }
194 }
195
196 // Option processing
197
198 // Initialize option table entry (required because these entries
199 // may have dynamic contents, thus cannot be statically initialized)
200 //
201 void
202 init_opts(struct option_info *opts, char flag, bool takes_arg, 
203           int arg_type, void *arg, bool *arg_set, char *name)
204 {
205     opts->flag = flag;
206     opts->takes_arg = takes_arg;
207     opts->arg_type = arg_type,
208     opts->arg = arg;
209     opts->arg_set = arg_set;
210     opts->name = name;
211 }
212
213 //
214 // Scan command line arguments (argc/argv), processing options, etc.
215 // returns:
216 //   0        on error
217 //   argc+1   if no default argument was specified,
218 //   (index of first non-option argument)+1 otherwise 
219 //
220 int
221 scan_opts(int argc, char *argv[], int first, 
222           struct option_info *opts, int num_opts, 
223           void *def_arg, int def_arg_type, char *def_descr)
224 {
225     int ok = true;
226     int ret = argc + 1;
227     bool flag_ok;
228     bool def_arg_set = false;
229     int i, j;
230     char c, *s;
231     struct option_info *opt;
232
233     if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) {
234         *(char **)def_arg = (char *)0;
235     }
236     opt = opts;
237     for (j = 0;  j < num_opts;  j++, opt++) {
238         if (opt->arg_set) {
239             *opt->arg_set = false;
240         }
241         if (!opt->takes_arg) {
242             switch (opt->arg_type) {
243             case OPTION_ARG_TYPE_NUM:
244                 *(int *)opt->arg = 0;
245                 break;
246             case OPTION_ARG_TYPE_FLG:
247                 *(bool *)opt->arg = false;
248                 break;
249             }
250         }
251     }
252     for (i = first;  i < argc;  i++) {
253         if (argv[i][0] == '-') {
254             c = argv[i][1];
255             flag_ok = false;
256             opt = opts;
257             for (j = 0;  j < num_opts;  j++, opt++) {
258                 if (c == opt->flag) {
259                     if (opt->arg_set && *opt->arg_set) {
260                         diag_printf("** Error: %s already specified\n", opt->name);
261                         ok = false;
262                     }
263                     if (opt->takes_arg) {
264                         if (argv[i][2] == '=') {
265                             s = &argv[i][3];
266                         } else {
267                             i++;
268                             if (i < argc) {
269                                 s = argv[i];
270                             } else {
271                                 diag_printf("** Error: option '%c' [%s] requires an argument\n",
272                                             c, opt->name);
273                                 ok = false;
274                                 flag_ok = true;
275                                 break;
276                             }
277                         }
278                         switch (opt->arg_type) {
279                         case OPTION_ARG_TYPE_NUM:
280                             if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) {
281                                 diag_printf("** Error: invalid number '%s' for %s\n", 
282                                             s, opt->name);
283                                 ok = false;
284                             }
285                             break;
286                         case OPTION_ARG_TYPE_STR:
287                             *(char **)opt->arg = s;
288                             break;
289                         }
290                         *opt->arg_set = true;
291                     } else {
292                         switch (opt->arg_type) {
293                         case OPTION_ARG_TYPE_NUM:
294                             *(int *)opt->arg = *(int *)opt->arg + 1;
295                             break;
296                         case OPTION_ARG_TYPE_FLG:
297                             *(bool *)opt->arg = true;
298                             break;
299                         }
300                     }
301                     flag_ok = true;
302                     break;
303                 }
304             }
305             if (!flag_ok) {
306                 diag_printf("** Error: invalid flag '%c'\n", c);
307                 ok = false;
308             }
309         } else {
310             if (def_arg) {
311                 ret = i + 1;
312                 if (def_arg_set) {
313                     diag_printf("** Error: %s already specified\n", def_descr);
314                     ok = false;
315                 }
316                 switch (def_arg_type) {
317                 case OPTION_ARG_TYPE_NUM:
318                     if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) {
319                         diag_printf("** Error: invalid number '%s' for %s\n", 
320                                     argv[i], def_descr);
321                         ok = false;
322                     }
323                     break;
324                 case OPTION_ARG_TYPE_STR:
325                     *(char **)def_arg = argv[i];
326                     break;
327                 }
328                 def_arg_set = true;
329             } else {
330                 diag_printf("** Error: no default/non-flag arguments supported\n");
331                 ok = false;
332             }
333         }
334     }
335     return ok ? ret : 0;
336 }
337
338 //
339 // Parse (scan) a number
340 //
341 bool
342 parse_num(char *s, unsigned long *val, char **es, char *delim)
343 {
344     bool first = true;
345     int radix = 10;
346     char c;
347     unsigned long result = 0;
348     int digit;
349
350     while (*s == ' ') s++;
351     while (*s) {
352         if (first && (s[0] == '0') && (_tolower(s[1]) == 'x')) {
353             radix = 16;
354             s += 2;
355         }
356         first = false;
357         c = *s++;
358         if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
359             // Valid digit
360 #ifdef CYGPKG_HAL_MIPS
361             // FIXME: tx49 compiler generates 0x2539018 for MUL which
362             // isn't any good.
363             if (16 == radix)
364                 result = result << 4;
365             else
366                 result = 10 * result;
367             result += digit;
368 #else
369             result = (result * radix) + digit;
370 #endif
371         } else {
372             if (delim != (char *)0) {
373                 // See if this character is one of the delimiters
374                 char *dp = delim;
375                 while (*dp && (c != *dp)) dp++;
376                 if (*dp) break;  // Found a good delimiter
377             }
378             return false;  // Malformatted number
379         }
380     }
381     *val = result;
382     if (es != (char **)0) {
383         *es = s;
384     }
385     return true;
386 }
387
388 bool
389 parse_bool(char *s, bool *val)
390 {
391     while (*s == ' ') s++;
392     if ((*s == 't') || (*s == 'T')) {
393         char *p = "rue";
394         char *P = "RUE";
395         // check for (partial) rest of the word and no extra including the
396         // terminating zero.  "tru" will match; "truef" will not.
397         while ( *++s ) {
398             if ( *p != *s && *P != *s ) return false;
399             p++; P++;
400         }
401         *val = true;
402     } else 
403     if ((*s == 'f') || (*s == 'F')) {
404         char *p = "alse";
405         char *P = "ALSE";
406         while ( *++s ) {
407             if ( *p != *s && *P != *s ) return false;
408             p++; P++;
409         }
410         *val = false;
411     } else {
412         return false;
413     }
414     return true;
415 }
416