diff options
author | Mike Frysinger <vapier@gentoo.org> | 2013-04-15 22:13:12 -0400 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2013-05-24 18:20:53 +1000 |
commit | be8d1c82cb0a9caeb7e2f804f9a9f845063d7d53 (patch) | |
tree | c850c488754c0d3144eaf2a4c7861e5eea50e6fb | |
parent | 4e76ec796c90d44d417f82d9db2d67cfe575f8ed (diff) | |
download | dtc-be8d1c82cb0a9caeb7e2f804f9a9f845063d7d53.zip dtc-be8d1c82cb0a9caeb7e2f804f9a9f845063d7d53.tar.gz dtc-be8d1c82cb0a9caeb7e2f804f9a9f845063d7d53.tar.bz2 |
fdtdump: make usage a bit more friendly
This starts a new usage framework and then cuts fdtdump over to it.
Now we can do `fdtdump -h` and get something useful back.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
-rw-r--r-- | fdtdump.c | 31 | ||||
-rw-r--r-- | util.c | 54 | ||||
-rw-r--r-- | util.h | 61 |
3 files changed, 138 insertions, 8 deletions
@@ -117,21 +117,36 @@ static void dump_blob(void *blob) } } +/* Usage related data. */ +static const char usage_synopsis[] = "fdtdump [options] <file>"; +static const char usage_short_opts[] = USAGE_COMMON_SHORT_OPTS; +static struct option const usage_long_opts[] = { + USAGE_COMMON_LONG_OPTS +}; +static const char * const usage_opts_help[] = { + USAGE_COMMON_OPTS_HELP +}; int main(int argc, char *argv[]) { + int opt; + const char *file; char *buf; - if (argc < 2) { - fprintf(stderr, "supply input filename\n"); - return 5; + while ((opt = util_getopt_long()) != EOF) { + switch (opt) { + case_USAGE_COMMON_FLAGS + } } + if (optind != argc - 1) + long_usage("missing input filename"); + file = argv[optind]; + + buf = utilfdt_read(file); + if (!buf) + die("could not read: %s\n", file); - buf = utilfdt_read(argv[1]); - if (buf) - dump_blob(buf); - else - return 10; + dump_blob(buf); return 0; } @@ -392,3 +392,57 @@ void util_version(void) printf("Version: %s\n", DTC_VERSION); exit(0); } + +void util_long_usage(const char *errmsg, const char *synopsis, + const char *short_opts, struct option const long_opts[], + const char * const opts_help[]) +{ + FILE *fp = errmsg ? stderr : stdout; + const char a_arg[] = "<arg>"; + size_t a_arg_len = strlen(a_arg) + 1; + size_t i; + int optlen; + + fprintf(fp, + "Usage: %s\n" + "\n" + "Options: -[%s]\n", synopsis, short_opts); + + /* prescan the --long opt length to auto-align */ + optlen = 0; + for (i = 0; long_opts[i].name; ++i) { + /* +1 is for space between --opt and help text */ + int l = strlen(long_opts[i].name) + 1; + if (long_opts[i].has_arg == a_argument) + l += a_arg_len; + if (optlen < l) + optlen = l; + } + + for (i = 0; long_opts[i].name; ++i) { + /* helps when adding new applets or options */ + assert(opts_help[i] != NULL); + + /* first output the short flag if it has one */ + if (long_opts[i].val > '~') + fprintf(fp, " "); + else + fprintf(fp, " -%c, ", long_opts[i].val); + + /* then the long flag */ + if (long_opts[i].has_arg == no_argument) + fprintf(fp, "--%-*s", optlen, long_opts[i].name); + else + fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg, + (int)(optlen - strlen(long_opts[i].name) - a_arg_len), ""); + + /* finally the help text */ + fprintf(fp, "%s\n", opts_help[i]); + } + + if (errmsg) { + fprintf(fp, "\nError: %s\n", errmsg); + exit(EXIT_FAILURE); + } else + exit(EXIT_SUCCESS); +} @@ -2,6 +2,7 @@ #define _UTIL_H #include <stdarg.h> +#include <getopt.h> /* * Copyright 2011 The Chromium Authors, All Rights Reserved. @@ -184,4 +185,64 @@ void utilfdt_print_data(const char *data, int len); */ void util_version(void) __attribute__((noreturn)); +/** + * Show usage and exit + * + * This helps standardize the output of various utils. You most likely want + * to use the long_usage() helper below rather than call this. + * + * @param errmsg If non-NULL, an error message to display + * @param synopsis The initial example usage text (and possible examples) + * @param short_opts The string of short options + * @param long_opts The structure of long options + * @param opts_help An array of help strings (should align with long_opts) + */ +void util_long_usage(const char *errmsg, const char *synopsis, + const char *short_opts, struct option const long_opts[], + const char * const opts_help[]) __attribute__((noreturn)); + +/** + * Show usage and exit + * + * If you name all your usage variables with usage_xxx, then you can call this + * help macro rather than expanding all arguments yourself. + * + * @param errmsg If non-NULL, an error message to display + */ +#define long_usage(errmsg) \ + util_long_usage(errmsg, usage_synopsis, usage_short_opts, \ + usage_long_opts, usage_opts_help) + +/** + * Call getopt_long() with standard options + * + * Since all util code runs getopt in the same way, provide a helper. + */ +#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \ + usage_long_opts, NULL) + +/* Helper for aligning long_opts array */ +#define a_argument required_argument + +/* Helper for usage_short_opts string constant */ +#define USAGE_COMMON_SHORT_OPTS "hV" + +/* Helper for usage_long_opts option array */ +#define USAGE_COMMON_LONG_OPTS \ + {"help", no_argument, NULL, 'h'}, \ + {"version", no_argument, NULL, 'V'}, \ + {NULL, no_argument, NULL, 0x0} + +/* Helper for usage_opts_help array */ +#define USAGE_COMMON_OPTS_HELP \ + "Print this help and exit", \ + "Print version and exit", \ + NULL + +/* Helper for getopt case statements */ +#define case_USAGE_COMMON_FLAGS \ + case 'h': long_usage(NULL); \ + case 'V': util_version(); \ + case '?': long_usage("unknown option"); + #endif /* _UTIL_H */ |