Message ID | 1330846683-19790-1-git-send-email-vapier@gentoo.org |
---|---|
State | Accepted |
Commit | 70db4212fcdb080444a23dccaf673b68a3ffc1fa |
Delegated to: | Mike Frysinger |
Headers | show |
On Sat, Mar 3, 2012 at 11:38 PM, Mike Frysinger <vapier@gentoo.org> wrote: > From: Simon Glass <sjg@chromium.org> > > 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> Acked-by: Simon Glass <sjg@chromium.org> > --- > v2 > - rework error detection to handle edge cases > - add comments all over > - do some renaming > - split into dedicated headers where applicable > - should be ready for merging now if people are happy > > arch/sandbox/cpu/os.c | 98 +++++++++++++++++++++++++++++ > arch/sandbox/cpu/start.c | 88 ++++++++++++++++++++++++++ > arch/sandbox/cpu/u-boot.lds | 4 + > arch/sandbox/include/asm/getopt.h | 71 +++++++++++++++++++++ > arch/sandbox/include/asm/sections.h | 22 +++++++ > arch/sandbox/include/asm/state.h | 5 ++ > arch/sandbox/include/asm/u-boot-sandbox.h | 1 + > arch/sandbox/lib/board.c | 1 + > include/os.h | 14 ++++ > 9 files changed, 304 insertions(+), 0 deletions(-) > create mode 100644 arch/sandbox/include/asm/getopt.h > create mode 100644 arch/sandbox/include/asm/sections.h > > diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c > index cb469e0..36637af 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 4a84486..6c3e8eb 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 0c56aa7..9960138 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 = .; > } > > diff --git a/arch/sandbox/include/asm/getopt.h b/arch/sandbox/include/asm/getopt.h > new file mode 100644 > index 0000000..685883c > --- /dev/null > +++ b/arch/sandbox/include/asm/getopt.h > @@ -0,0 +1,71 @@ > +/* > + * Code for setting up command line flags like `./u-boot --help` > + * > + * Copyright (c) 2011 The Chromium OS Authors. > + * > + * Licensed under the GPL-2 or later. > + */ > + > +#ifndef __SANDBOX_GETOPT_H > +#define __SANDBOX_GETOPT_H > + > +struct sandbox_state; > + > +/* > + * Internal structure for storing details about the flag. > + * Most people should not have to dig around in this as > + * it only gets parsed by the core sandbox code. End > + * consumer code should focus on the macros below and > + * the callback function. > + */ > +struct sb_cmdline_option { > + /* The long flag name: "help" for "--help" */ > + const char *flag; > + /* The (optional) short flag name: "h" for "-h" */ > + int flag_short; > + /* The help string shown to the user when processing --help */ > + const char *help; > + /* Whether this flag takes an argument */ > + int has_arg; > + /* Callback into the end consumer code with the option */ > + int (*callback)(struct sandbox_state *state, const char *opt); > +}; > + > +/* > + * Internal macro to expand the lower macros into the necessary > + * magic junk that makes this all work. > + */ > +#define _SB_CMDLINE_OPT(f, s, ha, h) \ > + static struct sb_cmdline_option sb_cmdline_option_##f = { \ > + .flag = #f, \ > + .flag_short = s, \ > + .help = h, \ > + .has_arg = ha, \ > + .callback = sb_cmdline_cb_##f, \ > + }; \ > + /* Ppointer to the struct in a special section for the linker script */ \ > + static __attribute__((section(".u_boot_sandbox_getopt"), used)) \ > + struct sb_cmdline_option *sb_cmdline_option_##f##_ptr = \ > + &sb_cmdline_option_##f > + > +/** > + * Macros for end code to declare new command line flags. > + * > + * @param f The long flag name e.g. help > + * @param ha Does the flag have an argument e.g. 0/1 > + * @param h The help string displayed when showing --help > + * > + * This invocation: > + * SB_CMDLINE_OPT(foo, 0, "The foo arg"); > + * Will create a new flag named "--foo" (no short option) that takes > + * no argument. If the user specifies "--foo", then the callback func > + * sb_cmdline_cb_foo() will automatically be called. > + */ > +#define SB_CMDLINE_OPT(f, ha, h) _SB_CMDLINE_OPT(f, 0, ha, h) > +/* > + * Same as above, but @s is used to specify a short flag e.g. > + * SB_CMDLINE_OPT(foo, 'f', 0, "The foo arg"); > + */ > +#define SB_CMDLINE_OPT_SHORT(f, s, ha, h) _SB_CMDLINE_OPT(f, s, ha, h) > + > +#endif > diff --git a/arch/sandbox/include/asm/sections.h b/arch/sandbox/include/asm/sections.h > new file mode 100644 > index 0000000..eafce7d > --- /dev/null > +++ b/arch/sandbox/include/asm/sections.h > @@ -0,0 +1,22 @@ > +/* > + * decls for symbols defined in the linker script > + * > + * Copyright (c) 2012 The Chromium OS Authors. > + * > + * Licensed under the GPL-2 or later. > + */ > + > +#ifndef __SANDBOX_SECTIONS_H > +#define __SANDBOX_SECTIONS_H > + > +struct sb_cmdline_option; > + > +extern struct sb_cmdline_option *__u_boot_sandbox_option_start[], > + *__u_boot_sandbox_option_end[]; > + > +static inline size_t __u_boot_sandbox_option_count(void) > +{ > + return __u_boot_sandbox_option_end - __u_boot_sandbox_option_start; > +} > + > +#endif > diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h > index 5b34e94..2b62b46 100644 > --- a/arch/sandbox/include/asm/state.h > +++ b/arch/sandbox/include/asm/state.h > @@ -22,6 +22,8 @@ > #ifndef __SANDBOX_STATE_H > #define __SANDBOX_STATE_H > > +#include <config.h> > + > /* How we exited U-Boot */ > enum exit_type_id { > STATE_EXIT_NORMAL, > @@ -33,6 +35,9 @@ enum exit_type_id { > struct sandbox_state { > const char *cmd; /* Command to execute */ > enum exit_type_id exit_type; /* How we exited U-Boot */ > + const char *parse_err; /* Error to report from parsing */ > + int argc; /* Program arguments */ > + char **argv; > }; > > /** > diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h > index 99e950b..50bf8c6 100644 > --- a/arch/sandbox/include/asm/u-boot-sandbox.h > +++ b/arch/sandbox/include/asm/u-boot-sandbox.h > @@ -36,6 +36,7 @@ int board_init(void); > int dram_init(void); > > /* start.c */ > +int sandbox_early_getopt_check(void); > int sandbox_main_loop_init(void); > > #endif /* _U_BOOT_SANDBOX_H_ */ > diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c > index 25a8d02..306d1ec 100644 > --- a/arch/sandbox/lib/board.c > +++ b/arch/sandbox/lib/board.c > @@ -134,6 +134,7 @@ init_fnc_t *init_sequence[] = { > env_init, /* initialize environment */ > serial_init, /* serial communications setup */ > console_init_f, /* stage 1 init of console */ > + sandbox_early_getopt_check, /* process command line flags (err/help) */ > display_banner, /* say that we are here */ > #if defined(CONFIG_DISPLAY_CPUINFO) > print_cpuinfo, /* display cpu info (and speed) */ > diff --git a/include/os.h b/include/os.h > index 6b7ee47..45729c1 100644 > --- a/include/os.h > +++ b/include/os.h > @@ -27,6 +27,8 @@ > #ifndef __OS_H__ > #define __OS_H__ > > +struct sandbox_state; > + > /** > * Access to the OS read() system call > * > @@ -122,4 +124,16 @@ void os_usleep(unsigned long usec); > */ > u64 os_get_nsec(void); > > +/** > + * Parse arguments and update sandbox state. > + * > + * @param state Sandbox state to update > + * @param argc Argument count > + * @param argv Argument vector > + * @return 0 if ok, and program should continue; > + * 1 if ok, but program should stop; > + * -1 on error: program should terminate. > + */ > +int os_parse_args(struct sandbox_state *state, int argc, char *argv[]); > + > #endif > -- > 1.7.8.4 >
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index cb469e0..36637af 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 4a84486..6c3e8eb 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 0c56aa7..9960138 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 = .; } diff --git a/arch/sandbox/include/asm/getopt.h b/arch/sandbox/include/asm/getopt.h new file mode 100644 index 0000000..685883c --- /dev/null +++ b/arch/sandbox/include/asm/getopt.h @@ -0,0 +1,71 @@ +/* + * Code for setting up command line flags like `./u-boot --help` + * + * Copyright (c) 2011 The Chromium OS Authors. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __SANDBOX_GETOPT_H +#define __SANDBOX_GETOPT_H + +struct sandbox_state; + +/* + * Internal structure for storing details about the flag. + * Most people should not have to dig around in this as + * it only gets parsed by the core sandbox code. End + * consumer code should focus on the macros below and + * the callback function. + */ +struct sb_cmdline_option { + /* The long flag name: "help" for "--help" */ + const char *flag; + /* The (optional) short flag name: "h" for "-h" */ + int flag_short; + /* The help string shown to the user when processing --help */ + const char *help; + /* Whether this flag takes an argument */ + int has_arg; + /* Callback into the end consumer code with the option */ + int (*callback)(struct sandbox_state *state, const char *opt); +}; + +/* + * Internal macro to expand the lower macros into the necessary + * magic junk that makes this all work. + */ +#define _SB_CMDLINE_OPT(f, s, ha, h) \ + static struct sb_cmdline_option sb_cmdline_option_##f = { \ + .flag = #f, \ + .flag_short = s, \ + .help = h, \ + .has_arg = ha, \ + .callback = sb_cmdline_cb_##f, \ + }; \ + /* Ppointer to the struct in a special section for the linker script */ \ + static __attribute__((section(".u_boot_sandbox_getopt"), used)) \ + struct sb_cmdline_option *sb_cmdline_option_##f##_ptr = \ + &sb_cmdline_option_##f + +/** + * Macros for end code to declare new command line flags. + * + * @param f The long flag name e.g. help + * @param ha Does the flag have an argument e.g. 0/1 + * @param h The help string displayed when showing --help + * + * This invocation: + * SB_CMDLINE_OPT(foo, 0, "The foo arg"); + * Will create a new flag named "--foo" (no short option) that takes + * no argument. If the user specifies "--foo", then the callback func + * sb_cmdline_cb_foo() will automatically be called. + */ +#define SB_CMDLINE_OPT(f, ha, h) _SB_CMDLINE_OPT(f, 0, ha, h) +/* + * Same as above, but @s is used to specify a short flag e.g. + * SB_CMDLINE_OPT(foo, 'f', 0, "The foo arg"); + */ +#define SB_CMDLINE_OPT_SHORT(f, s, ha, h) _SB_CMDLINE_OPT(f, s, ha, h) + +#endif diff --git a/arch/sandbox/include/asm/sections.h b/arch/sandbox/include/asm/sections.h new file mode 100644 index 0000000..eafce7d --- /dev/null +++ b/arch/sandbox/include/asm/sections.h @@ -0,0 +1,22 @@ +/* + * decls for symbols defined in the linker script + * + * Copyright (c) 2012 The Chromium OS Authors. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __SANDBOX_SECTIONS_H +#define __SANDBOX_SECTIONS_H + +struct sb_cmdline_option; + +extern struct sb_cmdline_option *__u_boot_sandbox_option_start[], + *__u_boot_sandbox_option_end[]; + +static inline size_t __u_boot_sandbox_option_count(void) +{ + return __u_boot_sandbox_option_end - __u_boot_sandbox_option_start; +} + +#endif diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 5b34e94..2b62b46 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -22,6 +22,8 @@ #ifndef __SANDBOX_STATE_H #define __SANDBOX_STATE_H +#include <config.h> + /* How we exited U-Boot */ enum exit_type_id { STATE_EXIT_NORMAL, @@ -33,6 +35,9 @@ enum exit_type_id { struct sandbox_state { const char *cmd; /* Command to execute */ enum exit_type_id exit_type; /* How we exited U-Boot */ + const char *parse_err; /* Error to report from parsing */ + int argc; /* Program arguments */ + char **argv; }; /** diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h index 99e950b..50bf8c6 100644 --- a/arch/sandbox/include/asm/u-boot-sandbox.h +++ b/arch/sandbox/include/asm/u-boot-sandbox.h @@ -36,6 +36,7 @@ int board_init(void); int dram_init(void); /* start.c */ +int sandbox_early_getopt_check(void); int sandbox_main_loop_init(void); #endif /* _U_BOOT_SANDBOX_H_ */ diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index 25a8d02..306d1ec 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -134,6 +134,7 @@ init_fnc_t *init_sequence[] = { env_init, /* initialize environment */ serial_init, /* serial communications setup */ console_init_f, /* stage 1 init of console */ + sandbox_early_getopt_check, /* process command line flags (err/help) */ display_banner, /* say that we are here */ #if defined(CONFIG_DISPLAY_CPUINFO) print_cpuinfo, /* display cpu info (and speed) */ diff --git a/include/os.h b/include/os.h index 6b7ee47..45729c1 100644 --- a/include/os.h +++ b/include/os.h @@ -27,6 +27,8 @@ #ifndef __OS_H__ #define __OS_H__ +struct sandbox_state; + /** * Access to the OS read() system call * @@ -122,4 +124,16 @@ void os_usleep(unsigned long usec); */ u64 os_get_nsec(void); +/** + * Parse arguments and update sandbox state. + * + * @param state Sandbox state to update + * @param argc Argument count + * @param argv Argument vector + * @return 0 if ok, and program should continue; + * 1 if ok, but program should stop; + * -1 on error: program should terminate. + */ +int os_parse_args(struct sandbox_state *state, int argc, char *argv[]); + #endif