1e415196aSJoakim Soderberg 
2e415196aSJoakim Soderberg /*
3e415196aSJoakim Soderberg  * Copyright (c) 1987, 1993, 1994, 1996
4e415196aSJoakim Soderberg  *	The Regents of the University of California.  All rights reserved.
5e415196aSJoakim Soderberg  *
6e415196aSJoakim Soderberg  * Redistribution and use in source and binary forms, with or without
7e415196aSJoakim Soderberg  * modification, are permitted provided that the following conditions
8e415196aSJoakim Soderberg  * are met:
9e415196aSJoakim Soderberg  * 1. Redistributions of source code must retain the above copyright
10e415196aSJoakim Soderberg  *    notice, this list of conditions and the following disclaimer.
11e415196aSJoakim Soderberg  * 2. Redistributions in binary form must reproduce the above copyright
12e415196aSJoakim Soderberg  *    notice, this list of conditions and the following disclaimer in the
13e415196aSJoakim Soderberg  *    documentation and/or other materials provided with the distribution.
1486df3edaSJoakim Soderberg  * 3. Neither the names of the copyright holders nor the names of its
1586df3edaSJoakim Soderberg  *    contributors may be used to endorse or promote products derived from
1686df3edaSJoakim Soderberg  *    this software without specific prior written permission.
17e415196aSJoakim Soderberg  *
1886df3edaSJoakim Soderberg  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
1986df3edaSJoakim Soderberg  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2086df3edaSJoakim Soderberg  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2186df3edaSJoakim Soderberg  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
2286df3edaSJoakim Soderberg  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2386df3edaSJoakim Soderberg  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2486df3edaSJoakim Soderberg  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2586df3edaSJoakim Soderberg  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2686df3edaSJoakim Soderberg  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2786df3edaSJoakim Soderberg  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2886df3edaSJoakim Soderberg  * POSSIBILITY OF SUCH DAMAGE.
29e415196aSJoakim Soderberg  */
30e415196aSJoakim Soderberg #include <assert.h>
31e415196aSJoakim Soderberg #include <errno.h>
32e415196aSJoakim Soderberg #include <stdio.h>
33e415196aSJoakim Soderberg #include <stdlib.h>
34e415196aSJoakim Soderberg #include <string.h>
35e415196aSJoakim Soderberg #include "getopt.h"
36e415196aSJoakim Soderberg 
37e415196aSJoakim Soderberg extern int	  opterr;	/* if error message should be printed */
38e415196aSJoakim Soderberg extern int	  optind;	/* index into parent argv vector */
39e415196aSJoakim Soderberg extern int	  optopt;	/* character checked for validity */
40e415196aSJoakim Soderberg extern int	  optreset;	/* reset getopt */
41e415196aSJoakim Soderberg extern char *optarg;	/* argument associated with option */
42e415196aSJoakim Soderberg 
43e415196aSJoakim Soderberg #define __P(x) x
44e415196aSJoakim Soderberg #define _DIAGASSERT(x) assert(x)
45e415196aSJoakim Soderberg 
46e415196aSJoakim Soderberg static char * __progname __P((char *));
47e415196aSJoakim Soderberg int getopt_internal __P((int, char * const *, const char *));
48e415196aSJoakim Soderberg 
49e415196aSJoakim Soderberg static char *
__progname(nargv0)50e415196aSJoakim Soderberg __progname(nargv0)
51e415196aSJoakim Soderberg 	char * nargv0;
52e415196aSJoakim Soderberg {
53e415196aSJoakim Soderberg 	char * tmp;
54e415196aSJoakim Soderberg 
55e415196aSJoakim Soderberg 	_DIAGASSERT(nargv0 != NULL);
56e415196aSJoakim Soderberg 
57e415196aSJoakim Soderberg 	tmp = strrchr(nargv0, '/');
58e415196aSJoakim Soderberg 	if (tmp)
59e415196aSJoakim Soderberg 		tmp++;
60e415196aSJoakim Soderberg 	else
61e415196aSJoakim Soderberg 		tmp = nargv0;
62e415196aSJoakim Soderberg 	return(tmp);
63e415196aSJoakim Soderberg }
64e415196aSJoakim Soderberg 
65e415196aSJoakim Soderberg #define	BADCH	(int)'?'
66e415196aSJoakim Soderberg #define	BADARG	(int)':'
67e415196aSJoakim Soderberg #define	EMSG	""
68e415196aSJoakim Soderberg 
69e415196aSJoakim Soderberg /*
70e415196aSJoakim Soderberg  * getopt --
71e415196aSJoakim Soderberg  *	Parse argc/argv argument vector.
72e415196aSJoakim Soderberg  */
73e415196aSJoakim Soderberg int
getopt_internal(nargc,nargv,ostr)74e415196aSJoakim Soderberg getopt_internal(nargc, nargv, ostr)
75e415196aSJoakim Soderberg 	int nargc;
76e415196aSJoakim Soderberg 	char * const *nargv;
77e415196aSJoakim Soderberg 	const char *ostr;
78e415196aSJoakim Soderberg {
79e415196aSJoakim Soderberg 	static char *place = EMSG;		/* option letter processing */
80e415196aSJoakim Soderberg 	char *oli;				/* option letter list index */
81e415196aSJoakim Soderberg 
82e415196aSJoakim Soderberg 	_DIAGASSERT(nargv != NULL);
83e415196aSJoakim Soderberg 	_DIAGASSERT(ostr != NULL);
84e415196aSJoakim Soderberg 
85e415196aSJoakim Soderberg 	if (optreset || !*place) {		/* update scanning pointer */
86e415196aSJoakim Soderberg 		optreset = 0;
87e415196aSJoakim Soderberg 		if (optind >= nargc || *(place = nargv[optind]) != '-') {
88e415196aSJoakim Soderberg 			place = EMSG;
89e415196aSJoakim Soderberg 			return (-1);
90e415196aSJoakim Soderberg 		}
91e415196aSJoakim Soderberg 		if (place[1] && *++place == '-') {	/* found "--" */
92e415196aSJoakim Soderberg 			/* ++optind; */
93e415196aSJoakim Soderberg 			place = EMSG;
94e415196aSJoakim Soderberg 			return (-2);
95e415196aSJoakim Soderberg 		}
96e415196aSJoakim Soderberg 	}					/* option letter okay? */
97e415196aSJoakim Soderberg 	if ((optopt = (int)*place++) == (int)':' ||
98e415196aSJoakim Soderberg 	    !(oli = strchr(ostr, optopt))) {
99e415196aSJoakim Soderberg 		/*
100e415196aSJoakim Soderberg 		 * if the user didn't specify '-' as an option,
101e415196aSJoakim Soderberg 		 * assume it means -1.
102e415196aSJoakim Soderberg 		 */
103e415196aSJoakim Soderberg 		if (optopt == (int)'-')
104e415196aSJoakim Soderberg 			return (-1);
105e415196aSJoakim Soderberg 		if (!*place)
106e415196aSJoakim Soderberg 			++optind;
107e415196aSJoakim Soderberg 		if (opterr && *ostr != ':')
108e415196aSJoakim Soderberg 			(void)fprintf(stderr,
109e415196aSJoakim Soderberg 			    "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
110e415196aSJoakim Soderberg 		return (BADCH);
111e415196aSJoakim Soderberg 	}
112e415196aSJoakim Soderberg 	if (*++oli != ':') {			/* don't need argument */
113e415196aSJoakim Soderberg 		optarg = NULL;
114e415196aSJoakim Soderberg 		if (!*place)
115e415196aSJoakim Soderberg 			++optind;
116e415196aSJoakim Soderberg 	} else {				/* need an argument */
117e415196aSJoakim Soderberg 		if (*place)			/* no white space */
118e415196aSJoakim Soderberg 			optarg = place;
119e415196aSJoakim Soderberg 		else if (nargc <= ++optind) {	/* no arg */
120e415196aSJoakim Soderberg 			place = EMSG;
121e415196aSJoakim Soderberg 			if ((opterr) && (*ostr != ':'))
122e415196aSJoakim Soderberg 				(void)fprintf(stderr,
123e415196aSJoakim Soderberg 				    "%s: option requires an argument -- %c\n",
124e415196aSJoakim Soderberg 				    __progname(nargv[0]), optopt);
125e415196aSJoakim Soderberg 			return (BADARG);
126e415196aSJoakim Soderberg 		} else				/* white space */
127e415196aSJoakim Soderberg 			optarg = nargv[optind];
128e415196aSJoakim Soderberg 		place = EMSG;
129e415196aSJoakim Soderberg 		++optind;
130e415196aSJoakim Soderberg 	}
131e415196aSJoakim Soderberg 	return (optopt);			/* dump back option letter */
132e415196aSJoakim Soderberg }
133e415196aSJoakim Soderberg 
134e415196aSJoakim Soderberg #if 0
135e415196aSJoakim Soderberg /*
136e415196aSJoakim Soderberg  * getopt --
137e415196aSJoakim Soderberg  *	Parse argc/argv argument vector.
138e415196aSJoakim Soderberg  */
139e415196aSJoakim Soderberg int
140e415196aSJoakim Soderberg getopt2(nargc, nargv, ostr)
141e415196aSJoakim Soderberg 	int nargc;
142e415196aSJoakim Soderberg 	char * const *nargv;
143e415196aSJoakim Soderberg 	const char *ostr;
144e415196aSJoakim Soderberg {
145e415196aSJoakim Soderberg 	int retval;
146e415196aSJoakim Soderberg 
147e415196aSJoakim Soderberg 	if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
148e415196aSJoakim Soderberg 		retval = -1;
149e415196aSJoakim Soderberg 		++optind;
150e415196aSJoakim Soderberg 	}
151e415196aSJoakim Soderberg 	return(retval);
152e415196aSJoakim Soderberg }
153e415196aSJoakim Soderberg #endif
154e415196aSJoakim Soderberg 
155e415196aSJoakim Soderberg /*
156e415196aSJoakim Soderberg  * getopt_long --
157e415196aSJoakim Soderberg  *	Parse argc/argv argument vector.
158e415196aSJoakim Soderberg  */
159e415196aSJoakim Soderberg int
getopt_long(nargc,nargv,options,long_options,index)160e415196aSJoakim Soderberg getopt_long(nargc, nargv, options, long_options, index)
161e415196aSJoakim Soderberg 	int nargc;
162e415196aSJoakim Soderberg 	char ** nargv;
16357abb359SNick Mathewson 	const char * options;
16457abb359SNick Mathewson 	const struct option * long_options;
165e415196aSJoakim Soderberg 	int * index;
166e415196aSJoakim Soderberg {
167e415196aSJoakim Soderberg 	int retval;
168e415196aSJoakim Soderberg 
169e415196aSJoakim Soderberg 	_DIAGASSERT(nargv != NULL);
170e415196aSJoakim Soderberg 	_DIAGASSERT(options != NULL);
171e415196aSJoakim Soderberg 	_DIAGASSERT(long_options != NULL);
172e415196aSJoakim Soderberg 	/* index may be NULL */
173e415196aSJoakim Soderberg 
174e415196aSJoakim Soderberg 	if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
175e415196aSJoakim Soderberg 		char *current_argv = nargv[optind++] + 2, *has_equal;
176*7c669cc7SAzat Khuzhin 		int i, match = -1;
177*7c669cc7SAzat Khuzhin 		size_t current_argv_len;
178e415196aSJoakim Soderberg 
179e415196aSJoakim Soderberg 		if (*current_argv == '\0') {
180e415196aSJoakim Soderberg 			return(-1);
181e415196aSJoakim Soderberg 		}
182e415196aSJoakim Soderberg 		if ((has_equal = strchr(current_argv, '=')) != NULL) {
183e415196aSJoakim Soderberg 			current_argv_len = has_equal - current_argv;
184e415196aSJoakim Soderberg 			has_equal++;
185e415196aSJoakim Soderberg 		} else
186e415196aSJoakim Soderberg 			current_argv_len = strlen(current_argv);
187e415196aSJoakim Soderberg 
188e415196aSJoakim Soderberg 		for (i = 0; long_options[i].name; i++) {
189e415196aSJoakim Soderberg 			if (strncmp(current_argv, long_options[i].name, current_argv_len))
190e415196aSJoakim Soderberg 				continue;
191e415196aSJoakim Soderberg 
192*7c669cc7SAzat Khuzhin 			if (strlen(long_options[i].name) == current_argv_len) {
193e415196aSJoakim Soderberg 				match = i;
194e415196aSJoakim Soderberg 				break;
195e415196aSJoakim Soderberg 			}
196e415196aSJoakim Soderberg 			if (match == -1)
197e415196aSJoakim Soderberg 				match = i;
198e415196aSJoakim Soderberg 		}
199e415196aSJoakim Soderberg 		if (match != -1) {
200e415196aSJoakim Soderberg 			if (long_options[match].has_arg == required_argument ||
201e415196aSJoakim Soderberg 			    long_options[match].has_arg == optional_argument) {
202e415196aSJoakim Soderberg 				if (has_equal)
203e415196aSJoakim Soderberg 					optarg = has_equal;
204e415196aSJoakim Soderberg 				else
205e415196aSJoakim Soderberg 					optarg = nargv[optind++];
206e415196aSJoakim Soderberg 			}
207e415196aSJoakim Soderberg 			if ((long_options[match].has_arg == required_argument)
208e415196aSJoakim Soderberg 			    && (optarg == NULL)) {
209e415196aSJoakim Soderberg 				/*
210e415196aSJoakim Soderberg 				 * Missing argument, leading :
211e415196aSJoakim Soderberg 				 * indicates no error should be generated
212e415196aSJoakim Soderberg 				 */
213e415196aSJoakim Soderberg 				if ((opterr) && (*options != ':'))
214e415196aSJoakim Soderberg 					(void)fprintf(stderr,
215e415196aSJoakim Soderberg 				      "%s: option requires an argument -- %s\n",
216e415196aSJoakim Soderberg 				      __progname(nargv[0]), current_argv);
217e415196aSJoakim Soderberg 				return (BADARG);
218e415196aSJoakim Soderberg 			}
219e415196aSJoakim Soderberg 		} else { /* No matching argument */
220e415196aSJoakim Soderberg 			if ((opterr) && (*options != ':'))
221e415196aSJoakim Soderberg 				(void)fprintf(stderr,
222e415196aSJoakim Soderberg 				    "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
223e415196aSJoakim Soderberg 			return (BADCH);
224e415196aSJoakim Soderberg 		}
225e415196aSJoakim Soderberg 		if (long_options[match].flag) {
226e415196aSJoakim Soderberg 			*long_options[match].flag = long_options[match].val;
227e415196aSJoakim Soderberg 			retval = 0;
228e415196aSJoakim Soderberg 		} else
229e415196aSJoakim Soderberg 			retval = long_options[match].val;
230e415196aSJoakim Soderberg 		if (index)
231e415196aSJoakim Soderberg 			*index = match;
232e415196aSJoakim Soderberg 	}
233e415196aSJoakim Soderberg 	return(retval);
234e415196aSJoakim Soderberg }
235