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