Initial commit
[authen-passphrase-scrypt.git] / scrypt-1.2.1 / libcperciva / util / getopt.c
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "getopt.h"
7
8 /*
9 * Standard getopt global variables. optreset starts as non-zero in order to
10 * trigger initialization behaviour.
11 */
12 const char * optarg = NULL;
13 int optind = 1;
14 int opterr = 1;
15 int optreset = 1;
16
17 /*
18 * Quasi-internal global variables -- these are used via GETOPT macros.
19 */
20 const char * getopt_dummy = "(dummy)";
21 int getopt_initialized = 0;
22
23 /*
24 * Internal variables.
25 */
26 static const char * cmdname = NULL;
27 static struct opt {
28 const char * os;
29 size_t olen;
30 int hasarg;
31 } * opts = NULL;
32 static size_t nopts;
33 static size_t opt_missing;
34 static size_t opt_default;
35 static size_t opt_found;
36 static const char * packedopts;
37 static char popt[3];
38 static int atexit_registered = 0;
39
40 /* Print a message. */
41 #define PRINTMSG(...) do { \
42 if (cmdname != NULL) \
43 fprintf(stderr, "%s: ", cmdname); \
44 fprintf(stderr, __VA_ARGS__); \
45 fprintf(stderr, "\n"); \
46 } while (0)
47
48 /* Print an error message and die. */
49 #define DIE(...) do { \
50 PRINTMSG(__VA_ARGS__); \
51 abort(); \
52 } while (0)
53
54 /* Print a warning, if warnings are enabled. */
55 #define WARN(...) do { \
56 if (opterr == 0) \
57 break; \
58 if (opt_missing != opt_default) \
59 break; \
60 PRINTMSG(__VA_ARGS__); \
61 } while (0)
62
63 /* Free allocated options array. */
64 static void
65 atexit_handler(void)
66 {
67
68 free(opts);
69 opts = NULL;
70 }
71
72 /* Reset internal state. */
73 static void
74 reset(int argc, char * const argv[])
75 {
76 const char * p;
77
78 /* If we have arguments, stash argv[0] for error messages. */
79 if (argc > 0) {
80 /* Find the basename, without leading directories. */
81 for (p = cmdname = argv[0]; *p != '\0'; p++) {
82 if (*p == '/')
83 cmdname = p + 1;
84 }
85 }
86
87 /* Discard any registered command-line options. */
88 free(opts);
89 opts = NULL;
90
91 /* Register atexit handler if we haven't done so already. */
92 if (!atexit_registered) {
93 atexit(atexit_handler);
94 atexit_registered = 1;
95 }
96
97 /* We will start scanning from the first option. */
98 optind = 1;
99
100 /* We're not in the middle of any packed options. */
101 packedopts = NULL;
102
103 /* We haven't found any option yet. */
104 opt_found = (size_t)(-1);
105
106 /* We're not initialized yet. */
107 getopt_initialized = 0;
108
109 /* Finished resetting state. */
110 optreset = 0;
111 }
112
113 /* Search for an option string. */
114 static size_t
115 searchopt(const char * os)
116 {
117 size_t i;
118
119 /* Scan the array of options. */
120 for (i = 0; i < nopts; i++) {
121 /* Is there an option in this slot? */
122 if (opts[i].os == NULL)
123 continue;
124
125 /* Does this match up to the length of the option string? */
126 if (strncmp(opts[i].os, os, opts[i].olen))
127 continue;
128
129 /* Do we have <option>\0 or <option>= ? */
130 if ((os[opts[i].olen] == '\0') || (os[opts[i].olen] == '='))
131 return (i);
132 }
133
134 /* Not found. */
135 return (opt_default);
136 }
137
138 const char *
139 getopt(int argc, char * const argv[])
140 {
141 const char * os = NULL;
142 const char * canonical_os = NULL;
143
144 /* No argument yet. */
145 optarg = NULL;
146
147 /* Reset the getopt state if needed. */
148 if (optreset)
149 reset(argc, argv);
150
151 /* If not initialized, return dummy option. */
152 if (!getopt_initialized)
153 return (GETOPT_DUMMY);
154
155 /* If we've run out of arguments, we're done. */
156 if (optind >= argc)
157 return (NULL);
158
159 /*
160 * If we're not already in the middle of a packed single-character
161 * options, see if we should start.
162 */
163 if ((packedopts == NULL) && (argv[optind][0] == '-') &&
164 (argv[optind][1] != '-') && (argv[optind][1] != '\0')) {
165 /* We have one or more single-character options. */
166 packedopts = &argv[optind][1];
167 }
168
169 /* If we're processing single-character options, fish one out. */
170 if (packedopts != NULL) {
171 /* Construct the option string. */
172 popt[0] = '-';
173 popt[1] = *packedopts;
174 popt[2] = '\0';
175 os = popt;
176
177 /* We've done this character. */
178 packedopts++;
179
180 /* Are we done with this string? */
181 if (*packedopts == '\0') {
182 packedopts = NULL;
183 optind++;
184 }
185 }
186
187 /* If we don't have an option yet, do we have dash-dash? */
188 if ((os == NULL) && (argv[optind][0] == '-') &&
189 (argv[optind][1] == '-')) {
190 /* If this is not "--\0", it's an option. */
191 if (argv[optind][2] != '\0')
192 os = argv[optind];
193
194 /* Either way, we want to eat the string. */
195 optind++;
196 }
197
198 /* If we have found nothing which looks like an option, we're done. */
199 if (os == NULL)
200 return (NULL);
201
202 /* Search for the potential option. */
203 opt_found = searchopt(os);
204
205 /* If the option is not registered, give up now. */
206 if (opt_found == opt_default) {
207 WARN("unknown option: %s", os);
208 return (os);
209 }
210
211 /* The canonical option string is the one registered. */
212 canonical_os = opts[opt_found].os;
213
214 /* Does the option take an argument? */
215 if (opts[opt_found].hasarg) {
216 /*
217 * If we're processing packed single-character options, the
218 * rest of the string is the argument to this option.
219 */
220 if (packedopts != NULL) {
221 optarg = packedopts;
222 packedopts = NULL;
223 optind++;
224 }
225
226 /*
227 * If the option string is <option>=<value>, extract that
228 * value as the option argument.
229 */
230 if (os[opts[opt_found].olen] == '=')
231 optarg = &os[opts[opt_found].olen + 1];
232
233 /*
234 * If we don't have an argument yet, take one from the
235 * remaining command line.
236 */
237 if ((optarg == NULL) && (optind < argc))
238 optarg = argv[optind++];
239
240 /* If we still have no option, declare it MIA. */
241 if (optarg == NULL) {
242 WARN("option requires an argument: %s",
243 opts[opt_found].os);
244 opt_found = opt_missing;
245 }
246 } else {
247 /* If we have --foo=bar, something went wrong. */
248 if (os[opts[opt_found].olen] == '=') {
249 WARN("option doesn't take an argument: %s",
250 opts[opt_found].os);
251 opt_found = opt_default;
252 }
253 }
254
255 /* Return the canonical option string. */
256 return (canonical_os);
257 }
258
259 size_t
260 getopt_lookup(const char * os)
261 {
262
263 /* Can't reset here. */
264 if (optreset)
265 DIE("Can't reset in the middle of getopt loop");
266
267 /* We should only be called after initialization is complete. */
268 assert(getopt_initialized);
269
270 /* GETOPT_DUMMY should never get passed back to us. */
271 assert(os != GETOPT_DUMMY);
272
273 /*
274 * Make sure the option passed back to us corresponds to the one we
275 * found earlier.
276 */
277 assert((opt_found == opt_missing) || (opt_found == opt_default) ||
278 ((opt_found < nopts) && (strcmp(os, opts[opt_found].os) == 0)));
279
280 /* Return the option number we identified earlier. */
281 return (opt_found);
282 }
283
284 void
285 getopt_register_opt(const char * os, size_t ln, int hasarg)
286 {
287
288 /* Can't reset here. */
289 if (optreset)
290 DIE("Can't reset in the middle of getopt loop");
291
292 /* We should only be called during initialization. */
293 assert(!getopt_initialized);
294
295 /* We should have space allocated for registering options. */
296 assert(opts != NULL);
297
298 /* We should not have registered an option here yet. */
299 assert(opts[ln].os == NULL);
300
301 /* Options should be "-X" or "--foo". */
302 if ((os[0] != '-') || (os[1] == '\0') ||
303 ((os[1] == '-') && (os[2] == '\0')) ||
304 ((os[1] != '-') && (os[2] != '\0')))
305 DIE("Not a valid command-line option: %s", os);
306
307 /* Make sure we haven't already registered this option. */
308 if (searchopt(os) != opt_default)
309 DIE("Command-line option registered twice: %s", os);
310
311 /* Record option. */
312 opts[ln].os = os;
313 opts[ln].olen = strlen(os);
314 opts[ln].hasarg = hasarg;
315 }
316
317 void
318 getopt_register_missing(size_t ln)
319 {
320
321 /* Can't reset here. */
322 if (optreset)
323 DIE("Can't reset in the middle of getopt loop");
324
325 /* We should only be called during initialization. */
326 assert(!getopt_initialized);
327
328 /* Record missing-argument value. */
329 opt_missing = ln;
330 }
331
332 void
333 getopt_setrange(size_t ln)
334 {
335 size_t i;
336
337 /* Can't reset here. */
338 if (optreset)
339 DIE("Can't reset in the middle of getopt loop");
340
341 /* We should only be called during initialization. */
342 assert(!getopt_initialized);
343
344 /* Allocate space for options. */
345 opts = malloc(ln * sizeof(struct opt));
346 if ((ln > 0) && (opts == NULL))
347 DIE("Failed to allocate memory in getopt");
348
349 /* Initialize options. */
350 for (i = 0; i < ln; i++)
351 opts[i].os = NULL;
352
353 /* Record the number of (potential) options. */
354 nopts = ln;
355
356 /* Record default missing-argument and no-such-option values. */
357 opt_missing = opt_default = ln + 1;
358 }
This page took 0.031391 seconds and 4 git commands to generate.