1 /* $NetBSD: getopt.c,v 1.1 2009/03/22 22:33:13 joerg Exp $*/
2 /* Modified by David Anderson to work with GNU/Linux and freebsd.
3 Added {} for clarity.
4 Switched to standard dwarfdump formatting.
5 Treatment of : modified so that :: gets dwoptarg NULL
6 if space follows the letter
7 (the dwoptarg is set to null).
8 renamed to make it clear this is a private version.
9 Oct 17 2017: Created dwgetopt_long(). See dwgetopt.h
10 */
11 /*
12 * Copyright (c) 1987, 1993, 1994
13 * The Regents of the University of California. All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40 /* This does not presently handle the option string
41 leading + or leading - features. Such are not used
42 by by libdwarfdump. Nor does it understand the
43 GNU Env var POSIXLY_CORRECT .
44 It does know of the leading ":" in the option string.
45 See BADCH below.
46 */
47
48 #include <stdio.h>
49 #ifdef HAVE_STDLIB_H
50 #include <stdlib.h>
51 #endif /* HAVE_STDLIB_H */
52 #include <string.h> /* For strchr */
53 #include "dwgetopt.h"
54
55 #define STRIP_OFF_CONSTNESS(a) ((void *)(size_t)(const void *)(a))
56
57 int dwopterr = 1, /* if error message should be printed */
58 dwoptind = 1, /* index into parent argv vector */
59 dwoptopt, /* character checked for validity */
60 dwoptreset; /* reset getopt */
61 char *dwoptarg; /* argument associated with option */
62
63 #define BADCH (int)'?'
64 #define BADARG (int)':'
65 #define EMSG ""
66
67 #define TRUE 1
68 #define FALSE 0
69
70 #if 0 /* FOR DEBUGGING ONLY */
71 /* Use for testing dwgetopt only.
72 Not a standard function. */
73 void
74 dwgetoptresetfortestingonly(void)
75 {
76 dwopterr = 1;
77 dwoptind = 1;
78 dwoptopt = 0;
79 dwoptreset = 0;
80 dwoptarg = 0;
81 }
82 #endif /* FOR DEBUGGING ONLY */
83
84
85 static const char *place = EMSG;/* option letter processing */
86
87
88 /* Post Condition:
89 if return FALSE then *argerr is set false. */
90 static int
dwoptnamematches(const struct dwoption * dwlopt,const char * iplace,const char ** argloc,int * argerr)91 dwoptnamematches(
92 const struct dwoption *dwlopt,
93 const char *iplace,
94 const char **argloc,
95 int *argerr)
96 {
97
98 const char *eq = 0;
99 size_t namelen = 0;
100 size_t arglen = 0;
101 int d = 0;
102
103 for(eq = iplace; *eq; ++eq) {
104 if (*eq != '=') {
105 continue;
106 }
107 /* Found =, arg should follow */
108 namelen = (eq - iplace);
109 if (namelen != (unsigned)strlen(dwlopt->name)) {
110 return FALSE;
111 }
112 eq++;
113 arglen = strlen(eq);
114 break;
115 }
116 if (namelen) {
117 d = strncmp(iplace,dwlopt->name,namelen);
118 if (d) {
119 return FALSE;
120 }
121 if (dwlopt->has_arg == 0) {
122 *argerr = TRUE;
123 return TRUE;
124 }
125 if (arglen) {
126 /* Discarding const, avoiding warning.
127 Data is in user space, so this is ok. */
128 dwoptarg = (char *)eq;
129 *argloc = (const char *)eq;
130 } else {
131 /* Has arg = but arg is empty. */
132 dwoptarg = 0;
133 }
134 return TRUE;
135 } else {
136 d = strcmp(iplace,dwlopt->name);
137 if (d) {
138 return FALSE;
139 }
140 if (dwlopt->has_arg == 1) {
141 *argerr = TRUE;
142 return TRUE;
143 }
144 dwoptarg = 0;
145 return TRUE;
146 }
147 }
148
149
150
151 /* dwgetopt_long
152 A reimplemenation of a portion of
153 the getopt(3) GNU/Linux getopt_long().
154 See dwgetopt.h for more details.
155 */
dwgetopt_long(int nargc,char * const nargv[],const char * ostr,const struct dwoption * longopts,int * longindex)156 int dwgetopt_long(int nargc, char *const nargv[],
157 const char *ostr,
158 const struct dwoption* longopts,
159 int *longindex)
160 {
161 char *lplace = 0;
162 if (dwoptreset) {
163 /* Not really supported. */
164 place = EMSG;
165 return (-1);
166 }
167 if (*place) {
168 int v = dwgetopt(nargc,nargv,ostr);
169 return v;
170 }
171 /* Use local lplace in case we need to call getopt()
172 just below. */
173 lplace = nargv[dwoptind];
174 if (dwoptind >= nargc || *lplace++ != '-') {
175 /* Argument is absent or is not an option */
176 place = EMSG;
177 return (-1);
178 }
179 if (*lplace != '-') {
180 /* Notice place not disturbed. */
181 int v = dwgetopt(nargc,nargv,ostr);
182 return v;
183 }
184 /* Starts with two dashes.
185 Now we set the global place */
186 place = lplace+1;
187 if (!*place) {
188 /* "--" => end of options */
189 ++dwoptind;
190 place = EMSG;
191 return (-1);
192 }
193
194 /* We think this is a longopt. */
195 {
196 int lo_num = 0;
197
198 for(;;lo_num++) {
199 const struct dwoption *dwlopt = longopts +lo_num;
200 const char * argloc = 0;
201 int argerr = 0;
202 int resmatch = 0;
203
204 if (!dwlopt->name) {
205 dwoptind++;
206 (void)fprintf(stderr,
207 "%s: invalid long option '--%s'\n",
208 nargv[0]?nargv[0]:"",
209 place);
210 /* Leave longindex unchanged. */
211 place = EMSG;
212 return (BADCH);
213 }
214 resmatch= dwoptnamematches(dwlopt,place,
215 &argloc,&argerr);
216 if (resmatch) {
217 dwoptarg = 0;
218 if (argloc) {
219 /* Must drop const here. Ugh. */
220 dwoptarg = (char *)argloc;
221 }
222 }
223 if (argerr) {
224 /* resmatch == TRUE
225
226 arg option missing if required, present
227 but not allowed.
228 GNU Behavior not well documented.
229 Had to experiment.
230
231 if argument-not-allowed, and we have one,
232 do ???
233
234 If argument-required,
235 then here GNU
236 would take the next argv as the argument.
237 we are not currently doing that. */
238 /**longindex = lo_num; */
239 if (dwlopt->has_arg) {
240 /* Missing required arg, this does not
241 match GNU getopt_long behavior
242 of taking next argv as the arg value.
243 and thus making getopt_long succeed. */
244 (void)fprintf(stderr,
245 "%s: missing required long option argument '--%s'\n",
246 nargv[0]?nargv[0]:"",
247 place);
248 } else {
249 /* has arg but should not */
250 (void)fprintf(stderr,
251 "%s: option '--%s' does not allow an argument\n",
252 nargv[0]?nargv[0]:"",
253 dwlopt->name);
254 }
255 dwoptind++;
256 place = EMSG;
257 return (BADCH);
258 }
259 if (resmatch) {
260 *longindex = lo_num;
261 place = EMSG;
262 dwoptind++;
263 return dwlopt->val;
264 }
265 }
266 /* Can never get here */
267 place = EMSG;
268 dwoptind++;
269 return (-1);
270 }
271 }
272
273 /*
274 * getopt --
275 * Parse argc/argv argument vector.
276 * a: means
277 * -afoo
278 * -a foo
279 * and 'foo' is returned in dwoptarg
280 * b:: means
281 * -b
282 * and dwoptarg is null
283 * -bother
284 * and dwoptarg is 'other'
285 */
286 int
dwgetopt(int nargc,char * const nargv[],const char * ostr)287 dwgetopt(int nargc, char * const nargv[], const char *ostr)
288 {
289 char *oli; /* option letter list index */
290
291 if (dwoptreset || *place == 0) { /* update scanning pointer */
292 dwoptreset = 0;
293 place = nargv[dwoptind];
294
295 if (dwoptind >= nargc || *place++ != '-') {
296 /* Argument is absent or is not an option */
297 place = EMSG;
298 return (-1);
299 }
300 dwoptopt = *place++;
301 if (dwoptopt == '-' && *place == 0) {
302 /* "--" => end of options */
303 ++dwoptind;
304 place = EMSG;
305 return (-1);
306 }
307 if (dwoptopt == 0) {
308 /* Solitary '-', treat as a '-' option
309 if the program (eg su) is looking for it. */
310 place = EMSG;
311 if (strchr(ostr, '-') == NULL) {
312 return -1;
313 }
314 dwoptopt = '-';
315 }
316 } else {
317 dwoptopt = *place++;
318 }
319 /* See if option letter is one the caller wanted... */
320 if (dwoptopt == ':' || (oli = strchr(ostr, dwoptopt)) == NULL) {
321 if (*place == 0) {
322 ++dwoptind;
323 }
324 if (dwopterr && *ostr != ':') {
325 (void)fprintf(stderr,
326 "%s: invalid option -- '%c'\n",
327 nargv[0]?nargv[0]:"",
328 dwoptopt);
329 }
330 return (BADCH);
331 }
332
333 /* Does this option need an argument? */
334 if (oli[1] != ':') {
335 /* don't need argument */
336 dwoptarg = NULL;
337 if (*place == 0) {
338 ++dwoptind;
339 }
340 } else {
341 int reqnextarg = 1;
342 if (oli[1] && (oli[2] == ':')) {
343 /* Pair of :: means special treatment of dwoptarg */
344 reqnextarg = 0;
345 }
346 /* Option-argument is either the rest of this argument or the
347 entire next argument. */
348 if (*place ) {
349 /* Whether : or :: */
350 dwoptarg = STRIP_OFF_CONSTNESS(place);
351 } else if (reqnextarg) {
352 /* ! *place */
353 if (nargc > (++dwoptind)) {
354 dwoptarg = nargv[dwoptind];
355 } else {
356 place=EMSG;
357 /* Next arg required, but is missing */
358 if (*ostr == ':') {
359 /* Leading : in ostr calls for BADARG return. */
360 return (BADARG);
361 }
362 if (dwopterr) {
363 (void)fprintf(stderr,
364 "%s: option requires an argument. -- '%c'\n",
365 nargv[0]?nargv[0]:"",
366 dwoptopt);
367 }
368 return (BADCH);
369 }
370 } else {
371 /* ! *place */
372 /* The key part of :: treatment. */
373 dwoptarg = NULL;
374 }
375 place = EMSG;
376 ++dwoptind;
377 }
378 return (dwoptopt); /* return option letter */
379 }
380