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