diff options
Diffstat (limited to 'arch/sandbox/cpu/os.c')
| -rw-r--r-- | arch/sandbox/cpu/os.c | 98 | 
1 files changed, 98 insertions, 0 deletions
| diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index cb469e051..36637af6c 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; +} |