"Fossies" - the Fresh Open Source Software Archive 
Member "scponly-20110526/netbsd_getopt_long.c" (20 Nov 2010, 10885 Bytes) of package /linux/privat/old/scponly-20110526.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* $NetBSD: getopt_long.c,v 1.11 2009/04/14 17:34:41 joerg Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Dieter Baron and Thomas Klausner.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE 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
32 #include "scponly_getopt.h"
33
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39
40 #undef __UNCONST
41 #define __UNCONST(a) ((void *)(size_t)(const void *)(a))
42
43 #define IGNORE_FIRST (*options == '-' || *options == '+')
44 #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
45 #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
46 /* XXX: GNU ignores PC if *options == '-' */
47 #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
48
49 /* return values */
50 #define BADCH (int)'?'
51 #define BADARG ((IGNORE_FIRST && options[1] == ':') \
52 || (*options == ':') ? (int)':' : (int)'?')
53 #define INORDER (int)1
54
55 #define EMSG ""
56
57 #ifndef _DIAGASSERT
58 #define _DIAGASSERT(X)
59 #endif
60
61 int optreset; /* reset getopt */
62
63 static int netbsd_getopt_internal(int, char **, const char *);
64 static int gcd(int, int);
65 static void permute_args(int, int, int, char **);
66
67 static const char *place = EMSG; /* option letter processing */
68
69 /* XXX: set optreset to 1 rather than these two */
70 static int nonopt_start = -1; /* first non option argument (for permute) */
71 static int nonopt_end = -1; /* first option after non options (for permute) */
72
73 /* Error messages */
74 static const char recargchar[] = "option requires an argument -- %c";
75 static const char recargstring[] = "option requires an argument -- %s";
76 static const char ambig[] = "ambiguous option -- %.*s";
77 static const char noarg[] = "option doesn't take an argument -- %.*s";
78 static const char illoptchar[] = "unknown option -- %c";
79 static const char illoptstring[] = "unknown option -- %s";
80
81 char opterrmsg[128];
82
83 /*
84 * Compute the greatest common divisor of a and b.
85 */
86 static int
87 gcd(int a, int b)
88 {
89 int c;
90
91 c = a % b;
92 while (c != 0) {
93 a = b;
94 b = c;
95 c = a % b;
96 }
97
98 return b;
99 }
100
101 /*
102 * Exchange the block from nonopt_start to nonopt_end with the block
103 * from nonopt_end to opt_end (keeping the same order of arguments
104 * in each block).
105 */
106 static void
107 permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv)
108 {
109 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
110 char *swap;
111
112 _DIAGASSERT(nargv != NULL);
113
114 /*
115 * compute lengths of blocks and number and size of cycles
116 */
117 nnonopts = panonopt_end - panonopt_start;
118 nopts = opt_end - panonopt_end;
119 ncycle = gcd(nnonopts, nopts);
120 cyclelen = (opt_end - panonopt_start) / ncycle;
121
122 for (i = 0; i < ncycle; i++) {
123 cstart = panonopt_end+i;
124 pos = cstart;
125 for (j = 0; j < cyclelen; j++) {
126 if (pos >= panonopt_end)
127 pos -= nnonopts;
128 else
129 pos += nopts;
130 swap = nargv[pos];
131 nargv[pos] = nargv[cstart];
132 nargv[cstart] = swap;
133 }
134 }
135 }
136
137 /*
138 * netbsd_getopt_internal --
139 * Parse argc/argv argument vector. Called by user level routines.
140 * Returns -2 if -- is found (can be long option or end of options marker).
141 */
142 static int
143 netbsd_getopt_internal(int nargc, char **nargv, const char *options)
144 {
145 char *oli; /* option letter list index */
146 int optchar;
147
148 _DIAGASSERT(nargv != NULL);
149 _DIAGASSERT(options != NULL);
150
151 optarg = NULL;
152
153 /*
154 * XXX Some programs (like rsyncd) expect to be able to
155 * XXX re-initialize optind to 0 and have getopt_long(3)
156 * XXX properly function again. Work around this braindamage.
157 */
158 if (optind == 0)
159 optind = 1;
160
161 if (optreset)
162 nonopt_start = nonopt_end = -1;
163 start:
164 if (optreset || !*place) { /* update scanning pointer */
165 optreset = 0;
166 if (optind >= nargc) { /* end of argument vector */
167 place = EMSG;
168 if (nonopt_end != -1) {
169 /* do permutation, if we have to */
170 permute_args(nonopt_start, nonopt_end,
171 optind, nargv);
172 optind -= nonopt_end - nonopt_start;
173 }
174 else if (nonopt_start != -1) {
175 /*
176 * If we skipped non-options, set optind
177 * to the first of them.
178 */
179 optind = nonopt_start;
180 }
181 nonopt_start = nonopt_end = -1;
182 return -1;
183 }
184 if ((*(place = nargv[optind]) != '-')
185 || (place[1] == '\0')) { /* found non-option */
186 place = EMSG;
187 if (IN_ORDER) {
188 /*
189 * GNU extension:
190 * return non-option as argument to option 1
191 */
192 optarg = nargv[optind++];
193 return INORDER;
194 }
195 if (!PERMUTE) {
196 /*
197 * if no permutation wanted, stop parsing
198 * at first non-option
199 */
200 return -1;
201 }
202 /* do permutation */
203 if (nonopt_start == -1)
204 nonopt_start = optind;
205 else if (nonopt_end != -1) {
206 permute_args(nonopt_start, nonopt_end,
207 optind, nargv);
208 nonopt_start = optind -
209 (nonopt_end - nonopt_start);
210 nonopt_end = -1;
211 }
212 optind++;
213 /* process next argument */
214 goto start;
215 }
216 if (nonopt_start != -1 && nonopt_end == -1)
217 nonopt_end = optind;
218 if (place[1] && *++place == '-') { /* found "--" */
219 place++;
220 return -2;
221 }
222 }
223 if ((optchar = (int)*place++) == (int)':' ||
224 (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
225 /* option letter unknown or ':' */
226 if (!*place)
227 ++optind;
228 optopt = optchar;
229 return BADCH;
230 }
231 if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
232 /* XXX: what if no long options provided (called by getopt)? */
233 if (*place)
234 return -2;
235
236 if (++optind >= nargc) { /* no arg */
237 place = EMSG;
238 optopt = optchar;
239 return BADARG;
240 } else /* white space */
241 place = nargv[optind];
242 /*
243 * Handle -W arg the same as --arg (which causes getopt to
244 * stop parsing).
245 */
246 return -2;
247 }
248 if (*++oli != ':') { /* doesn't take argument */
249 if (!*place)
250 ++optind;
251 } else { /* takes (optional) argument */
252 optarg = NULL;
253 if (*place) /* no white space */
254 optarg = __UNCONST(place);
255 /* XXX: disable test for :: if PC? (GNU doesn't) */
256 else if (oli[1] != ':') { /* arg not optional */
257 if (++optind >= nargc) { /* no arg */
258 place = EMSG;
259 optopt = optchar;
260 return BADARG;
261 } else
262 optarg = nargv[optind];
263 }
264 place = EMSG;
265 ++optind;
266 }
267 /* dump back option letter */
268 return optchar;
269 }
270
271
272 /*
273 * getopt_long --
274 * Parse argc/argv argument vector.
275 */
276 int
277 netbsd_getopt_long(int nargc, char * const *nargv, const char *options,
278 const struct option *long_options, int *idx)
279 {
280 int retval;
281
282 #define IDENTICAL_INTERPRETATION(_x, _y) \
283 (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
284 long_options[(_x)].flag == long_options[(_y)].flag && \
285 long_options[(_x)].val == long_options[(_y)].val)
286
287 if (nargv == NULL || options == NULL || long_options == NULL)
288 {
289 printf("getopt_long assertions failed!");
290 exit(42);
291 }
292
293 /* idx may be NULL */
294
295 retval = netbsd_getopt_internal(nargc, __UNCONST(nargv), options);
296 if (retval == -2) {
297 char *current_argv, *has_equal;
298 size_t current_argv_len;
299 int i, ambiguous, match;
300
301 current_argv = __UNCONST(place);
302 match = -1;
303 ambiguous = 0;
304
305 optind++;
306 place = EMSG;
307
308 if (*current_argv == '\0') { /* found "--" */
309 /*
310 * We found an option (--), so if we skipped
311 * non-options, we have to permute.
312 */
313 if (nonopt_end != -1) {
314 permute_args(nonopt_start, nonopt_end,
315 optind, __UNCONST(nargv));
316 optind -= nonopt_end - nonopt_start;
317 }
318 nonopt_start = nonopt_end = -1;
319 return -1;
320 }
321 if ((has_equal = strchr(current_argv, '=')) != NULL) {
322 /* argument found (--option=arg) */
323 current_argv_len = has_equal - current_argv;
324 has_equal++;
325 } else
326 current_argv_len = strlen(current_argv);
327
328 for (i = 0; long_options[i].name; i++) {
329 /* find matching long option */
330 if (strncmp(current_argv, long_options[i].name,
331 current_argv_len))
332 continue;
333
334 if (strlen(long_options[i].name) ==
335 (unsigned)current_argv_len) {
336 /* exact match */
337 match = i;
338 ambiguous = 0;
339 break;
340 }
341 if (match == -1) /* partial match */
342 match = i;
343 else if (!IDENTICAL_INTERPRETATION(i, match))
344 ambiguous = 1;
345 }
346 if (ambiguous) {
347 /* ambiguous abbreviation */
348 optopt = 0;
349 return BADCH;
350 }
351 if (match != -1) { /* option found */
352 if (long_options[match].has_arg == no_argument
353 && has_equal) {
354 /*
355 * XXX: GNU sets optopt to val regardless of
356 * flag
357 */
358 if (long_options[match].flag == NULL)
359 optopt = long_options[match].val;
360 else
361 optopt = 0;
362 return BADARG;
363 }
364 if (long_options[match].has_arg == required_argument ||
365 long_options[match].has_arg == optional_argument) {
366 if (has_equal)
367 optarg = has_equal;
368 else if (long_options[match].has_arg ==
369 required_argument) {
370 /*
371 * optional argument doesn't use
372 * next nargv
373 */
374 optarg = nargv[optind++];
375 }
376 }
377 if ((long_options[match].has_arg == required_argument)
378 && (optarg == NULL)) {
379 /*
380 * Missing argument; leading ':'
381 * indicates no error should be generated
382 */
383 /*
384 * XXX: GNU sets optopt to val regardless
385 * of flag
386 */
387 if (long_options[match].flag == NULL)
388 optopt = long_options[match].val;
389 else
390 optopt = 0;
391 --optind;
392 return BADARG;
393 }
394 } else { /* unknown option */
395 optopt = 0;
396 return BADCH;
397 }
398 if (long_options[match].flag) {
399 *long_options[match].flag = long_options[match].val;
400 retval = 0;
401 } else
402 retval = long_options[match].val;
403 if (idx)
404 *idx = match;
405 }
406 return retval;
407 #undef IDENTICAL_INTERPRETATION
408 }
409