-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathgetopt.c
165 lines (144 loc) · 3.86 KB
/
getopt.c
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/* getopt.c
* Simple getopt() implementation.
*
* Standard interface:
* extern int getopt(int argc, char *const *argv, const char *opts);
* extern int optind; current index in argv[]
* extern char *optarg; argument for the current option
* extern int optopt; the current option
* extern int opterr; to control error printing
*
* Some minor extensions:
* ignores leading `+' # opts[] (unemplemented GNU extension)
* handles optional arguments, in form "x::" in opts[]
* if opts[] starts with `:', will return `:' in case of missing required
* argument, instead of '?'.
*
* Compile with -DGETOPT_NO_OPTERR to never print errors internally.
* Compile with -DGETOPT_NO_STDIO to use write() calls instead of fprintf() for
* error reporting (ignored with -DGETOPT_NO_OPTERR).
* Compile with -DGETOPT_CLASS=static to get static linkage.
* Compile with -DGETOPT_MY to redefine all visible symbols to be prefixed
* with "my_", like my_getopt instead of getopt.
* Compile with -DTEST to get a test executable.
*
* Written by Michael Tokarev. Public domain.
*/
#include <string.h>
#ifndef GETOPT_CLASS
# define GETOPT_CLASS
#endif
#ifdef GETOPT_MY
# define optarg my_optarg
# define optind my_optind
# define opterr my_opterr
# define optopt my_optopt
# define getopt my_getopt
#endif
GETOPT_CLASS char *optarg /* = NULL */;
GETOPT_CLASS int optind = 1;
GETOPT_CLASS int opterr = 1;
GETOPT_CLASS int optopt;
static char *nextc /* = NULL */;
#if defined(GETOPT_NO_OPTERR)
#define printerr(argv, msg)
#elif defined(GETOPT_NO_STDIO)
extern int write(int, void *, int);
static void printerr(char *const *argv, const char *msg) {
if (opterr) {
char buf[64];
unsigned pl = strlen(argv[0]);
unsigned ml = strlen(msg);
char *p;
if (pl + /*": "*/2 + ml + /*" -- c\n"*/6 > sizeof(buf)) {
write(2, argv[0], pl);
p = buf;
}
else {
memcpy(buf, argv[0], ml);
p = buf + pl;
}
*p++ = ':'; *p++ = ' ';
memcpy(p, msg, ml); p += ml;
*p++ = ' '; *p++ = '-'; *p++ = '-'; *p++ = ' ';
*p++ = optopt;
*p++ = '\n';
write(2, buf, p - buf);
}
}
#else
#include <stdio.h>
static void printerr(char *const *argv, const char *msg) {
if (opterr)
fprintf(stderr, "%s: %s -- %c\n", argv[0], msg, optopt);
}
#endif
GETOPT_CLASS int getopt(int argc, char *const *argv, const char *opts) {
char *p;
optarg = 0;
if (*opts == '+') /* GNU extension (permutation) - isn't supported */
++opts;
if (!optind) { /* a way to reset things */
nextc = 0;
optind = 1;
}
if (!nextc || !*nextc) { /* advance to the next argv element */
/* done scanning? */
if (optind >= argc)
return -1;
/* not an optional argument */
if (argv[optind][0] != '-')
return -1;
/* bare `-' */
if (argv[optind][1] == '\0')
return -1;
/* special case `--' argument */
if (argv[optind][1] == '-' && argv[optind][2] == '\0') {
++optind;
return -1;
}
nextc = argv[optind] + 1;
}
optopt = *nextc++;
if (!*nextc)
++optind;
p = strchr(opts, optopt);
if (!p || optopt == ':') {
printerr(argv, "illegal option");
return '?';
}
if (p[1] == ':') {
if (*nextc) {
optarg = nextc;
nextc = NULL;
++optind;
}
else if (p[2] != ':') { /* required argument */
if (optind >= argc) {
printerr(argv, "option requires an argument");
return *opts == ':' ? ':' : '?';
}
else
optarg = argv[optind++];
}
}
return optopt;
}
#ifdef TEST
#include <stdio.h>
int main(int argc, char **argv) {
int c;
while((c = getopt(argc, argv, "ab:c::")) != -1) switch(c) {
case 'a':
case 'b':
case 'c':
printf("option %c %s\n", c, optarg ? optarg : "(none)");
break;
default:
return -1;
}
for(c = optind; c < argc; ++c)
printf("non-opt: %s\n", argv[c]);
return 0;
}
#endif