Blame lib/getopt.c

Packit Service a2489d
/* Getopt for GNU.
Packit Service a2489d
   Copyright (C) 1987-2018 Free Software Foundation, Inc.
Packit Service a2489d
   This file is part of the GNU C Library and is also part of gnulib.
Packit Service a2489d
   Patches to this file should be submitted to both projects.
Packit Service a2489d
Packit Service a2489d
   The GNU C Library is free software; you can redistribute it and/or
Packit Service a2489d
   modify it under the terms of the GNU General Public
Packit Service a2489d
   License as published by the Free Software Foundation; either
Packit Service a2489d
   version 3 of the License, or (at your option) any later version.
Packit Service a2489d
Packit Service a2489d
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service a2489d
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service a2489d
   General Public License for more details.
Packit Service a2489d
Packit Service a2489d
   You should have received a copy of the GNU General Public
Packit Service a2489d
   License along with the GNU C Library; if not, see
Packit Service a2489d
   <https://www.gnu.org/licenses/>.  */
Packit Service a2489d

Packit Service a2489d
#ifndef _LIBC
Packit Service a2489d
# include <config.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#include "getopt.h"
Packit Service a2489d
Packit Service a2489d
#include <stdio.h>
Packit Service a2489d
#include <stdlib.h>
Packit Service a2489d
#include <string.h>
Packit Service a2489d
#include <unistd.h>
Packit Service a2489d
Packit Service a2489d
#ifdef _LIBC
Packit Service a2489d
/* When used as part of glibc, error printing must be done differently
Packit Service a2489d
   for standards compliance.  getopt is not a cancellation point, so
Packit Service a2489d
   it must not call functions that are, and it is specified by an
Packit Service a2489d
   older standard than stdio locking, so it must not refer to
Packit Service a2489d
   functions in the "user namespace" related to stdio locking.
Packit Service a2489d
   Finally, it must use glibc's internal message translation so that
Packit Service a2489d
   the messages are looked up in the proper text domain.  */
Packit Service a2489d
# include <libintl.h>
Packit Service a2489d
# define fprintf __fxprintf_nocancel
Packit Service a2489d
# define flockfile(fp) _IO_flockfile (fp)
Packit Service a2489d
# define funlockfile(fp) _IO_funlockfile (fp)
Packit Service a2489d
#else
Packit Service a2489d
# include "gettext.h"
Packit Service a2489d
# define _(msgid) gettext (msgid)
Packit Service a2489d
/* When used standalone, flockfile and funlockfile might not be
Packit Service a2489d
   available.  */
Packit Service a2489d
# if (!defined _POSIX_THREAD_SAFE_FUNCTIONS \
Packit Service a2489d
      || (defined _WIN32 && ! defined __CYGWIN__))
Packit Service a2489d
#  define flockfile(fp) /* nop */
Packit Service a2489d
#  define funlockfile(fp) /* nop */
Packit Service a2489d
# endif
Packit Service a2489d
/* When used standalone, do not attempt to use alloca.  */
Packit Service a2489d
# define __libc_use_alloca(size) 0
Packit Service a2489d
# undef alloca
Packit Service a2489d
# define alloca(size) (abort (), (void *)0)
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
/* This implementation of 'getopt' has three modes for handling
Packit Service a2489d
   options interspersed with non-option arguments.  It can stop
Packit Service a2489d
   scanning for options at the first non-option argument encountered,
Packit Service a2489d
   as POSIX specifies.  It can continue scanning for options after the
Packit Service a2489d
   first non-option argument, but permute 'argv' as it goes so that,
Packit Service a2489d
   after 'getopt' is done, all the options precede all the non-option
Packit Service a2489d
   arguments and 'optind' points to the first non-option argument.
Packit Service a2489d
   Or, it can report non-option arguments as if they were arguments to
Packit Service a2489d
   the option character '\x01'.
Packit Service a2489d
Packit Service a2489d
   The default behavior of 'getopt_long' is to permute the argument list.
Packit Service a2489d
   When this implementation is used standalone, the default behavior of
Packit Service a2489d
   'getopt' is to stop at the first non-option argument, but when it is
Packit Service a2489d
   used as part of GNU libc it also permutes the argument list.  In both
Packit Service a2489d
   cases, setting the environment variable POSIXLY_CORRECT to any value
Packit Service a2489d
   disables permutation.
Packit Service a2489d
Packit Service a2489d
   If the first character of the OPTSTRING argument to 'getopt' or
Packit Service a2489d
   'getopt_long' is '+', both functions will stop at the first
Packit Service a2489d
   non-option argument.  If it is '-', both functions will report
Packit Service a2489d
   non-option arguments as arguments to the option character '\x01'.  */
Packit Service a2489d
Packit Service a2489d
#include "getopt_int.h"
Packit Service a2489d
Packit Service a2489d
/* For communication from 'getopt' to the caller.
Packit Service a2489d
   When 'getopt' finds an option that takes an argument,
Packit Service a2489d
   the argument value is returned here.
Packit Service a2489d
   Also, when 'ordering' is RETURN_IN_ORDER,
Packit Service a2489d
   each non-option ARGV-element is returned here.  */
Packit Service a2489d
Packit Service a2489d
char *optarg;
Packit Service a2489d
Packit Service a2489d
/* Index in ARGV of the next element to be scanned.
Packit Service a2489d
   This is used for communication to and from the caller
Packit Service a2489d
   and for communication between successive calls to 'getopt'.
Packit Service a2489d
Packit Service a2489d
   On entry to 'getopt', zero means this is the first call; initialize.
Packit Service a2489d
Packit Service a2489d
   When 'getopt' returns -1, this is the index of the first of the
Packit Service a2489d
   non-option elements that the caller should itself scan.
Packit Service a2489d
Packit Service a2489d
   Otherwise, 'optind' communicates from one call to the next
Packit Service a2489d
   how much of ARGV has been scanned so far.  */
Packit Service a2489d
Packit Service a2489d
/* 1003.2 says this must be 1 before any call.  */
Packit Service a2489d
int optind = 1;
Packit Service a2489d
Packit Service a2489d
/* Callers store zero here to inhibit the error message
Packit Service a2489d
   for unrecognized options.  */
Packit Service a2489d
Packit Service a2489d
int opterr = 1;
Packit Service a2489d
Packit Service a2489d
/* Set to an option character which was unrecognized.
Packit Service a2489d
   This must be initialized on some systems to avoid linking in the
Packit Service a2489d
   system's own getopt implementation.  */
Packit Service a2489d
Packit Service a2489d
int optopt = '?';
Packit Service a2489d
Packit Service a2489d
/* Keep a global copy of all internal members of getopt_data.  */
Packit Service a2489d
Packit Service a2489d
static struct _getopt_data getopt_data;
Packit Service a2489d

Packit Service a2489d
/* Exchange two adjacent subsequences of ARGV.
Packit Service a2489d
   One subsequence is elements [first_nonopt,last_nonopt)
Packit Service a2489d
   which contains all the non-options that have been skipped so far.
Packit Service a2489d
   The other is elements [last_nonopt,optind), which contains all
Packit Service a2489d
   the options processed since those non-options were skipped.
Packit Service a2489d
Packit Service a2489d
   'first_nonopt' and 'last_nonopt' are relocated so that they describe
Packit Service a2489d
   the new indices of the non-options in ARGV after they are moved.  */
Packit Service a2489d
Packit Service a2489d
static void
Packit Service a2489d
exchange (char **argv, struct _getopt_data *d)
Packit Service a2489d
{
Packit Service a2489d
  int bottom = d->__first_nonopt;
Packit Service a2489d
  int middle = d->__last_nonopt;
Packit Service a2489d
  int top = d->optind;
Packit Service a2489d
  char *tem;
Packit Service a2489d
Packit Service a2489d
  /* Exchange the shorter segment with the far end of the longer segment.
Packit Service a2489d
     That puts the shorter segment into the right place.
Packit Service a2489d
     It leaves the longer segment in the right place overall,
Packit Service a2489d
     but it consists of two parts that need to be swapped next.  */
Packit Service a2489d
Packit Service a2489d
  while (top > middle && middle > bottom)
Packit Service a2489d
    {
Packit Service a2489d
      if (top - middle > middle - bottom)
Packit Service a2489d
	{
Packit Service a2489d
	  /* Bottom segment is the short one.  */
Packit Service a2489d
	  int len = middle - bottom;
Packit Service a2489d
	  int i;
Packit Service a2489d
Packit Service a2489d
	  /* Swap it with the top part of the top segment.  */
Packit Service a2489d
	  for (i = 0; i < len; i++)
Packit Service a2489d
	    {
Packit Service a2489d
	      tem = argv[bottom + i];
Packit Service a2489d
	      argv[bottom + i] = argv[top - (middle - bottom) + i];
Packit Service a2489d
	      argv[top - (middle - bottom) + i] = tem;
Packit Service a2489d
	    }
Packit Service a2489d
	  /* Exclude the moved bottom segment from further swapping.  */
Packit Service a2489d
	  top -= len;
Packit Service a2489d
	}
Packit Service a2489d
      else
Packit Service a2489d
	{
Packit Service a2489d
	  /* Top segment is the short one.  */
Packit Service a2489d
	  int len = top - middle;
Packit Service a2489d
	  int i;
Packit Service a2489d
Packit Service a2489d
	  /* Swap it with the bottom part of the bottom segment.  */
Packit Service a2489d
	  for (i = 0; i < len; i++)
Packit Service a2489d
	    {
Packit Service a2489d
	      tem = argv[bottom + i];
Packit Service a2489d
	      argv[bottom + i] = argv[middle + i];
Packit Service a2489d
	      argv[middle + i] = tem;
Packit Service a2489d
	    }
Packit Service a2489d
	  /* Exclude the moved top segment from further swapping.  */
Packit Service a2489d
	  bottom += len;
Packit Service a2489d
	}
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  /* Update records for the slots the non-options now occupy.  */
Packit Service a2489d
Packit Service a2489d
  d->__first_nonopt += (d->optind - d->__last_nonopt);
Packit Service a2489d
  d->__last_nonopt = d->optind;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* Process the argument starting with d->__nextchar as a long option.
Packit Service a2489d
   d->optind should *not* have been advanced over this argument.
Packit Service a2489d
Packit Service a2489d
   If the value returned is -1, it was not actually a long option, the
Packit Service a2489d
   state is unchanged, and the argument should be processed as a set
Packit Service a2489d
   of short options (this can only happen when long_only is true).
Packit Service a2489d
   Otherwise, the option (and its argument, if any) have been consumed
Packit Service a2489d
   and the return value is the value to return from _getopt_internal_r.  */
Packit Service a2489d
static int
Packit Service a2489d
process_long_option (int argc, char **argv, const char *optstring,
Packit Service a2489d
		     const struct option *longopts, int *longind,
Packit Service a2489d
		     int long_only, struct _getopt_data *d,
Packit Service a2489d
		     int print_errors, const char *prefix)
Packit Service a2489d
{
Packit Service a2489d
  char *nameend;
Packit Service a2489d
  size_t namelen;
Packit Service a2489d
  const struct option *p;
Packit Service a2489d
  const struct option *pfound = NULL;
Packit Service a2489d
  int n_options;
Packit Service a2489d
  int option_index;
Packit Service a2489d
Packit Service a2489d
  for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
Packit Service a2489d
    /* Do nothing.  */ ;
Packit Service a2489d
  namelen = nameend - d->__nextchar;
Packit Service a2489d
Packit Service a2489d
  /* First look for an exact match, counting the options as a side
Packit Service a2489d
     effect.  */
Packit Service a2489d
  for (p = longopts, n_options = 0; p->name; p++, n_options++)
Packit Service a2489d
    if (!strncmp (p->name, d->__nextchar, namelen)
Packit Service a2489d
	&& namelen == strlen (p->name))
Packit Service a2489d
      {
Packit Service a2489d
	/* Exact match found.  */
Packit Service a2489d
	pfound = p;
Packit Service a2489d
	option_index = n_options;
Packit Service a2489d
	break;
Packit Service a2489d
      }
Packit Service a2489d
Packit Service a2489d
  if (pfound == NULL)
Packit Service a2489d
    {
Packit Service a2489d
      /* Didn't find an exact match, so look for abbreviations.  */
Packit Service a2489d
      unsigned char *ambig_set = NULL;
Packit Service a2489d
      int ambig_malloced = 0;
Packit Service a2489d
      int ambig_fallback = 0;
Packit Service a2489d
      int indfound = -1;
Packit Service a2489d
Packit Service a2489d
      for (p = longopts, option_index = 0; p->name; p++, option_index++)
Packit Service a2489d
	if (!strncmp (p->name, d->__nextchar, namelen))
Packit Service a2489d
	  {
Packit Service a2489d
	    if (pfound == NULL)
Packit Service a2489d
	      {
Packit Service a2489d
		/* First nonexact match found.  */
Packit Service a2489d
		pfound = p;
Packit Service a2489d
		indfound = option_index;
Packit Service a2489d
	      }
Packit Service a2489d
	    else if (long_only
Packit Service a2489d
		     || pfound->has_arg != p->has_arg
Packit Service a2489d
		     || pfound->flag != p->flag
Packit Service a2489d
		     || pfound->val != p->val)
Packit Service a2489d
	      {
Packit Service a2489d
		/* Second or later nonexact match found.  */
Packit Service a2489d
		if (!ambig_fallback)
Packit Service a2489d
		  {
Packit Service a2489d
		    if (!print_errors)
Packit Service a2489d
		      /* Don't waste effort tracking the ambig set if
Packit Service a2489d
			 we're not going to print it anyway.  */
Packit Service a2489d
		      ambig_fallback = 1;
Packit Service a2489d
		    else if (!ambig_set)
Packit Service a2489d
		      {
Packit Service a2489d
			if (__libc_use_alloca (n_options))
Packit Service a2489d
			  ambig_set = alloca (n_options);
Packit Service a2489d
			else if ((ambig_set = malloc (n_options)) == NULL)
Packit Service a2489d
			  /* Fall back to simpler error message.  */
Packit Service a2489d
			  ambig_fallback = 1;
Packit Service a2489d
			else
Packit Service a2489d
			  ambig_malloced = 1;
Packit Service a2489d
Packit Service a2489d
			if (ambig_set)
Packit Service a2489d
			  {
Packit Service a2489d
			    memset (ambig_set, 0, n_options);
Packit Service a2489d
			    ambig_set[indfound] = 1;
Packit Service a2489d
			  }
Packit Service a2489d
		      }
Packit Service a2489d
		    if (ambig_set)
Packit Service a2489d
		      ambig_set[option_index] = 1;
Packit Service a2489d
		  }
Packit Service a2489d
	      }
Packit Service a2489d
	  }
Packit Service a2489d
Packit Service a2489d
      if (ambig_set || ambig_fallback)
Packit Service a2489d
	{
Packit Service a2489d
	  if (print_errors)
Packit Service a2489d
	    {
Packit Service a2489d
	      if (ambig_fallback)
Packit Service a2489d
		fprintf (stderr, _("%s: option '%s%s' is ambiguous\n"),
Packit Service a2489d
			 argv[0], prefix, d->__nextchar);
Packit Service a2489d
	      else
Packit Service a2489d
		{
Packit Service a2489d
		  flockfile (stderr);
Packit Service a2489d
		  fprintf (stderr,
Packit Service a2489d
			   _("%s: option '%s%s' is ambiguous; possibilities:"),
Packit Service a2489d
			   argv[0], prefix, d->__nextchar);
Packit Service a2489d
Packit Service a2489d
		  for (option_index = 0; option_index < n_options; option_index++)
Packit Service a2489d
		    if (ambig_set[option_index])
Packit Service a2489d
		      fprintf (stderr, " '%s%s'",
Packit Service a2489d
			       prefix, longopts[option_index].name);
Packit Service a2489d
Packit Service a2489d
		  /* This must use 'fprintf' even though it's only
Packit Service a2489d
		     printing a single character, so that it goes through
Packit Service a2489d
		     __fxprintf_nocancel when compiled as part of glibc.  */
Packit Service a2489d
		  fprintf (stderr, "\n");
Packit Service a2489d
		  funlockfile (stderr);
Packit Service a2489d
		}
Packit Service a2489d
	    }
Packit Service a2489d
	  if (ambig_malloced)
Packit Service a2489d
	    free (ambig_set);
Packit Service a2489d
	  d->__nextchar += strlen (d->__nextchar);
Packit Service a2489d
	  d->optind++;
Packit Service a2489d
	  d->optopt = 0;
Packit Service a2489d
	  return '?';
Packit Service a2489d
	}
Packit Service a2489d
Packit Service a2489d
      option_index = indfound;
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  if (pfound == NULL)
Packit Service a2489d
    {
Packit Service a2489d
      /* Can't find it as a long option.  If this is not getopt_long_only,
Packit Service a2489d
	 or the option starts with '--' or is not a valid short option,
Packit Service a2489d
	 then it's an error.  */
Packit Service a2489d
      if (!long_only || argv[d->optind][1] == '-'
Packit Service a2489d
	  || strchr (optstring, *d->__nextchar) == NULL)
Packit Service a2489d
	{
Packit Service a2489d
	  if (print_errors)
Packit Service a2489d
	    fprintf (stderr, _("%s: unrecognized option '%s%s'\n"),
Packit Service a2489d
		     argv[0], prefix, d->__nextchar);
Packit Service a2489d
Packit Service a2489d
	  d->__nextchar = NULL;
Packit Service a2489d
	  d->optind++;
Packit Service a2489d
	  d->optopt = 0;
Packit Service a2489d
	  return '?';
Packit Service a2489d
	}
Packit Service a2489d
Packit Service a2489d
      /* Otherwise interpret it as a short option.  */
Packit Service a2489d
      return -1;
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  /* We have found a matching long option.  Consume it.  */
Packit Service a2489d
  d->optind++;
Packit Service a2489d
  d->__nextchar = NULL;
Packit Service a2489d
  if (*nameend)
Packit Service a2489d
    {
Packit Service a2489d
      /* Don't test has_arg with >, because some C compilers don't
Packit Service a2489d
	 allow it to be used on enums.  */
Packit Service a2489d
      if (pfound->has_arg)
Packit Service a2489d
	d->optarg = nameend + 1;
Packit Service a2489d
      else
Packit Service a2489d
	{
Packit Service a2489d
	  if (print_errors)
Packit Service a2489d
	    fprintf (stderr,
Packit Service a2489d
		     _("%s: option '%s%s' doesn't allow an argument\n"),
Packit Service a2489d
		     argv[0], prefix, pfound->name);
Packit Service a2489d
Packit Service a2489d
	  d->optopt = pfound->val;
Packit Service a2489d
	  return '?';
Packit Service a2489d
	}
Packit Service a2489d
    }
Packit Service a2489d
  else if (pfound->has_arg == 1)
Packit Service a2489d
    {
Packit Service a2489d
      if (d->optind < argc)
Packit Service a2489d
	d->optarg = argv[d->optind++];
Packit Service a2489d
      else
Packit Service a2489d
	{
Packit Service a2489d
	  if (print_errors)
Packit Service a2489d
	    fprintf (stderr,
Packit Service a2489d
		     _("%s: option '%s%s' requires an argument\n"),
Packit Service a2489d
		     argv[0], prefix, pfound->name);
Packit Service a2489d
Packit Service a2489d
	  d->optopt = pfound->val;
Packit Service a2489d
	  return optstring[0] == ':' ? ':' : '?';
Packit Service a2489d
	}
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  if (longind != NULL)
Packit Service a2489d
    *longind = option_index;
Packit Service a2489d
  if (pfound->flag)
Packit Service a2489d
    {
Packit Service a2489d
      *(pfound->flag) = pfound->val;
Packit Service a2489d
      return 0;
Packit Service a2489d
    }
Packit Service a2489d
  return pfound->val;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* Initialize internal data upon the first call to getopt.  */
Packit Service a2489d
Packit Service a2489d
static const char *
Packit Service a2489d
_getopt_initialize (int argc _GL_UNUSED,
Packit Service a2489d
		    char **argv _GL_UNUSED, const char *optstring,
Packit Service a2489d
		    struct _getopt_data *d, int posixly_correct)
Packit Service a2489d
{
Packit Service a2489d
  /* Start processing options with ARGV-element 1 (since ARGV-element 0
Packit Service a2489d
     is the program name); the sequence of previously skipped
Packit Service a2489d
     non-option ARGV-elements is empty.  */
Packit Service a2489d
  if (d->optind == 0)
Packit Service a2489d
    d->optind = 1;
Packit Service a2489d
Packit Service a2489d
  d->__first_nonopt = d->__last_nonopt = d->optind;
Packit Service a2489d
  d->__nextchar = NULL;
Packit Service a2489d
Packit Service a2489d
  /* Determine how to handle the ordering of options and nonoptions.  */
Packit Service a2489d
  if (optstring[0] == '-')
Packit Service a2489d
    {
Packit Service a2489d
      d->__ordering = RETURN_IN_ORDER;
Packit Service a2489d
      ++optstring;
Packit Service a2489d
    }
Packit Service a2489d
  else if (optstring[0] == '+')
Packit Service a2489d
    {
Packit Service a2489d
      d->__ordering = REQUIRE_ORDER;
Packit Service a2489d
      ++optstring;
Packit Service a2489d
    }
Packit Service a2489d
  else if (posixly_correct || !!getenv ("POSIXLY_CORRECT"))
Packit Service a2489d
    d->__ordering = REQUIRE_ORDER;
Packit Service a2489d
  else
Packit Service a2489d
    d->__ordering = PERMUTE;
Packit Service a2489d
Packit Service a2489d
  d->__initialized = 1;
Packit Service a2489d
  return optstring;
Packit Service a2489d
}
Packit Service a2489d

Packit Service a2489d
/* Scan elements of ARGV (whose length is ARGC) for option characters
Packit Service a2489d
   given in OPTSTRING.
Packit Service a2489d
Packit Service a2489d
   If an element of ARGV starts with '-', and is not exactly "-" or "--",
Packit Service a2489d
   then it is an option element.  The characters of this element
Packit Service a2489d
   (aside from the initial '-') are option characters.  If 'getopt'
Packit Service a2489d
   is called repeatedly, it returns successively each of the option characters
Packit Service a2489d
   from each of the option elements.
Packit Service a2489d
Packit Service a2489d
   If 'getopt' finds another option character, it returns that character,
Packit Service a2489d
   updating 'optind' and 'nextchar' so that the next call to 'getopt' can
Packit Service a2489d
   resume the scan with the following option character or ARGV-element.
Packit Service a2489d
Packit Service a2489d
   If there are no more option characters, 'getopt' returns -1.
Packit Service a2489d
   Then 'optind' is the index in ARGV of the first ARGV-element
Packit Service a2489d
   that is not an option.  (The ARGV-elements have been permuted
Packit Service a2489d
   so that those that are not options now come last.)
Packit Service a2489d
Packit Service a2489d
   OPTSTRING is a string containing the legitimate option characters.
Packit Service a2489d
   If an option character is seen that is not listed in OPTSTRING,
Packit Service a2489d
   return '?' after printing an error message.  If you set 'opterr' to
Packit Service a2489d
   zero, the error message is suppressed but we still return '?'.
Packit Service a2489d
Packit Service a2489d
   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
Packit Service a2489d
   so the following text in the same ARGV-element, or the text of the following
Packit Service a2489d
   ARGV-element, is returned in 'optarg'.  Two colons mean an option that
Packit Service a2489d
   wants an optional arg; if there is text in the current ARGV-element,
Packit Service a2489d
   it is returned in 'optarg', otherwise 'optarg' is set to zero.
Packit Service a2489d
Packit Service a2489d
   If OPTSTRING starts with '-' or '+', it requests different methods of
Packit Service a2489d
   handling the non-option ARGV-elements.
Packit Service a2489d
   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Packit Service a2489d
Packit Service a2489d
   Long-named options begin with '--' instead of '-'.
Packit Service a2489d
   Their names may be abbreviated as long as the abbreviation is unique
Packit Service a2489d
   or is an exact match for some defined option.  If they have an
Packit Service a2489d
   argument, it follows the option name in the same ARGV-element, separated
Packit Service a2489d
   from the option name by a '=', or else the in next ARGV-element.
Packit Service a2489d
   When 'getopt' finds a long-named option, it returns 0 if that option's
Packit Service a2489d
   'flag' field is nonzero, the value of the option's 'val' field
Packit Service a2489d
   if the 'flag' field is zero.
Packit Service a2489d
Packit Service a2489d
   The elements of ARGV aren't really const, because we permute them.
Packit Service a2489d
   But we pretend they're const in the prototype to be compatible
Packit Service a2489d
   with other systems.
Packit Service a2489d
Packit Service a2489d
   LONGOPTS is a vector of 'struct option' terminated by an
Packit Service a2489d
   element containing a name which is zero.
Packit Service a2489d
Packit Service a2489d
   LONGIND returns the index in LONGOPT of the long-named option found.
Packit Service a2489d
   It is only valid when a long-named option has been found by the most
Packit Service a2489d
   recent call.
Packit Service a2489d
Packit Service a2489d
   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
Packit Service a2489d
   long-named options.  */
Packit Service a2489d
Packit Service a2489d
int
Packit Service a2489d
_getopt_internal_r (int argc, char **argv, const char *optstring,
Packit Service a2489d
		    const struct option *longopts, int *longind,
Packit Service a2489d
		    int long_only, struct _getopt_data *d, int posixly_correct)
Packit Service a2489d
{
Packit Service a2489d
  int print_errors = d->opterr;
Packit Service a2489d
Packit Service a2489d
  if (argc < 1)
Packit Service a2489d
    return -1;
Packit Service a2489d
Packit Service a2489d
  d->optarg = NULL;
Packit Service a2489d
Packit Service a2489d
  if (d->optind == 0 || !d->__initialized)
Packit Service a2489d
    optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct);
Packit Service a2489d
  else if (optstring[0] == '-' || optstring[0] == '+')
Packit Service a2489d
    optstring++;
Packit Service a2489d
Packit Service a2489d
  if (optstring[0] == ':')
Packit Service a2489d
    print_errors = 0;
Packit Service a2489d
Packit Service a2489d
  /* Test whether ARGV[optind] points to a non-option argument.  */
Packit Service a2489d
#define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')
Packit Service a2489d
Packit Service a2489d
  if (d->__nextchar == NULL || *d->__nextchar == '\0')
Packit Service a2489d
    {
Packit Service a2489d
      /* Advance to the next ARGV-element.  */
Packit Service a2489d
Packit Service a2489d
      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
Packit Service a2489d
	 moved back by the user (who may also have changed the arguments).  */
Packit Service a2489d
      if (d->__last_nonopt > d->optind)
Packit Service a2489d
	d->__last_nonopt = d->optind;
Packit Service a2489d
      if (d->__first_nonopt > d->optind)
Packit Service a2489d
	d->__first_nonopt = d->optind;
Packit Service a2489d
Packit Service a2489d
      if (d->__ordering == PERMUTE)
Packit Service a2489d
	{
Packit Service a2489d
	  /* If we have just processed some options following some non-options,
Packit Service a2489d
	     exchange them so that the options come first.  */
Packit Service a2489d
Packit Service a2489d
	  if (d->__first_nonopt != d->__last_nonopt
Packit Service a2489d
	      && d->__last_nonopt != d->optind)
Packit Service a2489d
	    exchange (argv, d);
Packit Service a2489d
	  else if (d->__last_nonopt != d->optind)
Packit Service a2489d
	    d->__first_nonopt = d->optind;
Packit Service a2489d
Packit Service a2489d
	  /* Skip any additional non-options
Packit Service a2489d
	     and extend the range of non-options previously skipped.  */
Packit Service a2489d
Packit Service a2489d
	  while (d->optind < argc && NONOPTION_P)
Packit Service a2489d
	    d->optind++;
Packit Service a2489d
	  d->__last_nonopt = d->optind;
Packit Service a2489d
	}
Packit Service a2489d
Packit Service a2489d
      /* The special ARGV-element '--' means premature end of options.
Packit Service a2489d
	 Skip it like a null option,
Packit Service a2489d
	 then exchange with previous non-options as if it were an option,
Packit Service a2489d
	 then skip everything else like a non-option.  */
Packit Service a2489d
Packit Service a2489d
      if (d->optind != argc && !strcmp (argv[d->optind], "--"))
Packit Service a2489d
	{
Packit Service a2489d
	  d->optind++;
Packit Service a2489d
Packit Service a2489d
	  if (d->__first_nonopt != d->__last_nonopt
Packit Service a2489d
	      && d->__last_nonopt != d->optind)
Packit Service a2489d
	    exchange (argv, d);
Packit Service a2489d
	  else if (d->__first_nonopt == d->__last_nonopt)
Packit Service a2489d
	    d->__first_nonopt = d->optind;
Packit Service a2489d
	  d->__last_nonopt = argc;
Packit Service a2489d
Packit Service a2489d
	  d->optind = argc;
Packit Service a2489d
	}
Packit Service a2489d
Packit Service a2489d
      /* If we have done all the ARGV-elements, stop the scan
Packit Service a2489d
	 and back over any non-options that we skipped and permuted.  */
Packit Service a2489d
Packit Service a2489d
      if (d->optind == argc)
Packit Service a2489d
	{
Packit Service a2489d
	  /* Set the next-arg-index to point at the non-options
Packit Service a2489d
	     that we previously skipped, so the caller will digest them.  */
Packit Service a2489d
	  if (d->__first_nonopt != d->__last_nonopt)
Packit Service a2489d
	    d->optind = d->__first_nonopt;
Packit Service a2489d
	  return -1;
Packit Service a2489d
	}
Packit Service a2489d
Packit Service a2489d
      /* If we have come to a non-option and did not permute it,
Packit Service a2489d
	 either stop the scan or describe it to the caller and pass it by.  */
Packit Service a2489d
Packit Service a2489d
      if (NONOPTION_P)
Packit Service a2489d
	{
Packit Service a2489d
	  if (d->__ordering == REQUIRE_ORDER)
Packit Service a2489d
	    return -1;
Packit Service a2489d
	  d->optarg = argv[d->optind++];
Packit Service a2489d
	  return 1;
Packit Service a2489d
	}
Packit Service a2489d
Packit Service a2489d
      /* We have found another option-ARGV-element.
Packit Service a2489d
	 Check whether it might be a long option.  */
Packit Service a2489d
      if (longopts)
Packit Service a2489d
	{
Packit Service a2489d
	  if (argv[d->optind][1] == '-')
Packit Service a2489d
	    {
Packit Service a2489d
	      /* "--foo" is always a long option.  The special option
Packit Service a2489d
		 "--" was handled above.  */
Packit Service a2489d
	      d->__nextchar = argv[d->optind] + 2;
Packit Service a2489d
	      return process_long_option (argc, argv, optstring, longopts,
Packit Service a2489d
					  longind, long_only, d,
Packit Service a2489d
					  print_errors, "--");
Packit Service a2489d
	    }
Packit Service a2489d
Packit Service a2489d
	  /* If long_only and the ARGV-element has the form "-f",
Packit Service a2489d
	     where f is a valid short option, don't consider it an
Packit Service a2489d
	     abbreviated form of a long option that starts with f.
Packit Service a2489d
	     Otherwise there would be no way to give the -f short
Packit Service a2489d
	     option.
Packit Service a2489d
Packit Service a2489d
	     On the other hand, if there's a long option "fubar" and
Packit Service a2489d
	     the ARGV-element is "-fu", do consider that an
Packit Service a2489d
	     abbreviation of the long option, just like "--fu", and
Packit Service a2489d
	     not "-f" with arg "u".
Packit Service a2489d
Packit Service a2489d
	     This distinction seems to be the most useful approach.  */
Packit Service a2489d
	  if (long_only && (argv[d->optind][2]
Packit Service a2489d
			    || !strchr (optstring, argv[d->optind][1])))
Packit Service a2489d
	    {
Packit Service a2489d
	      int code;
Packit Service a2489d
	      d->__nextchar = argv[d->optind] + 1;
Packit Service a2489d
	      code = process_long_option (argc, argv, optstring, longopts,
Packit Service a2489d
					  longind, long_only, d,
Packit Service a2489d
					  print_errors, "-");
Packit Service a2489d
	      if (code != -1)
Packit Service a2489d
		return code;
Packit Service a2489d
	    }
Packit Service a2489d
	}
Packit Service a2489d
Packit Service a2489d
      /* It is not a long option.  Skip the initial punctuation.  */
Packit Service a2489d
      d->__nextchar = argv[d->optind] + 1;
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  /* Look at and handle the next short option-character.  */
Packit Service a2489d
Packit Service a2489d
  {
Packit Service a2489d
    char c = *d->__nextchar++;
Packit Service a2489d
    const char *temp = strchr (optstring, c);
Packit Service a2489d
Packit Service a2489d
    /* Increment 'optind' when we start to process its last character.  */
Packit Service a2489d
    if (*d->__nextchar == '\0')
Packit Service a2489d
      ++d->optind;
Packit Service a2489d
Packit Service a2489d
    if (temp == NULL || c == ':' || c == ';')
Packit Service a2489d
      {
Packit Service a2489d
	if (print_errors)
Packit Service a2489d
	  fprintf (stderr, _("%s: invalid option -- '%c'\n"), argv[0], c);
Packit Service a2489d
	d->optopt = c;
Packit Service a2489d
	return '?';
Packit Service a2489d
      }
Packit Service a2489d
Packit Service a2489d
    /* Convenience. Treat POSIX -W foo same as long option --foo */
Packit Service a2489d
    if (temp[0] == 'W' && temp[1] == ';' && longopts != NULL)
Packit Service a2489d
      {
Packit Service a2489d
	/* This is an option that requires an argument.  */
Packit Service a2489d
	if (*d->__nextchar != '\0')
Packit Service a2489d
	  d->optarg = d->__nextchar;
Packit Service a2489d
	else if (d->optind == argc)
Packit Service a2489d
	  {
Packit Service a2489d
	    if (print_errors)
Packit Service a2489d
	      fprintf (stderr,
Packit Service a2489d
		       _("%s: option requires an argument -- '%c'\n"),
Packit Service a2489d
		       argv[0], c);
Packit Service a2489d
Packit Service a2489d
	    d->optopt = c;
Packit Service a2489d
	    if (optstring[0] == ':')
Packit Service a2489d
	      c = ':';
Packit Service a2489d
	    else
Packit Service a2489d
	      c = '?';
Packit Service a2489d
	    return c;
Packit Service a2489d
	  }
Packit Service a2489d
	else
Packit Service a2489d
	  d->optarg = argv[d->optind];
Packit Service a2489d
Packit Service a2489d
	d->__nextchar = d->optarg;
Packit Service a2489d
	d->optarg = NULL;
Packit Service a2489d
	return process_long_option (argc, argv, optstring, longopts, longind,
Packit Service a2489d
				    0 /* long_only */, d, print_errors, "-W ");
Packit Service a2489d
      }
Packit Service a2489d
    if (temp[1] == ':')
Packit Service a2489d
      {
Packit Service a2489d
	if (temp[2] == ':')
Packit Service a2489d
	  {
Packit Service a2489d
	    /* This is an option that accepts an argument optionally.  */
Packit Service a2489d
	    if (*d->__nextchar != '\0')
Packit Service a2489d
	      {
Packit Service a2489d
		d->optarg = d->__nextchar;
Packit Service a2489d
		d->optind++;
Packit Service a2489d
	      }
Packit Service a2489d
	    else
Packit Service a2489d
	      d->optarg = NULL;
Packit Service a2489d
	    d->__nextchar = NULL;
Packit Service a2489d
	  }
Packit Service a2489d
	else
Packit Service a2489d
	  {
Packit Service a2489d
	    /* This is an option that requires an argument.  */
Packit Service a2489d
	    if (*d->__nextchar != '\0')
Packit Service a2489d
	      {
Packit Service a2489d
		d->optarg = d->__nextchar;
Packit Service a2489d
		/* If we end this ARGV-element by taking the rest as an arg,
Packit Service a2489d
		   we must advance to the next element now.  */
Packit Service a2489d
		d->optind++;
Packit Service a2489d
	      }
Packit Service a2489d
	    else if (d->optind == argc)
Packit Service a2489d
	      {
Packit Service a2489d
		if (print_errors)
Packit Service a2489d
		  fprintf (stderr,
Packit Service a2489d
			   _("%s: option requires an argument -- '%c'\n"),
Packit Service a2489d
			   argv[0], c);
Packit Service a2489d
Packit Service a2489d
		d->optopt = c;
Packit Service a2489d
		if (optstring[0] == ':')
Packit Service a2489d
		  c = ':';
Packit Service a2489d
		else
Packit Service a2489d
		  c = '?';
Packit Service a2489d
	      }
Packit Service a2489d
	    else
Packit Service a2489d
	      /* We already incremented 'optind' once;
Packit Service a2489d
		 increment it again when taking next ARGV-elt as argument.  */
Packit Service a2489d
	      d->optarg = argv[d->optind++];
Packit Service a2489d
	    d->__nextchar = NULL;
Packit Service a2489d
	  }
Packit Service a2489d
      }
Packit Service a2489d
    return c;
Packit Service a2489d
  }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int
Packit Service a2489d
_getopt_internal (int argc, char **argv, const char *optstring,
Packit Service a2489d
		  const struct option *longopts, int *longind, int long_only,
Packit Service a2489d
		  int posixly_correct)
Packit Service a2489d
{
Packit Service a2489d
  int result;
Packit Service a2489d
Packit Service a2489d
  getopt_data.optind = optind;
Packit Service a2489d
  getopt_data.opterr = opterr;
Packit Service a2489d
Packit Service a2489d
  result = _getopt_internal_r (argc, argv, optstring, longopts,
Packit Service a2489d
			       longind, long_only, &getopt_data,
Packit Service a2489d
			       posixly_correct);
Packit Service a2489d
Packit Service a2489d
  optind = getopt_data.optind;
Packit Service a2489d
  optarg = getopt_data.optarg;
Packit Service a2489d
  optopt = getopt_data.optopt;
Packit Service a2489d
Packit Service a2489d
  return result;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* glibc gets a LSB-compliant getopt and a POSIX-complaint __posix_getopt.
Packit Service a2489d
   Standalone applications just get a POSIX-compliant getopt.
Packit Service a2489d
   POSIX and LSB both require these functions to take 'char *const *argv'
Packit Service a2489d
   even though this is incorrect (because of the permutation).  */
Packit Service a2489d
#define GETOPT_ENTRY(NAME, POSIXLY_CORRECT)			\
Packit Service a2489d
  int								\
Packit Service a2489d
  NAME (int argc, char *const *argv, const char *optstring)	\
Packit Service a2489d
  {								\
Packit Service a2489d
    return _getopt_internal (argc, (char **)argv, optstring,	\
Packit Service a2489d
			     0, 0, 0, POSIXLY_CORRECT);		\
Packit Service a2489d
  }
Packit Service a2489d
Packit Service a2489d
#ifdef _LIBC
Packit Service a2489d
GETOPT_ENTRY(getopt, 0)
Packit Service a2489d
GETOPT_ENTRY(__posix_getopt, 1)
Packit Service a2489d
#else
Packit Service a2489d
GETOPT_ENTRY(getopt, 1)
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d

Packit Service a2489d
#ifdef TEST
Packit Service a2489d
Packit Service a2489d
/* Compile with -DTEST to make an executable for use in testing
Packit Service a2489d
   the above definition of 'getopt'.  */
Packit Service a2489d
Packit Service a2489d
int
Packit Service a2489d
main (int argc, char **argv)
Packit Service a2489d
{
Packit Service a2489d
  int c;
Packit Service a2489d
  int digit_optind = 0;
Packit Service a2489d
Packit Service a2489d
  while (1)
Packit Service a2489d
    {
Packit Service a2489d
      int this_option_optind = optind ? optind : 1;
Packit Service a2489d
Packit Service a2489d
      c = getopt (argc, argv, "abc:d:0123456789");
Packit Service a2489d
      if (c == -1)
Packit Service a2489d
	break;
Packit Service a2489d
Packit Service a2489d
      switch (c)
Packit Service a2489d
	{
Packit Service a2489d
	case '0':
Packit Service a2489d
	case '1':
Packit Service a2489d
	case '2':
Packit Service a2489d
	case '3':
Packit Service a2489d
	case '4':
Packit Service a2489d
	case '5':
Packit Service a2489d
	case '6':
Packit Service a2489d
	case '7':
Packit Service a2489d
	case '8':
Packit Service a2489d
	case '9':
Packit Service a2489d
	  if (digit_optind != 0 && digit_optind != this_option_optind)
Packit Service a2489d
	    printf ("digits occur in two different argv-elements.\n");
Packit Service a2489d
	  digit_optind = this_option_optind;
Packit Service a2489d
	  printf ("option %c\n", c);
Packit Service a2489d
	  break;
Packit Service a2489d
Packit Service a2489d
	case 'a':
Packit Service a2489d
	  printf ("option a\n");
Packit Service a2489d
	  break;
Packit Service a2489d
Packit Service a2489d
	case 'b':
Packit Service a2489d
	  printf ("option b\n");
Packit Service a2489d
	  break;
Packit Service a2489d
Packit Service a2489d
	case 'c':
Packit Service a2489d
	  printf ("option c with value '%s'\n", optarg);
Packit Service a2489d
	  break;
Packit Service a2489d
Packit Service a2489d
	case '?':
Packit Service a2489d
	  break;
Packit Service a2489d
Packit Service a2489d
	default:
Packit Service a2489d
	  printf ("?? getopt returned character code 0%o ??\n", c);
Packit Service a2489d
	}
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  if (optind < argc)
Packit Service a2489d
    {
Packit Service a2489d
      printf ("non-option ARGV-elements: ");
Packit Service a2489d
      while (optind < argc)
Packit Service a2489d
	printf ("%s ", argv[optind++]);
Packit Service a2489d
      printf ("\n");
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  exit (0);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#endif /* TEST */