OLD | NEW |
| (Empty) |
1 /* | |
2 Copyright (C) 1997 Gregory Pietsch | |
3 | |
4 [These files] are hereby placed in the public domain without restrictions. Just | |
5 give the author credit, don't claim you wrote it or prevent anyone else from | |
6 using it. | |
7 */ | |
8 | |
9 /**************************************************************************** | |
10 | |
11 getopt.c - Read command line options | |
12 | |
13 AUTHOR: Gregory Pietsch | |
14 CREATED Fri Jan 10 21:13:05 1997 | |
15 | |
16 DESCRIPTION: | |
17 | |
18 The getopt() function parses the command line arguments. Its arguments argc | |
19 and argv are the argument count and array as passed to the main() function | |
20 on program invocation. The argument optstring is a list of available option | |
21 characters. If such a character is followed by a colon (`:'), the option | |
22 takes an argument, which is placed in optarg. If such a character is | |
23 followed by two colons, the option takes an optional argument, which is | |
24 placed in optarg. If the option does not take an argument, optarg is NULL. | |
25 | |
26 The external variable optind is the index of the next array element of argv | |
27 to be processed; it communicates from one call to the next which element to | |
28 process. | |
29 | |
30 The getopt_long() function works like getopt() except that it also accepts | |
31 long options started by two dashes `--'. If these take values, it is either | |
32 in the form | |
33 | |
34 --arg=value | |
35 | |
36 or | |
37 | |
38 --arg value | |
39 | |
40 It takes the additional arguments longopts which is a pointer to the first | |
41 element of an array of type GETOPT_LONG_OPTION_T. The last element of the | |
42 array has to be filled with NULL for the name field. | |
43 | |
44 The longind pointer points to the index of the current long option relative | |
45 to longopts if it is non-NULL. | |
46 | |
47 The getopt() function returns the option character if the option was found | |
48 successfully, `:' if there was a missing parameter for one of the options, | |
49 `?' for an unknown option character, and EOF for the end of the option list. | |
50 | |
51 The getopt_long() function's return value is described in the header file. | |
52 | |
53 The function getopt_long_only() is identical to getopt_long(), except that a | |
54 plus sign `+' can introduce long options as well as `--'. | |
55 | |
56 The following describes how to deal with options that follow non-option | |
57 argv-elements. | |
58 | |
59 If the caller did not specify anything, the default is REQUIRE_ORDER if the | |
60 environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. | |
61 | |
62 REQUIRE_ORDER means don't recognize them as options; stop option processing | |
63 when the first non-option is seen. This is what Unix does. This mode of | |
64 operation is selected by either setting the environment variable | |
65 POSIXLY_CORRECT, or using `+' as the first character of the optstring | |
66 parameter. | |
67 | |
68 PERMUTE is the default. We permute the contents of ARGV as we scan, so that | |
69 eventually all the non-options are at the end. This allows options to be | |
70 given in any order, even with programs that were not written to expect this. | |
71 | |
72 RETURN_IN_ORDER is an option available to programs that were written to | |
73 expect options and other argv-elements in any order and that care about the | |
74 ordering of the two. We describe each non-option argv-element as if it were | |
75 the argument of an option with character code 1. Using `-' as the first | |
76 character of the optstring parameter selects this mode of operation. | |
77 | |
78 The special argument `--' forces an end of option-scanning regardless of the | |
79 value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause | |
80 getopt() and friends to return EOF with optind != argc. | |
81 | |
82 COPYRIGHT NOTICE AND DISCLAIMER: | |
83 | |
84 Copyright (C) 1997 Gregory Pietsch | |
85 | |
86 This file and the accompanying getopt.h header file are hereby placed in the | |
87 public domain without restrictions. Just give the author credit, don't | |
88 claim you wrote it or prevent anyone else from using it. | |
89 | |
90 Gregory Pietsch's current e-mail address: | |
91 gpietsch@comcast.net | |
92 ****************************************************************************/ | |
93 | |
94 /* include files */ | |
95 #include <stdio.h> | |
96 #include <stdlib.h> | |
97 #include <string.h> | |
98 #ifndef GETOPT_H | |
99 #include "getopt.h" | |
100 #endif | |
101 | |
102 /* macros */ | |
103 | |
104 /* types */ | |
105 typedef enum GETOPT_ORDERING_T | |
106 { | |
107 PERMUTE, | |
108 RETURN_IN_ORDER, | |
109 REQUIRE_ORDER | |
110 } GETOPT_ORDERING_T; | |
111 | |
112 /* globally-defined variables */ | |
113 char *optarg = NULL; | |
114 int optind = 0; | |
115 int opterr = 1; | |
116 int optopt = '?'; | |
117 | |
118 /* functions */ | |
119 | |
120 /* reverse_argv_elements: reverses num elements starting at argv */ | |
121 static void | |
122 reverse_argv_elements (char **argv, int num) | |
123 { | |
124 int i; | |
125 char *tmp; | |
126 | |
127 for (i = 0; i < (num >> 1); i++) | |
128 { | |
129 tmp = argv[i]; | |
130 argv[i] = argv[num - i - 1]; | |
131 argv[num - i - 1] = tmp; | |
132 } | |
133 } | |
134 | |
135 /* permute: swap two blocks of argv-elements given their lengths */ | |
136 static void | |
137 permute (char **argv, int len1, int len2) | |
138 { | |
139 reverse_argv_elements (argv, len1); | |
140 reverse_argv_elements (argv, len1 + len2); | |
141 reverse_argv_elements (argv, len2); | |
142 } | |
143 | |
144 /* is_option: is this argv-element an option or the end of the option list? */ | |
145 static int | |
146 is_option (char *argv_element, int only) | |
147 { | |
148 return ((argv_element == NULL) | |
149 || (argv_element[0] == '-') || (only && argv_element[0] == '+')); | |
150 } | |
151 | |
152 /* getopt_internal: the function that does all the dirty work */ | |
153 static int | |
154 getopt_internal (int argc, char **argv, char *shortopts, | |
155 GETOPT_LONG_OPTION_T * longopts, int *longind, int only) | |
156 { | |
157 GETOPT_ORDERING_T ordering = PERMUTE; | |
158 static size_t optwhere = 0; | |
159 size_t permute_from = 0; | |
160 int num_nonopts = 0; | |
161 int optindex = 0; | |
162 size_t match_chars = 0; | |
163 char *possible_arg = NULL; | |
164 int longopt_match = -1; | |
165 int has_arg = -1; | |
166 char *cp = NULL; | |
167 int arg_next = 0; | |
168 | |
169 /* first, deal with silly parameters and easy stuff */ | |
170 if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL)) | |
171 return (optopt = '?'); | |
172 if (optind >= argc || argv[optind] == NULL) | |
173 return EOF; | |
174 if (strcmp (argv[optind], "--") == 0) | |
175 { | |
176 optind++; | |
177 return EOF; | |
178 } | |
179 /* if this is our first time through */ | |
180 if (optind == 0) { | |
181 optind = 1; | |
182 optwhere = 1; | |
183 } | |
184 | |
185 /* define ordering */ | |
186 if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+')) | |
187 { | |
188 ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER; | |
189 shortopts++; | |
190 } | |
191 else | |
192 ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE; | |
193 | |
194 /* | |
195 * based on ordering, find our next option, if we're at the beginning of | |
196 * one | |
197 */ | |
198 if (optwhere == 1) | |
199 { | |
200 switch (ordering) | |
201 { | |
202 case PERMUTE: | |
203 permute_from = optind; | |
204 num_nonopts = 0; | |
205 while (!is_option (argv[optind], only)) | |
206 { | |
207 optind++; | |
208 num_nonopts++; | |
209 } | |
210 if (argv[optind] == NULL) | |
211 { | |
212 /* no more options */ | |
213 optind = (int)permute_from; | |
214 return EOF; | |
215 } | |
216 else if (strcmp (argv[optind], "--") == 0) | |
217 { | |
218 /* no more options, but have to get `--' out of the way */ | |
219 permute (argv + permute_from, num_nonopts, 1); | |
220 optind = (int)(permute_from + 1); | |
221 return EOF; | |
222 } | |
223 break; | |
224 case RETURN_IN_ORDER: | |
225 if (!is_option (argv[optind], only)) | |
226 { | |
227 optarg = argv[optind++]; | |
228 return (optopt = 1); | |
229 } | |
230 break; | |
231 case REQUIRE_ORDER: | |
232 if (!is_option (argv[optind], only)) | |
233 return EOF; | |
234 break; | |
235 } | |
236 } | |
237 /* we've got an option, so parse it */ | |
238 | |
239 /* first, is it a long option? */ | |
240 if (longopts != NULL | |
241 && (memcmp (argv[optind], "--", 2) == 0 | |
242 || (only && argv[optind][0] == '+')) && optwhere == 1) | |
243 { | |
244 /* handle long options */ | |
245 if (memcmp (argv[optind], "--", 2) == 0) | |
246 optwhere = 2; | |
247 longopt_match = -1; | |
248 possible_arg = strchr (argv[optind] + optwhere, '='); | |
249 if (possible_arg == NULL) | |
250 { | |
251 /* no =, so next argv might be arg */ | |
252 match_chars = strlen (argv[optind]); | |
253 possible_arg = argv[optind] + match_chars; | |
254 match_chars = match_chars - optwhere; | |
255 } | |
256 else | |
257 match_chars = (possible_arg - argv[optind]) - optwhere; | |
258 for (optindex = 0; longopts[optindex].name != NULL; optindex++) | |
259 { | |
260 if (memcmp (argv[optind] + optwhere, | |
261 longopts[optindex].name, match_chars) == 0) | |
262 { | |
263 /* do we have an exact match? */ | |
264 if (match_chars == strlen (longopts[optindex].name)) | |
265 { | |
266 longopt_match = optindex; | |
267 break; | |
268 } | |
269 /* do any characters match? */ | |
270 else | |
271 { | |
272 if (longopt_match < 0) | |
273 longopt_match = optindex; | |
274 else | |
275 { | |
276 /* we have ambiguous options */ | |
277 if (opterr) | |
278 fprintf (stderr, "%s: option `%s' is ambiguous " | |
279 "(could be `--%s' or `--%s')\n", | |
280 argv[0], | |
281 argv[optind], | |
282 longopts[longopt_match].name, | |
283 longopts[optindex].name); | |
284 return (optopt = '?'); | |
285 } | |
286 } | |
287 } | |
288 } | |
289 if (longopt_match >= 0) | |
290 has_arg = longopts[longopt_match].has_arg; | |
291 } | |
292 /* if we didn't find a long option, is it a short option? */ | |
293 if (longopt_match < 0 && shortopts != NULL) | |
294 { | |
295 cp = strchr (shortopts, argv[optind][optwhere]); | |
296 if (cp == NULL) | |
297 { | |
298 /* couldn't find option in shortopts */ | |
299 if (opterr) | |
300 fprintf (stderr, | |
301 "%s: invalid option -- `-%c'\n", | |
302 argv[0], argv[optind][optwhere]); | |
303 optwhere++; | |
304 if (argv[optind][optwhere] == '\0') | |
305 { | |
306 optind++; | |
307 optwhere = 1; | |
308 } | |
309 return (optopt = '?'); | |
310 } | |
311 has_arg = ((cp[1] == ':') | |
312 ? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argu
ment); | |
313 possible_arg = argv[optind] + optwhere + 1; | |
314 optopt = *cp; | |
315 } | |
316 /* get argument and reset optwhere */ | |
317 arg_next = 0; | |
318 switch (has_arg) | |
319 { | |
320 case OPTIONAL_ARG: | |
321 if (*possible_arg == '=') | |
322 possible_arg++; | |
323 if (*possible_arg != '\0') | |
324 { | |
325 optarg = possible_arg; | |
326 optwhere = 1; | |
327 } | |
328 else | |
329 optarg = NULL; | |
330 break; | |
331 case required_argument: | |
332 if (*possible_arg == '=') | |
333 possible_arg++; | |
334 if (*possible_arg != '\0') | |
335 { | |
336 optarg = possible_arg; | |
337 optwhere = 1; | |
338 } | |
339 else if (optind + 1 >= argc) | |
340 { | |
341 if (opterr) | |
342 { | |
343 fprintf (stderr, "%s: argument required for option `", argv[0]); | |
344 if (longopt_match >= 0) | |
345 fprintf (stderr, "--%s'\n", longopts[longopt_match].name); | |
346 else | |
347 fprintf (stderr, "-%c'\n", *cp); | |
348 } | |
349 optind++; | |
350 return (optopt = ':'); | |
351 } | |
352 else | |
353 { | |
354 optarg = argv[optind + 1]; | |
355 arg_next = 1; | |
356 optwhere = 1; | |
357 } | |
358 break; | |
359 case no_argument: | |
360 if (longopt_match < 0) | |
361 { | |
362 optwhere++; | |
363 if (argv[optind][optwhere] == '\0') | |
364 optwhere = 1; | |
365 } | |
366 else | |
367 optwhere = 1; | |
368 optarg = NULL; | |
369 break; | |
370 } | |
371 | |
372 /* do we have to permute or otherwise modify optind? */ | |
373 if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0) | |
374 { | |
375 permute (argv + permute_from, num_nonopts, 1 + arg_next); | |
376 optind = (int)(permute_from + 1 + arg_next); | |
377 } | |
378 else if (optwhere == 1) | |
379 optind = optind + 1 + arg_next; | |
380 | |
381 /* finally return */ | |
382 if (longopt_match >= 0) | |
383 { | |
384 if (longind != NULL) | |
385 *longind = longopt_match; | |
386 if (longopts[longopt_match].flag != NULL) | |
387 { | |
388 *(longopts[longopt_match].flag) = longopts[longopt_match].val; | |
389 return 0; | |
390 } | |
391 else | |
392 return longopts[longopt_match].val; | |
393 } | |
394 else | |
395 return optopt; | |
396 } | |
397 | |
398 int | |
399 getopt (int argc, char **argv, char *optstring) | |
400 { | |
401 return getopt_internal (argc, argv, optstring, NULL, NULL, 0); | |
402 } | |
403 | |
404 int | |
405 getopt_long (int argc, char **argv, const char *shortopts, | |
406 const GETOPT_LONG_OPTION_T * longopts, int *longind) | |
407 { | |
408 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)l
ongopts, longind, 0); | |
409 } | |
410 | |
411 int | |
412 getopt_long_only (int argc, char **argv, const char *shortopts, | |
413 const GETOPT_LONG_OPTION_T * longopts, int *longind) | |
414 { | |
415 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)l
ongopts, longind, 1); | |
416 } | |
417 | |
418 /* end of file GETOPT.C */ | |
OLD | NEW |