vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

getopt_long.c (11251B)


      1 /*	$NetBSD: getopt_long.c,v 1.19 2005/12/02 14:08:51 yamt Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Dieter Baron and Thomas Klausner.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *	notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *	notice, this list of conditions and the following disclaimer in the
     17  *	documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *	must display the following acknowledgement:
     20  *		This product includes software developed by the NetBSD
     21  *		Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *	contributors may be used to endorse or promote products derived
     24  *	from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <assert.h>
     40 #include <errno.h>
     41 #include "getopt.h"
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <stdio.h>
     45 
     46 int	opterr = 1;		/* if error message should be printed */
     47 int	optind = 1;		/* index into parent argv vector */
     48 int	optopt = '?';		/* character checked for validity */
     49 int	optreset;		/* reset getopt */
     50 char	*optarg;		/* argument associated with option */
     51 
     52 #define IGNORE_FIRST	(*options == '-' || *options == '+')
     53 #define PRINT_ERROR	((opterr) && ((*options != ':') \
     54 					  || (IGNORE_FIRST && options[1] != ':')))
     55 #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
     56 #define PERMUTE		 (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
     57 /* XXX: GNU ignores PC if *options == '-' */
     58 #define IN_ORDER		(!IS_POSIXLY_CORRECT && *options == '-')
     59 
     60 /* return values */
     61 #define	BADCH	(int)'?'
     62 #define	BADARG		((IGNORE_FIRST && options[1] == ':') \
     63 			 || (*options == ':') ? (int)':' : (int)'?')
     64 #define INORDER (int)1
     65 
     66 #define	EMSG	""
     67 
     68 static int getopt_internal (int, char **, const char *);
     69 static int gcd (int, int);
     70 static void permute_args (int, int, int, char **);
     71 
     72 static const char *place = EMSG; /* option letter processing */
     73 
     74 /* XXX: set optreset to 1 rather than these two */
     75 static int nonopt_start = -1; /* first non option argument (for permute) */
     76 static int nonopt_end = -1;   /* first option after non options (for permute) */
     77 
     78 /* Error messages */
     79 static const char recargchar[] = "option requires an argument -- %c";
     80 static const char recargstring[] = "option requires an argument -- %s";
     81 static const char ambig[] = "ambiguous option -- %.*s";
     82 static const char noarg[] = "option doesn't take an argument -- %.*s";
     83 static const char illoptchar[] = "unknown option -- %c";
     84 static const char illoptstring[] = "unknown option -- %s";
     85 
     86 
     87 /*
     88  * Compute the greatest common divisor of a and b.
     89  */
     90 static int
     91 gcd(a, b)
     92 	int a;
     93 	int b;
     94 {
     95 	int c;
     96 
     97 	c = a % b;
     98 	while (c != 0) {
     99 		a = b;
    100 		b = c;
    101 		c = a % b;
    102 	}
    103 	   
    104 	return b;
    105 }
    106 
    107 /*
    108  * Exchange the block from nonopt_start to nonopt_end with the block
    109  * from nonopt_end to opt_end (keeping the same order of arguments
    110  * in each block).
    111  */
    112 static void
    113 permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv)
    114 {
    115 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
    116 	char *swap;
    117 
    118 	/*
    119 	 * compute lengths of blocks and number and size of cycles
    120 	 */
    121 	nnonopts = panonopt_end - panonopt_start;
    122 	nopts = opt_end - panonopt_end;
    123 	ncycle = gcd(nnonopts, nopts);
    124 	cyclelen = (opt_end - panonopt_start) / ncycle;
    125 
    126 	for (i = 0; i < ncycle; i++) {
    127 		cstart = panonopt_end+i;
    128 		pos = cstart;
    129 		for (j = 0; j < cyclelen; j++) {
    130 			if (pos >= panonopt_end)
    131 				pos -= nnonopts;
    132 			else
    133 				pos += nopts;
    134 			swap = nargv[pos];
    135 			nargv[pos] = nargv[cstart];
    136 			nargv[cstart] = swap;
    137 		}
    138 	}
    139 }
    140 
    141 /*
    142  * getopt_internal --
    143  *	Parse argc/argv argument vector.  Called by user level routines.
    144  *  Returns -2 if -- is found (can be long option or end of options marker).
    145  */
    146 static int
    147 getopt_internal(int nargc, char **nargv, const char *options)
    148 {
    149 	char *oli;				/* option letter list index */
    150 	int optchar;
    151 
    152 	optarg = NULL;
    153 
    154 	/*
    155 	 * XXX Some programs (like rsyncd) expect to be able to
    156 	 * XXX re-initialize optind to 0 and have getopt_long(3)
    157 	 * XXX properly function again.  Work around this braindamage.
    158 	 */
    159 	if (optind == 0)
    160 		optind = 1;
    161 
    162 	if (optreset)
    163 		nonopt_start = nonopt_end = -1;
    164 start:
    165 	if (optreset || !*place) {		/* update scanning pointer */
    166 		optreset = 0;
    167 		if (optind >= nargc) {		  /* end of argument vector */
    168 			place = EMSG;
    169 			if (nonopt_end != -1) {
    170 				/* do permutation, if we have to */
    171 				permute_args(nonopt_start, nonopt_end,
    172 					optind, nargv);
    173 				optind -= nonopt_end - nonopt_start;
    174 			}
    175 			else if (nonopt_start != -1) {
    176 				/*
    177 				 * If we skipped non-options, set optind
    178 				 * to the first of them.
    179 				 */
    180 				optind = nonopt_start;
    181 			}
    182 			nonopt_start = nonopt_end = -1;
    183 			return -1;
    184 		}
    185 		if ((*(place = nargv[optind]) != '-')
    186 			|| (place[1] == '\0')) {	/* found non-option */
    187 			place = EMSG;
    188 			if (IN_ORDER) {
    189 				/*
    190 				 * GNU extension: 
    191 				 * return non-option as argument to option 1
    192 				 */
    193 				optarg = nargv[optind++];
    194 				return INORDER;
    195 			}
    196 			if (!PERMUTE) {
    197 				/*
    198 				 * if no permutation wanted, stop parsing
    199 				 * at first non-option
    200 				 */
    201 				return -1;
    202 			}
    203 			/* do permutation */
    204 			if (nonopt_start == -1)
    205 				nonopt_start = optind;
    206 			else if (nonopt_end != -1) {
    207 				permute_args(nonopt_start, nonopt_end,
    208 					optind, nargv);
    209 				nonopt_start = optind -
    210 					(nonopt_end - nonopt_start);
    211 				nonopt_end = -1;
    212 			}
    213 			optind++;
    214 			/* process next argument */
    215 			goto start;
    216 		}
    217 		if (nonopt_start != -1 && nonopt_end == -1)
    218 			nonopt_end = optind;
    219 		if (place[1] && *++place == '-') {	/* found "--" */
    220 			place++;
    221 			return -2;
    222 		}
    223 	}
    224 	if ((optchar = (int)*place++) == (int)':' ||
    225 		(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
    226 		/* option letter unknown or ':' */
    227 		if (!*place)
    228 			++optind;
    229 		if (PRINT_ERROR)
    230 			fprintf(stderr, illoptchar, optchar);
    231 		optopt = optchar;
    232 		return BADCH;
    233 	}
    234 	if (optchar == 'W' && oli[1] == ';') {		/* -W long-option */
    235 		/* XXX: what if no long options provided (called by getopt)? */
    236 		if (*place) 
    237 			return -2;
    238 
    239 		if (++optind >= nargc) {	/* no arg */
    240 			place = EMSG;
    241 			if (PRINT_ERROR)
    242 				fprintf(stderr, recargchar, optchar);
    243 			optopt = optchar;
    244 			return BADARG;
    245 		} else				/* white space */
    246 			place = nargv[optind];
    247 		/*
    248 		 * Handle -W arg the same as --arg (which causes getopt to
    249 		 * stop parsing).
    250 		 */
    251 		return -2;
    252 	}
    253 	if (*++oli != ':') {			/* doesn't take argument */
    254 		if (!*place)
    255 			++optind;
    256 	} else {				/* takes (optional) argument */
    257 		optarg = NULL;
    258 		if (*place)			/* no white space */
    259 			optarg = (char *) place;
    260 		/* XXX: disable test for :: if PC? (GNU doesn't) */
    261 		else if (oli[1] != ':') {	/* arg not optional */
    262 			if (++optind >= nargc) {	/* no arg */
    263 				place = EMSG;
    264 				if (PRINT_ERROR)
    265 					fprintf(stderr, recargchar, optchar);
    266 				optopt = optchar;
    267 				return BADARG;
    268 			} else
    269 				optarg = nargv[optind];
    270 		}
    271 		place = EMSG;
    272 		++optind;
    273 	}
    274 	/* dump back option letter */
    275 	return optchar;
    276 }
    277 
    278 /*
    279  * getopt_long --
    280  *	Parse argc/argv argument vector.
    281  */
    282 int
    283 getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx)
    284 {
    285 	int retval;
    286 
    287 	retval = getopt_internal(nargc, (char **) (nargv), options);
    288 	if (retval == -2) {
    289 		char *current_argv, *has_equal;
    290 		size_t current_argv_len;
    291 		int i, match;
    292 
    293 		current_argv = (char *) (place);
    294 		match = -1;
    295 
    296 		optind++;
    297 		place = EMSG;
    298 
    299 		if (*current_argv == '\0') {		/* found "--" */
    300 			/*
    301 			 * We found an option (--), so if we skipped
    302 			 * non-options, we have to permute.
    303 			 */
    304 			if (nonopt_end != -1) {
    305 				permute_args(nonopt_start, nonopt_end,
    306 					optind, (char **) (nargv));
    307 				optind -= nonopt_end - nonopt_start;
    308 			}
    309 			nonopt_start = nonopt_end = -1;
    310 			return -1;
    311 		}
    312 		if ((has_equal = strchr(current_argv, '=')) != NULL) {
    313 			/* argument found (--option=arg) */
    314 			current_argv_len = has_equal - current_argv;
    315 			has_equal++;
    316 		} else
    317 			current_argv_len = strlen(current_argv);
    318 		
    319 		for (i = 0; long_options[i].name; i++) {
    320 			/* find matching long option */
    321 			if (strncmp(current_argv, long_options[i].name,
    322 				current_argv_len))
    323 				continue;
    324 
    325 			if (strlen(long_options[i].name) ==
    326 				(unsigned)current_argv_len) {
    327 				/* exact match */
    328 				match = i;
    329 				break;
    330 			}
    331 			if (match == -1)		/* partial match */
    332 				match = i;
    333 			else {
    334 				/* ambiguous abbreviation */
    335 				if (PRINT_ERROR)
    336 					fprintf(stderr, ambig, (int)current_argv_len,
    337 						 current_argv);
    338 				optopt = 0;
    339 				return BADCH;
    340 			}
    341 		}
    342 		if (match != -1) {			/* option found */
    343 				if (long_options[match].has_arg == no_argument
    344 				&& has_equal) {
    345 				if (PRINT_ERROR)
    346 					fprintf(stderr, noarg, (int)current_argv_len,
    347 						 current_argv);
    348 				/*
    349 				 * XXX: GNU sets optopt to val regardless of
    350 				 * flag
    351 				 */
    352 				if (long_options[match].flag == NULL)
    353 					optopt = long_options[match].val;
    354 				else
    355 					optopt = 0;
    356 				return BADARG;
    357 			}
    358 			if (long_options[match].has_arg == required_argument ||
    359 				long_options[match].has_arg == optional_argument) {
    360 				if (has_equal)
    361 					optarg = has_equal;
    362 				else if (long_options[match].has_arg ==
    363 					required_argument) {
    364 					/*
    365 					 * optional argument doesn't use
    366 					 * next nargv
    367 					 */
    368 					optarg = nargv[optind++];
    369 				}
    370 			}
    371 			if ((long_options[match].has_arg == required_argument)
    372 				&& (optarg == NULL)) {
    373 				/*
    374 				 * Missing argument; leading ':'
    375 				 * indicates no error should be generated
    376 				 */
    377 				if (PRINT_ERROR)
    378 					fprintf(stderr, recargstring, current_argv);
    379 				/*
    380 				 * XXX: GNU sets optopt to val regardless
    381 				 * of flag
    382 				 */
    383 				if (long_options[match].flag == NULL)
    384 					optopt = long_options[match].val;
    385 				else
    386 					optopt = 0;
    387 				--optind;
    388 				return BADARG;
    389 			}
    390 		} else {			/* unknown option */
    391 			if (PRINT_ERROR)
    392 				fprintf(stderr, illoptstring, current_argv);
    393 			optopt = 0;
    394 			return BADCH;
    395 		}
    396 		if (long_options[match].flag) {
    397 			*long_options[match].flag = long_options[match].val;
    398 			retval = 0;
    399 		} else 
    400 			retval = long_options[match].val;
    401 		if (idx)
    402 			*idx = match;
    403 	}
    404 	return retval;
    405 }