1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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);
|