HuntnGather – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /**************************************************************************** |
2 | * getopt(): Return the next user option on each iteration. |
||
3 | * This is a clone of the usual UNIX getopt() function. |
||
4 | * If you have never used a getopt() before, you'll have to |
||
5 | * read about it on any UNIX machine or other C system that |
||
6 | * documents it. |
||
7 | * |
||
8 | * Author: Daniel J. Barrett, barrett@cs.umass.edu. |
||
9 | * |
||
10 | * License: This code is placed in the Public Domain. |
||
11 | * Give it away to anybody for free! |
||
12 | * Use it for any purpose you like! |
||
13 | * |
||
14 | * If you use this code in a program, please give me credit |
||
15 | * for my work. Thanks! |
||
16 | * |
||
17 | * Why I wrote it: |
||
18 | * |
||
19 | * Because every other getopt() function I have ever seen |
||
20 | * had source code that was difficult to understand. |
||
21 | * I wrote this code to be very modular and readable. |
||
22 | * I hope you find it instructive and/or helpful. |
||
23 | * |
||
24 | * BUGS |
||
25 | * "--JUNK" is treated as "--", the "end of options" flag. |
||
26 | * |
||
27 | * REVISION HISTORY: |
||
28 | * |
||
29 | * Version: 1.3 |
||
30 | * Date: January 21, 1993 |
||
31 | * Comments: Bugfix. Option "-:" was accepted as OK. Not anymore. |
||
32 | * |
||
33 | * Version: 1.2a |
||
34 | * Date: January 21, 1993 |
||
35 | * Comments: Improved the TESTME main program. More useful output. |
||
36 | * Rewrote Error() to eliminate redundancy. |
||
37 | * |
||
38 | * Version: 1.2 |
||
39 | * Date: January 21, 1993 |
||
40 | * Comments: If a legal option is not followed by a required |
||
41 | * argument, getopt() previously returned the option's |
||
42 | * character. It should have returned UNKNOWN_OPT. |
||
43 | * This has been fixed. Note that HandleArgument() |
||
44 | * now returns an int value rather than void. |
||
45 | * |
||
46 | * Version: 1.1b |
||
47 | * Date: December 17, 1991. |
||
48 | * Comments: Minor change of NULL to '\0' in 1 spot. |
||
49 | * |
||
50 | * Version: 1.1 |
||
51 | * Date: February 20, 1991. |
||
52 | * Comments: Bug fix in Pass(). Forgot to check that the |
||
53 | * current argument is non-empty and starts with |
||
54 | * a DASH. |
||
55 | * |
||
56 | * Got rid of the unnecessary "g_" at the beginning |
||
57 | * of each function name. Since they're static, we |
||
58 | * don't have to worry about duplication of names |
||
59 | * by the calling program. |
||
60 | * |
||
61 | * Version: 1.0 |
||
62 | * Date: April 12, 1990. |
||
63 | * Comments: First released version. |
||
64 | * |
||
65 | ****************************************************************************/ |
||
66 | |||
67 | #ifndef __STDIO_H /* If we haven't already included stdio.h, do it. */ |
||
68 | # include <stdio.h> /* Maybe someday I'll eliminate this. */ |
||
69 | #endif |
||
70 | |||
71 | #ifndef __STRING_H |
||
72 | # include <string.h> /* For index() */ |
||
73 | #endif |
||
74 | |||
75 | /************************************************************************ |
||
76 | * Some constants. |
||
77 | ************************************************************************/ |
||
78 | |||
79 | #define DASH '-' /* This preceeds an option. */ |
||
80 | #define ARG_COMING ':' /* In the option string, this indicates that |
||
81 | * that the option requires an argument. */ |
||
82 | #define UNKNOWN_OPT '?' /* The char returned for unknown option. */ |
||
83 | |||
84 | /************************************************************************ |
||
85 | * Internal error codes. |
||
86 | ************************************************************************/ |
||
87 | |||
88 | #define ERROR_BAD_OPTION 1 |
||
89 | #define ERROR_MISSING_ARGUMENT 2 |
||
90 | |||
91 | /************************************************************************ |
||
92 | * ANSI function prototypes. |
||
93 | ************************************************************************/ |
||
94 | |||
95 | int getopt(int argc, char *argv[], char *optString); |
||
96 | static int NextOption(char *argv[], char *optString); |
||
97 | static int RealOption(char *argv[], char *str, int *skip, int *ind, |
||
98 | int opt); |
||
99 | static int HandleArgument(char *argv[], int *optind, int *skip); |
||
100 | static void Error(int err, int c); |
||
101 | static void Pass(char *argv[], int *optind, int *optsSkipped); |
||
102 | |||
103 | /************************************************************************ |
||
104 | * Global variables. You must declare these externs in your program |
||
105 | * if you want to see their values! |
||
106 | ************************************************************************/ |
||
107 | |||
108 | char *optarg = NULL; /* This will point to a required argument, if any. */ |
||
109 | int optind = 1; /* The index of the next argument in argv. */ |
||
110 | int opterr = 1; /* 1 == print internal error messages. 0 else. */ |
||
111 | int optopt; /* The actual option letter that was found. */ |
||
112 | |||
113 | |||
114 | int getopt(int argc, char *argv[], char *optString) |
||
115 | { |
||
116 | optarg = NULL; |
||
117 | if (optind < argc) /* More arguments to check. */ |
||
118 | return(NextOption(argv, optString)); |
||
119 | else /* We're done. */ |
||
120 | return(EOF); |
||
121 | } |
||
122 | |||
123 | |||
124 | /* If the current argument does not begin with DASH, it is not an option. |
||
125 | * Return EOF. |
||
126 | * If we have ONLY a DASH, and nothing after it... return EOF as well. |
||
127 | * If we have a DASH followed immediately by another DASH, this is the |
||
128 | * special "--" option that means "no more options follow." Return EOF. |
||
129 | * Otherwise, we have an actual option or list of options. Process it. */ |
||
130 | |||
131 | static int NextOption(char *argv[], char *optString) |
||
132 | { |
||
133 | static int optsSkipped = 0; /* In a single argv[i]. */ |
||
134 | |||
135 | if ((argv[optind][0] == DASH) |
||
136 | && ((optopt = argv[optind][1+optsSkipped]) != '\0')) |
||
137 | { |
||
138 | if (optopt == DASH) |
||
139 | { |
||
140 | optind++; |
||
141 | return(EOF); |
||
142 | } |
||
143 | else |
||
144 | return(RealOption(argv, optString, &optsSkipped, |
||
145 | &optind, optopt)); |
||
146 | } |
||
147 | else |
||
148 | return(EOF); |
||
149 | } |
||
150 | |||
151 | |||
152 | /* At this point, we know that argv[optind] is an option or list of |
||
153 | * options. If this is a list of options, *optsSkipped tells us how |
||
154 | * many of those options have ALREADY been parsed on previous calls |
||
155 | * to getopt(). |
||
156 | * If the option is not legal (not in optString), complain and return |
||
157 | * UNKNOWN_OPT. |
||
158 | * If the option requires no argument, just return the option letter. |
||
159 | * If the option requires an argument, call HandleArgument and return |
||
160 | * the option letter. */ |
||
161 | |||
162 | static int RealOption(char *argv[], char *optString, int *optsSkipped, |
||
163 | int *optind, int optopt) |
||
164 | { |
||
165 | char *where; /* Pointer to the letter in optString. */ |
||
166 | int argWasOK; /* An indication that a required arg was found. */ |
||
167 | |||
168 | (*optsSkipped)++; |
||
169 | |||
170 | if (optopt == ARG_COMING) /* Special case of "-:" */ |
||
171 | { |
||
172 | Error(ERROR_BAD_OPTION, optopt); |
||
173 | Pass(argv, optind, optsSkipped); |
||
174 | return(UNKNOWN_OPT); |
||
175 | } |
||
176 | |||
177 | else if (where = index(optString, optopt)) |
||
178 | { |
||
179 | argWasOK = 1; /* Assume any argument will be found. */ |
||
180 | |||
181 | if (*(where+1) == ARG_COMING) |
||
182 | argWasOK = HandleArgument(argv, optind, optsSkipped); |
||
183 | |||
184 | Pass(argv, optind, optsSkipped); |
||
185 | |||
186 | return(argWasOK ? optopt : UNKNOWN_OPT); |
||
187 | } |
||
188 | |||
189 | else |
||
190 | { |
||
191 | Error(ERROR_BAD_OPTION, optopt); |
||
192 | Pass(argv, optind, optsSkipped); |
||
193 | return(UNKNOWN_OPT); |
||
194 | } |
||
195 | } |
||
196 | |||
197 | |||
198 | /* We have an option in argv[optind] that requires an argument. If there |
||
199 | * is no whitespace after the option letter itself, take the rest of |
||
200 | * argv[optind] to be the argument. |
||
201 | * If there IS whitespace after the option letter, take argv[optind+1] to |
||
202 | * be the argument. |
||
203 | * Otherwise, if there is NO argument, complain! |
||
204 | * Return 1 on success, 0 on error. |
||
205 | */ |
||
206 | |||
207 | static int HandleArgument(char *argv[], int *optind, int *optsSkipped) |
||
208 | { |
||
209 | int OK; |
||
210 | |||
211 | if (argv[*optind][1+(*optsSkipped)]) |
||
212 | { |
||
213 | optarg = argv[*optind] + 1 + (*optsSkipped); |
||
214 | OK = 1; |
||
215 | } |
||
216 | else if (argv[(*optind)+1]) |
||
217 | { |
||
218 | optarg = argv[(*optind)+1]; |
||
219 | (*optind)++; |
||
220 | OK = 1; |
||
221 | } |
||
222 | else |
||
223 | { |
||
224 | Error(ERROR_MISSING_ARGUMENT, optopt); |
||
225 | OK = 0; |
||
226 | } |
||
227 | |||
228 | (*optsSkipped) = 0; |
||
229 | (*optind)++; |
||
230 | return(OK); |
||
231 | } |
||
232 | |||
233 | |||
234 | /* Print an appropriate error message. */ |
||
235 | |||
236 | static void Error(int err, int c) |
||
237 | { |
||
238 | if (opterr) |
||
239 | { |
||
240 | fprintf(stderr, "-%c: ", c); |
||
241 | switch (err) |
||
242 | { |
||
243 | case ERROR_BAD_OPTION: |
||
244 | fprintf(stderr, "Illegal option.\n"); |
||
245 | break; |
||
246 | case ERROR_MISSING_ARGUMENT: |
||
247 | fprintf(stderr, |
||
248 | "An argument is required, but missing.\n"); |
||
249 | break; |
||
250 | default: |
||
251 | fprintf(stderr, |
||
252 | "An unknown error occurred.\n"); |
||
253 | break; |
||
254 | } |
||
255 | } |
||
256 | } |
||
257 | |||
258 | |||
259 | /* We have reached the end of argv[optind]... there are no more options |
||
260 | * in it to parse. Skip to the next item in argv. */ |
||
261 | |||
262 | static void Pass(char *argv[], int *optind, int *optsSkipped) |
||
263 | { |
||
264 | if (argv[*optind] |
||
265 | && (argv[*optind][0] == DASH) |
||
266 | && (argv[*optind][1+(*optsSkipped)] == '\0')) |
||
267 | { |
||
268 | (*optind)++; |
||
269 | (*optsSkipped) = 0; |
||
270 | } |
||
271 | } |
||
272 | |||
273 | /*************************************************************************** |
||
274 | * A test program. Compile this file with -DTESTME as an option. |
||
275 | ***************************************************************************/ |
||
276 | |||
277 | #ifdef TESTME |
||
278 | main(int argc, char *argv[]) |
||
279 | { |
||
280 | char c; |
||
281 | int i; |
||
282 | |||
283 | while ((c = getopt(argc, argv, "a:b:cde")) != EOF) |
||
284 | { |
||
285 | printf("OPTION %c", c); |
||
286 | if ((c == 'a') || (c == 'b')) |
||
287 | printf(", arg=\"%s\"\n", optarg); |
||
288 | else |
||
289 | printf("\n"); |
||
290 | } |
||
291 | |||
292 | for (i=optind; i<argc; i++) |
||
293 | { |
||
294 | printf("Arg %d (argv[%d]): \"%s\"\n", |
||
295 | i - optind + 1, |
||
296 | i, |
||
297 | argv[i]); |
||
298 | } |
||
299 | |||
300 | exit(0); |
||
301 | } |
||
302 | #endif |