Commit | Line | Data |
---|---|---|
4ede3a83 DE |
1 | /* Simulator option handling. |
2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. | |
3 | Contributed by Cygnus Support. | |
4 | ||
5 | This file is part of GDB, the GNU debugger. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License along | |
18 | with this program; if not, write to the Free Software Foundation, Inc., | |
19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
20 | ||
21 | #include "sim-main.h" | |
22 | #ifdef HAVE_STRING_H | |
23 | #include <string.h> | |
24 | #else | |
25 | #ifdef HAVE_STRINGS_H | |
26 | #include <strings.h> | |
27 | #endif | |
28 | #endif | |
50a2a691 AC |
29 | #ifdef HAVE_STDLIB_H |
30 | #include <stdlib.h> | |
31 | #endif | |
32 | #include <ctype.h> | |
4ede3a83 DE |
33 | #include "libiberty.h" |
34 | #include "../libiberty/alloca-conf.h" | |
35 | #include "sim-options.h" | |
36 | #include "sim-io.h" | |
50a2a691 | 37 | #include "sim-assert.h" |
4ede3a83 | 38 | |
4ede3a83 DE |
39 | /* Add a set of options to the simulator. |
40 | TABLE is an array of OPTIONS terminated by a NULL `opt.name' entry. | |
41 | This is intended to be called by modules in their `install' handler. */ | |
42 | ||
43 | SIM_RC | |
44 | sim_add_option_table (sd, table) | |
45 | SIM_DESC sd; | |
46 | const OPTION *table; | |
47 | { | |
48 | struct option_list *ol = ((struct option_list *) | |
49 | xmalloc (sizeof (struct option_list))); | |
50 | ||
51 | /* Note: The list is constructed in the reverse order we're called so | |
52 | later calls will override earlier ones (in case that ever happens). | |
53 | This is the intended behaviour. */ | |
54 | ol->next = STATE_OPTIONS (sd); | |
55 | ol->options = table; | |
56 | STATE_OPTIONS (sd) = ol; | |
57 | ||
58 | return SIM_RC_OK; | |
59 | } | |
60 | ||
61 | /* Standard option table. | |
62 | Modules may specify additional ones. | |
63 | The caller of sim_parse_args may also specify additional options | |
64 | by calling sim_add_option_table first. */ | |
65 | ||
66 | static DECLARE_OPTION_HANDLER (standard_option_handler); | |
67 | ||
68 | /* FIXME: We shouldn't print in --help output options that aren't usable. | |
69 | Some fine tuning will be necessary. One can either move less general | |
70 | options to another table or use a HAVE_FOO macro to ifdef out unavailable | |
71 | options. */ | |
72 | ||
e65bd1d8 DE |
73 | /* ??? One might want to conditionally compile out the entries that |
74 | aren't enabled. There's a distinction, however, between options a | |
75 | simulator can't support and options that haven't been configured in. | |
76 | Certainly options a simulator can't support shouldn't appear in the | |
77 | output of --help. Whether the same thing applies to options that haven't | |
78 | been configured in or not isn't something I can get worked up over. | |
79 | [Note that conditionally compiling them out might simply involve moving | |
80 | the option to another table.] | |
81 | If you decide to conditionally compile them out as well, delete this | |
82 | comment and add a comment saying that that is the rule. */ | |
83 | ||
4ede3a83 DE |
84 | #define OPTION_DEBUG_INSN (OPTION_START + 0) |
85 | #define OPTION_DEBUG_FILE (OPTION_START + 1) | |
43c53e07 | 86 | #define OPTION_DO_COMMAND (OPTION_START + 2) |
4ede3a83 DE |
87 | |
88 | static const OPTION standard_options[] = | |
89 | { | |
90 | { {"verbose", no_argument, NULL, 'v'}, | |
91 | 'v', NULL, "Verbose output", | |
92 | standard_option_handler }, | |
93 | ||
e65bd1d8 DE |
94 | #if defined (SIM_HAVE_BIENDIAN) /* ??? && WITH_TARGET_BYTE_ORDER == 0 */ |
95 | { {"endian", required_argument, NULL, 'E'}, | |
96 | 'E', "big|little", "Set endianness", | |
97 | standard_option_handler }, | |
98 | #endif | |
99 | ||
4ede3a83 DE |
100 | { {"debug", no_argument, NULL, 'D'}, |
101 | 'D', NULL, "Print debugging messages", | |
102 | standard_option_handler }, | |
103 | { {"debug-insn", no_argument, NULL, OPTION_DEBUG_INSN}, | |
104 | '\0', NULL, "Print instruction debugging messages", | |
105 | standard_option_handler }, | |
106 | { {"debug-file", required_argument, NULL, OPTION_DEBUG_FILE}, | |
107 | '\0', "FILE NAME", "Specify debugging output file", | |
108 | standard_option_handler }, | |
109 | ||
4ede3a83 DE |
110 | #ifdef SIM_H8300 /* FIXME: Should be movable to h8300 dir. */ |
111 | { {"h8300h", no_argument, NULL, 'h'}, | |
112 | 'h', NULL, "Indicate the CPU is h8/300h or h8/300s", | |
113 | standard_option_handler }, | |
114 | #endif | |
115 | ||
4ede3a83 DE |
116 | #ifdef SIM_HAVE_FLATMEM |
117 | { {"mem-size", required_argument, NULL, 'm'}, | |
118 | 'm', "MEMORY SIZE", "Specify memory size", | |
119 | standard_option_handler }, | |
120 | #endif | |
121 | ||
43c53e07 | 122 | { {"do-command", required_argument, NULL, OPTION_DO_COMMAND}, |
50a2a691 | 123 | '\0', "COMMAND", ""/*undocumented*/, |
43c53e07 AC |
124 | standard_option_handler }, |
125 | ||
4ede3a83 DE |
126 | { {"help", no_argument, NULL, 'H'}, |
127 | 'H', NULL, "Print help information", | |
128 | standard_option_handler }, | |
129 | ||
130 | { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } | |
131 | }; | |
132 | ||
133 | static SIM_RC | |
50a2a691 | 134 | standard_option_handler (sd, opt, arg, is_command) |
4ede3a83 DE |
135 | SIM_DESC sd; |
136 | int opt; | |
137 | char *arg; | |
50a2a691 | 138 | int is_command; |
4ede3a83 DE |
139 | { |
140 | int i,n; | |
4ede3a83 DE |
141 | |
142 | switch (opt) | |
143 | { | |
144 | case 'v' : | |
145 | STATE_VERBOSE_P (sd) = 1; | |
146 | break; | |
147 | ||
e65bd1d8 DE |
148 | #ifdef SIM_HAVE_BIENDIAN |
149 | case 'E' : | |
150 | if (strcmp (arg, "big") == 0) | |
151 | { | |
152 | if (WITH_TARGET_BYTE_ORDER == LITTLE_ENDIAN) | |
153 | { | |
154 | sim_io_eprintf (sd, "Simulator compiled for little endian only.\n"); | |
155 | return SIM_RC_FAIL; | |
156 | } | |
157 | /* FIXME:wip: Need to set something in STATE_CONFIG. */ | |
50a2a691 | 158 | current_target_byte_order = BIG_ENDIAN; |
e65bd1d8 DE |
159 | } |
160 | else if (strcmp (arg, "little") == 0) | |
161 | { | |
162 | if (WITH_TARGET_BYTE_ORDER == BIG_ENDIAN) | |
163 | { | |
164 | sim_io_eprintf (sd, "Simulator compiled for big endian only.\n"); | |
165 | return SIM_RC_FAIL; | |
166 | } | |
167 | /* FIXME:wip: Need to set something in STATE_CONFIG. */ | |
50a2a691 | 168 | current_target_byte_order = LITTLE_ENDIAN; |
e65bd1d8 DE |
169 | } |
170 | else | |
171 | { | |
172 | sim_io_eprintf (sd, "Invalid endian specification `%s'\n", arg); | |
173 | return SIM_RC_FAIL; | |
174 | } | |
175 | break; | |
176 | #endif | |
177 | ||
4ede3a83 DE |
178 | case 'D' : |
179 | if (! WITH_DEBUG) | |
180 | sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n"); | |
181 | else | |
182 | { | |
183 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
184 | for (i = 0; i < MAX_DEBUG_VALUES; ++i) | |
185 | CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[i] = 1; | |
186 | } | |
187 | break; | |
188 | ||
189 | case OPTION_DEBUG_INSN : | |
190 | if (! WITH_DEBUG) | |
191 | sim_io_eprintf (sd, "Debugging not compiled in, `--debug-insn' ignored\n"); | |
192 | else | |
193 | { | |
194 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
195 | CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[DEBUG_INSN_IDX] = 1; | |
196 | } | |
197 | break; | |
198 | ||
199 | case OPTION_DEBUG_FILE : | |
200 | if (! WITH_DEBUG) | |
201 | sim_io_eprintf (sd, "Debugging not compiled in, `--debug-file' ignored\n"); | |
202 | else | |
203 | { | |
204 | FILE *f = fopen (arg, "w"); | |
205 | ||
206 | if (f == NULL) | |
207 | { | |
208 | sim_io_eprintf (sd, "Unable to open debug output file `%s'\n", arg); | |
209 | return SIM_RC_FAIL; | |
210 | } | |
211 | for (n = 0; n < MAX_NR_PROCESSORS; ++n) | |
212 | CPU_DEBUG_FILE (STATE_CPU (sd, n)) = f; | |
213 | } | |
214 | break; | |
215 | ||
4ede3a83 DE |
216 | #ifdef SIM_H8300 /* FIXME: Can be moved to h8300 dir. */ |
217 | case 'h' : | |
218 | set_h8300h (1); | |
219 | break; | |
220 | #endif | |
221 | ||
4ede3a83 DE |
222 | #ifdef SIM_HAVE_FLATMEM |
223 | case 'm': | |
43c53e07 AC |
224 | { |
225 | unsigned long ul = strtol (arg, NULL, 0); | |
226 | /* 16384: some minimal amount */ | |
227 | if (! isdigit (arg[0]) || ul < 16384) | |
228 | { | |
229 | sim_io_eprintf (sd, "Invalid memory size `%s'", arg); | |
230 | return SIM_RC_FAIL; | |
231 | } | |
232 | STATE_MEM_SIZE (sd) = ul; | |
233 | } | |
4ede3a83 DE |
234 | break; |
235 | #endif | |
236 | ||
43c53e07 AC |
237 | case OPTION_DO_COMMAND: |
238 | sim_do_command (sd, arg); | |
239 | break; | |
240 | ||
4ede3a83 | 241 | case 'H': |
2f2e6c5d | 242 | sim_print_help (sd, is_command); |
4ede3a83 DE |
243 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) |
244 | exit (0); | |
245 | /* FIXME: 'twould be nice to do something similar if gdb. */ | |
246 | break; | |
247 | } | |
248 | ||
249 | return SIM_RC_OK; | |
250 | } | |
251 | ||
c967f187 | 252 | /* Add the standard option list to the simulator. */ |
4ede3a83 DE |
253 | |
254 | SIM_RC | |
c967f187 | 255 | standard_install (SIM_DESC sd) |
4ede3a83 | 256 | { |
50a2a691 | 257 | SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); |
4ede3a83 DE |
258 | if (sim_add_option_table (sd, standard_options) != SIM_RC_OK) |
259 | return SIM_RC_FAIL; | |
4ede3a83 DE |
260 | return SIM_RC_OK; |
261 | } | |
262 | ||
263 | /* Return non-zero if arg is a duplicate argument. | |
264 | If ARG is NULL, initialize. */ | |
265 | ||
266 | #define ARG_HASH_SIZE 97 | |
267 | #define ARG_HASH(a) ((256 * (unsigned char) a[0] + (unsigned char) a[1]) % ARG_HASH_SIZE) | |
268 | ||
269 | static int | |
270 | dup_arg_p (arg) | |
271 | char *arg; | |
272 | { | |
273 | int hash; | |
274 | static char **arg_table = NULL; | |
275 | ||
276 | if (arg == NULL) | |
277 | { | |
278 | if (arg_table == NULL) | |
279 | arg_table = (char **) xmalloc (ARG_HASH_SIZE * sizeof (char *)); | |
280 | memset (arg_table, 0, ARG_HASH_SIZE * sizeof (char *)); | |
281 | return 0; | |
282 | } | |
283 | ||
284 | hash = ARG_HASH (arg); | |
285 | while (arg_table[hash] != NULL) | |
286 | { | |
287 | if (strcmp (arg, arg_table[hash]) == 0) | |
288 | return 1; | |
289 | /* We assume there won't be more than ARG_HASH_SIZE arguments so we | |
290 | don't check if the table is full. */ | |
291 | if (++hash == ARG_HASH_SIZE) | |
292 | hash = 0; | |
293 | } | |
294 | arg_table[hash] = arg; | |
295 | return 0; | |
296 | } | |
297 | ||
298 | /* Called by sim_open to parse the arguments. */ | |
299 | ||
300 | SIM_RC | |
301 | sim_parse_args (sd, argv) | |
302 | SIM_DESC sd; | |
303 | char **argv; | |
304 | { | |
305 | int i, argc, num_opts; | |
306 | char *p, *short_options; | |
307 | /* The `val' option struct entry is dynamically assigned for options that | |
308 | only come in the long form. ORIG_VAL is used to get the original value | |
309 | back. */ | |
8786d426 | 310 | unsigned char *orig_val; |
4ede3a83 DE |
311 | struct option *lp, *long_options; |
312 | const struct option_list *ol; | |
313 | const OPTION *opt; | |
314 | OPTION_HANDLER **handlers; | |
315 | ||
316 | /* Count the number of arguments. */ | |
317 | for (argc = 0; argv[argc] != NULL; ++argc) | |
318 | continue; | |
319 | ||
320 | /* Count the number of options. */ | |
321 | num_opts = 0; | |
322 | for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) | |
323 | for (opt = ol->options; opt->opt.name != NULL; ++opt) | |
324 | ++num_opts; | |
325 | ||
326 | /* Initialize duplicate argument checker. */ | |
327 | (void) dup_arg_p (NULL); | |
328 | ||
329 | /* Build the option table for getopt. */ | |
330 | long_options = (struct option *) alloca ((num_opts + 1) * sizeof (struct option)); | |
331 | lp = long_options; | |
332 | short_options = (char *) alloca (num_opts * 3 + 1); | |
333 | p = short_options; | |
334 | #if 0 /* ??? necessary anymore? */ | |
335 | /* Set '+' as first char so argument permutation isn't done. This is done | |
336 | to workaround a problem with invoking getopt_long in run.c.: optind gets | |
337 | decremented when the program name is reached. */ | |
338 | *p++ = '+'; | |
339 | #endif | |
340 | handlers = (OPTION_HANDLER **) alloca (256 * sizeof (OPTION_HANDLER *)); | |
341 | memset (handlers, 0, 256 * sizeof (OPTION_HANDLER *)); | |
8786d426 | 342 | orig_val = (unsigned char *) alloca (256); |
4ede3a83 DE |
343 | for (i = OPTION_START, ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) |
344 | for (opt = ol->options; opt->opt.name != NULL; ++opt) | |
345 | { | |
346 | if (dup_arg_p (opt->opt.name)) | |
347 | continue; | |
348 | if (opt->shortopt != 0) | |
349 | { | |
350 | *p++ = opt->shortopt; | |
351 | if (opt->opt.has_arg == required_argument) | |
352 | *p++ = ':'; | |
353 | else if (opt->opt.has_arg == optional_argument) | |
354 | { *p++ = ':'; *p++ = ':'; } | |
355 | } | |
356 | *lp = opt->opt; | |
357 | /* Dynamically assign `val' numbers for long options that don't have | |
358 | a short option equivalent. */ | |
359 | if (OPTION_LONG_ONLY_P (opt->opt.val)) | |
360 | lp->val = i++; | |
361 | handlers[(unsigned char) lp->val] = opt->handler; | |
362 | orig_val[(unsigned char) lp->val] = opt->opt.val; | |
363 | ++lp; | |
364 | } | |
365 | *p = 0; | |
366 | lp->name = NULL; | |
367 | ||
368 | /* Ensure getopt is initialized. */ | |
369 | optind = 0; | |
370 | while (1) | |
371 | { | |
372 | int longind, optc; | |
373 | ||
374 | optc = getopt_long (argc, argv, short_options, long_options, &longind); | |
375 | if (optc == -1) | |
376 | { | |
377 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) | |
d07dddd2 | 378 | STATE_PROG_ARGV (sd) = sim_copy_argv (argv + optind); |
4ede3a83 DE |
379 | break; |
380 | } | |
381 | if (optc == '?') | |
382 | return SIM_RC_FAIL; | |
383 | ||
50a2a691 | 384 | if ((*handlers[optc]) (sd, orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL) |
4ede3a83 DE |
385 | return SIM_RC_FAIL; |
386 | } | |
387 | ||
388 | return SIM_RC_OK; | |
389 | } | |
390 | ||
391 | /* Print help messages for the options. */ | |
392 | ||
393 | void | |
2f2e6c5d | 394 | sim_print_help (sd, is_command) |
4ede3a83 | 395 | SIM_DESC sd; |
2f2e6c5d | 396 | int is_command; |
4ede3a83 DE |
397 | { |
398 | const struct option_list *ol; | |
399 | const OPTION *opt; | |
400 | ||
401 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) | |
402 | sim_io_printf (sd, "Usage: %s [options] program [program args]\n", | |
403 | STATE_MY_NAME (sd)); | |
404 | ||
405 | /* Initialize duplicate argument checker. */ | |
406 | (void) dup_arg_p (NULL); | |
407 | ||
d07dddd2 AC |
408 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) |
409 | sim_io_printf (sd, "Options:\n"); | |
410 | else | |
411 | sim_io_printf (sd, "Commands:\n"); | |
412 | ||
4ede3a83 DE |
413 | for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) |
414 | for (opt = ol->options; opt->opt.name != NULL; ++opt) | |
415 | { | |
416 | int comma, len; | |
417 | const OPTION *o; | |
418 | ||
419 | if (dup_arg_p (opt->opt.name)) | |
420 | continue; | |
421 | ||
422 | if (opt->doc == NULL) | |
423 | continue; | |
424 | ||
50a2a691 AC |
425 | if (opt->doc_name != NULL && opt->doc_name [0] == '\0') |
426 | continue; | |
427 | ||
4ede3a83 DE |
428 | sim_io_printf (sd, " "); |
429 | ||
430 | comma = 0; | |
431 | len = 2; | |
432 | ||
2f2e6c5d | 433 | if (!is_command) |
4ede3a83 | 434 | { |
2f2e6c5d AC |
435 | o = opt; |
436 | do | |
4ede3a83 | 437 | { |
2f2e6c5d | 438 | if (o->shortopt != '\0') |
4ede3a83 | 439 | { |
2f2e6c5d AC |
440 | sim_io_printf (sd, "%s-%c", comma ? ", " : "", o->shortopt); |
441 | len += (comma ? 2 : 0) + 2; | |
442 | if (o->arg != NULL) | |
43c53e07 | 443 | { |
2f2e6c5d AC |
444 | if (o->opt.has_arg == optional_argument) |
445 | { | |
446 | sim_io_printf (sd, "[%s]", o->arg); | |
447 | len += 1 + strlen (o->arg) + 1; | |
448 | } | |
449 | else | |
450 | { | |
451 | sim_io_printf (sd, " %s", o->arg); | |
452 | len += 1 + strlen (o->arg); | |
453 | } | |
4ede3a83 | 454 | } |
2f2e6c5d | 455 | comma = 1; |
4ede3a83 | 456 | } |
2f2e6c5d | 457 | ++o; |
4ede3a83 | 458 | } |
2f2e6c5d | 459 | while (o->opt.name != NULL && o->doc == NULL); |
4ede3a83 | 460 | } |
2f2e6c5d | 461 | |
4ede3a83 DE |
462 | o = opt; |
463 | do | |
464 | { | |
50a2a691 AC |
465 | const char *name; |
466 | if (o->doc_name != NULL) | |
467 | name = o->doc_name; | |
468 | else | |
469 | name = o->opt.name; | |
470 | if (name != NULL) | |
4ede3a83 | 471 | { |
2f2e6c5d | 472 | sim_io_printf (sd, "%s%s%s", |
4ede3a83 | 473 | comma ? ", " : "", |
2f2e6c5d | 474 | is_command ? "" : "--", |
50a2a691 | 475 | name); |
4ede3a83 | 476 | len += ((comma ? 2 : 0) |
2f2e6c5d | 477 | + (is_command ? 0 : 2) |
50a2a691 | 478 | + strlen (name)); |
4ede3a83 DE |
479 | if (o->arg != NULL) |
480 | { | |
43c53e07 AC |
481 | if (o->opt.has_arg == optional_argument) |
482 | { | |
483 | sim_io_printf (sd, " [%s]", o->arg); | |
484 | len += 2 + strlen (o->arg) + 1; | |
485 | } | |
486 | else | |
487 | { | |
488 | sim_io_printf (sd, " %s", o->arg); | |
489 | len += 1 + strlen (o->arg); | |
490 | } | |
4ede3a83 DE |
491 | } |
492 | comma = 1; | |
493 | } | |
494 | ++o; | |
495 | } | |
496 | while (o->opt.name != NULL && o->doc == NULL); | |
497 | ||
498 | if (len >= 30) | |
499 | { | |
500 | sim_io_printf (sd, "\n"); | |
501 | len = 0; | |
502 | } | |
503 | ||
504 | for (; len < 30; len++) | |
505 | sim_io_printf (sd, " "); | |
506 | ||
507 | sim_io_printf (sd, "%s\n", opt->doc); | |
508 | } | |
509 | ||
d07dddd2 AC |
510 | sim_io_printf (sd, "\n"); |
511 | sim_io_printf (sd, "Note: Depending on the simulator configuration some %ss\n", | |
512 | STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE ? "option" : "command"); | |
513 | sim_io_printf (sd, " may not be applicable\n"); | |
514 | ||
4ede3a83 DE |
515 | if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) |
516 | { | |
517 | sim_io_printf (sd, "\n"); | |
518 | sim_io_printf (sd, "program args Arguments to pass to simulated program.\n"); | |
519 | sim_io_printf (sd, " Note: Very few simulators support this.\n"); | |
520 | } | |
521 | } | |
43c53e07 AC |
522 | |
523 | ||
524 | ||
525 | ||
526 | SIM_RC | |
527 | sim_args_command (sd, cmd) | |
528 | SIM_DESC sd; | |
529 | char *cmd; | |
530 | { | |
531 | /* something to do? */ | |
532 | if (cmd == NULL) | |
533 | return SIM_RC_OK; /* FIXME - perhaphs help would be better */ | |
534 | ||
535 | if (cmd [0] == '-') | |
536 | { | |
537 | /* user specified -<opt> ... form? */ | |
538 | char **argv = buildargv (cmd); | |
539 | SIM_RC rc = sim_parse_args (sd, argv); | |
540 | freeargv (argv); | |
541 | return rc; | |
542 | } | |
543 | else | |
544 | { | |
545 | /* user specified <opt> form? */ | |
546 | const struct option_list *ol; | |
547 | const OPTION *opt; | |
548 | char **argv = buildargv (cmd); | |
50a2a691 AC |
549 | /* most recent option match */ |
550 | const OPTION *matching_opt = NULL; | |
551 | int matching_argi = -1; | |
552 | if (argv [0] != NULL) | |
553 | for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) | |
554 | for (opt = ol->options; opt->opt.name != NULL; ++opt) | |
555 | { | |
556 | int argi = 0; | |
557 | const char *name = opt->opt.name; | |
558 | while (strncmp (name, argv [argi], strlen (argv [argi])) == 0) | |
559 | { | |
560 | name = &name [strlen (argv[argi])]; | |
561 | if (name [0] == '-') | |
562 | { | |
563 | /* leading match ...<a-b-c>-d-e-f - continue search */ | |
564 | name ++; /* skip `-' */ | |
565 | argi ++; | |
566 | continue; | |
567 | } | |
568 | else if (name [0] == '\0') | |
569 | { | |
570 | /* exact match ...<a-b-c-d-e-f> - better than before? */ | |
571 | if (argi > matching_argi) | |
572 | { | |
573 | matching_argi = argi; | |
574 | matching_opt = opt; | |
575 | } | |
576 | break; | |
577 | } | |
578 | else | |
43c53e07 | 579 | break; |
50a2a691 AC |
580 | } |
581 | } | |
582 | if (matching_opt != NULL) | |
583 | { | |
584 | switch (matching_opt->opt.has_arg) | |
585 | { | |
586 | case no_argument: | |
587 | if (argv [matching_argi + 1] == NULL) | |
588 | matching_opt->handler (sd, matching_opt->opt.val, | |
589 | NULL, 1/*is_command*/); | |
590 | else | |
591 | sim_io_eprintf (sd, "Command `%s' takes no arguments\n", | |
592 | matching_opt->opt.name); | |
593 | break; | |
594 | case optional_argument: | |
595 | if (argv [matching_argi + 1] == NULL) | |
596 | matching_opt->handler (sd, matching_opt->opt.val, | |
597 | NULL, 1/*is_command*/); | |
598 | else if (argv [matching_argi + 2] == NULL) | |
599 | matching_opt->handler (sd, matching_opt->opt.val, | |
600 | argv [matching_argi + 1], 1/*is_command*/); | |
601 | else | |
602 | sim_io_eprintf (sd, "Command `%s' requires no more than one argument\n", | |
603 | matching_opt->opt.name); | |
604 | break; | |
605 | case required_argument: | |
606 | if (argv [matching_argi + 1] == NULL) | |
607 | sim_io_eprintf (sd, "Command `%s' requires an argument\n", | |
608 | matching_opt->opt.name); | |
609 | else if (argv [matching_argi + 2] == NULL) | |
610 | matching_opt->handler (sd, matching_opt->opt.val, | |
611 | argv [matching_argi + 1], 1/*is_command*/); | |
612 | else | |
613 | sim_io_eprintf (sd, "Command `%s' requires only one argument\n", | |
614 | matching_opt->opt.name); | |
615 | } | |
616 | return SIM_RC_OK; | |
617 | } | |
43c53e07 | 618 | } |
50a2a691 AC |
619 | |
620 | /* didn't find anything that remotly matched */ | |
43c53e07 AC |
621 | return SIM_RC_FAIL; |
622 | } |