From: Mike Frysinger <[email protected]>

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 <[email protected]>
Signed-off-by: David Gibson <[email protected]>
---
 fdtdump.c |   31 +++++++++++++++++++++++--------
 util.c    |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 util.h    |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 138 insertions(+), 8 deletions(-)

diff --git a/fdtdump.c b/fdtdump.c
index 03ea429..a6e522c 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -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;
 }
diff --git a/util.c b/util.c
index 350cf8b..d9a823a 100644
--- a/util.c
+++ b/util.c
@@ -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);
+}
diff --git a/util.h b/util.h
index 95ae531..1da3bd3 100644
--- a/util.h
+++ b/util.h
@@ -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 */
-- 
1.7.10.4

_______________________________________________
devicetree-discuss mailing list
[email protected]
https://lists.ozlabs.org/listinfo/devicetree-discuss

Reply via email to