[U-Boot] [PATCH 3/3] sandbox: add getopt support

Mike Frysinger vapier at gentoo.org
Sun Feb 26 23:38:51 CET 2012


Signed-off-by: Mike Frysinger <vapier at gentoo.org>
---
 arch/sandbox/cpu/os.c                     |   64 ++++++++++++++++++++++
 arch/sandbox/cpu/start.c                  |   83 +++++++++++++++++++++++++++++
 arch/sandbox/cpu/u-boot.lds               |    4 ++
 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                              |   35 ++++++++++++
 7 files changed, 193 insertions(+), 0 deletions(-)

diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index cb469e0..4b1c987 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>
@@ -32,6 +33,7 @@
 #include <linux/types.h>
 
 #include <os.h>
+#include <asm/state.h>
 
 /* Operating System Interface */
 
@@ -155,3 +157,65 @@ u64 os_get_nsec(void)
 	return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
 #endif
 }
+
+extern struct sb_cmdline_option *__u_boot_sb_getopt_start[],
+	*__u_boot_sb_getopt_end[];
+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_sb_getopt_start;
+	size_t num_flags = __u_boot_sb_getopt_end - __u_boot_sb_getopt_start;
+	size_t i;
+
+	int hidden_short_opt;
+	size_t si;
+
+	int c;
+
+	if (short_opts || long_opts)
+		os_exit(1);
+
+	state->argc = argc;
+	state->argv = argv;
+
+	short_opts = os_malloc(sizeof(*short_opts) * (num_flags + 1));
+	long_opts = os_malloc(sizeof(*long_opts) * num_flags);
+	if (!short_opts || !long_opts)
+		os_exit(1);
+
+	si = 0;
+	hidden_short_opt = 0x80;
+	for (i = 0; i < num_flags; ++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;
+		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;
+
+	while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
+		for (i = 0; i < num_flags; ++i) {
+			if (sb_opt[i]->flag_short == c) {
+				sb_opt[i]->callback(state, optarg);
+				break;
+			}
+		}
+		if (i == num_flags) {
+			/* store the faulting flag index for later */
+			state->parse_err = -optind;
+			break;
+		}
+	}
+
+	return 0;
+}
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index dc020ee..895ec49 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -22,19 +22,102 @@
 #include <common.h>
 #include <asm/state.h>
 
+#include <os.h>
+
+extern struct sb_cmdline_option *__u_boot_sb_getopt_start[],
+	*__u_boot_sb_getopt_end[];
+
+int sb_early_getopt_check(void)
+{
+	struct sandbox_state *state = state_get_current();
+	struct sb_cmdline_option **sb_opt = __u_boot_sb_getopt_start;
+	size_t num_flags = __u_boot_sb_getopt_end - __u_boot_sb_getopt_start;
+	size_t i;
+	int max_arg_len, max_noarg_len;
+
+	if (state->parse_err == 0)
+		return 0;
+
+	if (state->parse_err < 0)
+		printf("error: unknown option: %s\n\n",
+			state->argv[-state->parse_err - 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_flags; ++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_flags; ++i) {
+		/* first output the short flag if it has one */
+		if (sb_opt[i]->flag_short >= 0x80)
+			printf("      ");
+		else
+			printf("  -%c, ", sb_opt[i]->flag_short);
+
+		/* then the long flag */
+		if (sb_opt[i]->has_arg)
+			printf("--%-*s", max_noarg_len, sb_opt[i]->flag);
+		else
+			printf("--%-*s <arg> ", max_arg_len, sb_opt[i]->flag);
+
+		/* finally the help text */
+		printf("  %s\n", sb_opt[i]->help);
+	}
+
+	os_exit(state->parse_err < 0 ? 1 : 0);
+}
+
+static int sb_cmdline_cb_help(struct sandbox_state *state, const char *arg)
+{
+	/* just flag to sb_early_getopt_check to show usage */
+	state->parse_err = 1;
+	return 0;
+}
+SB_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help");
+
 int sb_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();
+	os_parse_args(state, argc, argv);
+
 	/*
 	 * 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..2ca6b8c 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_sb_getopt_start = .;
+	_u_boot_sb_getopt : { *(.u_boot_sb_getopt) }
+	__u_boot_sb_getopt_end = .;
+
 	__bss_start = .;
 }
 
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index 5b34e94..edeef08 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 */
+	int 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 f0e8b3c..8255e9d 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 sb_early_getopt_check(void);
 int sb_main_loop_init(void);
 
 #endif	/* _U_BOOT_SANDBOX_H_ */
diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c
index 1082e7d..5c6da5b 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 */
+	sb_early_getopt_check,
 	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..aea4503 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,37 @@ 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[]);
+
+struct sb_cmdline_option {
+	const char *flag;
+	char flag_short;
+	const char *help;
+	int has_arg;
+	int (*callback)(struct sandbox_state *state, const char *opt);
+};
+#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, \
+	}; \
+	static __attribute__((section(".u_boot_sb_getopt"), used)) \
+		struct sb_cmdline_option *sb_cmdline_option_##f##_ptr = \
+		&sb_cmdline_option_##f
+#define SB_CMDLINE_OPT(f, ha, h) _SB_CMDLINE_OPT(f, 0, ha, h)
+#define SB_CMDLINE_OPT_SHORT(f, s, ha, h) _SB_CMDLINE_OPT(f, s, ha, h)
+
 #endif
-- 
1.7.8.4



More information about the U-Boot mailing list