OpenVPN 3 Core Library
Loading...
Searching...
No Matches
getopt.hpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-4-Clause-UC */
2/* Source: pkg:generic/netbsd?download_url=http%3A%2F%2Fcvsweb.netbsd.org%2Fbsdweb.cgi%2F~checkout~%2Fsrc%2Flib%2Flibc%2Fstdlib%2Fgetopt_long.c%3Frev%3D1.1#src/lib/libc/stdlib/getopt_long.c */
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 name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef OPENVPN_COMMON_GETOPT_H
33#define OPENVPN_COMMON_GETOPT_H
34
38
39#if !defined(OPENVPN_PLATFORM_WIN)
40#include <getopt.h>
41#else
42
43#include <cstring> // for std::strlen, std::strchr, std::strncmp
44
45#define GETOPT_BADCH (int)'?'
46#define GETOPT_BADARG (int)':'
47#define GETOPT_EMSG ""
48
49namespace openvpn {
50
51OPENVPN_SIMPLE_EXCEPTION(getopt_assert);
52OPENVPN_EXCEPTION(getopt_exception);
53
54int opterr = 1; /* if error message should be printed */
55int optind = 1; /* index into parent argv vector */
56int optopt = 0; /* character checked for validity */
57int optreset = 0; /* reset getopt */
58const char *optarg = nullptr; /* argument associated with option */
59
60struct option
61{
62 const char *name;
63 int has_arg;
64 int *flag;
65 int val;
66};
67
68enum
69{
70 no_argument = 0,
71 required_argument = 1,
72 optional_argument = 2
73};
74
75namespace getopt_private {
76inline void error(const char *prefix, int arg)
77{
78 std::string err = prefix;
79 err += " -- ";
80 err += (char)arg;
81 throw getopt_exception(err);
82}
83
84inline void error(const char *prefix, const char *arg)
85{
86 std::string err = prefix;
87 err += " -- ";
88 err += arg;
89 throw getopt_exception(err);
90}
91
92/*
93 * getopt --
94 * Parse argc/argv argument vector.
95 */
96inline int getopt_internal(int nargc, char *const *nargv, const char *ostr)
97{
98 static const char *place = GETOPT_EMSG; /* option letter processing */
99 const char *oli; /* option letter list index */
100
101 if (!nargv || !ostr)
102 throw getopt_assert();
103
104 if (optreset || !*place)
105 { /* update scanning pointer */
106 optreset = 0;
107 if (optind >= nargc || *(place = nargv[optind]) != '-')
108 {
109 place = GETOPT_EMSG;
110 return (-1);
111 }
112 if (place[1] && *++place == '-')
113 { /* found "--" */
114 /* ++optind; */
115 place = GETOPT_EMSG;
116 return (-2);
117 }
118 } /* option letter okay? */
119 if ((optopt = (int)*place++) == (int)':' || !(oli = std::strchr(ostr, optopt)))
120 {
121 /*
122 * if the user didn't specify '-' as an option,
123 * assume it means -1.
124 */
125 if (optopt == (int)'-')
126 return (-1);
127 if (!*place)
128 ++optind;
129 if (opterr && *ostr != ':')
130 getopt_private::error("illegal option", optopt);
131 return (GETOPT_BADCH);
132 }
133 if (*++oli != ':')
134 { /* don't need argument */
135 optarg = nullptr;
136 if (!*place)
137 ++optind;
138 }
139 else
140 { /* need an argument */
141 if (*place) /* no white space */
142 optarg = place;
143 else if (nargc <= ++optind)
144 { /* no arg */
145 place = GETOPT_EMSG;
146 if ((opterr) && (*ostr != ':'))
147 getopt_private::error("option requires an argument", optopt);
148 return (GETOPT_BADARG);
149 }
150 else /* white space */
151 optarg = nargv[optind];
152 place = GETOPT_EMSG;
153 ++optind;
154 }
155 return (optopt); /* dump back option letter */
156}
157} // namespace getopt_private
158
159/*
160 * getopt_long --
161 * Parse argc/argv argument vector.
162 */
163inline int getopt_long(int nargc,
164 char *const *nargv,
165 const char *options,
166 const struct option *long_options,
167 int *index)
168{
169 int retval;
170
171 if (!nargv || !options || !long_options)
172 throw getopt_assert();
173
174 if ((retval = getopt_private::getopt_internal(nargc, nargv, options)) == -2)
175 {
176 char *current_argv = nargv[optind++] + 2;
177 char *has_equal;
178 int i;
179 size_t current_argv_len;
180 int match = -1;
181
182 if (*current_argv == '\0')
183 return (-1);
184 if ((has_equal = std::strchr(current_argv, '=')) != nullptr)
185 {
186 current_argv_len = has_equal - current_argv;
187 has_equal++;
188 }
189 else
190 current_argv_len = std::strlen(current_argv);
191
192 for (i = 0; long_options[i].name; i++)
193 {
194 if (std::strncmp(current_argv, long_options[i].name, current_argv_len))
195 continue;
196
197 if (std::strlen(long_options[i].name) == (unsigned)current_argv_len)
198 {
199 match = i;
200 break;
201 }
202 if (match == -1)
203 match = i;
204 }
205 if (match != -1)
206 {
207 if (long_options[match].has_arg == required_argument
208 || long_options[match].has_arg == optional_argument)
209 {
210 if (has_equal)
211 optarg = has_equal;
212 else
213 optarg = nargv[optind++];
214 }
215 if ((long_options[match].has_arg == required_argument)
216 && (optarg == nullptr))
217 {
218 /*
219 * Missing argument, leading :
220 * indicates no error should be generated
221 */
222 if ((opterr) && (*options != ':'))
223 getopt_private::error("option requires an argument", current_argv);
224 return (GETOPT_BADARG);
225 }
226 }
227 else
228 { /* No matching argument */
229 if ((opterr) && (*options != ':'))
230 getopt_private::error("illegal option", current_argv);
231 return (GETOPT_BADCH);
232 }
233 if (long_options[match].flag)
234 {
235 *long_options[match].flag = long_options[match].val;
236 retval = 0;
237 }
238 else
239 retval = long_options[match].val;
240 if (index)
241 *index = match;
242 }
243 return (retval);
244}
245
246} // namespace openvpn
247#endif
248#endif
#define OPENVPN_SIMPLE_EXCEPTION(C)
Definition exception.hpp:75
#define OPENVPN_EXCEPTION(C)
Error error(CFStringRef domain, CFIndex code, CFDictionaryRef userInfo)
Definition cf.hpp:325
const char * name(const KeyDerivation kd)