"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/getopt_long.c" (11 Sep 2018, 12815 Bytes) of package /linux/misc/file-5.35.tar.gz:


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. For more information about "getopt_long.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

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