1 #ifndef __GETOPT_H__
2 /**
3  * DISCLAIMER
4  * This file has no copyright assigned and is placed in the Public Domain.
5  * This file is part of the mingw-w64 runtime package.
6  *
7  * The mingw-w64 runtime package and its code is distributed in the hope that it
8  * will be useful but WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESSED OR
9  * IMPLIED ARE HEREBY DISCLAIMED.  This includes but is not limited to
10  * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 #pragma warning(disable:4996)
14 
15 #define __GETOPT_H__
16 
17 /* All the headers include this file. */
18 #include <crtdefs.h>
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <windows.h>
25 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
30 #define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */
31 
32 #ifdef REPLACE_GETOPT
33 int	opterr = 1;		/* if error message should be printed */
34 int	optind = 1;		/* index into parent argv vector */
35 int	optopt = '?';		/* character checked for validity */
36 #undef	optreset		/* see getopt.h */
37 #define	optreset		__mingw_optreset
38 int	optreset;		/* reset getopt */
39 char    *optarg;		/* argument associated with option */
40 #endif
41 
42 //extern int optind;		/* index of first non-option in argv      */
43 //extern int optopt;		/* single option character, as parsed     */
44 //extern int opterr;		/* flag to enable built-in diagnostics... */
45 //				/* (user may set to zero, to suppress)    */
46 //
47 //extern char *optarg;		/* pointer to argument of current option  */
48 
49 #define PRINT_ERROR	((opterr) && (*options != ':'))
50 
51 #define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
52 #define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
53 #define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
54 
55 /* return values */
56 #define	BADCH		(int)'?'
57 #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
58 #define	INORDER 	(int)1
59 
60 #ifndef __CYGWIN__
61 #define __progname __argv[0]
62 #else
63 extern char __declspec(dllimport) *__progname;
64 #endif
65 
66 #ifdef __CYGWIN__
67 static char EMSG[] = "";
68 #else
69 #define	EMSG		""
70 #endif
71 
72 static int getopt_internal(int, char * const *, const char *,
73 			   const struct option *, int *, int);
74 static int parse_long_options(char * const *, const char *,
75 			      const struct option *, int *, int);
76 static int gcd(int, int);
77 static void permute_args(int, int, int, char * const *);
78 
79 static char *place = EMSG; /* option letter processing */
80 
81 /* XXX: set optreset to 1 rather than these two */
82 static int nonopt_start = -1; /* first non option argument (for permute) */
83 static int nonopt_end = -1;   /* first option after non options (for permute) */
84 
85 /* Error messages */
86 static const char recargchar[] = "option requires an argument -- %c";
87 static const char recargstring[] = "option requires an argument -- %s";
88 static const char ambig[] = "ambiguous option -- %.*s";
89 static const char noarg[] = "option doesn't take an argument -- %.*s";
90 static const char illoptchar[] = "unknown option -- %c";
91 static const char illoptstring[] = "unknown option -- %s";
92 
93 static void
_vwarnx(const char * fmt,va_list ap)94 _vwarnx(const char *fmt,va_list ap)
95 {
96   (void)fprintf(stderr,"%s: ",__progname);
97   if (fmt != NULL)
98     (void)vfprintf(stderr,fmt,ap);
99   (void)fprintf(stderr,"\n");
100 }
101 
102 static void
warnx(const char * fmt,...)103 warnx(const char *fmt,...)
104 {
105   va_list ap;
106   va_start(ap,fmt);
107   _vwarnx(fmt,ap);
108   va_end(ap);
109 }
110 
111 /*
112  * Compute the greatest common divisor of a and b.
113  */
114 static int
gcd(int a,int b)115 gcd(int a, int b)
116 {
117 	int c;
118 
119 	c = a % b;
120 	while (c != 0) {
121 		a = b;
122 		b = c;
123 		c = a % b;
124 	}
125 
126 	return (b);
127 }
128 
129 /*
130  * Exchange the block from nonopt_start to nonopt_end with the block
131  * from nonopt_end to opt_end (keeping the same order of arguments
132  * in each block).
133  */
134 static void
permute_args(int panonopt_start,int panonopt_end,int opt_end,char * const * nargv)135 permute_args(int panonopt_start, int panonopt_end, int opt_end,
136 	char * const *nargv)
137 {
138 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
139 	char *swap;
140 
141 	/*
142 	 * compute lengths of blocks and number and size of cycles
143 	 */
144 	nnonopts = panonopt_end - panonopt_start;
145 	nopts = opt_end - panonopt_end;
146 	ncycle = gcd(nnonopts, nopts);
147 	cyclelen = (opt_end - panonopt_start) / ncycle;
148 
149 	for (i = 0; i < ncycle; i++) {
150 		cstart = panonopt_end+i;
151 		pos = cstart;
152 		for (j = 0; j < cyclelen; j++) {
153 			if (pos >= panonopt_end)
154 				pos -= nnonopts;
155 			else
156 				pos += nopts;
157 			swap = nargv[pos];
158 			/* LINTED const cast */
159 			((char **) nargv)[pos] = nargv[cstart];
160 			/* LINTED const cast */
161 			((char **)nargv)[cstart] = swap;
162 		}
163 	}
164 }
165 
166 #ifdef REPLACE_GETOPT
167 /*
168  * getopt --
169  *	Parse argc/argv argument vector.
170  *
171  * [eventually this will replace the BSD getopt]
172  */
173 int
getopt(int nargc,char * const * nargv,const char * options)174 getopt(int nargc, char * const *nargv, const char *options)
175 {
176 
177 	/*
178 	 * We don't pass FLAG_PERMUTE to getopt_internal() since
179 	 * the BSD getopt(3) (unlike GNU) has never done this.
180 	 *
181 	 * Furthermore, since many privileged programs call getopt()
182 	 * before dropping privileges it makes sense to keep things
183 	 * as simple (and bug-free) as possible.
184 	 */
185 	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
186 }
187 #endif /* REPLACE_GETOPT */
188 
189 //extern int getopt(int nargc, char * const *nargv, const char *options);
190 
191 #ifdef _BSD_SOURCE
192 /*
193  * BSD adds the non-standard `optreset' feature, for reinitialisation
194  * of `getopt' parsing.  We support this feature, for applications which
195  * proclaim their BSD heritage, before including this header; however,
196  * to maintain portability, developers are advised to avoid it.
197  */
198 # define optreset  __mingw_optreset
199 extern int optreset;
200 #endif
201 #ifdef __cplusplus
202 }
203 #endif
204 /*
205  * POSIX requires the `getopt' API to be specified in `unistd.h';
206  * thus, `unistd.h' includes this header.  However, we do not want
207  * to expose the `getopt_long' or `getopt_long_only' APIs, when
208  * included in this manner.  Thus, close the standard __GETOPT_H__
209  * declarations block, and open an additional __GETOPT_LONG_H__
210  * specific block, only when *not* __UNISTD_H_SOURCED__, in which
211  * to declare the extended API.
212  */
213 #endif /* !defined(__GETOPT_H__) */
214 
215 #if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
216 #define __GETOPT_LONG_H__
217 
218 #ifdef __cplusplus
219 extern "C" {
220 #endif
221 
222 struct option		/* specification for a long form option...	*/
223 {
224   const char *name;		/* option name, without leading hyphens */
225   int         has_arg;		/* does it take an argument?		*/
226   int        *flag;		/* where to save its status, or NULL	*/
227   int         val;		/* its associated status value		*/
228 };
229 
230 enum    		/* permitted values for its `has_arg' field...	*/
231 {
232   no_argument = 0,      	/* option never takes an argument	*/
233   required_argument,		/* option always requires an argument	*/
234   optional_argument		/* option may take an argument		*/
235 };
236 
237 /*
238  * parse_long_options --
239  *	Parse long options in argc/argv argument vector.
240  * Returns -1 if short_too is set and the option does not match long_options.
241  */
242 static int
parse_long_options(char * const * nargv,const char * options,const struct option * long_options,int * idx,int short_too)243 parse_long_options(char * const *nargv, const char *options,
244 	const struct option *long_options, int *idx, int short_too)
245 {
246 	char *current_argv, *has_equal;
247 	size_t current_argv_len;
248 	int i, ambiguous, match;
249 
250 #define IDENTICAL_INTERPRETATION(_x, _y)                                \
251 	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
252 	 long_options[(_x)].flag == long_options[(_y)].flag &&          \
253 	 long_options[(_x)].val == long_options[(_y)].val)
254 
255 	current_argv = place;
256 	match = -1;
257 	ambiguous = 0;
258 
259 	optind++;
260 
261 	if ((has_equal = strchr(current_argv, '=')) != NULL) {
262 		/* argument found (--option=arg) */
263 		current_argv_len = has_equal - current_argv;
264 		has_equal++;
265 	} else
266 		current_argv_len = strlen(current_argv);
267 
268 	for (i = 0; long_options[i].name; i++) {
269 		/* find matching long option */
270 		if (strncmp(current_argv, long_options[i].name,
271 		    current_argv_len))
272 			continue;
273 
274 		if (strlen(long_options[i].name) == current_argv_len) {
275 			/* exact match */
276 			match = i;
277 			ambiguous = 0;
278 			break;
279 		}
280 		/*
281 		 * If this is a known short option, don't allow
282 		 * a partial match of a single character.
283 		 */
284 		if (short_too && current_argv_len == 1)
285 			continue;
286 
287 		if (match == -1)	/* partial match */
288 			match = i;
289 		else if (!IDENTICAL_INTERPRETATION(i, match))
290 			ambiguous = 1;
291 	}
292 	if (ambiguous) {
293 		/* ambiguous abbreviation */
294 		if (PRINT_ERROR)
295 			warnx(ambig, (int)current_argv_len,
296 			     current_argv);
297 		optopt = 0;
298 		return (BADCH);
299 	}
300 	if (match != -1) {		/* option found */
301 		if (long_options[match].has_arg == no_argument
302 		    && has_equal) {
303 			if (PRINT_ERROR)
304 				warnx(noarg, (int)current_argv_len,
305 				     current_argv);
306 			/*
307 			 * XXX: GNU sets optopt to val regardless of flag
308 			 */
309 			if (long_options[match].flag == NULL)
310 				optopt = long_options[match].val;
311 			else
312 				optopt = 0;
313 			return (BADARG);
314 		}
315 		if (long_options[match].has_arg == required_argument ||
316 		    long_options[match].has_arg == optional_argument) {
317 			if (has_equal)
318 				optarg = has_equal;
319 			else if (long_options[match].has_arg ==
320 			    required_argument) {
321 				/*
322 				 * optional argument doesn't use next nargv
323 				 */
324 				optarg = nargv[optind++];
325 			}
326 		}
327 		if ((long_options[match].has_arg == required_argument)
328 		    && (optarg == NULL)) {
329 			/*
330 			 * Missing argument; leading ':' indicates no error
331 			 * should be generated.
332 			 */
333 			if (PRINT_ERROR)
334 				warnx(recargstring,
335 				    current_argv);
336 			/*
337 			 * XXX: GNU sets optopt to val regardless of flag
338 			 */
339 			if (long_options[match].flag == NULL)
340 				optopt = long_options[match].val;
341 			else
342 				optopt = 0;
343 			--optind;
344 			return (BADARG);
345 		}
346 	} else {			/* unknown option */
347 		if (short_too) {
348 			--optind;
349 			return (-1);
350 		}
351 		if (PRINT_ERROR)
352 			warnx(illoptstring, current_argv);
353 		optopt = 0;
354 		return (BADCH);
355 	}
356 	if (idx)
357 		*idx = match;
358 	if (long_options[match].flag) {
359 		*long_options[match].flag = long_options[match].val;
360 		return (0);
361 	} else
362 		return (long_options[match].val);
363 #undef IDENTICAL_INTERPRETATION
364 }
365 
366 /*
367  * getopt_internal --
368  *	Parse argc/argv argument vector.  Called by user level routines.
369  */
370 static int
getopt_internal(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx,int flags)371 getopt_internal(int nargc, char * const *nargv, const char *options,
372 	const struct option *long_options, int *idx, int flags)
373 {
374 	char *oli;				/* option letter list index */
375 	int optchar, short_too;
376 	static int posixly_correct = -1;
377 
378 	if (options == NULL)
379 		return (-1);
380 
381 	/*
382 	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
383 	 * XXX using optreset.  Work around this braindamage.
384 	 */
385 	if (optind == 0)
386 		optind = optreset = 1;
387 
388 	/*
389 	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
390 	 * string begins with a '+'.
391 	 *
392 	 * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
393 	 *                 optreset != 0 for GNU compatibility.
394 	 */
395 	if (posixly_correct == -1 || optreset != 0)
396 		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
397 	if (*options == '-')
398 		flags |= FLAG_ALLARGS;
399 	else if (posixly_correct || *options == '+')
400 		flags &= ~FLAG_PERMUTE;
401 	if (*options == '+' || *options == '-')
402 		options++;
403 
404 	optarg = NULL;
405 	if (optreset)
406 		nonopt_start = nonopt_end = -1;
407 start:
408 	if (optreset || !*place) {		/* update scanning pointer */
409 		optreset = 0;
410 		if (optind >= nargc) {          /* end of argument vector */
411 			place = EMSG;
412 			if (nonopt_end != -1) {
413 				/* do permutation, if we have to */
414 				permute_args(nonopt_start, nonopt_end,
415 				    optind, nargv);
416 				optind -= nonopt_end - nonopt_start;
417 			}
418 			else if (nonopt_start != -1) {
419 				/*
420 				 * If we skipped non-options, set optind
421 				 * to the first of them.
422 				 */
423 				optind = nonopt_start;
424 			}
425 			nonopt_start = nonopt_end = -1;
426 			return (-1);
427 		}
428 		if (*(place = nargv[optind]) != '-' ||
429 		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
430 			place = EMSG;		/* found non-option */
431 			if (flags & FLAG_ALLARGS) {
432 				/*
433 				 * GNU extension:
434 				 * return non-option as argument to option 1
435 				 */
436 				optarg = nargv[optind++];
437 				return (INORDER);
438 			}
439 			if (!(flags & FLAG_PERMUTE)) {
440 				/*
441 				 * If no permutation wanted, stop parsing
442 				 * at first non-option.
443 				 */
444 				return (-1);
445 			}
446 			/* do permutation */
447 			if (nonopt_start == -1)
448 				nonopt_start = optind;
449 			else if (nonopt_end != -1) {
450 				permute_args(nonopt_start, nonopt_end,
451 				    optind, nargv);
452 				nonopt_start = optind -
453 				    (nonopt_end - nonopt_start);
454 				nonopt_end = -1;
455 			}
456 			optind++;
457 			/* process next argument */
458 			goto start;
459 		}
460 		if (nonopt_start != -1 && nonopt_end == -1)
461 			nonopt_end = optind;
462 
463 		/*
464 		 * If we have "-" do nothing, if "--" we are done.
465 		 */
466 		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
467 			optind++;
468 			place = EMSG;
469 			/*
470 			 * We found an option (--), so if we skipped
471 			 * non-options, we have to permute.
472 			 */
473 			if (nonopt_end != -1) {
474 				permute_args(nonopt_start, nonopt_end,
475 				    optind, nargv);
476 				optind -= nonopt_end - nonopt_start;
477 			}
478 			nonopt_start = nonopt_end = -1;
479 			return (-1);
480 		}
481 	}
482 
483 	/*
484 	 * Check long options if:
485 	 *  1) we were passed some
486 	 *  2) the arg is not just "-"
487 	 *  3) either the arg starts with -- we are getopt_long_only()
488 	 */
489 	if (long_options != NULL && place != nargv[optind] &&
490 	    (*place == '-' || (flags & FLAG_LONGONLY))) {
491 		short_too = 0;
492 		if (*place == '-')
493 			place++;		/* --foo long option */
494 		else if (*place != ':' && strchr(options, *place) != NULL)
495 			short_too = 1;		/* could be short option too */
496 
497 		optchar = parse_long_options(nargv, options, long_options,
498 		    idx, short_too);
499 		if (optchar != -1) {
500 			place = EMSG;
501 			return (optchar);
502 		}
503 	}
504 
505 	if ((optchar = (int)*place++) == (int)':' ||
506 	    (optchar == (int)'-' && *place != '\0') ||
507 	    (oli = (char*)strchr(options, optchar)) == NULL) {
508 		/*
509 		 * If the user specified "-" and  '-' isn't listed in
510 		 * options, return -1 (non-option) as per POSIX.
511 		 * Otherwise, it is an unknown option character (or ':').
512 		 */
513 		if (optchar == (int)'-' && *place == '\0')
514 			return (-1);
515 		if (!*place)
516 			++optind;
517 		if (PRINT_ERROR)
518 			warnx(illoptchar, optchar);
519 		optopt = optchar;
520 		return (BADCH);
521 	}
522 	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
523 		/* -W long-option */
524 		if (*place)			/* no space */
525 			/* NOTHING */;
526 		else if (++optind >= nargc) {	/* no arg */
527 			place = EMSG;
528 			if (PRINT_ERROR)
529 				warnx(recargchar, optchar);
530 			optopt = optchar;
531 			return (BADARG);
532 		} else				/* white space */
533 			place = nargv[optind];
534 		optchar = parse_long_options(nargv, options, long_options,
535 		    idx, 0);
536 		place = EMSG;
537 		return (optchar);
538 	}
539 	if (*++oli != ':') {			/* doesn't take argument */
540 		if (!*place)
541 			++optind;
542 	} else {				/* takes (optional) argument */
543 		optarg = NULL;
544 		if (*place)			/* no white space */
545 			optarg = place;
546 		else if (oli[1] != ':') {	/* arg not optional */
547 			if (++optind >= nargc) {	/* no arg */
548 				place = EMSG;
549 				if (PRINT_ERROR)
550 					warnx(recargchar, optchar);
551 				optopt = optchar;
552 				return (BADARG);
553 			} else
554 				optarg = nargv[optind];
555 		}
556 		place = EMSG;
557 		++optind;
558 	}
559 	/* dump back option letter */
560 	return (optchar);
561 }
562 
563 /*
564  * getopt_long --
565  *	Parse argc/argv argument vector.
566  */
567 int
getopt_long(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)568 getopt_long(int nargc, char * const *nargv, const char *options,
569     const struct option *long_options, int *idx)
570 {
571 
572 	return (getopt_internal(nargc, nargv, options, long_options, idx,
573 	    FLAG_PERMUTE));
574 }
575 
576 /*
577  * getopt_long_only --
578  *	Parse argc/argv argument vector.
579  */
580 int
getopt_long_only(int nargc,char * const * nargv,const char * options,const struct option * long_options,int * idx)581 getopt_long_only(int nargc, char * const *nargv, const char *options,
582     const struct option *long_options, int *idx)
583 {
584 
585 	return (getopt_internal(nargc, nargv, options, long_options, idx,
586 	    FLAG_PERMUTE|FLAG_LONGONLY));
587 }
588 
589 //extern int getopt_long(int nargc, char * const *nargv, const char *options,
590 //    const struct option *long_options, int *idx);
591 //extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
592 //    const struct option *long_options, int *idx);
593 /*
594  * Previous MinGW implementation had...
595  */
596 #ifndef HAVE_DECL_GETOPT
597 /*
598  * ...for the long form API only; keep this for compatibility.
599  */
600 # define HAVE_DECL_GETOPT	1
601 #endif
602 
603 #ifdef __cplusplus
604 }
605 #endif
606 
607 #endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
608