-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathcmdline.c
128 lines (116 loc) · 2.81 KB
/
cmdline.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
/* cmdline.c: a reentrant version of getopt().
*
* Written 1997-2001 by Brian Raiter. This code is in the public
* domain.
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "gen.h"
#include "cmdline.h"
/* Initialize the state structure.
*/
void initoptions(cmdlineinfo *opt, int argc, char **argv, char const *list)
{
opt->options = list;
opt->argc = argc;
opt->argv = argv;
opt->index = 0;
opt->argptr = NULL;
opt->stop = FALSE;
}
/* Find the next option on the cmdline.
*/
int readoption(cmdlineinfo *opt)
{
char const *str;
if (!opt->options || !opt->argc || !opt->argv)
return -1;
/* If argptr is NULL or points to a \0, then we're done with this
* argument, and it's time to move on to the next one (if any).
*/
redo:
if (!opt->argptr || !*opt->argptr) {
if (opt->index >= opt->argc) {
opt->type = OPT_END;
return -1;
}
opt->argptr = opt->argv[opt->index];
++opt->index;
/* Special case: if the next argument is "--", we skip over it and
* stop looking for options for the rest of the cmdline.
*/
if (!opt->stop && opt->argptr[0] == '-'
&& opt->argptr[1] == '-'
&& opt->argptr[2] == '\0') {
opt->argptr = NULL;
opt->stop = TRUE;
goto redo;
}
/* Arguments not starting with a '-' or appearing after a
* "--" argument are not options.
*/
if (*opt->argptr != '-' || opt->stop) {
opt->opt = 0;
opt->val = opt->argptr;
opt->type = OPT_NONOPTION;
opt->argptr = NULL;
return 0;
}
/* Check for special cases.
*/
++opt->argptr;
if (!*opt->argptr) { /* The "-" case. */
opt->opt = 0;
opt->val = opt->argptr - 1;
opt->type = OPT_DASH;
return 0;
}
if (*opt->argptr == '-') {
opt->opt = 0; /* The "--foo" case. */
opt->val = opt->argptr - 1;
opt->type = OPT_LONG;
opt->argptr = NULL;
return '-';
}
}
/* We are currently looking at the next option.
*/
opt->type = OPT_OPTION;
opt->opt = *opt->argptr;
++opt->argptr;
/* Is it on the list? If so, does it expect a value to follow?
*/
str = strchr(opt->options, opt->opt);
if (!str) {
opt->val = opt->argptr - 1;
opt->type = OPT_BADOPTION;
return '?';
} else if (str[1] == ':') {
if (*opt->argptr) { /* Is the value here? */
opt->val = opt->argptr;
opt->argptr = NULL;
} else {
if (opt->index >= opt->argc) { /* Or in the next argument? */
opt->val = NULL;
opt->type = OPT_NOVALUE;
return ':';
} else {
opt->val = opt->argv[opt->index];
++opt->index;
}
}
} else
opt->val = NULL;
return opt->opt;
}
/* Ignore the next argument on the cmdline.
*/
int skipoption(cmdlineinfo *opt)
{
if (opt->index >= opt->argc)
return -1;
opt->val = opt->argv[opt->index];
++opt->index;
return 0;
}