~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to system/lib/libc/stdlib/getopt_long.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $       */
 
2
/*      $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $      */
 
3
 
 
4
/*
 
5
 * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
 
6
 *
 
7
 * Permission to use, copy, modify, and distribute this software for any
 
8
 * purpose with or without fee is hereby granted, provided that the above
 
9
 * copyright notice and this permission notice appear in all copies.
 
10
 *
 
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
18
 *
 
19
 * Sponsored in part by the Defense Advanced Research Projects
 
20
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
 
21
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
22
 */
 
23
/*-
 
24
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 
25
 * All rights reserved.
 
26
 *
 
27
 * This code is derived from software contributed to The NetBSD Foundation
 
28
 * by Dieter Baron and Thomas Klausner.
 
29
 *
 
30
 * Redistribution and use in source and binary forms, with or without
 
31
 * modification, are permitted provided that the following conditions
 
32
 * are met:
 
33
 * 1. Redistributions of source code must retain the above copyright
 
34
 *    notice, this list of conditions and the following disclaimer.
 
35
 * 2. Redistributions in binary form must reproduce the above copyright
 
36
 *    notice, this list of conditions and the following disclaimer in the
 
37
 *    documentation and/or other materials provided with the distribution.
 
38
 *
 
39
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 
40
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
41
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
42
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 
43
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
44
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
45
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
46
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
47
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
48
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
49
 * POSSIBILITY OF SUCH DAMAGE.
 
50
 */
 
51
 
 
52
#include <err.h>
 
53
#include <errno.h>
 
54
#include <getopt.h>
 
55
#include <stdlib.h>
 
56
#include <string.h>
 
57
 
 
58
int     opterr = 1;             /* if error message should be printed */
 
59
int     optind = 1;             /* index into parent argv vector */
 
60
int     optopt = '?';           /* character checked for validity */
 
61
int     optreset;               /* reset getopt */
 
62
char    *optarg;                /* argument associated with option */
 
63
 
 
64
#define PRINT_ERROR     ((opterr) && (*options != ':'))
 
65
 
 
66
#define FLAG_PERMUTE    0x01    /* permute non-options to the end of argv */
 
67
#define FLAG_ALLARGS    0x02    /* treat non-options as args to option "-1" */
 
68
#define FLAG_LONGONLY   0x04    /* operate as getopt_long_only */
 
69
 
 
70
/* return values */
 
71
#define BADCH           (int)'?'
 
72
#define BADARG          ((*options == ':') ? (int)':' : (int)'?')
 
73
#define INORDER         (int)1
 
74
 
 
75
#define EMSG            ""
 
76
 
 
77
static int getopt_internal(int, char * const *, const char *,
 
78
                           const struct option *, int *, int);
 
79
static int parse_long_options(char * const *, const char *,
 
80
                              const struct option *, int *, int);
 
81
static int gcd(int, int);
 
82
static void permute_args(int, int, int, char * const *);
 
83
 
 
84
static char *place = EMSG; /* option letter processing */
 
85
 
 
86
/* XXX: set optreset to 1 rather than these two */
 
87
static int nonopt_start = -1; /* first non option argument (for permute) */
 
88
static int nonopt_end = -1;   /* first option after non options (for permute) */
 
89
 
 
90
/* Error messages */
 
91
static const char recargchar[] = "option requires an argument -- %c";
 
92
static const char recargstring[] = "option requires an argument -- %s";
 
93
static const char ambig[] = "ambiguous option -- %.*s";
 
94
static const char noarg[] = "option doesn't take an argument -- %.*s";
 
95
static const char illoptchar[] = "unknown option -- %c";
 
96
static const char illoptstring[] = "unknown option -- %s";
 
97
 
 
98
/*
 
99
 * Compute the greatest common divisor of a and b.
 
100
 */
 
101
static int
 
102
gcd(int a, int b)
 
103
{
 
104
        int c;
 
105
 
 
106
        c = a % b;
 
107
        while (c != 0) {
 
108
                a = b;
 
109
                b = c;
 
110
                c = a % b;
 
111
        }
 
112
 
 
113
        return (b);
 
114
}
 
115
 
 
116
/*
 
117
 * Exchange the block from nonopt_start to nonopt_end with the block
 
118
 * from nonopt_end to opt_end (keeping the same order of arguments
 
119
 * in each block).
 
120
 */
 
121
static void
 
122
permute_args(int panonopt_start, int panonopt_end, int opt_end,
 
123
        char * const *nargv)
 
124
{
 
125
        int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
 
126
        char *swap;
 
127
 
 
128
        /*
 
129
         * compute lengths of blocks and number and size of cycles
 
130
         */
 
131
        nnonopts = panonopt_end - panonopt_start;
 
132
        nopts = opt_end - panonopt_end;
 
133
        ncycle = gcd(nnonopts, nopts);
 
134
        cyclelen = (opt_end - panonopt_start) / ncycle;
 
135
 
 
136
        for (i = 0; i < ncycle; i++) {
 
137
                cstart = panonopt_end+i;
 
138
                pos = cstart;
 
139
                for (j = 0; j < cyclelen; j++) {
 
140
                        if (pos >= panonopt_end)
 
141
                                pos -= nnonopts;
 
142
                        else
 
143
                                pos += nopts;
 
144
                        swap = nargv[pos];
 
145
                        /* LINTED const cast */
 
146
                        ((char **) nargv)[pos] = nargv[cstart];
 
147
                        /* LINTED const cast */
 
148
                        ((char **)nargv)[cstart] = swap;
 
149
                }
 
150
        }
 
151
}
 
152
 
 
153
/*
 
154
 * parse_long_options --
 
155
 *      Parse long options in argc/argv argument vector.
 
156
 * Returns -1 if short_too is set and the option does not match long_options.
 
157
 */
 
158
static int
 
159
parse_long_options(char * const *nargv, const char *options,
 
160
        const struct option *long_options, int *idx, int short_too)
 
161
{
 
162
        char *current_argv, *has_equal;
 
163
        size_t current_argv_len;
 
164
        int i, match;
 
165
 
 
166
        current_argv = place;
 
167
        match = -1;
 
168
 
 
169
        optind++;
 
170
 
 
171
        if ((has_equal = strchr(current_argv, '=')) != NULL) {
 
172
                /* argument found (--option=arg) */
 
173
                current_argv_len = has_equal - current_argv;
 
174
                has_equal++;
 
175
        } else
 
176
                current_argv_len = strlen(current_argv);
 
177
 
 
178
        for (i = 0; long_options[i].name; i++) {
 
179
                /* find matching long option */
 
180
                if (strncmp(current_argv, long_options[i].name,
 
181
                    current_argv_len))
 
182
                        continue;
 
183
 
 
184
                if (strlen(long_options[i].name) == current_argv_len) {
 
185
                        /* exact match */
 
186
                        match = i;
 
187
                        break;
 
188
                }
 
189
                /*
 
190
                 * If this is a known short option, don't allow
 
191
                 * a partial match of a single character.
 
192
                 */
 
193
                if (short_too && current_argv_len == 1)
 
194
                        continue;
 
195
 
 
196
                if (match == -1)        /* partial match */
 
197
                        match = i;
 
198
                else {
 
199
                        /* ambiguous abbreviation */
 
200
                        if (PRINT_ERROR)
 
201
                                warnx(ambig, (int)current_argv_len,
 
202
                                     current_argv);
 
203
                        optopt = 0;
 
204
                        return (BADCH);
 
205
                }
 
206
        }
 
207
        if (match != -1) {              /* option found */
 
208
                if (long_options[match].has_arg == no_argument
 
209
                    && has_equal) {
 
210
                        if (PRINT_ERROR)
 
211
                                warnx(noarg, (int)current_argv_len,
 
212
                                     current_argv);
 
213
                        /*
 
214
                         * XXX: GNU sets optopt to val regardless of flag
 
215
                         */
 
216
                        if (long_options[match].flag == NULL)
 
217
                                optopt = long_options[match].val;
 
218
                        else
 
219
                                optopt = 0;
 
220
                        return (BADARG);
 
221
                }
 
222
                if (long_options[match].has_arg == required_argument ||
 
223
                    long_options[match].has_arg == optional_argument) {
 
224
                        if (has_equal)
 
225
                                optarg = has_equal;
 
226
                        else if (long_options[match].has_arg ==
 
227
                            required_argument) {
 
228
                                /*
 
229
                                 * optional argument doesn't use next nargv
 
230
                                 */
 
231
                                optarg = nargv[optind++];
 
232
                        }
 
233
                }
 
234
                if ((long_options[match].has_arg == required_argument)
 
235
                    && (optarg == NULL)) {
 
236
                        /*
 
237
                         * Missing argument; leading ':' indicates no error
 
238
                         * should be generated.
 
239
                         */
 
240
                        if (PRINT_ERROR)
 
241
                                warnx(recargstring,
 
242
                                    current_argv);
 
243
                        /*
 
244
                         * XXX: GNU sets optopt to val regardless of flag
 
245
                         */
 
246
                        if (long_options[match].flag == NULL)
 
247
                                optopt = long_options[match].val;
 
248
                        else
 
249
                                optopt = 0;
 
250
                        --optind;
 
251
                        return (BADARG);
 
252
                }
 
253
        } else {                        /* unknown option */
 
254
                if (short_too) {
 
255
                        --optind;
 
256
                        return (-1);
 
257
                }
 
258
                if (PRINT_ERROR)
 
259
                        warnx(illoptstring, current_argv);
 
260
                optopt = 0;
 
261
                return (BADCH);
 
262
        }
 
263
        if (idx)
 
264
                *idx = match;
 
265
        if (long_options[match].flag) {
 
266
                *long_options[match].flag = long_options[match].val;
 
267
                return (0);
 
268
        } else
 
269
                return (long_options[match].val);
 
270
}
 
271
 
 
272
/*
 
273
 * getopt_internal --
 
274
 *      Parse argc/argv argument vector.  Called by user level routines.
 
275
 */
 
276
static int
 
277
getopt_internal(int nargc, char * const *nargv, const char *options,
 
278
        const struct option *long_options, int *idx, int flags)
 
279
{
 
280
        char *oli;                              /* option letter list index */
 
281
        int optchar, short_too;
 
282
        static int posixly_correct = -1;
 
283
 
 
284
        if (options == NULL)
 
285
                return (-1);
 
286
 
 
287
        /*
 
288
         * XXX Some GNU programs (like cvs) set optind to 0 instead of
 
289
         * XXX using optreset.  Work around this braindamage.
 
290
         */
 
291
        if (optind == 0)
 
292
                optind = optreset = 1;
 
293
 
 
294
        /*
 
295
         * Disable GNU extensions if POSIXLY_CORRECT is set or options
 
296
         * string begins with a '+'.
 
297
         */
 
298
        if (posixly_correct == -1 || optreset)
 
299
                posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
 
300
        if (*options == '-')
 
301
                flags |= FLAG_ALLARGS;
 
302
        else if (posixly_correct || *options == '+')
 
303
                flags &= ~FLAG_PERMUTE;
 
304
        if (*options == '+' || *options == '-')
 
305
                options++;
 
306
 
 
307
        optarg = NULL;
 
308
        if (optreset)
 
309
                nonopt_start = nonopt_end = -1;
 
310
start:
 
311
        if (optreset || !*place) {              /* update scanning pointer */
 
312
                optreset = 0;
 
313
                if (optind >= nargc) {          /* end of argument vector */
 
314
                        place = EMSG;
 
315
                        if (nonopt_end != -1) {
 
316
                                /* do permutation, if we have to */
 
317
                                permute_args(nonopt_start, nonopt_end,
 
318
                                    optind, nargv);
 
319
                                optind -= nonopt_end - nonopt_start;
 
320
                        }
 
321
                        else if (nonopt_start != -1) {
 
322
                                /*
 
323
                                 * If we skipped non-options, set optind
 
324
                                 * to the first of them.
 
325
                                 */
 
326
                                optind = nonopt_start;
 
327
                        }
 
328
                        nonopt_start = nonopt_end = -1;
 
329
                        return (-1);
 
330
                }
 
331
                if (*(place = nargv[optind]) != '-' ||
 
332
                    (place[1] == '\0' && strchr(options, '-') == NULL)) {
 
333
                        place = EMSG;           /* found non-option */
 
334
                        if (flags & FLAG_ALLARGS) {
 
335
                                /*
 
336
                                 * GNU extension:
 
337
                                 * return non-option as argument to option 1
 
338
                                 */
 
339
                                optarg = nargv[optind++];
 
340
                                return (INORDER);
 
341
                        }
 
342
                        if (!(flags & FLAG_PERMUTE)) {
 
343
                                /*
 
344
                                 * If no permutation wanted, stop parsing
 
345
                                 * at first non-option.
 
346
                                 */
 
347
                                return (-1);
 
348
                        }
 
349
                        /* do permutation */
 
350
                        if (nonopt_start == -1)
 
351
                                nonopt_start = optind;
 
352
                        else if (nonopt_end != -1) {
 
353
                                permute_args(nonopt_start, nonopt_end,
 
354
                                    optind, nargv);
 
355
                                nonopt_start = optind -
 
356
                                    (nonopt_end - nonopt_start);
 
357
                                nonopt_end = -1;
 
358
                        }
 
359
                        optind++;
 
360
                        /* process next argument */
 
361
                        goto start;
 
362
                }
 
363
                if (nonopt_start != -1 && nonopt_end == -1)
 
364
                        nonopt_end = optind;
 
365
 
 
366
                /*
 
367
                 * If we have "-" do nothing, if "--" we are done.
 
368
                 */
 
369
                if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
 
370
                        optind++;
 
371
                        place = EMSG;
 
372
                        /*
 
373
                         * We found an option (--), so if we skipped
 
374
                         * non-options, we have to permute.
 
375
                         */
 
376
                        if (nonopt_end != -1) {
 
377
                                permute_args(nonopt_start, nonopt_end,
 
378
                                    optind, nargv);
 
379
                                optind -= nonopt_end - nonopt_start;
 
380
                        }
 
381
                        nonopt_start = nonopt_end = -1;
 
382
                        return (-1);
 
383
                }
 
384
        }
 
385
 
 
386
        /*
 
387
         * Check long options if:
 
388
         *  1) we were passed some
 
389
         *  2) the arg is not just "-"
 
390
         *  3) either the arg starts with -- we are getopt_long_only()
 
391
         */
 
392
        if (long_options != NULL && place != nargv[optind] &&
 
393
            (*place == '-' || (flags & FLAG_LONGONLY))) {
 
394
                short_too = 0;
 
395
                if (*place == '-')
 
396
                        place++;                /* --foo long option */
 
397
                else if (*place != ':' && strchr(options, *place) != NULL)
 
398
                        short_too = 1;          /* could be short option too */
 
399
 
 
400
                optchar = parse_long_options(nargv, options, long_options,
 
401
                    idx, short_too);
 
402
                if (optchar != -1) {
 
403
                        place = EMSG;
 
404
                        return (optchar);
 
405
                }
 
406
        }
 
407
 
 
408
        if ((optchar = (int)*place++) == (int)':' ||
 
409
            (optchar == (int)'-' && *place != '\0') ||
 
410
            (oli = strchr(options, optchar)) == NULL) {
 
411
                /*
 
412
                 * If the user specified "-" and  '-' isn't listed in
 
413
                 * options, return -1 (non-option) as per POSIX.
 
414
                 * Otherwise, it is an unknown option character (or ':').
 
415
                 */
 
416
                if (optchar == (int)'-' && *place == '\0')
 
417
                        return (-1);
 
418
                if (!*place)
 
419
                        ++optind;
 
420
                if (PRINT_ERROR)
 
421
                        warnx(illoptchar, optchar);
 
422
                optopt = optchar;
 
423
                return (BADCH);
 
424
        }
 
425
        if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
 
426
                /* -W long-option */
 
427
                if (*place)                     /* no space */
 
428
                        /* NOTHING */;
 
429
                else if (++optind >= nargc) {   /* no arg */
 
430
                        place = EMSG;
 
431
                        if (PRINT_ERROR)
 
432
                                warnx(recargchar, optchar);
 
433
                        optopt = optchar;
 
434
                        return (BADARG);
 
435
                } else                          /* white space */
 
436
                        place = nargv[optind];
 
437
                optchar = parse_long_options(nargv, options, long_options,
 
438
                    idx, 0);
 
439
                place = EMSG;
 
440
                return (optchar);
 
441
        }
 
442
        if (*++oli != ':') {                    /* doesn't take argument */
 
443
                if (!*place)
 
444
                        ++optind;
 
445
        } else {                                /* takes (optional) argument */
 
446
                optarg = NULL;
 
447
                if (*place)                     /* no white space */
 
448
                        optarg = place;
 
449
                else if (oli[1] != ':') {       /* arg not optional */
 
450
                        if (++optind >= nargc) {        /* no arg */
 
451
                                place = EMSG;
 
452
                                if (PRINT_ERROR)
 
453
                                        warnx(recargchar, optchar);
 
454
                                optopt = optchar;
 
455
                                return (BADARG);
 
456
                        } else
 
457
                                optarg = nargv[optind];
 
458
                }
 
459
                place = EMSG;
 
460
                ++optind;
 
461
        }
 
462
        /* dump back option letter */
 
463
        return (optchar);
 
464
}
 
465
 
 
466
/*
 
467
 * getopt --
 
468
 *      Parse argc/argv argument vector.
 
469
 *
 
470
 * [eventually this will replace the BSD getopt]
 
471
 */
 
472
int
 
473
getopt(int nargc, char * const *nargv, const char *options)
 
474
{
 
475
 
 
476
        /*
 
477
         * We don't pass FLAG_PERMUTE to getopt_internal() since
 
478
         * the BSD getopt(3) (unlike GNU) has never done this.
 
479
         *
 
480
         * Furthermore, since many privileged programs call getopt()
 
481
         * before dropping privileges it makes sense to keep things
 
482
         * as simple (and bug-free) as possible.
 
483
         */
 
484
        return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
 
485
}
 
486
 
 
487
/*
 
488
 * getopt_long --
 
489
 *      Parse argc/argv argument vector.
 
490
 */
 
491
int
 
492
getopt_long(int nargc, char * const *nargv, const char *options,
 
493
    const struct option *long_options, int *idx)
 
494
{
 
495
 
 
496
        return (getopt_internal(nargc, nargv, options, long_options, idx,
 
497
            FLAG_PERMUTE));
 
498
}
 
499
 
 
500
/*
 
501
 * getopt_long_only --
 
502
 *      Parse argc/argv argument vector.
 
503
 */
 
504
int
 
505
getopt_long_only(int nargc, char * const *nargv, const char *options,
 
506
    const struct option *long_options, int *idx)
 
507
{
 
508
 
 
509
        return (getopt_internal(nargc, nargv, options, long_options, idx,
 
510
            FLAG_PERMUTE|FLAG_LONGONLY));
 
511
}