1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * All rights reserved.
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
8 *
9 * Contributors:
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
12
13 /*
14 * includes
15 *******************************************************************************
16 */
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <getopt.h>
21
22 /*
23 * global variables, types & constants
24 * may be removed if already defined
25 *******************************************************************************
26 */
27 int opterr = 1;
28 int optopt = 0;
29 int optind = 1;
30 char *optarg = NULL;
31
32 /*
33 * internal values needed by getopt
34 * DO NOT CHANGE or REMOVE
35 */
36 enum {
37 OPTIONAL_ARG = 0,
38 MANDATORY_ARG = 1,
39 NO_ARG = 2
40 };
41
42 /*
43 * variables needed by getopt & getopt_long!
44 * DO NOT REMOVE
45 */
46 static char *optstart = NULL;
47
48 int
getopt(int argc,char ** argv,const char * options)49 getopt(int argc, char **argv, const char *options)
50 {
51 char *optptr;
52 char *argptr;
53 int optman;
54 int idx;
55 int ret = 0;
56 int argpresent;
57
58 /*
59 * reset used global values
60 */
61 optopt = 0;
62 optarg = NULL;
63
64 /*
65 * reset getopt if a new argv pointer is passed
66 */
67 if (optstart != argv[0]) {
68 optopt = 0;
69 optind = 1;
70 optarg = NULL;
71 optstart = argv[0];
72 }
73
74 /*
75 * return if no more arguments are available
76 */
77 if (optind >= argc) {
78 return -1;
79 }
80
81 /*
82 * start parsing argv[optind]
83 */
84 idx = 0;
85
86 /*
87 * return if the option does not begin with a '-' or has more than 2 characters
88 */
89 if (argv[optind][idx] != '-') {
90
91 if (opterr != 0) {
92 printf("unknown option \'%s\', expecting \'-\'\n",
93 argv[optind]);
94 }
95
96 optopt = (int) argv[optind][idx];
97 optind++;
98
99 return '?';
100 }
101
102 /*
103 * continue to the next character in argv[optind]
104 */
105 idx++;
106
107 /*
108 * identify the option
109 * make sure if an option contains a ':' to invalidate the option
110 */
111 optptr = strchr(argv[optind], ':');
112
113 if (optptr == NULL) {
114 optptr = strchr(options, (int) argv[optind][idx]);
115 } else {
116 optptr = NULL;
117 }
118
119 /*
120 * check whether the option is present
121 */
122 if (optptr == NULL) {
123 /*
124 * unknown option detected
125 */
126 if (opterr != 0) {
127 printf("unknown option \'%s\'\n", argv[optind]);
128 }
129
130 optopt = (int) argv[optind][idx];
131 optind++;
132
133 return '?';
134 }
135
136 /*
137 * the option is present in the option string
138 * setup return value
139 */
140 ret = (int) *optptr;
141
142 /*
143 * get option argument if needed
144 */
145 optptr++;
146
147 /*
148 * determine between mandatory and optional argument
149 */
150 optman = NO_ARG;
151
152 if (*optptr == ':') {
153 optman--; // now set to MANDATORY_ARG
154 }
155
156 if (optman == MANDATORY_ARG) {
157 optptr++;
158
159 if (*optptr == ':') {
160 optman--; // now set to OPTIONAL_ARG
161 }
162
163 }
164
165 /*
166 * if strlen( argv[optind ) is greater than 2,
167 * the argument is in the same argv
168 */
169 if (strlen(argv[optind]) > 2) {
170 argptr = &argv[optind][2];
171
172 /*
173 * do not allow '-' in an argument
174 */
175 if (strchr(argptr, '-') != NULL) {
176
177 if (opterr != 0) {
178 printf
179 ("illegal argument value \'%s\' for option \'-%c\'\n",
180 argptr, ret);
181 }
182
183 optopt = ret;
184
185 return '?';
186 }
187
188 } else {
189 /*
190 * move on to the next argv
191 * it now either contains an argument or the next option
192 */
193 optind++;
194
195 /*
196 * make sure not to overflow
197 */
198 if (optind < argc) {
199 argptr = argv[optind];
200 } else {
201 argptr = NULL;
202 }
203
204 }
205
206 /*
207 * do the needed actions for the argument state
208 */
209 switch (optman) {
210 case OPTIONAL_ARG:
211
212 if (argptr == NULL) {
213 break;
214 }
215
216 if (*argptr != '-') {
217 /*
218 * argument present
219 */
220 optarg = argptr;
221 optind++;
222
223 }
224
225
226 break;
227
228 case MANDATORY_ARG:
229 argpresent = (argptr != NULL);
230
231 if (argpresent) {
232 argpresent = (*argptr != '-');
233 }
234
235 if (argpresent) {
236 /*
237 * argument present
238 */
239 optarg = argptr;
240 optind++;
241 } else {
242 /*
243 * mandatory argument missing
244 */
245 if (opterr != 0) {
246 printf
247 ("missing argument for option \'-%c\'\n",
248 ret);
249 }
250
251 optopt = ret;
252
253 /*
254 * if the first character of options is a ':'
255 * return a ':' instead of a '?' in case of
256 * a missing argument
257 */
258 if (*options == ':') {
259 ret = ':';
260 } else {
261 ret = '?';
262 }
263
264 }
265
266
267 break;
268
269 case NO_ARG:
270
271 if (strlen(argv[optind - 1]) > 2) {
272
273 if (opterr != 0) {
274 printf
275 ("too many arguments for option \'-%c\'\n",
276 ret);
277 }
278
279 optopt = ret;
280 ret = '?';
281 }
282
283
284 break;
285
286 }
287
288 return ret;
289 }
290
291 int
getopt_long(int argc,char ** argv,const char * shortopts,const struct option * longopts,int * indexptr)292 getopt_long(int argc, char **argv, const char *shortopts,
293 const struct option *longopts, int *indexptr)
294 {
295 struct option *optptr = (struct option *) longopts;
296 int optidx = 0;
297 int idx;
298 int ret = 0;
299 int argpresent;
300
301 /*
302 * reset used global values
303 */
304 optopt = 0;
305 optarg = NULL;
306
307 /*
308 * reset indexptr
309 */
310 *indexptr = -1;
311
312 /*
313 * reset getopt if a new argv pointer is passed
314 */
315 if (optstart != argv[0]) {
316 optopt = 0;
317 optind = 1;
318 optarg = NULL;
319 optstart = argv[0];
320 }
321
322 /*
323 * return if no more arguments are available
324 */
325 if (optind >= argc) {
326 return -1;
327 }
328
329 /*
330 * start parsing argv[optind]
331 */
332 idx = 0;
333
334 /*
335 * return if the option does not begin with a '-'
336 */
337 if (argv[optind][idx] != '-') {
338 printf("unknown option \'%s\', expecting \'-\'\n",
339 argv[optind]);
340
341 optind++;
342
343 return '?';
344 }
345
346 /*
347 * move on to the next character in argv[optind]
348 */
349 idx++;
350
351 /*
352 * return getopt() in case of a short option
353 */
354 if (argv[optind][idx] != '-') {
355 return getopt(argc, argv, shortopts);
356 }
357
358 /*
359 * handle a long option
360 */
361 idx++;
362
363 while (optptr->name != NULL) {
364
365 if (strcmp(&argv[optind][idx], optptr->name) == 0) {
366 break;
367 }
368
369 optptr++;
370 optidx++;
371 }
372
373 /*
374 * no matching option found
375 */
376 if (optptr->name == NULL) {
377 printf("unknown option \'%s\'\n", argv[optind]);
378
379 optind++;
380
381 return '?';
382 }
383
384 /*
385 * option was found, set up index pointer
386 */
387 *indexptr = optidx;
388
389 /*
390 * get argument
391 */
392 optind++;
393
394 switch (optptr->has_arg) {
395 case no_argument:
396 /*
397 * nothing to do
398 */
399
400 break;
401
402 case required_argument:
403 argpresent = (optind != argc);
404
405 if (argpresent) {
406 argpresent = (argv[optind][0] != '-');
407 }
408
409 if (argpresent) {
410 /*
411 * argument present
412 */
413 optarg = argv[optind];
414 optind++;
415 } else {
416 /*
417 * mandatory argument missing
418 */
419 printf("missing argument for option \'%s\'\n",
420 argv[optind - 1]);
421
422 ret = '?';
423 }
424
425
426 break;
427
428 case optional_argument:
429
430 if (optind == argc) {
431 break;
432 }
433
434 if (argv[optind][0] != '-') {
435 /*
436 * argument present
437 */
438 optarg = argv[optind];
439 optind++;
440 }
441
442
443 break;
444
445 default:
446 printf("unknown argument option for option \'%s\'\n",
447 argv[optind - 1]);
448
449 ret = '?';
450
451 break;
452
453 }
454
455 /*
456 * setup return values
457 */
458 if (ret != '?') {
459
460 if (optptr->flag == NULL) {
461 ret = optptr->val;
462 } else {
463 *optptr->flag = optptr->val;
464 ret = 0;
465 }
466
467 }
468
469 return ret;
470 }
471