Blame lib/getopt.c

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