all repos — mgba @ 67905d281bfecbb06f51f2ca5ac939df378734a5

mGBA Game Boy Advance Emulator

src/platform/windows/getopt.h (view raw)

  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
 27extern "C" {
 28#endif
 29
 30#define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */
 31
 32#ifdef REPLACE_GETOPT
 33int	opterr = 1;		/* if error message should be printed */
 34int	optind = 1;		/* index into parent argv vector */
 35int	optopt = '?';		/* character checked for validity */
 36#undef	optreset		/* see getopt.h */
 37#define	optreset		__mingw_optreset
 38int	optreset;		/* reset getopt */
 39char    *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
 63extern char __declspec(dllimport) *__progname;
 64#endif
 65
 66#ifdef __CYGWIN__
 67static char EMSG[] = "";
 68#else
 69#define	EMSG		""
 70#endif
 71
 72static int getopt_internal(int, char * const *, const char *,
 73			   const struct option *, int *, int);
 74static int parse_long_options(char * const *, const char *,
 75			      const struct option *, int *, int);
 76static int gcd(int, int);
 77static void permute_args(int, int, int, char * const *);
 78
 79static char *place = EMSG; /* option letter processing */
 80
 81/* XXX: set optreset to 1 rather than these two */
 82static int nonopt_start = -1; /* first non option argument (for permute) */
 83static int nonopt_end = -1;   /* first option after non options (for permute) */
 84
 85/* Error messages */
 86static const char recargchar[] = "option requires an argument -- %c";
 87static const char recargstring[] = "option requires an argument -- %s";
 88static const char ambig[] = "ambiguous option -- %.*s";
 89static const char noarg[] = "option doesn't take an argument -- %.*s";
 90static const char illoptchar[] = "unknown option -- %c";
 91static const char illoptstring[] = "unknown option -- %s";
 92
 93static void
 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
102static void
103warnx(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 */
114static int
115gcd(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 */
134static void
135permute_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 */
173int
174getopt(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
199extern 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
219extern "C" {
220#endif
221
222struct 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
230enum    		/* 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 */
242static int
243parse_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 */
370static int
371getopt_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;
407start:
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 */
567int
568getopt_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 */
580int
581getopt_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__) */