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