📄 sim-options.c
字号:
SIM_RCsim_parse_args (sd, argv) SIM_DESC sd; char **argv;{ int c, i, argc, num_opts; char *p, *short_options; /* The `val' option struct entry is dynamically assigned for options that only come in the long form. ORIG_VAL is used to get the original value back. */ int *orig_val; struct option *lp, *long_options; const struct option_list *ol; const OPTION *opt; OPTION_HANDLER **handlers; sim_cpu **opt_cpu; SIM_RC result = SIM_RC_OK; /* Count the number of arguments. */ for (argc = 0; argv[argc] != NULL; ++argc) continue; /* Count the number of options. */ num_opts = 0; for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) for (opt = ol->options; OPTION_VALID_P (opt); ++opt) ++num_opts; for (i = 0; i < MAX_NR_PROCESSORS; ++i) for (ol = CPU_OPTIONS (STATE_CPU (sd, i)); ol != NULL; ol = ol->next) for (opt = ol->options; OPTION_VALID_P (opt); ++opt) ++num_opts; /* Initialize duplicate argument checker. */ (void) dup_arg_p (NULL); /* Build the option table for getopt. */ long_options = NZALLOC (struct option, num_opts + 1); lp = long_options; short_options = NZALLOC (char, num_opts * 3 + 1); p = short_options; handlers = NZALLOC (OPTION_HANDLER *, OPTION_START + num_opts); orig_val = NZALLOC (int, OPTION_START + num_opts); opt_cpu = NZALLOC (sim_cpu *, OPTION_START + num_opts); /* Set '+' as first char so argument permutation isn't done. This is done to stop getopt_long returning options that appear after the target program. Such options should be passed unchanged into the program image. */ *p++ = '+'; for (i = OPTION_START, ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) for (opt = ol->options; OPTION_VALID_P (opt); ++opt) { if (dup_arg_p (opt->opt.name)) continue; if (opt->shortopt != 0) { *p++ = opt->shortopt; if (opt->opt.has_arg == required_argument) *p++ = ':'; else if (opt->opt.has_arg == optional_argument) { *p++ = ':'; *p++ = ':'; } handlers[(unsigned char) opt->shortopt] = opt->handler; if (opt->opt.val != 0) orig_val[(unsigned char) opt->shortopt] = opt->opt.val; else orig_val[(unsigned char) opt->shortopt] = opt->shortopt; } if (opt->opt.name != NULL) { *lp = opt->opt; /* Dynamically assign `val' numbers for long options. */ lp->val = i++; handlers[lp->val] = opt->handler; orig_val[lp->val] = opt->opt.val; opt_cpu[lp->val] = NULL; ++lp; } } for (c = 0; c < MAX_NR_PROCESSORS; ++c) { sim_cpu *cpu = STATE_CPU (sd, c); for (ol = CPU_OPTIONS (cpu); ol != NULL; ol = ol->next) for (opt = ol->options; OPTION_VALID_P (opt); ++opt) {#if 0 /* Each option is prepended with --<cpuname>- so this greatly cuts down on the need for dup_arg_p checking. Maybe in the future it'll be needed so this is just commented out, and not deleted. */ if (dup_arg_p (opt->opt.name)) continue;#endif /* Don't allow short versions of cpu specific options for now. */ if (opt->shortopt != 0) { sim_io_eprintf (sd, "internal error, short cpu specific option"); result = SIM_RC_FAIL; break; } if (opt->opt.name != NULL) { char *name; *lp = opt->opt; /* Prepend --<cpuname>- to the option. */ asprintf (&name, "%s-%s", CPU_NAME (cpu), lp->name); lp->name = name; /* Dynamically assign `val' numbers for long options. */ lp->val = i++; handlers[lp->val] = opt->handler; orig_val[lp->val] = opt->opt.val; opt_cpu[lp->val] = cpu; ++lp; } } } /* Terminate the short and long option lists. */ *p = 0; lp->name = NULL; /* Ensure getopt is initialized. */ optind = 0; while (1) { int longind, optc; optc = getopt_long (argc, argv, short_options, long_options, &longind); if (optc == -1) { if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) STATE_PROG_ARGV (sd) = dupargv (argv + optind); break; } if (optc == '?') { result = SIM_RC_FAIL; break; } if ((*handlers[optc]) (sd, opt_cpu[optc], orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL) { result = SIM_RC_FAIL; break; } } zfree (long_options); zfree (short_options); zfree (handlers); zfree (opt_cpu); zfree (orig_val); return result;}/* Utility of sim_print_help to print a list of option tables. */static voidprint_help (SIM_DESC sd, sim_cpu *cpu, const struct option_list *ol, int is_command){ const OPTION *opt; for ( ; ol != NULL; ol = ol->next) for (opt = ol->options; OPTION_VALID_P (opt); ++opt) { const int indent = 30; int comma, len; const OPTION *o; if (dup_arg_p (opt->opt.name)) continue; if (opt->doc == NULL) continue; if (opt->doc_name != NULL && opt->doc_name [0] == '\0') continue; sim_io_printf (sd, " "); comma = 0; len = 2; /* list any short options (aliases) for the current OPT */ if (!is_command) { o = opt; do { if (o->shortopt != '\0') { sim_io_printf (sd, "%s-%c", comma ? ", " : "", o->shortopt); len += (comma ? 2 : 0) + 2; if (o->arg != NULL) { if (o->opt.has_arg == optional_argument) { sim_io_printf (sd, "[%s]", o->arg); len += 1 + strlen (o->arg) + 1; } else { sim_io_printf (sd, " %s", o->arg); len += 1 + strlen (o->arg); } } comma = 1; } ++o; } while (OPTION_VALID_P (o) && o->doc == NULL); } /* list any long options (aliases) for the current OPT */ o = opt; do { const char *name; const char *cpu_prefix = cpu ? CPU_NAME (cpu) : NULL; if (o->doc_name != NULL) name = o->doc_name; else name = o->opt.name; if (name != NULL) { sim_io_printf (sd, "%s%s%s%s%s", comma ? ", " : "", is_command ? "" : "--", cpu ? cpu_prefix : "", cpu ? "-" : "", name); len += ((comma ? 2 : 0) + (is_command ? 0 : 2) + strlen (name)); if (o->arg != NULL) { if (o->opt.has_arg == optional_argument) { sim_io_printf (sd, "[=%s]", o->arg); len += 2 + strlen (o->arg) + 1; } else { sim_io_printf (sd, " %s", o->arg); len += 1 + strlen (o->arg); } } comma = 1; } ++o; } while (OPTION_VALID_P (o) && o->doc == NULL); if (len >= indent) { sim_io_printf (sd, "\n%*s", indent, ""); } else sim_io_printf (sd, "%*s", indent - len, ""); /* print the description, word wrap long lines */ { const char *chp = opt->doc; unsigned doc_width = 80 - indent; while (strlen (chp) >= doc_width) /* some slack */ { const char *end = chp + doc_width - 1; while (end > chp && !isspace (*end)) end --; if (end == chp) end = chp + doc_width - 1; /* The cast should be ok - its distances between to points in a string. */ sim_io_printf (sd, "%.*s\n%*s", (int) (end - chp), chp, indent, ""); chp = end; while (isspace (*chp) && *chp != '\0') chp++; } sim_io_printf (sd, "%s\n", chp); } }}/* Print help messages for the options. */voidsim_print_help (sd, is_command) SIM_DESC sd; int is_command;{ if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) sim_io_printf (sd, "Usage: %s [options] program [program args]\n", STATE_MY_NAME (sd)); /* Initialize duplicate argument checker. */ (void) dup_arg_p (NULL); if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) sim_io_printf (sd, "Options:\n"); else sim_io_printf (sd, "Commands:\n"); print_help (sd, NULL, STATE_OPTIONS (sd), is_command); sim_io_printf (sd, "\n"); /* Print cpu-specific options. */ { int i; for (i = 0; i < MAX_NR_PROCESSORS; ++i) { sim_cpu *cpu = STATE_CPU (sd, i); if (CPU_OPTIONS (cpu) == NULL) continue; sim_io_printf (sd, "CPU %s specific options:\n", CPU_NAME (cpu)); print_help (sd, cpu, CPU_OPTIONS (cpu), is_command); sim_io_printf (sd, "\n"); } } sim_io_printf (sd, "Note: Depending on the simulator configuration some %ss\n", STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE ? "option" : "command"); sim_io_printf (sd, " may not be applicable\n"); if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) { sim_io_printf (sd, "\n"); sim_io_printf (sd, "program args Arguments to pass to simulated program.\n"); sim_io_printf (sd, " Note: Very few simulators support this.\n"); }}/* Utility of sim_args_command to find the closest match for a command. Commands that have "-" in them can be specified as separate words. e.g. sim memory-region 0x800000,0x4000 or sim memory region 0x800000,0x4000 If CPU is non-null, use its option table list, otherwise use the main one. *PARGI is where to start looking in ARGV. It is updated to point past the found option. */static const OPTION *find_match (SIM_DESC sd, sim_cpu *cpu, char *argv[], int *pargi){ const struct option_list *ol; const OPTION *opt; /* most recent option match */ const OPTION *matching_opt = NULL; int matching_argi = -1; if (cpu) ol = CPU_OPTIONS (cpu); else ol = STATE_OPTIONS (sd); /* Skip passed elements specified by *PARGI. */ argv += *pargi; for ( ; ol != NULL; ol = ol->next) for (opt = ol->options; OPTION_VALID_P (opt); ++opt) { int argi = 0; const char *name = opt->opt.name; if (name == NULL) continue; while (argv [argi] != NULL && strncmp (name, argv [argi], strlen (argv [argi])) == 0) { name = &name [strlen (argv[argi])]; if (name [0] == '-') { /* leading match ...<a-b-c>-d-e-f - continue search */ name ++; /* skip `-' */ argi ++; continue; } else if (name [0] == '\0') { /* exact match ...<a-b-c-d-e-f> - better than before? */ if (argi > matching_argi) { matching_argi = argi; matching_opt = opt; } break; } else break; } } *pargi = matching_argi; return matching_opt;}SIM_RCsim_args_command (SIM_DESC sd, char *cmd){ /* something to do? */ if (cmd == NULL) return SIM_RC_OK; /* FIXME - perhaps help would be better */ if (cmd [0] == '-') { /* user specified -<opt> ... form? */ char **argv = buildargv (cmd); SIM_RC rc = sim_parse_args (sd, argv); freeargv (argv); return rc; } else { char **argv = buildargv (cmd); const OPTION *matching_opt = NULL; int matching_argi; sim_cpu *cpu; if (argv [0] == NULL) return SIM_RC_OK; /* FIXME - perhaps help would be better */ /* First check for a cpu selector. */ { char *cpu_name = xstrdup (argv[0]); char *hyphen = strchr (cpu_name, '-'); if (hyphen) *hyphen = 0; cpu = sim_cpu_lookup (sd, cpu_name); if (cpu) { /* If <cpuname>-<command>, point argv[0] at <command>. */ if (hyphen) { matching_argi = 0; argv[0] += hyphen - cpu_name + 1; } else matching_argi = 1; matching_opt = find_match (sd, cpu, argv, &matching_argi); /* If hyphen found restore argv[0]. */ if (hyphen) argv[0] -= hyphen - cpu_name + 1; } free (cpu_name); } /* If that failed, try the main table. */ if (matching_opt == NULL) { matching_argi = 0; matching_opt = find_match (sd, NULL, argv, &matching_argi); } if (matching_opt != NULL) { switch (matching_opt->opt.has_arg) { case no_argument: if (argv [matching_argi + 1] == NULL) matching_opt->handler (sd, cpu, matching_opt->opt.val, NULL, 1/*is_command*/); else sim_io_eprintf (sd, "Command `%s' takes no arguments\n", matching_opt->opt.name); break; case optional_argument: if (argv [matching_argi + 1] == NULL) matching_opt->handler (sd, cpu, matching_opt->opt.val, NULL, 1/*is_command*/); else if (argv [matching_argi + 2] == NULL) matching_opt->handler (sd, cpu, matching_opt->opt.val, argv [matching_argi + 1], 1/*is_command*/); else sim_io_eprintf (sd, "Command `%s' requires no more than one argument\n", matching_opt->opt.name); break; case required_argument: if (argv [matching_argi + 1] == NULL) sim_io_eprintf (sd, "Command `%s' requires an argument\n", matching_opt->opt.name); else if (argv [matching_argi + 2] == NULL) matching_opt->handler (sd, cpu, matching_opt->opt.val, argv [matching_argi + 1], 1/*is_command*/); else sim_io_eprintf (sd, "Command `%s' requires only one argument\n", matching_opt->opt.name); } freeargv (argv); return SIM_RC_OK; } freeargv (argv); } /* didn't find anything that remotly matched */ return SIM_RC_FAIL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -