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
77
78
79
80
81
82
83
84
85
86
|
#ifndef OPT_H
#define OPT_H
#define OPT_ARG 1
#define OPT_AT_END 0
#define OPT_ERR_NO_PARAM -1
#define OPT_ERR_BAD_OPT -2
#define OPTF_MID_SHORT 1
#define OPTF_IGNORE 2
#define OPTF_NO_PRINT_ERR 4
/* fmt is a set of short option chars, preceded by : if they accept an
* argument, followed by [foo] for a corresponding long option name. */
int opt_next(int *optf, int *argc, const char ***argv, const char *fmt);
#ifdef OPT_IMPL
#include <stdio.h>
#include <string.h>
#include <assert.h>
int opt_next(int *optf, int *argc, const char ***argv, const char *fmt) {
if (~*optf & OPTF_MID_SHORT) {
*argv += 1, *argc -= 1;
if (*argc < 1) return OPT_AT_END;
}
if (*optf & OPTF_IGNORE) return OPT_ARG;
int is_long = 0;
if (~*optf & OPTF_MID_SHORT) {
if ((**argv)[0] != '-') return OPT_ARG;
is_long = (**argv)[1] == '-';
if (is_long && !(**argv)[2]) {
*optf |= OPTF_IGNORE;
return opt_next(optf, argc, argv, fmt);
}
}
const char *opt = **argv + is_long + !(*optf & OPTF_MID_SHORT);
const char *opt_end = is_long ? strchr(opt, '=') : opt + 1;
if (!opt_end) opt_end = opt + strlen(opt);
unsigned opt_len = opt_end - opt;
int opt_arg = 0, match = 0;
char opt_char = '\0';
while (*fmt && !match) {
opt_arg = (*fmt == ':');
if (opt_arg) fmt++;
opt_char = *fmt++;
assert(opt_char);
match = !is_long && *opt == opt_char;
if (*fmt == '[') {
const char *rt = strchr(++fmt, ']');
assert(rt);
match |= is_long && rt-fmt == opt_len && !memcmp(opt, fmt, opt_len);
fmt = rt + 1;
}
}
*optf &= ~OPTF_MID_SHORT;
if (match && opt_arg) {
if (*opt_end) {
**argv = opt_end + is_long;
} else {
*argv += 1, *argc -= 1;
if (*argc > 0) return opt_char;
if (~*optf & OPTF_NO_PRINT_ERR) {
fprintf(stderr, "option '%.*s' expected parameter, but none given\n", opt_len, opt);
}
return OPT_ERR_NO_PARAM;
}
} else if (!is_long && *opt_end) {
*optf |= OPTF_MID_SHORT;
**argv = opt_end;
}
if (!match && ~*optf & OPTF_NO_PRINT_ERR) {
fprintf(stderr, "unrecognized option '%.*s'\n", opt_len, opt);
}
return match ? opt_char : OPT_ERR_BAD_OPT;
}
#endif
#endif
|