-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpigetopt.c
More file actions
227 lines (203 loc) · 4.87 KB
/
pigetopt.c
File metadata and controls
227 lines (203 loc) · 4.87 KB
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*
*
* pigetopt.c
*
* Author: Markku Rossi <[email protected]>
*
* Copyright (c) 2003-2016 Markku Rossi.
*
* See the LICENSE file for the details on licensing.
*
* Command line option parsing.
*
*/
#include "piincludes.h"
#include "pigetopt.h"
/*********************** Parsing command line options ***********************/
int
pi_getopt(int argc, char *argv[], PiGetOptCtx ctx, PiGetOptOption options)
{
int i;
/* Init the context unless it is already initialized. */
if (ctx->program == NULL)
{
ctx->program = strrchr(argv[0], '/');
if (ctx->program)
ctx->program++;
else
ctx->program = argv[0];
ctx->optind++;
ctx->short_index = 0;
}
/* Is parsing of short bundled options pending? */
if (ctx->short_index)
{
/* Yes it is. */
ctx->short_index++;
if (ctx->short_index < strlen(argv[ctx->optind]))
/* More to come. */
goto process_short_option;
/* Short bundled option parsed. */
ctx->short_index = 0;
ctx->optind++;
}
/* Move to the next argument. */
if (ctx->optind >= argc)
/* All options processed. */
return -1;
/* Check what kind of option this is. */
if (argv[ctx->optind][0] == '-')
{
if (argv[ctx->optind][1] == '-')
{
size_t len;
char *cp;
int index = -1;
int nfound = 0;
bool exact_match = false;
/* A long option. */
cp = strchr(argv[ctx->optind], '=');
if (cp)
len = cp - argv[ctx->optind] - 2;
else
len = strlen(argv[ctx->optind]) - 2;
if (len == 0)
/* String `--' found. */
return -1;
/* Lookup the long option. */
for (i = 0; options[i].long_option; i++)
if (strlen(options[i].long_option) >= len
&& memcmp(options[i].long_option,
argv[ctx->optind] + 2, len) == 0)
{
if (index < 0)
index = i;
nfound++;
/* Check for exact match if some long options share
common prefix with a full option. */
if (strlen(options[i].long_option) == len)
exact_match = true;
}
if (nfound == 0)
{
/* Unknown option. */
fprintf(stderr, "%s: unknown option -- %s\n",
ctx->program, argv[ctx->optind] + 2);
return '?';
}
else if (nfound > 1 && !exact_match)
{
/* Ambiguous option. */
fprintf(stderr, "%s: ambiguous option -- %s\n",
ctx->program, argv[ctx->optind] + 2);
return '?';
}
/* Found a match. Its index is in `index'. */
switch (options[index].arg_type)
{
case PI_GETOPT_NO_ARGUMENT:
if (cp)
{
fprintf(stderr,
"%s: option doesn't take an argument "
"-- %s\n",
ctx->program, argv[ctx->optind] + 2);
return '?';
}
ctx->optarg = NULL;
break;
case PI_GETOPT_REQUIRED_ARGUMENT:
if (cp == NULL)
{
fprintf(stderr,
"%s: option requires an argument -- %s\n",
ctx->program, argv[ctx->optind] + 2);
return '?';
}
ctx->optarg = cp + 1;
break;
case PI_GETOPT_OPTIONAL_ARGUMENT:
if (cp)
ctx->optarg = cp + 1;
else
ctx->optarg = NULL;
break;
}
ctx->optind++;
return options[index].short_option;
}
else if (argv[ctx->optind][1])
{
/* A short option. */
ctx->short_index = 1;
process_short_option:
/* Lookup the short option. */
for (i = 0; options[i].long_option; i++)
if (options[i].short_option == argv[ctx->optind][ctx->short_index])
break;
if (options[i].long_option == NULL)
{
fprintf(stderr, "%s: unknown option -- %c\n",
ctx->program,
argv[ctx->optind][ctx->short_index]);
return '?';
}
/* Found it. Now check its type. */
switch (options[i].arg_type)
{
case PI_GETOPT_NO_ARGUMENT:
/* No arguments. */
ctx->optarg = NULL;
break;
case PI_GETOPT_REQUIRED_ARGUMENT:
case PI_GETOPT_OPTIONAL_ARGUMENT:
if (argv[ctx->optind][ctx->short_index + 1])
{
/* Argument follows immediately after the option letter. */
ctx->optarg = argv[ctx->optind] + ctx->short_index + 1;
/* No bundled short index after this. */
ctx->short_index = 0;
ctx->optind++;
}
else
{
/* Argument is the next argument in the options
array. */
if (ctx->optind + 1 < argc)
{
ctx->optind++;
ctx->optarg = argv[ctx->optind];
/* No bundled short index after this. */
ctx->short_index = 0;
ctx->optind++;
}
else
{
if (options[i].arg_type == PI_GETOPT_REQUIRED_ARGUMENT)
{
fprintf(stderr,
"%s: option requires an argument "
"-- %c\n",
ctx->program,
argv[ctx->optind][ctx->short_index]);
return '?';
}
else
{
ctx->optarg = NULL;
}
}
}
break;
}
return options[i].short_option;
}
else
{
/* A plain `-'. This end option processing */
return -1;
}
}
/* End of options. */
return -1;
}