LCOV - code coverage report
Current view: top level - builtins - getopts.def (source / functions) Hit Total Coverage
Test: cov-sh.info Lines: 4 112 3.6 %
Date: 2020-10-29 14:49:55 Functions: 1 4 25.0 %

          Line data    Source code
       1             : This file is getopts.def, from which is created getopts.c.
       2             : It implements the builtin "getopts" in Bash.
       3             : 
       4             : Copyright (C) 1987-2015 Free Software Foundation, Inc.
       5             : 
       6             : This file is part of GNU Bash, the Bourne Again SHell.
       7             : 
       8             : Bash is free software: you can redistribute it and/or modify
       9             : it under the terms of the GNU General Public License as published by
      10             : the Free Software Foundation, either version 3 of the License, or
      11             : (at your option) any later version.
      12             : 
      13             : Bash is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      20             : 
      21             : $PRODUCES getopts.c
      22             : 
      23             : $BUILTIN getopts
      24             : $FUNCTION getopts_builtin
      25             : $SHORT_DOC getopts optstring name [arg]
      26             : Parse option arguments.
      27             : 
      28             : Getopts is used by shell procedures to parse positional parameters
      29             : as options.
      30             : 
      31             : OPTSTRING contains the option letters to be recognized; if a letter
      32             : is followed by a colon, the option is expected to have an argument,
      33             : which should be separated from it by white space.
      34             : 
      35             : Each time it is invoked, getopts will place the next option in the
      36             : shell variable $name, initializing name if it does not exist, and
      37             : the index of the next argument to be processed into the shell
      38             : variable OPTIND.  OPTIND is initialized to 1 each time the shell or
      39             : a shell script is invoked.  When an option requires an argument,
      40             : getopts places that argument into the shell variable OPTARG.
      41             : 
      42             : getopts reports errors in one of two ways.  If the first character
      43             : of OPTSTRING is a colon, getopts uses silent error reporting.  In
      44             : this mode, no error messages are printed.  If an invalid option is
      45             : seen, getopts places the option character found into OPTARG.  If a
      46             : required argument is not found, getopts places a ':' into NAME and
      47             : sets OPTARG to the option character found.  If getopts is not in
      48             : silent mode, and an invalid option is seen, getopts places '?' into
      49             : NAME and unsets OPTARG.  If a required argument is not found, a '?'
      50             : is placed in NAME, OPTARG is unset, and a diagnostic message is
      51             : printed.
      52             : 
      53             : If the shell variable OPTERR has the value 0, getopts disables the
      54             : printing of error messages, even if the first character of
      55             : OPTSTRING is not a colon.  OPTERR has the value 1 by default.
      56             : 
      57             : Getopts normally parses the positional parameters ($0 - $9), but if
      58             : more arguments are given, they are parsed instead.
      59             : 
      60             : Exit Status:
      61             : Returns success if an option is found; fails if the end of options is
      62             : encountered or an error occurs.
      63             : $END
      64             : 
      65             : #include <config.h>
      66             : 
      67             : #include <stdio.h>
      68             : 
      69             : #if defined (HAVE_UNISTD_H)
      70             : #  ifdef _MINIX
      71             : #    include <sys/types.h>
      72             : #  endif
      73             : #  include <unistd.h>
      74             : #endif
      75             : 
      76             : #include "../bashansi.h"
      77             : #include "../bashintl.h"
      78             : 
      79             : #include "../shell.h"
      80             : #include "common.h"
      81             : #include "bashgetopt.h"
      82             : #include "getopt.h"
      83             : 
      84             : #define G_EOF           -1
      85             : #define G_INVALID_OPT   -2
      86             : #define G_ARG_MISSING   -3
      87             : 
      88             : extern char *this_command_name;
      89             : 
      90             : static int getopts_unbind_variable __P((char *));
      91             : static int getopts_bind_variable __P((char *, char *));
      92             : static int dogetopts __P((int, char **));
      93             : 
      94             : /* getopts_reset is magic code for when OPTIND is reset.  N is the
      95             :    value that has just been assigned to OPTIND. */
      96             : void
      97     9542939 : getopts_reset (newind)
      98             :      int newind;
      99             : {
     100     9542939 :   sh_optind = newind;
     101     9542939 :   sh_badopt = 0;
     102     9542939 : }
     103             : 
     104             : static int
     105             : getopts_unbind_variable (name)
     106             :      char *name;
     107             : {
     108             : #if 0
     109             :   return (unbind_variable (name));
     110             : #else
     111           0 :   return (unbind_variable_noref (name));
     112             : #endif
     113             : }
     114             : 
     115             : static int
     116           0 : getopts_bind_variable (name, value)
     117             :      char *name, *value;
     118             : {
     119           0 :   SHELL_VAR *v;
     120             : 
     121           0 :   if (legal_identifier (name))
     122             :     {
     123           0 :       v = bind_variable (name, value, 0);
     124           0 :       if (v && (readonly_p (v) || noassign_p (v)))
     125             :         return (EX_MISCERROR);
     126           0 :       return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
     127             :     }
     128             :   else
     129             :     {
     130           0 :       sh_invalidid (name);
     131           0 :       return (EXECUTION_FAILURE);
     132             :     }
     133             : }
     134             : 
     135             : /* Error handling is now performed as specified by Posix.2, draft 11
     136             :    (identical to that of ksh-88).  The special handling is enabled if
     137             :    the first character of the option string is a colon; this handling
     138             :    disables diagnostic messages concerning missing option arguments
     139             :    and invalid option characters.  The handling is as follows.
     140             : 
     141             :    INVALID OPTIONS:
     142             :         name -> "?"
     143             :         if (special_error) then
     144             :                 OPTARG = option character found
     145             :                 no error output
     146             :         else
     147             :                 OPTARG unset
     148             :                 diagnostic message
     149             :         fi
     150             :  
     151             :   MISSING OPTION ARGUMENT;
     152             :         if (special_error) then
     153             :                 name -> ":"
     154             :                 OPTARG = option character found
     155             :         else
     156             :                 name -> "?"
     157             :                 OPTARG unset
     158             :                 diagnostic message
     159             :         fi
     160             :  */
     161             : 
     162             : static int
     163           0 : dogetopts (argc, argv)
     164             :      int argc;
     165             :      char **argv;
     166             : {
     167           0 :   int ret, special_error, old_opterr, i, n;
     168           0 :   char strval[2], numval[16];
     169           0 :   char *optstr;                 /* list of options */
     170           0 :   char *name;                   /* variable to get flag val */
     171           0 :   char *t;
     172             : 
     173           0 :   if (argc < 3)
     174             :     {
     175           0 :       builtin_usage ();
     176           0 :       return (EX_USAGE);
     177             :     }
     178             : 
     179             :   /* argv[0] is "getopts". */
     180             : 
     181           0 :   optstr = argv[1];
     182           0 :   name = argv[2];
     183           0 :   argc -= 2;
     184           0 :   argv += 2;
     185             : 
     186           0 :   special_error = optstr[0] == ':';
     187             : 
     188           0 :   if (special_error)
     189             :     {
     190           0 :       old_opterr = sh_opterr;
     191           0 :       optstr++;
     192           0 :       sh_opterr = 0;            /* suppress diagnostic messages */
     193             :     }
     194             : 
     195           0 :   if (argc > 1)
     196             :     {
     197           0 :       sh_getopt_restore_state (argv);
     198           0 :       t = argv[0];
     199           0 :       argv[0] = dollar_vars[0];
     200           0 :       ret = sh_getopt (argc, argv, optstr);
     201           0 :       argv[0] = t;
     202             :     }
     203           0 :   else if (rest_of_args == (WORD_LIST *)NULL)
     204             :     {
     205           0 :       for (i = 0; i < 10 && dollar_vars[i]; i++)
     206           0 :         ;
     207             : 
     208           0 :       sh_getopt_restore_state (dollar_vars);
     209           0 :       ret = sh_getopt (i, dollar_vars, optstr);
     210             :     }
     211             :   else
     212             :     {
     213             :       register WORD_LIST *words;
     214             :       char **v;
     215             : 
     216           0 :       for (i = 0; i < 10 && dollar_vars[i]; i++)
     217           0 :         ;
     218           0 :       for (words = rest_of_args; words; words = words->next, i++)
     219           0 :         ;
     220           0 :       v = strvec_create (i + 1);
     221           0 :       for (i = 0; i < 10 && dollar_vars[i]; i++)
     222           0 :         v[i] = dollar_vars[i];
     223           0 :       for (words = rest_of_args; words; words = words->next, i++)
     224           0 :         v[i] = words->word->word;
     225           0 :       v[i] = (char *)NULL;
     226           0 :       sh_getopt_restore_state (v);
     227           0 :       ret = sh_getopt (i, v, optstr);
     228           0 :       free (v);
     229             :     }
     230             : 
     231           0 :   if (special_error)
     232           0 :     sh_opterr = old_opterr;
     233             : 
     234             :   /* Set the OPTIND variable in any case, to handle "--" skipping.  It's
     235             :      highly unlikely that 14 digits will be too few. */
     236           0 :   if (sh_optind < 10)
     237             :     {
     238           0 :       numval[14] = sh_optind + '0';
     239           0 :       numval[15] = '\0';
     240           0 :       i = 14;
     241             :     }
     242             :   else
     243             :     {
     244           0 :       numval[i = 15] = '\0';
     245           0 :       n = sh_optind;
     246           0 :       do
     247             :         {
     248           0 :           numval[--i] = (n % 10) + '0';
     249             :         }
     250           0 :       while (n /= 10);
     251             :     }
     252           0 :   bind_variable ("OPTIND", numval + i, 0);
     253             : 
     254             :   /* If an error occurred, decide which one it is and set the return
     255             :      code appropriately.  In all cases, the option character in error
     256             :      is in OPTOPT.  If an invalid option was encountered, OPTARG is
     257             :      NULL.  If a required option argument was missing, OPTARG points
     258             :      to a NULL string (that is, sh_optarg[0] == 0). */
     259           0 :   if (ret == '?')
     260             :     {
     261           0 :       if (sh_optarg == NULL)
     262             :         ret = G_INVALID_OPT;
     263           0 :       else if (sh_optarg[0] == '\0')
     264             :         ret = G_ARG_MISSING;
     265             :     }
     266             :             
     267           0 :   if (ret == G_EOF)
     268             :     {
     269           0 :       getopts_unbind_variable ("OPTARG");
     270           0 :       getopts_bind_variable (name, "?");
     271           0 :       return (EXECUTION_FAILURE);
     272             :     }
     273             : 
     274           0 :   if (ret == G_INVALID_OPT)
     275             :     {
     276             :       /* Invalid option encountered. */
     277           0 :       ret = getopts_bind_variable (name, "?");
     278             : 
     279           0 :       if (special_error)
     280             :         {
     281           0 :           strval[0] = (char)sh_optopt;
     282           0 :           strval[1] = '\0';
     283           0 :           bind_variable ("OPTARG", strval, 0);
     284             :         }
     285             :       else
     286           0 :         getopts_unbind_variable ("OPTARG");
     287             : 
     288           0 :       return (ret);
     289             :     }
     290             : 
     291           0 :   if (ret == G_ARG_MISSING)
     292             :     {
     293             :       /* Required argument missing. */
     294           0 :       if (special_error)
     295             :         {
     296           0 :           ret = getopts_bind_variable (name, ":");
     297             : 
     298           0 :           strval[0] = (char)sh_optopt;
     299           0 :           strval[1] = '\0';
     300           0 :           bind_variable ("OPTARG", strval, 0);
     301             :         }
     302             :       else
     303             :         {
     304           0 :           ret = getopts_bind_variable (name, "?");
     305           0 :           getopts_unbind_variable ("OPTARG");
     306             :         }
     307           0 :       return (ret);
     308             :     }                   
     309             : 
     310           0 :   bind_variable ("OPTARG", sh_optarg, 0);
     311             : 
     312           0 :   strval[0] = (char) ret;
     313           0 :   strval[1] = '\0';
     314           0 :   return (getopts_bind_variable (name, strval));
     315             : }
     316             : 
     317             : /* The getopts builtin.  Build an argv, and call dogetopts with it. */
     318             : int
     319           0 : getopts_builtin (list)
     320             :      WORD_LIST *list;
     321             : {
     322           0 :   char **av;
     323           0 :   int ac, ret;
     324             : 
     325           0 :   if (list == 0)
     326             :     {
     327           0 :       builtin_usage ();
     328           0 :       return EX_USAGE;
     329             :     }
     330             : 
     331           0 :   reset_internal_getopt ();
     332           0 :   if ((ret = internal_getopt (list, "")) != -1)
     333             :     {
     334           0 :       if (ret == GETOPT_HELP)
     335           0 :         builtin_help ();
     336             :       else
     337           0 :         builtin_usage ();
     338           0 :       return (EX_USAGE);
     339             :     }
     340           0 :   list = loptend;
     341             : 
     342           0 :   av = make_builtin_argv (list, &ac);
     343           0 :   ret = dogetopts (ac, av);
     344           0 :   free ((char *)av);
     345             : 
     346           0 :   return (ret);
     347             : }

Generated by: LCOV version 1.14.0.6.4058