source: mainline/uspace/lib/c/generic/getopt.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/* $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt 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/* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */
33
34#include <assert.h>
35#include <stdarg.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <stddef.h>
39#include <errno.h>
40#include <getopt.h>
41#include <str.h>
42
43/* HelenOS Port : We're incorporating only the modern getopt_long with wrappers
44 * to keep legacy getopt() usage from breaking. All references to REPLACE_GETOPT
45 * are dropped, we just include the code */
46
47int opterr = 1; /* if error message should be printed */
48int optind = 1; /* index into parent argv vector */
49int optopt = '?'; /* character checked for validity */
50int optreset; /* reset getopt */
51char *optarg; /* argument associated with option */
52
53
54#define IGNORE_FIRST (*options == '-' || *options == '+')
55#define PRINT_ERROR ((opterr) && ((*options != ':') \
56 || (IGNORE_FIRST && options[1] != ':')))
57/*HelenOS Port - POSIXLY_CORRECT is always false */
58#define IS_POSIXLY_CORRECT 0
59#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
60/* XXX: GNU ignores PC if *options == '-' */
61#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
62
63/* return values */
64#define BADCH (int)'?'
65#define BADARG ((IGNORE_FIRST && options[1] == ':') \
66 || (*options == ':') ? (int)':' : (int)'?')
67#define INORDER (int)1
68
69static char EMSG[] = "";
70
71static int getopt_internal(int, char **, const char *);
72static int gcd(int, int);
73static void permute_args(int, int, int, char **);
74
75static char *place = EMSG; /* option letter processing */
76
77/* XXX: set optreset to 1 rather than these two */
78static int nonopt_start = -1; /* first non option argument (for permute) */
79static int nonopt_end = -1; /* first option after non options (for permute) */
80
81/* Error messages */
82
83/* HelenOS Port: Calls to warnx() were eliminated (as we have no stderr that
84 * may be redirected) and replaced with printf. As such, error messages now
85 * end in a newline */
86
87static const char recargchar[] = "option requires an argument -- %c\n";
88static const char recargstring[] = "option requires an argument -- %s\n";
89static const char ambig[] = "ambiguous option -- %.*s\n";
90static const char noarg[] = "option doesn't take an argument -- %.*s\n";
91static const char illoptchar[] = "unknown option -- %c\n";
92static const char illoptstring[] = "unknown option -- %s\n";
93
94
95/*
96 * Compute the greatest common divisor of a and b.
97 */
98static int gcd(int a, int b)
99{
100 int c;
101
102 c = a % b;
103 while (c != 0) {
104 a = b;
105 b = c;
106 c = a % b;
107 }
108
109 return b;
110}
111
112/*
113 * Exchange the block from nonopt_start to nonopt_end with the block
114 * from nonopt_end to opt_end (keeping the same order of arguments
115 * in each block).
116 */
117static void permute_args(int panonopt_start, int panonopt_end, int opt_end,
118 char **nargv)
119{
120 int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
121 char *swap;
122
123 assert(nargv != NULL);
124
125 /*
126 * compute lengths of blocks and number and size of cycles
127 */
128 nnonopts = panonopt_end - panonopt_start;
129 nopts = opt_end - panonopt_end;
130 ncycle = gcd(nnonopts, nopts);
131 cyclelen = (opt_end - panonopt_start) / ncycle;
132
133 for (i = 0; i < ncycle; i++) {
134 cstart = panonopt_end+i;
135 pos = cstart;
136 for (j = 0; j < cyclelen; j++) {
137 if (pos >= panonopt_end)
138 pos -= nnonopts;
139 else
140 pos += nopts;
141 swap = nargv[pos];
142 nargv[pos] = nargv[cstart];
143 nargv[cstart] = swap;
144 }
145 }
146}
147
148/*
149 * getopt_internal --
150 * Parse argc/argv argument vector. Called by user level routines.
151 * Returns -2 if -- is found (can be long option or end of options marker).
152 */
153static int getopt_internal(int nargc, char **nargv, const char *options)
154{
155 const char *oli; /* option letter list index */
156 int optchar;
157
158 assert(nargv != NULL);
159 assert(options != NULL);
160
161 optarg = NULL;
162
163 /*
164 * XXX Some programs (like rsyncd) expect to be able to
165 * XXX re-initialize optind to 0 and have getopt_long(3)
166 * XXX properly function again. Work around this braindamage.
167 */
168 if (optind == 0)
169 optind = 1;
170
171 if (optreset)
172 nonopt_start = nonopt_end = -1;
173start:
174 if (optreset || !*place) { /* update scanning pointer */
175 optreset = 0;
176 if (optind >= nargc) { /* end of argument vector */
177 place = EMSG;
178 if (nonopt_end != -1) {
179 /* do permutation, if we have to */
180 permute_args(nonopt_start, nonopt_end,
181 optind, nargv);
182 optind -= nonopt_end - nonopt_start;
183 }
184 else if (nonopt_start != -1) {
185 /*
186 * If we skipped non-options, set optind
187 * to the first of them.
188 */
189 optind = nonopt_start;
190 }
191 nonopt_start = nonopt_end = -1;
192 return -1;
193 }
194 if ((*(place = nargv[optind]) != '-')
195 || (place[1] == '\0')) { /* found non-option */
196 place = EMSG;
197 if (IN_ORDER) {
198 /*
199 * GNU extension:
200 * return non-option as argument to option 1
201 */
202 optarg = nargv[optind++];
203 return INORDER;
204 }
205 if (!PERMUTE) {
206 /*
207 * if no permutation wanted, stop parsing
208 * at first non-option
209 */
210 return -1;
211 }
212 /* do permutation */
213 if (nonopt_start == -1)
214 nonopt_start = optind;
215 else if (nonopt_end != -1) {
216 permute_args(nonopt_start, nonopt_end,
217 optind, nargv);
218 nonopt_start = optind -
219 (nonopt_end - nonopt_start);
220 nonopt_end = -1;
221 }
222 optind++;
223 /* process next argument */
224 goto start;
225 }
226 if (nonopt_start != -1 && nonopt_end == -1)
227 nonopt_end = optind;
228 if (place[1] && *++place == '-') { /* found "--" */
229 place++;
230 return -2;
231 }
232 }
233 if ((optchar = (int)*place++) == (int)':' ||
234 (oli = str_chr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
235 /* option letter unknown or ':' */
236 if (!*place)
237 ++optind;
238 if (PRINT_ERROR)
239 printf(illoptchar, optchar);
240 optopt = optchar;
241 return BADCH;
242 }
243 if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
244 /* XXX: what if no long options provided (called by getopt)? */
245 if (*place)
246 return -2;
247
248 if (++optind >= nargc) { /* no arg */
249 place = EMSG;
250 if (PRINT_ERROR)
251 printf(recargchar, optchar);
252 optopt = optchar;
253 return BADARG;
254 } else /* white space */
255 place = nargv[optind];
256 /*
257 * Handle -W arg the same as --arg (which causes getopt to
258 * stop parsing).
259 */
260 return -2;
261 }
262 if (*++oli != ':') { /* doesn't take argument */
263 if (!*place)
264 ++optind;
265 } else { /* takes (optional) argument */
266 optarg = NULL;
267 if (*place) /* no white space */
268 optarg = place;
269 /* XXX: disable test for :: if PC? (GNU doesn't) */
270 else if (oli[1] != ':') { /* arg not optional */
271 if (++optind >= nargc) { /* no arg */
272 place = EMSG;
273 if (PRINT_ERROR)
274 printf(recargchar, optchar);
275 optopt = optchar;
276 return BADARG;
277 } else
278 optarg = nargv[optind];
279 }
280 place = EMSG;
281 ++optind;
282 }
283 /* dump back option letter */
284 return optchar;
285}
286
287/*
288 * getopt --
289 * Parse argc/argv argument vector.
290 */
291int getopt(int nargc, char * const *nargv, const char *options)
292{
293 int retval;
294
295 assert(nargv != NULL);
296 assert(options != NULL);
297
298 retval = getopt_internal(nargc, (char **)nargv, options);
299 if (retval == -2) {
300 ++optind;
301 /*
302 * We found an option (--), so if we skipped non-options,
303 * we have to permute.
304 */
305 if (nonopt_end != -1) {
306 permute_args(nonopt_start, nonopt_end, optind,
307 (char **)nargv);
308 optind -= nonopt_end - nonopt_start;
309 }
310 nonopt_start = nonopt_end = -1;
311 retval = -1;
312 }
313 return retval;
314}
315
316/*
317 * getopt_long --
318 * Parse argc/argv argument vector.
319 */
320int getopt_long(int nargc, char * const *nargv, const char *options,
321 const struct option *long_options, int *idx)
322{
323 int retval;
324
325#define IDENTICAL_INTERPRETATION(_x, _y) \
326 (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
327 long_options[(_x)].flag == long_options[(_y)].flag && \
328 long_options[(_x)].val == long_options[(_y)].val)
329
330 assert(nargv != NULL);
331 assert(options != NULL);
332 assert(long_options != NULL);
333 /* idx may be NULL */
334
335 retval = getopt_internal(nargc, (char **)nargv, options);
336 if (retval == -2) {
337 char *current_argv;
338 char *has_equal;
339 size_t current_argv_len;
340 int i, ambiguous, match;
341
342 current_argv = (char *)place;
343 match = -1;
344 ambiguous = 0;
345
346 optind++;
347 place = EMSG;
348
349 if (*current_argv == '\0') { /* found "--" */
350 /*
351 * We found an option (--), so if we skipped
352 * non-options, we have to permute.
353 */
354 if (nonopt_end != -1) {
355 permute_args(nonopt_start, nonopt_end,
356 optind, (char **)nargv);
357 optind -= nonopt_end - nonopt_start;
358 }
359 nonopt_start = nonopt_end = -1;
360 return -1;
361 }
362 if ((has_equal = str_chr(current_argv, '=')) != NULL) {
363 /* argument found (--option=arg) */
364 current_argv_len = has_equal - current_argv;
365 has_equal++;
366 } else
367 current_argv_len = str_size(current_argv);
368
369 for (i = 0; long_options[i].name; i++) {
370 /* find matching long option */
371 if (str_lcmp(current_argv, long_options[i].name,
372 str_nlength(current_argv, current_argv_len)))
373 continue;
374
375 if (str_size(long_options[i].name) ==
376 (unsigned)current_argv_len) {
377 /* exact match */
378 match = i;
379 ambiguous = 0;
380 break;
381 }
382 if (match == -1) /* partial match */
383 match = i;
384 else if (!IDENTICAL_INTERPRETATION(i, match))
385 ambiguous = 1;
386 }
387 if (ambiguous) {
388 /* ambiguous abbreviation */
389 if (PRINT_ERROR)
390 printf(ambig, (int)current_argv_len,
391 current_argv);
392 optopt = 0;
393 return BADCH;
394 }
395 if (match != -1) { /* option found */
396 if (long_options[match].has_arg == no_argument
397 && has_equal) {
398 if (PRINT_ERROR)
399 printf(noarg, (int)current_argv_len,
400 current_argv);
401 /*
402 * XXX: GNU sets optopt to val regardless of
403 * flag
404 */
405 if (long_options[match].flag == NULL)
406 optopt = long_options[match].val;
407 else
408 optopt = 0;
409 return BADARG;
410 }
411 if (long_options[match].has_arg == required_argument ||
412 long_options[match].has_arg == optional_argument) {
413 if (has_equal)
414 optarg = has_equal;
415 else if (long_options[match].has_arg ==
416 required_argument) {
417 /*
418 * optional argument doesn't use
419 * next nargv
420 */
421 optarg = nargv[optind++];
422 }
423 }
424 if ((long_options[match].has_arg == required_argument)
425 && (optarg == NULL)) {
426 /*
427 * Missing argument; leading ':'
428 * indicates no error should be generated
429 */
430 if (PRINT_ERROR)
431 printf(recargstring, current_argv);
432 /*
433 * XXX: GNU sets optopt to val regardless
434 * of flag
435 */
436 if (long_options[match].flag == NULL)
437 optopt = long_options[match].val;
438 else
439 optopt = 0;
440 --optind;
441 return BADARG;
442 }
443 } else { /* unknown option */
444 if (PRINT_ERROR)
445 printf(illoptstring, current_argv);
446 optopt = 0;
447 return BADCH;
448 }
449 if (long_options[match].flag) {
450 *long_options[match].flag = long_options[match].val;
451 retval = 0;
452 } else
453 retval = long_options[match].val;
454 if (idx)
455 *idx = match;
456 }
457 return retval;
458#undef IDENTICAL_INTERPRETATION
459}
460
Note: See TracBrowser for help on using the repository browser.