1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,152 @@ |
1 |
+#include <stdlib.h> |
|
2 |
+#include <stdio.h> |
|
3 |
+ |
|
4 |
+ |
|
5 |
+struct arg_const { |
|
6 |
+ char const * name; |
|
7 |
+ int const value; |
|
8 |
+}; |
|
9 |
+ |
|
10 |
+ |
|
11 |
+#ifndef ARG_HELP |
|
12 |
+#define ARG_HELP help |
|
13 |
+#endif |
|
14 |
+#ifndef ARG_VERSION |
|
15 |
+#define ARG_VERSION version |
|
16 |
+#endif |
|
17 |
+#ifndef ARG_USAGE |
|
18 |
+#define ARG_USAGE usage |
|
19 |
+#endif |
|
20 |
+#ifndef ARG_FORMAT_HEADER |
|
21 |
+#define ARG_FORMAT_HEADER "Recognized values for <%s>:\n" |
|
22 |
+#endif |
|
23 |
+#ifndef ARG_FORMAT_NAME |
|
24 |
+#define ARG_FORMAT_NAME " %s\n" |
|
25 |
+#endif |
|
26 |
+#ifndef ARG_FORMAT_POSITIONAL |
|
27 |
+#define ARG_FORMAT_POSITIONAL "No %s specified" |
|
28 |
+#endif |
|
29 |
+#ifndef ARG_FORMAT_COLON |
|
30 |
+#define ARG_FORMAT_COLON "Option -%c requires an argument" |
|
31 |
+#endif |
|
32 |
+#ifndef ARG_FORMAT_QUESTIONMARK |
|
33 |
+#define ARG_FORMAT_QUESTIONMARK "Unrecognized option: '-%c'" |
|
34 |
+#endif |
|
35 |
+#ifndef ARG_FORMAT_DEFAULT |
|
36 |
+#define ARG_FORMAT_DEFAULT "Failed to parse option: '-%c'" |
|
37 |
+#endif |
|
38 |
+#ifndef ARG_FORMAT_FIND |
|
39 |
+#define ARG_FORMAT_FIND "Unrecognized %s: '%s'" |
|
40 |
+#endif |
|
41 |
+#ifndef ARG_FORMAT_CATCH |
|
42 |
+#define ARG_FORMAT_CATCH "Unrecognized argument: '%s'" |
|
43 |
+#endif |
|
44 |
+ |
|
45 |
+#define ARG_PRINT(STREAM, ARG, ARGS) \ |
|
46 |
+ fprintf(STREAM, ARG_FORMAT_HEADER, #ARG); \ |
|
47 |
+ for (size_t argi = 0; argi < sizeof(ARGS) / sizeof(*ARGS); ++argi) { \ |
|
48 |
+ void const * arg = &((char const *)ARGS)[argi * sizeof(*ARGS)]; \ |
|
49 |
+ fprintf(STREAM, ARG_FORMAT_NAME, *(char const **)arg); \ |
|
50 |
+ } |
|
51 |
+ |
|
52 |
+#define ARG_SPECIALS() \ |
|
53 |
+ if (argc > 1) { \ |
|
54 |
+ if ( \ |
|
55 |
+ 0 == strcmp(argv[1], "-h") || \ |
|
56 |
+ 0 == strcmp(argv[1], "--help") \ |
|
57 |
+ ) { \ |
|
58 |
+ ARG_HELP(stdout); \ |
|
59 |
+ exit(EXIT_SUCCESS); \ |
|
60 |
+ } \ |
|
61 |
+ if ( \ |
|
62 |
+ 0 == strcmp(argv[1], "--version") \ |
|
63 |
+ ) { \ |
|
64 |
+ ARG_VERSION(stdout); \ |
|
65 |
+ exit(EXIT_SUCCESS); \ |
|
66 |
+ } \ |
|
67 |
+ } |
|
68 |
+ |
|
69 |
+#define ARG_DECLARE(ARG, DEFAULT) \ |
|
70 |
+ char const * arg_##ARG = DEFAULT; |
|
71 |
+ |
|
72 |
+#define ARG_POSITIONAL(ARG) \ |
|
73 |
+ if (optind >= argc) { \ |
|
74 |
+ fprintf(stderr, ARG_FORMAT_POSITIONAL "\n\n", #ARG); \ |
|
75 |
+ ARG_USAGE(stderr); \ |
|
76 |
+ exit(EXIT_FAILURE); \ |
|
77 |
+ } \ |
|
78 |
+ arg_##ARG = argv[optind++]; |
|
79 |
+ |
|
80 |
+#define ARG_GETOPT_BEGIN(OPTSTRING) \ |
|
81 |
+ { \ |
|
82 |
+ int opt; \ |
|
83 |
+ int opterr = 0; \ |
|
84 |
+ while (-1 != (opt = getopt(argc, argv, ":" OPTSTRING))) { \ |
|
85 |
+ switch(opt) { |
|
86 |
+ |
|
87 |
+#define ARG_GETOPT(OPT, ARG) \ |
|
88 |
+ case OPT: arg_##ARG = argv[optind]; break; |
|
89 |
+ |
|
90 |
+#define ARG_GETOPT_WITH_ARGUMENT(OPT, ARG) \ |
|
91 |
+ case OPT: arg_##ARG = optarg; break; |
|
92 |
+ |
|
93 |
+#define ARG_GETOPT_END() \ |
|
94 |
+ case ':': \ |
|
95 |
+ fprintf(stderr, ARG_FORMAT_COLON "\n\n", optopt); \ |
|
96 |
+ opterr = 1; \ |
|
97 |
+ break; \ |
|
98 |
+ case '?': \ |
|
99 |
+ fprintf(stderr, ARG_FORMAT_QUESTIONMARK "\n\n", optopt); \ |
|
100 |
+ opterr = 1; \ |
|
101 |
+ break; \ |
|
102 |
+ default: \ |
|
103 |
+ fprintf(stderr, ARG_FORMAT_DEFAULT "\n\n", opt); \ |
|
104 |
+ opterr = 1; \ |
|
105 |
+ break; \ |
|
106 |
+ } \ |
|
107 |
+ } \ |
|
108 |
+ if (opterr) { \ |
|
109 |
+ ARG_USAGE(stderr); \ |
|
110 |
+ exit(EXIT_FAILURE); \ |
|
111 |
+ } \ |
|
112 |
+ } |
|
113 |
+ |
|
114 |
+#define ARG_CONVERT_BOOL(ARG) \ |
|
115 |
+ int ARG = !!arg_##ARG; |
|
116 |
+ |
|
117 |
+#define ARG_CONVERT_NULL(ARG) \ |
|
118 |
+ char const * ARG = *(arg_##ARG) ? (arg_##ARG) : NULL; |
|
119 |
+ |
|
120 |
+#define ARG_CONVERT_FIND(TYPE, ARG, ARGS) \ |
|
121 |
+ struct TYPE const * ARG = NULL; \ |
|
122 |
+ for (size_t argi = 0; argi < sizeof(ARGS) / sizeof(*ARGS); ++argi) { \ |
|
123 |
+ void const * arg = &((char const *)ARGS)[argi * sizeof(*ARGS)]; \ |
|
124 |
+ if (0 == strcmp(arg_##ARG, *(char const **)arg)) \ |
|
125 |
+ ARG = arg; \ |
|
126 |
+ } \ |
|
127 |
+ if (!ARG) { \ |
|
128 |
+ fprintf(stderr, ARG_FORMAT_FIND "\n\n", #ARG, arg_##ARG); \ |
|
129 |
+ ARG_USAGE(stderr); \ |
|
130 |
+ exit(EXIT_FAILURE); \ |
|
131 |
+ } \ |
|
132 |
+ |
|
133 |
+#define ARG_CONVERT_FIND_CONST(ARG, ARGS) \ |
|
134 |
+ struct arg_const const * arg_const_##ARG = NULL; \ |
|
135 |
+ for (size_t argi = 0; argi < sizeof(ARGS) / sizeof(*ARGS); ++argi) { \ |
|
136 |
+ void const * arg = &((char const *)ARGS)[argi * sizeof(*ARGS)]; \ |
|
137 |
+ if (0 == strcmp(arg_##ARG, *(char const **)arg)) \ |
|
138 |
+ arg_const_##ARG = arg; \ |
|
139 |
+ } \ |
|
140 |
+ if (!arg_const_##ARG) { \ |
|
141 |
+ fprintf(stderr, ARG_FORMAT_FIND "\n\n", #ARG, arg_##ARG); \ |
|
142 |
+ ARG_USAGE(stderr); \ |
|
143 |
+ exit(EXIT_FAILURE); \ |
|
144 |
+ } \ |
|
145 |
+ int ARG = arg_const_##ARG->value; \ |
|
146 |
+ |
|
147 |
+#define ARG_CATCH() \ |
|
148 |
+ if (optind < argc) { \ |
|
149 |
+ fprintf(stderr, ARG_FORMAT_CATCH "\n\n", argv[optind]); \ |
|
150 |
+ ARG_USAGE(stderr); \ |
|
151 |
+ exit(EXIT_FAILURE); \ |
|
152 |
+ } |