LCOV - code coverage report
Current view: top level - bash-4.4.23/builtins - getopt.c (source / functions) Hit Total Coverage
Test: cov-bash.info Lines: 12 70 17.1 %
Date: 2020-10-29 14:49:28 Functions: 1 6 16.7 %

          Line data    Source code
       1             : /* getopt.c - getopt for Bash.  Used by the getopt builtin. */
       2             : 
       3             : /* Copyright (C) 1993-2009 Free Software Foundation, Inc.
       4             : 
       5             :    This file is part of GNU Bash, the Bourne Again SHell.
       6             : 
       7             :    Bash is free software: you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation, either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    Bash is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #if defined (HAVE_UNISTD_H)
      24             : #  ifdef _MINIX
      25             : #    include <sys/types.h>
      26             : #  endif
      27             : #  include <unistd.h>
      28             : #endif
      29             : 
      30             : #include <stdio.h>
      31             : #include "memalloc.h"
      32             : #include "../bashintl.h"
      33             : #include "../shell.h"
      34             : #include "getopt.h"
      35             : 
      36             : /* For communication from `sh_getopt' to the caller.
      37             :    When `sh_getopt' finds an option that takes an argument,
      38             :    the argument value is returned here. */
      39             : char *sh_optarg = 0;
      40             : 
      41             : /* Index in ARGV of the next element to be scanned.
      42             :    This is used for communication to and from the caller
      43             :    and for communication between successive calls to `sh_getopt'.
      44             : 
      45             :    On entry to `sh_getopt', zero means this is the first call; initialize.
      46             : 
      47             :    When `sh_getopt' returns EOF, this is the index of the first of the
      48             :    non-option elements that the caller should itself scan.
      49             : 
      50             :    Otherwise, `sh_optind' communicates from one call to the next
      51             :    how much of ARGV has been scanned so far.  */
      52             : 
      53             : /* XXX 1003.2 says this must be 1 before any call.  */
      54             : int sh_optind = 0;
      55             : 
      56             : /* Index of the current argument. */
      57             : static int sh_curopt;
      58             : 
      59             : /* The next char to be scanned in the option-element
      60             :    in which the last option character we returned was found.
      61             :    This allows us to pick up the scan where we left off.
      62             : 
      63             :    If this is zero, or a null string, it means resume the scan
      64             :    by advancing to the next ARGV-element.  */
      65             : 
      66             : static char *nextchar;
      67             : static int sh_charindex;
      68             : 
      69             : /* Callers store zero here to inhibit the error message
      70             :    for unrecognized options.  */
      71             : 
      72             : int sh_opterr = 1;
      73             : 
      74             : /* Set to an option character which was unrecognized.
      75             :    This must be initialized on some systems to avoid linking in the
      76             :    system's own getopt implementation.  */
      77             : 
      78             : int sh_optopt = '?';
      79             : 
      80             : /* Set to 1 when we see an invalid option; public so getopts can reset it. */
      81             : int sh_badopt = 0;
      82             : 
      83             : /* Scan elements of ARGV (whose length is ARGC) for option characters
      84             :    given in OPTSTRING.
      85             : 
      86             :    If an element of ARGV starts with '-', and is not exactly "-" or "--",
      87             :    then it is an option element.  The characters of this element
      88             :    (aside from the initial '-') are option characters.  If `sh_getopt'
      89             :    is called repeatedly, it returns successively each of the option characters
      90             :    from each of the option elements.
      91             : 
      92             :    If `sh_getopt' finds another option character, it returns that character,
      93             :    updating `sh_optind' and `nextchar' so that the next call to `sh_getopt' can
      94             :    resume the scan with the following option character or ARGV-element.
      95             : 
      96             :    If there are no more option characters, `sh_getopt' returns `EOF'.
      97             :    Then `sh_optind' is the index in ARGV of the first ARGV-element
      98             :    that is not an option.
      99             : 
     100             :    OPTSTRING is a string containing the legitimate option characters.
     101             :    If an option character is seen that is not listed in OPTSTRING,
     102             :    return '?' after printing an error message.  If you set `sh_opterr' to
     103             :    zero, the error message is suppressed but we still return '?'.
     104             : 
     105             :    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
     106             :    so the following text in the same ARGV-element, or the text of the following
     107             :    ARGV-element, is returned in `sh_optarg'. */
     108             : 
     109             : /* 1003.2 specifies the format of this message.  */
     110             : #define BADOPT(x)  fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], x)
     111             : #define NEEDARG(x) fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], x)
     112             : 
     113             : int
     114           0 : sh_getopt (argc, argv, optstring)
     115             :      int argc;
     116             :      char *const *argv;
     117             :      const char *optstring;
     118             : {
     119           0 :   char c, *temp;
     120             : 
     121           0 :   sh_optarg = 0;
     122             : 
     123           0 :   if (sh_optind >= argc || sh_optind < 0) /* XXX was sh_optind > argc */
     124             :     {
     125           0 :       sh_optind = argc;
     126           0 :       return (EOF);
     127             :     }
     128             : 
     129             :   /* Initialize the internal data when the first call is made.
     130             :      Start processing options with ARGV-element 1 (since ARGV-element 0
     131             :      is the program name); the sequence of previously skipped
     132             :      non-option ARGV-elements is empty.  */
     133             : 
     134           0 :   if (sh_optind == 0)
     135             :     {
     136           0 :       sh_optind = 1;
     137           0 :       nextchar = (char *)NULL;
     138             :     }
     139             : 
     140           0 :   if (nextchar == 0 || *nextchar == '\0')
     141             :     {
     142             :       /* If we have done all the ARGV-elements, stop the scan. */
     143           0 :       if (sh_optind >= argc)
     144             :         return EOF;
     145             : 
     146           0 :       temp = argv[sh_optind];
     147             : 
     148             :       /* Special ARGV-element `--' means premature end of options.
     149             :          Skip it like a null option, and return EOF. */
     150           0 :       if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0')
     151             :         {
     152           0 :           sh_optind++;
     153           0 :           return EOF;
     154             :         }
     155             : 
     156             :       /* If we have come to a non-option, either stop the scan or describe
     157             :          it to the caller and pass it by.  This makes the pseudo-option
     158             :          `-' mean the end of options, but does not skip over it. */
     159           0 :       if (temp[0] != '-' || temp[1] == '\0')
     160             :         return EOF;
     161             : 
     162             :       /* We have found another option-ARGV-element.
     163             :          Start decoding its characters.  */
     164           0 :       nextchar = argv[sh_curopt = sh_optind] + 1;
     165           0 :       sh_charindex = 1;
     166             :     }
     167             : 
     168             :   /* Look at and handle the next option-character.  */
     169             : 
     170           0 :   c = *nextchar++; sh_charindex++;
     171           0 :   temp = strchr (optstring, c);
     172             : 
     173           0 :   sh_optopt = c;
     174             : 
     175             :   /* Increment `sh_optind' when we start to process its last character.  */
     176           0 :   if (nextchar == 0 || *nextchar == '\0')
     177             :     {
     178           0 :       sh_optind++;
     179           0 :       nextchar = (char *)NULL;
     180             :     }
     181             : 
     182           0 :   if (sh_badopt = (temp == NULL || c == ':'))
     183             :     {
     184           0 :       if (sh_opterr)
     185           0 :         BADOPT (c);
     186             : 
     187           0 :       return '?';
     188             :     }
     189             : 
     190           0 :   if (temp[1] == ':')
     191             :     {
     192           0 :       if (nextchar && *nextchar)
     193             :         {
     194             :           /* This is an option that requires an argument.  */
     195           0 :           sh_optarg = nextchar;
     196             :           /* If we end this ARGV-element by taking the rest as an arg,
     197             :              we must advance to the next element now.  */
     198           0 :           sh_optind++;
     199             :         }
     200           0 :       else if (sh_optind == argc)
     201             :         {
     202           0 :           if (sh_opterr)
     203           0 :             NEEDARG (c);
     204             : 
     205           0 :           sh_optopt = c;
     206           0 :           sh_optarg = "";     /* Needed by getopts. */
     207           0 :           c = (optstring[0] == ':') ? ':' : '?';
     208             :         }
     209             :       else
     210             :         /* We already incremented `sh_optind' once;
     211             :            increment it again when taking next ARGV-elt as argument.  */
     212           0 :         sh_optarg = argv[sh_optind++];
     213           0 :       nextchar = (char *)NULL;
     214             :     }
     215           0 :   return c;
     216             : }
     217             : 
     218             : void
     219           0 : sh_getopt_restore_state (argv)
     220             :      char **argv;
     221             : {
     222           0 :   if (nextchar)
     223           0 :     nextchar = argv[sh_curopt] + sh_charindex;
     224           0 : }
     225             : 
     226             : sh_getopt_state_t *
     227           0 : sh_getopt_alloc_istate ()
     228             : {
     229        7489 :   sh_getopt_state_t *ret;
     230             : 
     231           0 :   ret = (sh_getopt_state_t *)xmalloc (sizeof (sh_getopt_state_t));
     232        7489 :   return ret;
     233             : }
     234             : 
     235             : void
     236           0 : sh_getopt_dispose_istate (gs)
     237             :      sh_getopt_state_t *gs;
     238             : {
     239           0 :   free (gs);
     240           0 : }
     241             : 
     242             : sh_getopt_state_t *
     243        7489 : sh_getopt_save_istate ()
     244             : {
     245        7489 :   sh_getopt_state_t *ret;
     246             : 
     247        7489 :   ret = sh_getopt_alloc_istate ();
     248             : 
     249        7489 :   ret->gs_optarg = sh_optarg;
     250        7489 :   ret->gs_optind = sh_optind;
     251        7489 :   ret->gs_curopt = sh_curopt;
     252        7489 :   ret->gs_nextchar = nextchar;               /* XXX */
     253        7489 :   ret->gs_charindex = sh_charindex;
     254        7489 :   ret->gs_flags = 0;                 /* XXX for later use */
     255             : 
     256        7489 :   return ret;
     257             : }
     258             : 
     259             : void
     260           0 : sh_getopt_restore_istate (state)
     261             :      sh_getopt_state_t *state;
     262             : {
     263           0 :   sh_optarg = state->gs_optarg;
     264           0 :   sh_optind = state->gs_optind;
     265           0 :   sh_curopt = state->gs_curopt;
     266           0 :   nextchar = state->gs_nextchar;     /* XXX - probably not usable */
     267           0 :   sh_charindex = state->gs_charindex;
     268             : 
     269           0 :   sh_getopt_dispose_istate (state);
     270           0 : }
     271             : 
     272             : #if 0
     273             : void
     274             : sh_getopt_debug_restore_state (argv)
     275             :      char **argv;
     276             : {
     277             :   if (nextchar && nextchar != argv[sh_curopt] + sh_charindex)
     278             :     {
     279             :       itrace("sh_getopt_debug_restore_state: resetting nextchar");
     280             :       nextchar = argv[sh_curopt] + sh_charindex;
     281             :     }
     282             : }
     283             : #endif
     284             :  
     285             : #ifdef TEST
     286             : 
     287             : /* Compile with -DTEST to make an executable for use in testing
     288             :    the above definition of `sh_getopt'.  */
     289             : 
     290             : int
     291             : main (argc, argv)
     292             :      int argc;
     293             :      char **argv;
     294             : {
     295             :   int c;
     296             :   int digit_sh_optind = 0;
     297             : 
     298             :   while (1)
     299             :     {
     300             :       int this_option_sh_optind = sh_optind ? sh_optind : 1;
     301             : 
     302             :       c = sh_getopt (argc, argv, "abc:d:0123456789");
     303             :       if (c == EOF)
     304             :         break;
     305             : 
     306             :       switch (c)
     307             :         {
     308             :         case '0':
     309             :         case '1':
     310             :         case '2':
     311             :         case '3':
     312             :         case '4':
     313             :         case '5':
     314             :         case '6':
     315             :         case '7':
     316             :         case '8':
     317             :         case '9':
     318             :           if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind)
     319             :             printf ("digits occur in two different argv-elements.\n");
     320             :           digit_sh_optind = this_option_sh_optind;
     321             :           printf ("option %c\n", c);
     322             :           break;
     323             : 
     324             :         case 'a':
     325             :           printf ("option a\n");
     326             :           break;
     327             : 
     328             :         case 'b':
     329             :           printf ("option b\n");
     330             :           break;
     331             : 
     332             :         case 'c':
     333             :           printf ("option c with value `%s'\n", sh_optarg);
     334             :           break;
     335             : 
     336             :         case '?':
     337             :           break;
     338             : 
     339             :         default:
     340             :           printf ("?? sh_getopt returned character code 0%o ??\n", c);
     341             :         }
     342             :     }
     343             : 
     344             :   if (sh_optind < argc)
     345             :     {
     346             :       printf ("non-option ARGV-elements: ");
     347             :       while (sh_optind < argc)
     348             :         printf ("%s ", argv[sh_optind++]);
     349             :       printf ("\n");
     350             :     }
     351             : 
     352             :   exit (0);
     353             : }
     354             : 
     355             : #endif /* TEST */

Generated by: LCOV version 1.14.0.6.4058