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