Browse code

WIP: Add implementation

Robert Cranston authored on 06/02/2021 04:14:21
Showing 1 changed files
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
+    }