Coverage Report

Created: 2025-06-15 00:57

/src/cmp_tool/test/fuzz/getopt_long_quiet.c
Line
Count
Source (jump to first uncovered line)
1
/*  $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert 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
__extension__
54
19
#define warnx(format, ...) (void)0
55
#include <errno.h>
56
#include <getopt.h>
57
#include <stdlib.h>
58
#include <string.h>
59
60
#define GNU_COMPATIBLE    /* Be more compatible, configure's use us! */
61
62
#if 1
63
#define REPLACE_GETOPT    /* use this getopt as the system getopt(3) */
64
#endif
65
66
#ifdef REPLACE_GETOPT
67
int opterr = 1;   /* if error message should be printed */
68
int optind = 1;   /* index into parent argv vector */
69
int optopt = '?';   /* character checked for validity */
70
int optreset;   /* reset getopt */
71
char    *optarg;    /* argument associated with option */
72
#endif
73
74
19
#define PRINT_ERROR ((opterr) && (*options != ':'))
75
76
10.8k
#define FLAG_PERMUTE  0x01  /* permute non-options to the end of argv */
77
1.80k
#define FLAG_ALLARGS  0x02  /* treat non-options as args to option "-1" */
78
7.21k
#define FLAG_LONGONLY 0x04  /* operate as getopt_long_only */
79
80
/* return values */
81
19
#define BADCH   (int)'?'
82
4
#define BADARG    ((*options == ':') ? (int)':' : (int)'?')
83
0
#define INORDER   (int)1
84
85
static char EMSG[] = "";
86
87
#ifdef GNU_COMPATIBLE
88
#define NO_PREFIX (-1)
89
206
#define D_PREFIX  0
90
404
#define DD_PREFIX 1
91
0
#define W_PREFIX  2
92
#endif
93
94
static int getopt_internal(int, char * const *, const char *,
95
         const struct option *, int *, int);
96
static int parse_long_options(char * const *, const char *,
97
            const struct option *, int *, int, int);
98
static int gcd(int, int);
99
static void permute_args(int, int, int, char * const *);
100
101
static char *place = EMSG; /* option letter processing */
102
103
/* XXX: set optreset to 1 rather than these two */
104
static int nonopt_start = -1; /* first non option argument (for permute) */
105
static int nonopt_end = -1;   /* first option after non options (for permute) */
106
107
/* Error messages */
108
static const char recargchar[] = "option requires an argument -- %c";
109
static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */
110
#ifdef GNU_COMPATIBLE
111
static int dash_prefix = NO_PREFIX;
112
static const char gnuoptchar[] = "invalid option -- %c";
113
114
static const char recargstring[] = "option `%s%s' requires an argument";
115
static const char ambig[] = "option `%s%.*s' is ambiguous";
116
static const char noarg[] = "option `%s%.*s' doesn't allow an argument";
117
static const char illoptstring[] = "unrecognized option `%s%s'";
118
#else
119
static const char recargstring[] = "option requires an argument -- %s";
120
static const char ambig[] = "ambiguous option -- %.*s";
121
static const char noarg[] = "option doesn't take an argument -- %.*s";
122
static const char illoptstring[] = "unknown option -- %s";
123
#endif
124
125
/*
126
 * Compute the greatest common divisor of a and b.
127
 */
128
static int
129
gcd(int a, int b)
130
244
{
131
244
  int c;
132
133
244
  c = a % b;
134
421
  while (c != 0) {
135
177
    a = b;
136
177
    b = c;
137
177
    c = a % b;
138
177
  }
139
140
244
  return (b);
141
244
}
142
143
/*
144
 * Exchange the block from nonopt_start to nonopt_end with the block
145
 * from nonopt_end to opt_end (keeping the same order of arguments
146
 * in each block).
147
 */
148
static void
149
permute_args(int panonopt_start, int panonopt_end, int opt_end,
150
  char * const *nargv)
151
244
{
152
244
  int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
153
244
  char *swap;
154
155
  /*
156
   * compute lengths of blocks and number and size of cycles
157
   */
158
244
  nnonopts = panonopt_end - panonopt_start;
159
244
  nopts = opt_end - panonopt_end;
160
244
  ncycle = gcd(nnonopts, nopts);
161
244
  cyclelen = (opt_end - panonopt_start) / ncycle;
162
163
640
  for (i = 0; i < ncycle; i++) {
164
396
    cstart = panonopt_end+i;
165
396
    pos = cstart;
166
3.32k
    for (j = 0; j < cyclelen; j++) {
167
2.93k
      if (pos >= panonopt_end)
168
723
        pos -= nnonopts;
169
2.21k
      else
170
2.21k
        pos += nopts;
171
2.93k
      swap = nargv[pos];
172
      /* LINTED const cast */
173
2.93k
      ((char **) nargv)[pos] = nargv[cstart];
174
      /* LINTED const cast */
175
2.93k
      ((char **)nargv)[cstart] = swap;
176
2.93k
    }
177
396
  }
178
244
}
179
180
/*
181
 * parse_long_options --
182
 *  Parse long options in argc/argv argument vector.
183
 * Returns -1 if short_too is set and the option does not match long_options.
184
 */
185
static int
186
parse_long_options(char * const *nargv, const char *options,
187
  const struct option *long_options, int *idx, int short_too, int flags)
188
202
{
189
202
  char *current_argv, *has_equal;
190
202
#ifdef GNU_COMPATIBLE
191
202
  const char *current_dash;
192
202
#endif
193
202
  size_t current_argv_len;
194
202
  int i, match, exact_match, second_partial_match;
195
196
202
  current_argv = place;
197
202
#ifdef GNU_COMPATIBLE
198
202
  switch (dash_prefix) {
199
0
    case D_PREFIX:
200
0
      current_dash = "-";
201
0
      break;
202
202
    case DD_PREFIX:
203
202
      current_dash = "--";
204
202
      break;
205
0
    case W_PREFIX:
206
0
      current_dash = "-W ";
207
0
      break;
208
0
    default:
209
0
      current_dash = "";
210
0
      break;
211
202
  }
212
202
#endif
213
202
  match = -1;
214
202
  exact_match = 0;
215
202
  second_partial_match = 0;
216
217
202
  optind++;
218
219
202
  if ((has_equal = strchr(current_argv, '=')) != NULL) {
220
    /* argument found (--option=arg) */
221
41
    current_argv_len = has_equal - current_argv;
222
41
    has_equal++;
223
41
  } else
224
161
    current_argv_len = strlen(current_argv);
225
226
2.12k
  for (i = 0; long_options[i].name; i++) {
227
    /* find matching long option */
228
2.04k
    if (strncmp(current_argv, long_options[i].name,
229
2.04k
        current_argv_len))
230
1.80k
      continue;
231
232
243
    if (strlen(long_options[i].name) == current_argv_len) {
233
      /* exact match */
234
129
      match = i;
235
129
      exact_match = 1;
236
129
      break;
237
129
    }
238
    /*
239
     * If this is a known short option, don't allow
240
     * a partial match of a single character.
241
     */
242
114
    if (short_too && current_argv_len == 1)
243
0
      continue;
244
245
114
    if (match == -1)  /* first partial match */
246
71
      match = i;
247
43
    else if ((flags & FLAG_LONGONLY) ||
248
43
       long_options[i].has_arg !=
249
43
           long_options[match].has_arg ||
250
43
       long_options[i].flag != long_options[match].flag ||
251
43
       long_options[i].val != long_options[match].val)
252
43
      second_partial_match = 1;
253
114
  }
254
202
  if (!exact_match && second_partial_match) {
255
    /* ambiguous abbreviation */
256
6
    if (PRINT_ERROR)
257
6
      warnx(ambig,
258
6
#ifdef GNU_COMPATIBLE
259
6
           current_dash,
260
6
#endif
261
6
           (int)current_argv_len,
262
6
           current_argv);
263
6
    optopt = 0;
264
6
    return (BADCH);
265
6
  }
266
196
  if (match != -1) {   /* option found */
267
194
    if (long_options[match].has_arg == no_argument
268
194
        && has_equal) {
269
1
      if (PRINT_ERROR)
270
1
        warnx(noarg,
271
1
#ifdef GNU_COMPATIBLE
272
1
             current_dash,
273
1
#endif
274
1
             (int)current_argv_len,
275
1
             current_argv);
276
      /*
277
       * XXX: GNU sets optopt to val regardless of flag
278
       */
279
1
      if (long_options[match].flag == NULL)
280
1
        optopt = long_options[match].val;
281
0
      else
282
0
        optopt = 0;
283
1
#ifdef GNU_COMPATIBLE
284
1
      return (BADCH);
285
#else
286
      return (BADARG);
287
#endif
288
1
    }
289
193
    if (long_options[match].has_arg == required_argument ||
290
193
        long_options[match].has_arg == optional_argument) {
291
158
      if (has_equal)
292
37
        optarg = has_equal;
293
121
      else if (long_options[match].has_arg ==
294
121
          required_argument) {
295
        /*
296
         * optional argument doesn't use next nargv
297
         */
298
9
        optarg = nargv[optind++];
299
9
      }
300
158
    }
301
193
    if ((long_options[match].has_arg == required_argument)
302
193
        && (optarg == NULL)) {
303
      /*
304
       * Missing argument; leading ':' indicates no error
305
       * should be generated.
306
       */
307
0
      if (PRINT_ERROR)
308
0
        warnx(recargstring,
309
0
#ifdef GNU_COMPATIBLE
310
0
            current_dash,
311
0
#endif
312
0
            current_argv);
313
      /*
314
       * XXX: GNU sets optopt to val regardless of flag
315
       */
316
0
      if (long_options[match].flag == NULL)
317
0
        optopt = long_options[match].val;
318
0
      else
319
0
        optopt = 0;
320
0
      --optind;
321
0
      return (BADARG);
322
0
    }
323
193
  } else {     /* unknown option */
324
2
    if (short_too) {
325
0
      --optind;
326
0
      return (-1);
327
0
    }
328
2
    if (PRINT_ERROR)
329
2
      warnx(illoptstring,
330
2
#ifdef GNU_COMPATIBLE
331
2
            current_dash,
332
2
#endif
333
2
            current_argv);
334
2
    optopt = 0;
335
2
    return (BADCH);
336
2
  }
337
193
  if (idx)
338
0
    *idx = match;
339
193
  if (long_options[match].flag) {
340
0
    *long_options[match].flag = long_options[match].val;
341
0
    return (0);
342
0
  } else
343
193
    return (long_options[match].val);
344
193
}
345
346
/*
347
 * getopt_internal --
348
 *  Parse argc/argv argument vector.  Called by user level routines.
349
 */
350
static int
351
getopt_internal(int nargc, char * const *nargv, const char *options,
352
  const struct option *long_options, int *idx, int flags)
353
9.08k
{
354
9.08k
  char *oli;        /* option letter list index */
355
9.08k
  int optchar, short_too;
356
9.08k
  static int posixly_correct = -1;
357
358
9.08k
  if (options == NULL)
359
0
    return (-1);
360
361
  /*
362
   * XXX Some GNU programs (like cvs) set optind to 0 instead of
363
   * XXX using optreset.  Work around this braindamage.
364
   */
365
9.08k
  if (optind == 0)
366
1.74k
    optind = optreset = 1;
367
368
  /*
369
   * Disable GNU extensions if POSIXLY_CORRECT is set or options
370
   * string begins with a '+'.
371
   */
372
9.08k
  if (posixly_correct == -1 || optreset)
373
1.74k
    posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
374
9.08k
  if (*options == '-')
375
0
    flags |= FLAG_ALLARGS;
376
9.08k
  else if (posixly_correct || *options == '+')
377
0
    flags &= ~FLAG_PERMUTE;
378
9.08k
  if (*options == '+' || *options == '-')
379
0
    options++;
380
381
9.08k
  optarg = NULL;
382
9.08k
  if (optreset)
383
1.74k
    nonopt_start = nonopt_end = -1;
384
10.8k
start:
385
10.8k
  if (optreset || !*place) {   /* update scanning pointer */
386
10.4k
    optreset = 0;
387
10.4k
    if (optind >= nargc) {          /* end of argument vector */
388
1.69k
      place = EMSG;
389
1.69k
      if (nonopt_end != -1) {
390
        /* do permutation, if we have to */
391
154
        permute_args(nonopt_start, nonopt_end,
392
154
            optind, nargv);
393
154
        optind -= nonopt_end - nonopt_start;
394
154
      }
395
1.54k
      else if (nonopt_start != -1) {
396
        /*
397
         * If we skipped non-options, set optind
398
         * to the first of them.
399
         */
400
0
        optind = nonopt_start;
401
0
      }
402
1.69k
      nonopt_start = nonopt_end = -1;
403
1.69k
      return (-1);
404
1.69k
    }
405
8.77k
    if (*(place = nargv[optind]) != '-' ||
406
8.77k
#ifdef GNU_COMPATIBLE
407
8.77k
        place[1] == '\0') {
408
#else
409
        (place[1] == '\0' && strchr(options, '-') == NULL)) {
410
#endif
411
1.80k
      place = EMSG;   /* found non-option */
412
1.80k
      if (flags & FLAG_ALLARGS) {
413
        /*
414
         * GNU extension:
415
         * return non-option as argument to option 1
416
         */
417
0
        optarg = nargv[optind++];
418
0
        return (INORDER);
419
0
      }
420
1.80k
      if (!(flags & FLAG_PERMUTE)) {
421
        /*
422
         * If no permutation wanted, stop parsing
423
         * at first non-option.
424
         */
425
0
        return (-1);
426
0
      }
427
      /* do permutation */
428
1.80k
      if (nonopt_start == -1)
429
168
        nonopt_start = optind;
430
1.64k
      else if (nonopt_end != -1) {
431
77
        permute_args(nonopt_start, nonopt_end,
432
77
            optind, nargv);
433
77
        nonopt_start = optind -
434
77
            (nonopt_end - nonopt_start);
435
77
        nonopt_end = -1;
436
77
      }
437
1.80k
      optind++;
438
      /* process next argument */
439
1.80k
      goto start;
440
1.80k
    }
441
6.97k
    if (nonopt_start != -1 && nonopt_end == -1)
442
245
      nonopt_end = optind;
443
444
    /*
445
     * If we have "-" do nothing, if "--" we are done.
446
     */
447
6.97k
    if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
448
15
      optind++;
449
15
      place = EMSG;
450
      /*
451
       * We found an option (--), so if we skipped
452
       * non-options, we have to permute.
453
       */
454
15
      if (nonopt_end != -1) {
455
13
        permute_args(nonopt_start, nonopt_end,
456
13
            optind, nargv);
457
13
        optind -= nonopt_end - nonopt_start;
458
13
      }
459
15
      nonopt_start = nonopt_end = -1;
460
15
      return (-1);
461
15
    }
462
6.97k
  }
463
464
  /*
465
   * Check long options if:
466
   *  1) we were passed some
467
   *  2) the arg is not just "-"
468
   *  3) either the arg starts with -- we are getopt_long_only()
469
   */
470
7.37k
  if (long_options != NULL && place != nargv[optind] &&
471
7.37k
      (*place == '-' || (flags & FLAG_LONGONLY))) {
472
206
    short_too = 0;
473
206
#ifdef GNU_COMPATIBLE
474
206
    dash_prefix = D_PREFIX;
475
206
#endif
476
206
    if (*place == '-') {
477
206
      place++;    /* --foo long option */
478
206
      if (*place == '\0')
479
4
        return (BADARG);  /* malformed option */
480
202
#ifdef GNU_COMPATIBLE
481
202
      dash_prefix = DD_PREFIX;
482
202
#endif
483
202
    } else if (*place != ':' && strchr(options, *place) != NULL)
484
0
      short_too = 1;    /* could be short option too */
485
486
202
    optchar = parse_long_options(nargv, options, long_options,
487
202
        idx, short_too, flags);
488
202
    if (optchar != -1) {
489
202
      place = EMSG;
490
202
      return (optchar);
491
202
    }
492
202
  }
493
494
7.16k
  if ((optchar = (int)*place++) == (int)':' ||
495
7.16k
      (optchar == (int)'-' && *place != '\0') ||
496
7.16k
      (oli = strchr(options, optchar)) == NULL) {
497
    /*
498
     * If the user specified "-" and  '-' isn't listed in
499
     * options, return -1 (non-option) as per POSIX.
500
     * Otherwise, it is an unknown option character (or ':').
501
     */
502
10
    if (optchar == (int)'-' && *place == '\0')
503
0
      return (-1);
504
10
    if (!*place)
505
6
      ++optind;
506
10
#ifdef GNU_COMPATIBLE
507
10
    if (PRINT_ERROR)
508
10
      warnx(posixly_correct ? illoptchar : gnuoptchar,
509
10
            optchar);
510
#else
511
    if (PRINT_ERROR)
512
      warnx(illoptchar, optchar);
513
#endif
514
10
    optopt = optchar;
515
10
    return (BADCH);
516
10
  }
517
7.15k
  if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
518
    /* -W long-option */
519
0
    if (*place)     /* no space */
520
0
      /* NOTHING */;
521
0
    else if (++optind >= nargc) { /* no arg */
522
0
      place = EMSG;
523
0
      if (PRINT_ERROR)
524
0
        warnx(recargchar, optchar);
525
0
      optopt = optchar;
526
0
      return (BADARG);
527
0
    } else        /* white space */
528
0
      place = nargv[optind];
529
0
#ifdef GNU_COMPATIBLE
530
0
    dash_prefix = W_PREFIX;
531
0
#endif
532
0
    optchar = parse_long_options(nargv, options, long_options,
533
0
        idx, 0, flags);
534
0
    place = EMSG;
535
0
    return (optchar);
536
0
  }
537
7.15k
  if (*++oli != ':') {     /* doesn't take argument */
538
478
    if (!*place)
539
60
      ++optind;
540
6.67k
  } else {       /* takes (optional) argument */
541
6.67k
    optarg = NULL;
542
6.67k
    if (*place)      /* no white space */
543
6.57k
      optarg = place;
544
104
    else if (oli[1] != ':') { /* arg not optional */
545
104
      if (++optind >= nargc) { /* no arg */
546
0
        place = EMSG;
547
0
        if (PRINT_ERROR)
548
0
          warnx(recargchar, optchar);
549
0
        optopt = optchar;
550
0
        return (BADARG);
551
0
      } else
552
104
        optarg = nargv[optind];
553
104
    }
554
6.67k
    place = EMSG;
555
6.67k
    ++optind;
556
6.67k
  }
557
  /* dump back option letter */
558
7.15k
  return (optchar);
559
7.15k
}
560
561
#ifdef REPLACE_GETOPT
562
/*
563
 * getopt --
564
 *  Parse argc/argv argument vector.
565
 *
566
 * [eventually this will replace the BSD getopt]
567
 */
568
int
569
getopt(int nargc, char * const *nargv, const char *options)
570
0
{
571
572
  /*
573
   * We don't pass FLAG_PERMUTE to getopt_internal() since
574
   * the BSD getopt(3) (unlike GNU) has never done this.
575
   *
576
   * Furthermore, since many privileged programs call getopt()
577
   * before dropping privileges it makes sense to keep things
578
   * as simple (and bug-free) as possible.
579
   */
580
0
  return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
581
0
}
582
#endif /* REPLACE_GETOPT */
583
584
/*
585
 * getopt_long --
586
 *  Parse argc/argv argument vector.
587
 */
588
int
589
getopt_long(int nargc, char * const *nargv, const char *options,
590
  const struct option *long_options, int *idx)
591
9.08k
{
592
593
9.08k
  return (getopt_internal(nargc, nargv, options, long_options, idx,
594
9.08k
      FLAG_PERMUTE));
595
9.08k
}
596
597
/*
598
 * getopt_long_only --
599
 *  Parse argc/argv argument vector.
600
 */
601
int
602
getopt_long_only(int nargc, char * const *nargv, const char *options,
603
  const struct option *long_options, int *idx)
604
0
{
605
606
0
  return (getopt_internal(nargc, nargv, options, long_options, idx,
607
0
      FLAG_PERMUTE|FLAG_LONGONLY));
608
0
}