summaryrefslogtreecommitdiff
path: root/src/util/option.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/option.h')
-rw-r--r--src/util/option.h76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/util/option.h b/src/util/option.h
new file mode 100644
index 0000000..780a6e9
--- /dev/null
+++ b/src/util/option.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <stdbool.h>
+
+
+enum option_spec_kind {
+ OPTSPECKIND_SETBOOL,
+ OPTSPECKIND_CALL,
+ OPTSPECKIND_CALLP,
+
+ OPTSPECKIND_HELPUSAGE,
+ OPTSPECKIND_VERSION,
+
+ OPTSPECKIND_END, // end of spec list (rest of spec entry ignored)
+};
+
+// For usage info, see option_parse() below.
+struct option_spec {
+ char optc; // short option character
+ // TODO: long options?
+
+ // From here, the fields should be filled in using the OPTION_* macros.
+ enum option_spec_kind kind;
+ union {
+ struct { bool *ptr; } setbool;
+ struct { void (*fun)(void); } call;
+ struct { void (*fun)(void*); void *data; } callp;
+ struct { const char *usagestr; } helpusage;
+ struct {} version;
+ } spec_sub;
+};
+
+// Takes a bool* and stores 'true' there if the flag is found.
+#define OPTION_SETBOOL(boolptr) \
+ OPTSPECKIND_SETBOOL, {.setbool={.ptr=(boolptr)}}
+
+// Takes a void(*)(void) and calls it every time the flag is found.
+#define OPTION_CALL(funptr) \
+ OPTSPECKIND_CALL, {.call={.fun=(funptr)}}
+
+// Takes a void(*)(void*) and a 'void *data', and calls the function with 'data'
+// every time the flag is found.
+#define OPTION_CALLP(funptr, dataptr) \
+ OPTSPECKIND_CALLP, {.callp={.fun=(funptr), .data=(dataptr)}}
+
+// Takes a printf format string with a single %s, which is substituted (by
+// printf) for argv[0]. Prints the formatted string and exits with code 0.
+#define OPTION_HELPUSAGE(usagestring) \
+ OPTSPECKIND_HELPUSAGE, {.helpusage={.usagestr=(usagestring)}}
+
+// Prints version of the tool and exits with code 0.
+#define OPTION_VERSION() \
+ OPTSPECKIND_VERSION, {.version={}}
+
+// This must be the final entry in the list of option specs; contrary to the
+// other OPTION_* macros, it is an _entire_ 'struct option_spec'.
+#define OPTION_SPEC_END {'\0', OPTSPECKIND_END, {}}
+
+// The spec must not contain duplicate entries for the same short option
+// character.
+// Reshuffles positional arguments to the end of the argument list; returns a
+// pointer to the first positional argument after reshuffling.
+//
+// The specs array is most conveniently declared as a C array:
+//
+// const struct option_spec[] = {
+// {'h', OPTION_HELPUSAGE("Gebruik: %s <args>\n")},
+// {'V', OPTION_VERSION()},
+// OPTION_SPEC_END
+// }
+//
+// The individual option specs should be initialised with a brace-initialiser
+// containing the short option character followed by one of the OPTION_* macros,
+// as shown in the example above. See the comments above the macros for their
+// meaning. End the list with OPTION_SPEC_END.
+char** option_parse(int argc, char **argv, const struct option_spec *specs);