1 /* $Id: getopt.c 15794 2009-03-18 09:10:28Z moritz $ */
2 /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
3 /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
4
5 /*
6 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *
20 * Sponsored in part by the Defense Advanced Research Projects
21 * Agency (DARPA) and Air Force Research Laboratory, Air Force
22 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
23 */
24 /*-
25 * Copyright (c) 2000 The NetBSD Foundation, Inc.
26 * All rights reserved.
27 *
28 * This code is derived from software contributed to The NetBSD Foundation
29 * by Dieter Baron and Thomas Klausner.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
41 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
44 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
50 * POSSIBILITY OF SUCH DAMAGE.
51 */
52
53 #ifdef HAVE_CONFIG_H
54 # include "config.h"
55 #endif /* HAVE_CONFIG_H */
56
57 #include "ezstream.h"
58
59 int local_getopt(int, char * const *, const char *);
60
61 #ifndef HAVE_GETOPT
62
63 int opterr = 1; /* if error message should be printed */
64 int optind = 1; /* index into parent argv vector */
65 int optopt = '?'; /* character checked for validity */
66 int optreset; /* reset getopt */
67 char *optarg; /* argument associated with option */
68
69 #define PRINT_ERROR ((opterr) && (*options != ':'))
70
71 #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
72 #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
73 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
74
75 /* return values */
76 #define BADCH (int)'?'
77 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
78 #define INORDER (int)1
79
80 #define EMSG ""
81
82 static int getopt_internal(int, char * const *, const char *, int);
83 static int gcd(int, int);
84 static void permute_args(int, int, int, char * const *);
85
86 static char *place = EMSG; /* option letter processing */
87
88 /* XXX: set optreset to 1 rather than these two */
89 static int nonopt_start = -1; /* first non option argument (for permute) */
90 static int nonopt_end = -1; /* first option after non options (for permute) */
91
92 /* Error messages */
93 static const char recargchar[] = "option requires an argument -- %c\n";
94 static const char illoptchar[] = "unknown option -- %c\n";
95
96 /*
97 * Compute the greatest common divisor of a and b.
98 */
99 static int
gcd(int a,int b)100 gcd(int a, int b)
101 {
102 int c;
103
104 c = a % b;
105 while (c != 0) {
106 a = b;
107 b = c;
108 c = a % b;
109 }
110
111 return (b);
112 }
113
114 /*
115 * Exchange the block from nonopt_start to nonopt_end with the block
116 * from nonopt_end to opt_end (keeping the same order of arguments
117 * in each block).
118 */
119 static void
permute_args(int panonopt_start,int panonopt_end,int opt_end,char * const * nargv)120 permute_args(int panonopt_start, int panonopt_end, int opt_end,
121 char * const *nargv)
122 {
123 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
124 char *swap;
125
126 /*
127 * compute lengths of blocks and number and size of cycles
128 */
129 nnonopts = panonopt_end - panonopt_start;
130 nopts = opt_end - panonopt_end;
131 ncycle = gcd(nnonopts, nopts);
132 cyclelen = (opt_end - panonopt_start) / ncycle;
133
134 for (i = 0; i < ncycle; i++) {
135 cstart = panonopt_end+i;
136 pos = cstart;
137 for (j = 0; j < cyclelen; j++) {
138 if (pos >= panonopt_end)
139 pos -= nnonopts;
140 else
141 pos += nopts;
142 swap = nargv[pos];
143 /* LINTED const cast */
144 ((char **) nargv)[pos] = nargv[cstart];
145 /* LINTED const cast */
146 ((char **)nargv)[cstart] = swap;
147 }
148 }
149 }
150
151 /*
152 * getopt_internal --
153 * Parse argc/argv argument vector. Called by user level routines.
154 */
155 static int
getopt_internal(int nargc,char * const * nargv,const char * options,int flags)156 getopt_internal(int nargc, char * const *nargv, const char *options, int flags)
157 {
158 char *oli; /* option letter list index */
159 int optchar;
160 static int posixly_correct = -1;
161
162 if (options == NULL)
163 return (-1);
164
165 /*
166 * Disable GNU extensions if POSIXLY_CORRECT is set or options
167 * string begins with a '+'.
168 */
169 if (posixly_correct == -1)
170 posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
171 if (posixly_correct || *options == '+')
172 flags &= ~FLAG_PERMUTE;
173 else if (*options == '-')
174 flags |= FLAG_ALLARGS;
175 if (*options == '+' || *options == '-')
176 options++;
177
178 /*
179 * XXX Some GNU programs (like cvs) set optind to 0 instead of
180 * XXX using optreset. Work around this braindamage.
181 */
182 if (optind == 0)
183 optind = optreset = 1;
184
185 optarg = NULL;
186 if (optreset)
187 nonopt_start = nonopt_end = -1;
188 start:
189 if (optreset || !*place) { /* update scanning pointer */
190 optreset = 0;
191 if (optind >= nargc) { /* end of argument vector */
192 place = EMSG;
193 if (nonopt_end != -1) {
194 /* do permutation, if we have to */
195 permute_args(nonopt_start, nonopt_end,
196 optind, nargv);
197 optind -= nonopt_end - nonopt_start;
198 }
199 else if (nonopt_start != -1) {
200 /*
201 * If we skipped non-options, set optind
202 * to the first of them.
203 */
204 optind = nonopt_start;
205 }
206 nonopt_start = nonopt_end = -1;
207 return (-1);
208 }
209 if (*(place = nargv[optind]) != '-' ||
210 (place[1] == '\0' && strchr(options, '-') == NULL)) {
211 place = EMSG; /* found non-option */
212 if (flags & FLAG_ALLARGS) {
213 /*
214 * GNU extension:
215 * return non-option as argument to option 1
216 */
217 optarg = nargv[optind++];
218 return (INORDER);
219 }
220 if (!(flags & FLAG_PERMUTE)) {
221 /*
222 * If no permutation wanted, stop parsing
223 * at first non-option.
224 */
225 return (-1);
226 }
227 /* do permutation */
228 if (nonopt_start == -1)
229 nonopt_start = optind;
230 else if (nonopt_end != -1) {
231 permute_args(nonopt_start, nonopt_end,
232 optind, nargv);
233 nonopt_start = optind -
234 (nonopt_end - nonopt_start);
235 nonopt_end = -1;
236 }
237 optind++;
238 /* process next argument */
239 goto start;
240 }
241 if (nonopt_start != -1 && nonopt_end == -1)
242 nonopt_end = optind;
243
244 /*
245 * If we have "-" do nothing, if "--" we are done.
246 */
247 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
248 optind++;
249 place = EMSG;
250 /*
251 * We found an option (--), so if we skipped
252 * non-options, we have to permute.
253 */
254 if (nonopt_end != -1) {
255 permute_args(nonopt_start, nonopt_end,
256 optind, nargv);
257 optind -= nonopt_end - nonopt_start;
258 }
259 nonopt_start = nonopt_end = -1;
260 return (-1);
261 }
262 }
263
264 if ((optchar = (int)*place++) == (int)':' ||
265 (optchar == (int)'-' && *place != '\0') ||
266 (oli = strchr(options, optchar)) == NULL) {
267 /*
268 * If the user specified "-" and '-' isn't listed in
269 * options, return -1 (non-option) as per POSIX.
270 * Otherwise, it is an unknown option character (or ':').
271 */
272 if (optchar == (int)'-' && *place == '\0')
273 return (-1);
274 if (!*place)
275 ++optind;
276 if (PRINT_ERROR)
277 fprintf(stderr, illoptchar, optchar);
278 optopt = optchar;
279 return (BADCH);
280 }
281 if (*++oli != ':') { /* doesn't take argument */
282 if (!*place)
283 ++optind;
284 } else { /* takes (optional) argument */
285 optarg = NULL;
286 if (*place) /* no white space */
287 optarg = place;
288 else if (oli[1] != ':') { /* arg not optional */
289 if (++optind >= nargc) { /* no arg */
290 place = EMSG;
291 if (PRINT_ERROR)
292 fprintf(stderr, recargchar, optchar);
293 optopt = optchar;
294 return (BADARG);
295 } else
296 optarg = nargv[optind];
297 }
298 place = EMSG;
299 ++optind;
300 }
301 /* dump back option letter */
302 return (optchar);
303 }
304
305 #endif /* !HAVE_GETOPT */
306
307 /*
308 * getopt --
309 * Parse argc/argv argument vector.
310 *
311 * [eventually this will replace the BSD getopt]
312 */
313 int
local_getopt(int nargc,char * const * nargv,const char * options)314 local_getopt(int nargc, char * const *nargv, const char *options)
315 {
316 #ifdef HAVE_GETOPT
317 return (getopt(nargc, nargv, options));
318 #else /* HAVE_GETOPT */
319
320 /*
321 * We don't pass FLAG_PERMUTE to getopt_internal() since
322 * the BSD getopt(3) (unlike GNU) has never done this.
323 *
324 * Furthermore, since many privileged programs call getopt()
325 * before dropping privileges it makes sense to keep things
326 * as simple (and bug-free) as possible.
327 */
328 return (getopt_internal(nargc, nargv, options, 0));
329 #endif /* HAVE_GETOPT */
330 }
331