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