diff options
author | Simon Glass <sjg@chromium.org> | 2012-02-15 15:51:16 -0800 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2012-03-12 11:06:01 -0400 |
commit | 70db4212fcdb080444a23dccaf673b68a3ffc1fa (patch) | |
tree | bbb9a51e44cc6b1a87a583f89673d8e6de040207 /arch/sandbox/cpu | |
parent | ab4e07eb71ca1913e5291316565c9d073987de85 (diff) | |
download | u-boot-70db4212fcdb080444a23dccaf673b68a3ffc1fa.tar.gz u-boot-70db4212fcdb080444a23dccaf673b68a3ffc1fa.tar.xz u-boot-70db4212fcdb080444a23dccaf673b68a3ffc1fa.zip |
sandbox: add getopt support
This adds simple command-line parsing to sandbox. The idea is that it
sets up the state with options provided, and this state can then be
queried later, as needed.
New flags are declared with the SB_CMDLINE_OPT_SHORT helper macro,
pointers are automatically gathered up in a special section, and
then the core code takes care of gathering them up and processing
at runtime. This way there is no central place where we have to
store a list of flags with ifdefs.
Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/sandbox/cpu')
-rw-r--r-- | arch/sandbox/cpu/os.c | 98 | ||||
-rw-r--r-- | arch/sandbox/cpu/start.c | 88 | ||||
-rw-r--r-- | arch/sandbox/cpu/u-boot.lds | 4 |
3 files changed, 190 insertions, 0 deletions
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index cb469e0510..36637af6ce 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -21,6 +21,7 @@ #include <errno.h> #include <fcntl.h> +#include <getopt.h> #include <stdlib.h> #include <termios.h> #include <time.h> @@ -31,6 +32,9 @@ #include <sys/types.h> #include <linux/types.h> +#include <asm/getopt.h> +#include <asm/sections.h> +#include <asm/state.h> #include <os.h> /* Operating System Interface */ @@ -155,3 +159,97 @@ u64 os_get_nsec(void) return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000; #endif } + +static char *short_opts; +static struct option *long_opts; + +int os_parse_args(struct sandbox_state *state, int argc, char *argv[]) +{ + struct sb_cmdline_option **sb_opt = __u_boot_sandbox_option_start; + size_t num_options = __u_boot_sandbox_option_count(); + size_t i; + + int hidden_short_opt; + size_t si; + + int c; + + if (short_opts || long_opts) + return 1; + + state->argc = argc; + state->argv = argv; + + /* dynamically construct the arguments to the system getopt_long */ + short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1); + long_opts = os_malloc(sizeof(*long_opts) * num_options); + if (!short_opts || !long_opts) + return 1; + + /* + * getopt_long requires "val" to be unique (since that is what the + * func returns), so generate unique values automatically for flags + * that don't have a short option. pick 0x100 as that is above the + * single byte range (where ASCII/ISO-XXXX-X charsets live). + */ + hidden_short_opt = 0x100; + si = 0; + for (i = 0; i < num_options; ++i) { + long_opts[i].name = sb_opt[i]->flag; + long_opts[i].has_arg = sb_opt[i]->has_arg ? + required_argument : no_argument; + long_opts[i].flag = NULL; + + if (sb_opt[i]->flag_short) { + short_opts[si++] = long_opts[i].val = sb_opt[i]->flag_short; + if (long_opts[i].has_arg == required_argument) + short_opts[si++] = ':'; + } else + long_opts[i].val = sb_opt[i]->flag_short = hidden_short_opt++; + } + short_opts[si] = '\0'; + + /* we need to handle output ourselves since u-boot provides printf */ + opterr = 0; + + /* + * walk all of the options the user gave us on the command line, + * figure out what u-boot option structure they belong to (via + * the unique short val key), and call the appropriate callback. + */ + while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { + for (i = 0; i < num_options; ++i) { + if (sb_opt[i]->flag_short == c) { + if (sb_opt[i]->callback(state, optarg)) { + state->parse_err = sb_opt[i]->flag; + return 0; + } + break; + } + } + if (i == num_options) { + /* + * store the faulting flag for later display. we have to + * store the flag itself as the getopt parsing itself is + * tricky: need to handle the following flags (assume all + * of the below are unknown): + * -a optopt='a' optind=<next> + * -abbbb optopt='a' optind=<this> + * -aaaaa optopt='a' optind=<this> + * --a optopt=0 optind=<this> + * as you can see, it is impossible to determine the exact + * faulting flag without doing the parsing ourselves, so + * we just report the specific flag that failed. + */ + if (optopt) { + static char parse_err[3] = { '-', 0, '\0', }; + parse_err[1] = optopt; + state->parse_err = parse_err; + } else + state->parse_err = argv[optind - 1]; + break; + } + } + + return 0; +} diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 4a84486c1e..6c3e8eb379 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -20,21 +20,109 @@ */ #include <common.h> +#include <asm/getopt.h> +#include <asm/sections.h> #include <asm/state.h> +#include <os.h> + +int sandbox_early_getopt_check(void) +{ + struct sandbox_state *state = state_get_current(); + struct sb_cmdline_option **sb_opt = __u_boot_sandbox_option_start; + size_t num_options = __u_boot_sandbox_option_count(); + size_t i; + int max_arg_len, max_noarg_len; + + /* parse_err will be a string of the faulting option */ + if (!state->parse_err) + return 0; + + if (strcmp(state->parse_err, "help")) { + printf("u-boot: error: failed while parsing option: %s\n" + "\ttry running with --help for more information.\n", + state->parse_err); + os_exit(1); + } + + printf( + "u-boot, a command line test interface to U-Boot\n\n" + "Usage: u-boot [options]\n" + "Options:\n"); + + max_arg_len = 0; + for (i = 0; i < num_options; ++i) + max_arg_len = max(strlen(sb_opt[i]->flag), max_arg_len); + max_noarg_len = max_arg_len + 7; + + for (i = 0; i < num_options; ++i) { + struct sb_cmdline_option *opt = sb_opt[i]; + + /* first output the short flag if it has one */ + if (opt->flag_short >= 0x100) + printf(" "); + else + printf(" -%c, ", opt->flag_short); + + /* then the long flag */ + if (opt->has_arg) + printf("--%-*s", max_noarg_len, opt->flag); + else + printf("--%-*s <arg> ", max_arg_len, opt->flag); + + /* finally the help text */ + printf(" %s\n", opt->help); + } + + os_exit(0); +} + +static int sb_cmdline_cb_help(struct sandbox_state *state, const char *arg) +{ + /* just flag to sandbox_early_getopt_check to show usage */ + return 1; +} +SB_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help"); + int sandbox_main_loop_init(void) { + struct sandbox_state *state = state_get_current(); + + /* Execute command if required */ + if (state->cmd) { + /* TODO: redo this when cmd tidy-up series lands */ +#ifdef CONFIG_SYS_HUSH_PARSER + run_command(state->cmd, 0); +#else + parse_string_outer(state->cmd, FLAG_PARSE_SEMICOLON | + FLAG_EXIT_FROM_LOOP); +#endif + os_exit(state->exit_type); + } + return 0; } +static int sb_cmdline_cb_command(struct sandbox_state *state, const char *arg) +{ + state->cmd = arg; + return 0; +} +SB_CMDLINE_OPT_SHORT(command, 'c', 1, "Execute U-Boot command"); + int main(int argc, char *argv[]) { + struct sandbox_state *state; int err; err = state_init(); if (err) return err; + state = state_get_current(); + if (os_parse_args(state, argc, argv)) + return 1; + /* * Do pre- and post-relocation init, then start up U-Boot. This will * never return. diff --git a/arch/sandbox/cpu/u-boot.lds b/arch/sandbox/cpu/u-boot.lds index 0c56aa7793..99601387cb 100644 --- a/arch/sandbox/cpu/u-boot.lds +++ b/arch/sandbox/cpu/u-boot.lds @@ -28,6 +28,10 @@ SECTIONS _u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end = .; + __u_boot_sandbox_option_start = .; + _u_boot_sandbox_getopt : { *(.u_boot_sandbox_getopt) } + __u_boot_sandbox_option_end = .; + __bss_start = .; } |