Blame argp/argp-help.c

Packit 6c4009
/* Hierarchial argument parsing help output
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Written by Miles Bader <miles@gnu.ai.mit.edu>.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifndef _GNU_SOURCE
Packit 6c4009
# define _GNU_SOURCE	1
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef HAVE_CONFIG_H
Packit 6c4009
#include <config.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* AIX requires this to be the first thing in the file.  */
Packit 6c4009
#ifndef __GNUC__
Packit 6c4009
# if HAVE_ALLOCA_H || defined _LIBC
Packit 6c4009
#  include <alloca.h>
Packit 6c4009
# else
Packit 6c4009
#  ifdef _AIX
Packit 6c4009
#pragma alloca
Packit 6c4009
#  else
Packit 6c4009
#   ifndef alloca /* predefined by HP cc +Olibcalls */
Packit 6c4009
char *alloca ();
Packit 6c4009
#   endif
Packit 6c4009
#  endif
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <stdarg.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# include <../libio/libioP.h>
Packit 6c4009
# include <wchar.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef _
Packit 6c4009
/* This is for other GNU distributions with internationalized messages.  */
Packit 6c4009
# if defined HAVE_LIBINTL_H || defined _LIBC
Packit 6c4009
#  include <libintl.h>
Packit 6c4009
#  ifdef _LIBC
Packit 6c4009
#   undef dgettext
Packit 6c4009
#   define dgettext(domain, msgid) \
Packit 6c4009
  __dcgettext (domain, msgid, LC_MESSAGES)
Packit 6c4009
#  endif
Packit 6c4009
# else
Packit 6c4009
#  define dgettext(domain, msgid) (msgid)
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef _LIBC
Packit 6c4009
# if HAVE_STRERROR_R
Packit 6c4009
#  if !HAVE_DECL_STRERROR_R
Packit 6c4009
char *strerror_r (int errnum, char *buf, size_t buflen);
Packit 6c4009
#  endif
Packit 6c4009
# else
Packit 6c4009
#  if !HAVE_DECL_STRERROR
Packit 6c4009
char *strerror (int errnum);
Packit 6c4009
#  endif
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <argp.h>
Packit 6c4009
#include <argp-fmtstream.h>
Packit 6c4009
#include "argp-namefrob.h"
Packit 6c4009
Packit 6c4009
#ifndef SIZE_MAX
Packit 6c4009
# define SIZE_MAX ((size_t) -1)
Packit 6c4009
#endif
Packit 6c4009

Packit 6c4009
/* User-selectable (using an environment variable) formatting parameters.
Packit 6c4009
Packit 6c4009
   These may be specified in an environment variable called `ARGP_HELP_FMT',
Packit 6c4009
   with a contents like:  VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2
Packit 6c4009
   Where VALn must be a positive integer.  The list of variables is in the
Packit 6c4009
   UPARAM_NAMES vector, below.  */
Packit 6c4009
Packit 6c4009
/* Default parameters.  */
Packit 6c4009
#define DUP_ARGS      0		/* True if option argument can be duplicated. */
Packit 6c4009
#define DUP_ARGS_NOTE 1		/* True to print a note about duplicate args. */
Packit 6c4009
#define SHORT_OPT_COL 2		/* column in which short options start */
Packit 6c4009
#define LONG_OPT_COL  6		/* column in which long options start */
Packit 6c4009
#define DOC_OPT_COL   2		/* column in which doc options start */
Packit 6c4009
#define OPT_DOC_COL  29		/* column in which option text starts */
Packit 6c4009
#define HEADER_COL    1		/* column in which group headers are printed */
Packit 6c4009
#define USAGE_INDENT 12		/* indentation of wrapped usage lines */
Packit 6c4009
#define RMARGIN      79		/* right margin used for wrapping */
Packit 6c4009
Packit 6c4009
/* User-selectable (using an environment variable) formatting parameters.
Packit 6c4009
   They must all be of type `int' for the parsing code to work.  */
Packit 6c4009
struct uparams
Packit 6c4009
{
Packit 6c4009
  /* If true, arguments for an option are shown with both short and long
Packit 6c4009
     options, even when a given option has both, e.g. `-x ARG, --longx=ARG'.
Packit 6c4009
     If false, then if an option has both, the argument is only shown with
Packit 6c4009
     the long one, e.g., `-x, --longx=ARG', and a message indicating that
Packit 6c4009
     this really means both is printed below the options.  */
Packit 6c4009
  int dup_args;
Packit 6c4009
Packit 6c4009
  /* This is true if when DUP_ARGS is false, and some duplicate arguments have
Packit 6c4009
     been suppressed, an explanatory message should be printed.  */
Packit 6c4009
  int dup_args_note;
Packit 6c4009
Packit 6c4009
  /* Various output columns.  */
Packit 6c4009
  int short_opt_col;
Packit 6c4009
  int long_opt_col;
Packit 6c4009
  int doc_opt_col;
Packit 6c4009
  int opt_doc_col;
Packit 6c4009
  int header_col;
Packit 6c4009
  int usage_indent;
Packit 6c4009
  int rmargin;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* This is a global variable, as user options are only ever read once.  */
Packit 6c4009
static struct uparams uparams = {
Packit 6c4009
  DUP_ARGS, DUP_ARGS_NOTE,
Packit 6c4009
  SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
Packit 6c4009
  USAGE_INDENT, RMARGIN
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* A particular uparam, and what the user name is.  */
Packit 6c4009
struct uparam_name
Packit 6c4009
{
Packit 6c4009
  const char name[14];		/* User name.  */
Packit 6c4009
  bool is_bool;			/* Whether it's `boolean'.  */
Packit 6c4009
  uint8_t uparams_offs;		/* Location of the (int) field in UPARAMS.  */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* The name-field mappings we know about.  */
Packit 6c4009
static const struct uparam_name uparam_names[] =
Packit 6c4009
{
Packit 6c4009
  { "dup-args",       true, offsetof (struct uparams, dup_args) },
Packit 6c4009
  { "dup-args-note",  true, offsetof (struct uparams, dup_args_note) },
Packit 6c4009
  { "short-opt-col",  false, offsetof (struct uparams, short_opt_col) },
Packit 6c4009
  { "long-opt-col",   false, offsetof (struct uparams, long_opt_col) },
Packit 6c4009
  { "doc-opt-col",    false, offsetof (struct uparams, doc_opt_col) },
Packit 6c4009
  { "opt-doc-col",    false, offsetof (struct uparams, opt_doc_col) },
Packit 6c4009
  { "header-col",     false, offsetof (struct uparams, header_col) },
Packit 6c4009
  { "usage-indent",   false, offsetof (struct uparams, usage_indent) },
Packit 6c4009
  { "rmargin",        false, offsetof (struct uparams, rmargin) }
Packit 6c4009
};
Packit 6c4009
#define nuparam_names (sizeof (uparam_names) / sizeof (uparam_names[0]))
Packit 6c4009
Packit 6c4009
/* Read user options from the environment, and fill in UPARAMS appropriately.  */
Packit 6c4009
static void
Packit 6c4009
fill_in_uparams (const struct argp_state *state)
Packit 6c4009
{
Packit 6c4009
  const char *var = getenv ("ARGP_HELP_FMT");
Packit 6c4009
Packit 6c4009
#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0);
Packit 6c4009
Packit 6c4009
  if (var)
Packit 6c4009
    /* Parse var. */
Packit 6c4009
    while (*var)
Packit 6c4009
      {
Packit 6c4009
	SKIPWS (var);
Packit 6c4009
Packit 6c4009
	if (isalpha (*var))
Packit 6c4009
	  {
Packit 6c4009
	    size_t var_len;
Packit 6c4009
	    const struct uparam_name *un;
Packit 6c4009
	    int unspec = 0, val = 0;
Packit 6c4009
	    const char *arg = var;
Packit 6c4009
Packit 6c4009
	    while (isalnum (*arg) || *arg == '-' || *arg == '_')
Packit 6c4009
	      arg++;
Packit 6c4009
	    var_len = arg - var;
Packit 6c4009
Packit 6c4009
	    SKIPWS (arg);
Packit 6c4009
Packit 6c4009
	    if (*arg == '\0' || *arg == ',')
Packit 6c4009
	      unspec = 1;
Packit 6c4009
	    else if (*arg == '=')
Packit 6c4009
	      {
Packit 6c4009
		arg++;
Packit 6c4009
		SKIPWS (arg);
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    if (unspec)
Packit 6c4009
	      {
Packit 6c4009
		if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
Packit 6c4009
		  {
Packit 6c4009
		    val = 0;
Packit 6c4009
		    var += 3;
Packit 6c4009
		    var_len -= 3;
Packit 6c4009
		  }
Packit 6c4009
		else
Packit 6c4009
		  val = 1;
Packit 6c4009
	      }
Packit 6c4009
	    else if (isdigit (*arg))
Packit 6c4009
	      {
Packit 6c4009
		val = atoi (arg);
Packit 6c4009
		while (isdigit (*arg))
Packit 6c4009
		  arg++;
Packit 6c4009
		SKIPWS (arg);
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    un = uparam_names;
Packit 6c4009
	    size_t u;
Packit 6c4009
	    for (u = 0; u < nuparam_names; ++un, ++u)
Packit 6c4009
	      if (strlen (un->name) == var_len
Packit 6c4009
		  && strncmp (var, un->name, var_len) == 0)
Packit 6c4009
		{
Packit 6c4009
		  if (unspec && !un->is_bool)
Packit 6c4009
		    __argp_failure (state, 0, 0,
Packit 6c4009
				    dgettext (state == NULL ? NULL
Packit 6c4009
					      : state->root_argp->argp_domain,
Packit 6c4009
					      "\
Packit 6c4009
%.*s: ARGP_HELP_FMT parameter requires a value"),
Packit 6c4009
				    (int) var_len, var);
Packit 6c4009
		  else
Packit 6c4009
		    *(int *)((char *)&uparams + un->uparams_offs) = val;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	    if (u == nuparam_names)
Packit 6c4009
	      __argp_failure (state, 0, 0,
Packit 6c4009
			      dgettext (state == NULL ? NULL
Packit 6c4009
					: state->root_argp->argp_domain, "\
Packit 6c4009
%.*s: Unknown ARGP_HELP_FMT parameter"),
Packit 6c4009
			      (int) var_len, var);
Packit 6c4009
Packit 6c4009
	    var = arg;
Packit 6c4009
	    if (*var == ',')
Packit 6c4009
	      var++;
Packit 6c4009
	  }
Packit 6c4009
	else if (*var)
Packit 6c4009
	  {
Packit 6c4009
	    __argp_failure (state, 0, 0,
Packit 6c4009
			    dgettext (state == NULL ? NULL
Packit 6c4009
				      : state->root_argp->argp_domain,
Packit 6c4009
				      "Garbage in ARGP_HELP_FMT: %s"), var);
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Returns true if OPT hasn't been marked invisible.  Visibility only affects
Packit 6c4009
   whether OPT is displayed or used in sorting, not option shadowing.  */
Packit 6c4009
#define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN))
Packit 6c4009
Packit 6c4009
/* Returns true if OPT is an alias for an earlier option.  */
Packit 6c4009
#define oalias(opt) ((opt)->flags & OPTION_ALIAS)
Packit 6c4009
Packit 6c4009
/* Returns true if OPT is an documentation-only entry.  */
Packit 6c4009
#define odoc(opt) ((opt)->flags & OPTION_DOC)
Packit 6c4009
Packit 6c4009
/* Returns true if OPT is the end-of-list marker for a list of options.  */
Packit 6c4009
#define oend(opt) __option_is_end (opt)
Packit 6c4009
Packit 6c4009
/* Returns true if OPT has a short option.  */
Packit 6c4009
#define oshort(opt) __option_is_short (opt)
Packit 6c4009

Packit 6c4009
/*
Packit 6c4009
   The help format for a particular option is like:
Packit 6c4009
Packit 6c4009
     -xARG, -yARG, --long1=ARG, --long2=ARG        Documentation...
Packit 6c4009
Packit 6c4009
   Where ARG will be omitted if there's no argument, for this option, or
Packit 6c4009
   will be surrounded by "[" and "]" appropriately if the argument is
Packit 6c4009
   optional.  The documentation string is word-wrapped appropriately, and if
Packit 6c4009
   the list of options is long enough, it will be started on a separate line.
Packit 6c4009
   If there are no short options for a given option, the first long option is
Packit 6c4009
   indented slightly in a way that's supposed to make most long options appear
Packit 6c4009
   to be in a separate column.
Packit 6c4009
Packit 6c4009
   For example, the following output (from ps):
Packit 6c4009
Packit 6c4009
     -p PID, --pid=PID          List the process PID
Packit 6c4009
	 --pgrp=PGRP            List processes in the process group PGRP
Packit 6c4009
     -P, -x, --no-parent        Include processes without parents
Packit 6c4009
     -Q, --all-fields           Don't elide unusable fields (normally if there's
Packit 6c4009
				some reason ps can't print a field for any
Packit 6c4009
				process, it's removed from the output entirely)
Packit 6c4009
     -r, --reverse, --gratuitously-long-reverse-option
Packit 6c4009
				Reverse the order of any sort
Packit 6c4009
	 --session[=SID]        Add the processes from the session SID (which
Packit 6c4009
				defaults to the sid of the current process)
Packit 6c4009
Packit 6c4009
    Here are some more options:
Packit 6c4009
     -f ZOT, --foonly=ZOT       Glork a foonly
Packit 6c4009
     -z, --zaza                 Snit a zar
Packit 6c4009
Packit 6c4009
     -?, --help                 Give this help list
Packit 6c4009
	 --usage                Give a short usage message
Packit 6c4009
     -V, --version              Print program version
Packit 6c4009
Packit 6c4009
   The struct argp_option array for the above could look like:
Packit 6c4009
Packit 6c4009
   {
Packit 6c4009
     {"pid",       'p',      "PID",  0, "List the process PID"},
Packit 6c4009
     {"pgrp",      OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"},
Packit 6c4009
     {"no-parent", 'P',	      0,     0, "Include processes without parents"},
Packit 6c4009
     {0,           'x',       0,     OPTION_ALIAS},
Packit 6c4009
     {"all-fields",'Q',       0,     0, "Don't elide unusable fields (normally"
Packit 6c4009
					" if there's some reason ps can't"
Packit 6c4009
					" print a field for any process, it's"
Packit 6c4009
					" removed from the output entirely)" },
Packit 6c4009
     {"reverse",   'r',       0,     0, "Reverse the order of any sort"},
Packit 6c4009
     {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
Packit 6c4009
     {"session",   OPT_SESS,  "SID", OPTION_ARG_OPTIONAL,
Packit 6c4009
					"Add the processes from the session"
Packit 6c4009
					" SID (which defaults to the sid of"
Packit 6c4009
					" the current process)" },
Packit 6c4009
Packit 6c4009
     {0,0,0,0, "Here are some more options:"},
Packit 6c4009
     {"foonly", 'f', "ZOT", 0, "Glork a foonly"},
Packit 6c4009
     {"zaza", 'z', 0, 0, "Snit a zar"},
Packit 6c4009
Packit 6c4009
     {0}
Packit 6c4009
   }
Packit 6c4009
Packit 6c4009
   Note that the last three options are automatically supplied by argp_parse,
Packit 6c4009
   unless you tell it not to with ARGP_NO_HELP.
Packit 6c4009
Packit 6c4009
*/
Packit 6c4009

Packit 6c4009
/* Returns true if CH occurs between BEG and END.  */
Packit 6c4009
static int
Packit 6c4009
find_char (char ch, char *beg, char *end)
Packit 6c4009
{
Packit 6c4009
  while (beg < end)
Packit 6c4009
    if (*beg == ch)
Packit 6c4009
      return 1;
Packit 6c4009
    else
Packit 6c4009
      beg++;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
struct hol_cluster;		/* fwd decl */
Packit 6c4009
Packit 6c4009
struct hol_entry
Packit 6c4009
{
Packit 6c4009
  /* First option.  */
Packit 6c4009
  const struct argp_option *opt;
Packit 6c4009
  /* Number of options (including aliases).  */
Packit 6c4009
  unsigned num;
Packit 6c4009
Packit 6c4009
  /* A pointers into the HOL's short_options field, to the first short option
Packit 6c4009
     letter for this entry.  The order of the characters following this point
Packit 6c4009
     corresponds to the order of options pointed to by OPT, and there are at
Packit 6c4009
     most NUM.  A short option recorded in an option following OPT is only
Packit 6c4009
     valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's
Packit 6c4009
     probably been shadowed by some other entry).  */
Packit 6c4009
  char *short_options;
Packit 6c4009
Packit 6c4009
  /* Entries are sorted by their group first, in the order:
Packit 6c4009
       1, 2, ..., n, 0, -m, ..., -2, -1
Packit 6c4009
     and then alphabetically within each group.  The default is 0.  */
Packit 6c4009
  int group;
Packit 6c4009
Packit 6c4009
  /* The cluster of options this entry belongs to, or 0 if none.  */
Packit 6c4009
  struct hol_cluster *cluster;
Packit 6c4009
Packit 6c4009
  /* The argp from which this option came.  */
Packit 6c4009
  const struct argp *argp;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* A cluster of entries to reflect the argp tree structure.  */
Packit 6c4009
struct hol_cluster
Packit 6c4009
{
Packit 6c4009
  /* A descriptive header printed before options in this cluster.  */
Packit 6c4009
  const char *header;
Packit 6c4009
Packit 6c4009
  /* Used to order clusters within the same group with the same parent,
Packit 6c4009
     according to the order in which they occurred in the parent argp's child
Packit 6c4009
     list.  */
Packit 6c4009
  int index;
Packit 6c4009
Packit 6c4009
  /* How to sort this cluster with respect to options and other clusters at the
Packit 6c4009
     same depth (clusters always follow options in the same group).  */
Packit 6c4009
  int group;
Packit 6c4009
Packit 6c4009
  /* The cluster to which this cluster belongs, or 0 if it's at the base
Packit 6c4009
     level.  */
Packit 6c4009
  struct hol_cluster *parent;
Packit 6c4009
Packit 6c4009
  /* The argp from which this cluster is (eventually) derived.  */
Packit 6c4009
  const struct argp *argp;
Packit 6c4009
Packit 6c4009
  /* The distance this cluster is from the root.  */
Packit 6c4009
  int depth;
Packit 6c4009
Packit 6c4009
  /* Clusters in a given hol are kept in a linked list, to make freeing them
Packit 6c4009
     possible.  */
Packit 6c4009
  struct hol_cluster *next;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* A list of options for help.  */
Packit 6c4009
struct hol
Packit 6c4009
{
Packit 6c4009
  /* An array of hol_entry's.  */
Packit 6c4009
  struct hol_entry *entries;
Packit 6c4009
  /* The number of entries in this hol.  If this field is zero, the others
Packit 6c4009
     are undefined.  */
Packit 6c4009
  unsigned num_entries;
Packit 6c4009
Packit 6c4009
  /* A string containing all short options in this HOL.  Each entry contains
Packit 6c4009
     pointers into this string, so the order can't be messed with blindly.  */
Packit 6c4009
  char *short_options;
Packit 6c4009
Packit 6c4009
  /* Clusters of entries in this hol.  */
Packit 6c4009
  struct hol_cluster *clusters;
Packit 6c4009
};
Packit 6c4009

Packit 6c4009
/* Create a struct hol from the options in ARGP.  CLUSTER is the
Packit 6c4009
   hol_cluster in which these entries occur, or 0, if at the root.  */
Packit 6c4009
static struct hol *
Packit 6c4009
make_hol (const struct argp *argp, struct hol_cluster *cluster)
Packit 6c4009
{
Packit 6c4009
  char *so;
Packit 6c4009
  const struct argp_option *o;
Packit 6c4009
  const struct argp_option *opts = argp->options;
Packit 6c4009
  struct hol_entry *entry;
Packit 6c4009
  unsigned num_short_options = 0;
Packit 6c4009
  struct hol *hol = malloc (sizeof (struct hol));
Packit 6c4009
Packit 6c4009
  assert (hol);
Packit 6c4009
Packit 6c4009
  hol->num_entries = 0;
Packit 6c4009
  hol->clusters = 0;
Packit 6c4009
Packit 6c4009
  if (opts)
Packit 6c4009
    {
Packit 6c4009
      int cur_group = 0;
Packit 6c4009
Packit 6c4009
      /* The first option must not be an alias.  */
Packit 6c4009
      assert (! oalias (opts));
Packit 6c4009
Packit 6c4009
      /* Calculate the space needed.  */
Packit 6c4009
      for (o = opts; ! oend (o); o++)
Packit 6c4009
	{
Packit 6c4009
	  if (! oalias (o))
Packit 6c4009
	    hol->num_entries++;
Packit 6c4009
	  if (oshort (o))
Packit 6c4009
	    num_short_options++;	/* This is an upper bound.  */
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries);
Packit 6c4009
      hol->short_options = malloc (num_short_options + 1);
Packit 6c4009
Packit 6c4009
      assert (hol->entries && hol->short_options);
Packit 6c4009
#if SIZE_MAX <= UINT_MAX
Packit 6c4009
      assert (hol->num_entries <= SIZE_MAX / sizeof (struct hol_entry));
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      /* Fill in the entries.  */
Packit 6c4009
      so = hol->short_options;
Packit 6c4009
      for (o = opts, entry = hol->entries; ! oend (o); entry++)
Packit 6c4009
	{
Packit 6c4009
	  entry->opt = o;
Packit 6c4009
	  entry->num = 0;
Packit 6c4009
	  entry->short_options = so;
Packit 6c4009
	  entry->group = cur_group =
Packit 6c4009
	    o->group
Packit 6c4009
	    ? o->group
Packit 6c4009
	    : ((!o->name && !o->key)
Packit 6c4009
	       ? cur_group + 1
Packit 6c4009
	       : cur_group);
Packit 6c4009
	  entry->cluster = cluster;
Packit 6c4009
	  entry->argp = argp;
Packit 6c4009
Packit 6c4009
	  do
Packit 6c4009
	    {
Packit 6c4009
	      entry->num++;
Packit 6c4009
	      if (oshort (o) && ! find_char (o->key, hol->short_options, so))
Packit 6c4009
		/* O has a valid short option which hasn't already been used.*/
Packit 6c4009
		*so++ = o->key;
Packit 6c4009
	      o++;
Packit 6c4009
	    }
Packit 6c4009
	  while (! oend (o) && oalias (o));
Packit 6c4009
	}
Packit 6c4009
      *so = '\0';		/* null terminated so we can find the length */
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return hol;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the
Packit 6c4009
   associated argp child list entry), INDEX, and PARENT, and return a pointer
Packit 6c4009
   to it.  ARGP is the argp that this cluster results from.  */
Packit 6c4009
static struct hol_cluster *
Packit 6c4009
hol_add_cluster (struct hol *hol, int group, const char *header, int index,
Packit 6c4009
		 struct hol_cluster *parent, const struct argp *argp)
Packit 6c4009
{
Packit 6c4009
  struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
Packit 6c4009
  if (cl)
Packit 6c4009
    {
Packit 6c4009
      cl->group = group;
Packit 6c4009
      cl->header = header;
Packit 6c4009
Packit 6c4009
      cl->index = index;
Packit 6c4009
      cl->parent = parent;
Packit 6c4009
      cl->argp = argp;
Packit 6c4009
      cl->depth = parent ? parent->depth + 1 : 0;
Packit 6c4009
Packit 6c4009
      cl->next = hol->clusters;
Packit 6c4009
      hol->clusters = cl;
Packit 6c4009
    }
Packit 6c4009
  return cl;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Free HOL and any resources it uses.  */
Packit 6c4009
static void
Packit 6c4009
hol_free (struct hol *hol)
Packit 6c4009
{
Packit 6c4009
  struct hol_cluster *cl = hol->clusters;
Packit 6c4009
Packit 6c4009
  while (cl)
Packit 6c4009
    {
Packit 6c4009
      struct hol_cluster *next = cl->next;
Packit 6c4009
      free (cl);
Packit 6c4009
      cl = next;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (hol->num_entries > 0)
Packit 6c4009
    {
Packit 6c4009
      free (hol->entries);
Packit 6c4009
      free (hol->short_options);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  free (hol);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
static int
Packit 6c4009
hol_entry_short_iterate (const struct hol_entry *entry,
Packit 6c4009
			 int (*func)(const struct argp_option *opt,
Packit 6c4009
				     const struct argp_option *real,
Packit 6c4009
				     const char *domain, void *cookie),
Packit 6c4009
			 const char *domain, void *cookie)
Packit 6c4009
{
Packit 6c4009
  unsigned nopts;
Packit 6c4009
  int val = 0;
Packit 6c4009
  const struct argp_option *opt, *real = entry->opt;
Packit 6c4009
  char *so = entry->short_options;
Packit 6c4009
Packit 6c4009
  for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
Packit 6c4009
    if (oshort (opt) && *so == opt->key)
Packit 6c4009
      {
Packit 6c4009
	if (!oalias (opt))
Packit 6c4009
	  real = opt;
Packit 6c4009
	if (ovisible (opt))
Packit 6c4009
	  val = (*func)(opt, real, domain, cookie);
Packit 6c4009
	so++;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  return val;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute__ ((always_inline))
Packit 6c4009
hol_entry_long_iterate (const struct hol_entry *entry,
Packit 6c4009
			int (*func)(const struct argp_option *opt,
Packit 6c4009
				    const struct argp_option *real,
Packit 6c4009
				    const char *domain, void *cookie),
Packit 6c4009
			const char *domain, void *cookie)
Packit 6c4009
{
Packit 6c4009
  unsigned nopts;
Packit 6c4009
  int val = 0;
Packit 6c4009
  const struct argp_option *opt, *real = entry->opt;
Packit 6c4009
Packit 6c4009
  for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
Packit 6c4009
    if (opt->name)
Packit 6c4009
      {
Packit 6c4009
	if (!oalias (opt))
Packit 6c4009
	  real = opt;
Packit 6c4009
	if (ovisible (opt))
Packit 6c4009
	  val = (*func)(opt, real, domain, cookie);
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  return val;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Iterator that returns true for the first short option.  */
Packit 6c4009
static inline int
Packit 6c4009
until_short (const struct argp_option *opt, const struct argp_option *real,
Packit 6c4009
	     const char *domain, void *cookie)
Packit 6c4009
{
Packit 6c4009
  return oshort (opt) ? opt->key : 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Returns the first valid short option in ENTRY, or 0 if there is none.  */
Packit 6c4009
static char
Packit 6c4009
hol_entry_first_short (const struct hol_entry *entry)
Packit 6c4009
{
Packit 6c4009
  return hol_entry_short_iterate (entry, until_short,
Packit 6c4009
				  entry->argp->argp_domain, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Returns the first valid long option in ENTRY, or 0 if there is none.  */
Packit 6c4009
static const char *
Packit 6c4009
hol_entry_first_long (const struct hol_entry *entry)
Packit 6c4009
{
Packit 6c4009
  const struct argp_option *opt;
Packit 6c4009
  unsigned num;
Packit 6c4009
  for (opt = entry->opt, num = entry->num; num > 0; opt++, num--)
Packit 6c4009
    if (opt->name && ovisible (opt))
Packit 6c4009
      return opt->name;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Returns the entry in HOL with the long option name NAME, or 0 if there is
Packit 6c4009
   none.  */
Packit 6c4009
static struct hol_entry *
Packit 6c4009
hol_find_entry (struct hol *hol, const char *name)
Packit 6c4009
{
Packit 6c4009
  struct hol_entry *entry = hol->entries;
Packit 6c4009
  unsigned num_entries = hol->num_entries;
Packit 6c4009
Packit 6c4009
  while (num_entries-- > 0)
Packit 6c4009
    {
Packit 6c4009
      const struct argp_option *opt = entry->opt;
Packit 6c4009
      unsigned num_opts = entry->num;
Packit 6c4009
Packit 6c4009
      while (num_opts-- > 0)
Packit 6c4009
	if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0)
Packit 6c4009
	  return entry;
Packit 6c4009
	else
Packit 6c4009
	  opt++;
Packit 6c4009
Packit 6c4009
      entry++;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* If an entry with the long option NAME occurs in HOL, set it's special
Packit 6c4009
   sort position to GROUP.  */
Packit 6c4009
static void
Packit 6c4009
hol_set_group (struct hol *hol, const char *name, int group)
Packit 6c4009
{
Packit 6c4009
  struct hol_entry *entry = hol_find_entry (hol, name);
Packit 6c4009
  if (entry)
Packit 6c4009
    entry->group = group;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Order by group:  0, 1, 2, ..., n, -m, ..., -2, -1.
Packit 6c4009
   EQ is what to return if GROUP1 and GROUP2 are the same.  */
Packit 6c4009
static int
Packit 6c4009
group_cmp (int group1, int group2, int eq)
Packit 6c4009
{
Packit 6c4009
  if (group1 == group2)
Packit 6c4009
    return eq;
Packit 6c4009
  else if ((group1 < 0 && group2 < 0) || (group1 >= 0 && group2 >= 0))
Packit 6c4009
    return group1 - group2;
Packit 6c4009
  else
Packit 6c4009
    return group2 - group1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Compare clusters CL1 & CL2 by the order that they should appear in
Packit 6c4009
   output.  */
Packit 6c4009
static int
Packit 6c4009
hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2)
Packit 6c4009
{
Packit 6c4009
  /* If one cluster is deeper than the other, use its ancestor at the same
Packit 6c4009
     level, so that finding the common ancestor is straightforward.  */
Packit 6c4009
  while (cl1->depth > cl2->depth)
Packit 6c4009
    cl1 = cl1->parent;
Packit 6c4009
  while (cl2->depth > cl1->depth)
Packit 6c4009
    cl2 = cl2->parent;
Packit 6c4009
Packit 6c4009
  /* Now reduce both clusters to their ancestors at the point where both have
Packit 6c4009
     a common parent; these can be directly compared.  */
Packit 6c4009
  while (cl1->parent != cl2->parent)
Packit 6c4009
    cl1 = cl1->parent, cl2 = cl2->parent;
Packit 6c4009
Packit 6c4009
  return group_cmp (cl1->group, cl2->group, cl2->index - cl1->index);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the ancestor of CL that's just below the root (i.e., has a parent
Packit 6c4009
   of 0).  */
Packit 6c4009
static struct hol_cluster *
Packit 6c4009
hol_cluster_base (struct hol_cluster *cl)
Packit 6c4009
{
Packit 6c4009
  while (cl->parent)
Packit 6c4009
    cl = cl->parent;
Packit 6c4009
  return cl;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return true if CL1 is a child of CL2.  */
Packit 6c4009
static int
Packit 6c4009
hol_cluster_is_child (const struct hol_cluster *cl1,
Packit 6c4009
		      const struct hol_cluster *cl2)
Packit 6c4009
{
Packit 6c4009
  while (cl1 && cl1 != cl2)
Packit 6c4009
    cl1 = cl1->parent;
Packit 6c4009
  return cl1 == cl2;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Given the name of a OPTION_DOC option, modifies NAME to start at the tail
Packit 6c4009
   that should be used for comparisons, and returns true iff it should be
Packit 6c4009
   treated as a non-option.  */
Packit 6c4009
static int
Packit 6c4009
canon_doc_option (const char **name)
Packit 6c4009
{
Packit 6c4009
  int non_opt;
Packit 6c4009
  /* Skip initial whitespace.  */
Packit 6c4009
  while (isspace (**name))
Packit 6c4009
    (*name)++;
Packit 6c4009
  /* Decide whether this looks like an option (leading `-') or not.  */
Packit 6c4009
  non_opt = (**name != '-');
Packit 6c4009
  /* Skip until part of name used for sorting.  */
Packit 6c4009
  while (**name && !isalnum (**name))
Packit 6c4009
    (*name)++;
Packit 6c4009
  return non_opt;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Order ENTRY1 & ENTRY2 by the order which they should appear in a help
Packit 6c4009
   listing.  */
Packit 6c4009
static int
Packit 6c4009
hol_entry_cmp (const struct hol_entry *entry1,
Packit 6c4009
	       const struct hol_entry *entry2)
Packit 6c4009
{
Packit 6c4009
  /* The group numbers by which the entries should be ordered; if either is
Packit 6c4009
     in a cluster, then this is just the group within the cluster.  */
Packit 6c4009
  int group1 = entry1->group, group2 = entry2->group;
Packit 6c4009
Packit 6c4009
  if (entry1->cluster != entry2->cluster)
Packit 6c4009
    {
Packit 6c4009
      /* The entries are not within the same cluster, so we can't compare them
Packit 6c4009
	 directly, we have to use the appropriate clustering level too.  */
Packit 6c4009
      if (! entry1->cluster)
Packit 6c4009
	/* ENTRY1 is at the `base level', not in a cluster, so we have to
Packit 6c4009
	   compare it's group number with that of the base cluster in which
Packit 6c4009
	   ENTRY2 resides.  Note that if they're in the same group, the
Packit 6c4009
	   clustered option always comes last.  */
Packit 6c4009
	return group_cmp (group1, hol_cluster_base (entry2->cluster)->group, -1);
Packit 6c4009
      else if (! entry2->cluster)
Packit 6c4009
	/* Likewise, but ENTRY2's not in a cluster.  */
Packit 6c4009
	return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1);
Packit 6c4009
      else
Packit 6c4009
	/* Both entries are in clusters, we can just compare the clusters.  */
Packit 6c4009
	return hol_cluster_cmp (entry1->cluster, entry2->cluster);
Packit 6c4009
    }
Packit 6c4009
  else if (group1 == group2)
Packit 6c4009
    /* The entries are both in the same cluster and group, so compare them
Packit 6c4009
       alphabetically.  */
Packit 6c4009
    {
Packit 6c4009
      int short1 = hol_entry_first_short (entry1);
Packit 6c4009
      int short2 = hol_entry_first_short (entry2);
Packit 6c4009
      int doc1 = odoc (entry1->opt);
Packit 6c4009
      int doc2 = odoc (entry2->opt);
Packit 6c4009
      const char *long1 = hol_entry_first_long (entry1);
Packit 6c4009
      const char *long2 = hol_entry_first_long (entry2);
Packit 6c4009
Packit 6c4009
      if (doc1)
Packit 6c4009
	doc1 = long1 != NULL && canon_doc_option (&long1;;
Packit 6c4009
      if (doc2)
Packit 6c4009
	doc2 = long2 != NULL && canon_doc_option (&long2;;
Packit 6c4009
Packit 6c4009
      if (doc1 != doc2)
Packit 6c4009
	/* `documentation' options always follow normal options (or
Packit 6c4009
	   documentation options that *look* like normal options).  */
Packit 6c4009
	return doc1 - doc2;
Packit 6c4009
      else if (!short1 && !short2 && long1 && long2)
Packit 6c4009
	/* Only long options.  */
Packit 6c4009
	return __strcasecmp (long1, long2);
Packit 6c4009
      else
Packit 6c4009
	/* Compare short/short, long/short, short/long, using the first
Packit 6c4009
	   character of long options.  Entries without *any* valid
Packit 6c4009
	   options (such as options with OPTION_HIDDEN set) will be put
Packit 6c4009
	   first, but as they're not displayed, it doesn't matter where
Packit 6c4009
	   they are.  */
Packit 6c4009
	{
Packit 6c4009
	  char first1 = short1 ? short1 : long1 ? *long1 : 0;
Packit 6c4009
	  char first2 = short2 ? short2 : long2 ? *long2 : 0;
Packit 6c4009
#ifdef _tolower
Packit 6c4009
	  int lower_cmp = _tolower (first1) - _tolower (first2);
Packit 6c4009
#else
Packit 6c4009
	  int lower_cmp = tolower (first1) - tolower (first2);
Packit 6c4009
#endif
Packit 6c4009
	  /* Compare ignoring case, except when the options are both the
Packit 6c4009
	     same letter, in which case lower-case always comes first.  */
Packit 6c4009
	  return lower_cmp ? lower_cmp : first2 - first1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    /* Within the same cluster, but not the same group, so just compare
Packit 6c4009
       groups.  */
Packit 6c4009
    return group_cmp (group1, group2, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Version of hol_entry_cmp with correct signature for qsort.  */
Packit 6c4009
static int
Packit 6c4009
hol_entry_qcmp (const void *entry1_v, const void *entry2_v)
Packit 6c4009
{
Packit 6c4009
  return hol_entry_cmp (entry1_v, entry2_v);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Sort HOL by group and alphabetically by option name (with short options
Packit 6c4009
   taking precedence over long).  Since the sorting is for display purposes
Packit 6c4009
   only, the shadowing of options isn't effected.  */
Packit 6c4009
static void
Packit 6c4009
hol_sort (struct hol *hol)
Packit 6c4009
{
Packit 6c4009
  if (hol->num_entries > 0)
Packit 6c4009
    qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry),
Packit 6c4009
	   hol_entry_qcmp);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Append MORE to HOL, destroying MORE in the process.  Options in HOL shadow
Packit 6c4009
   any in MORE with the same name.  */
Packit 6c4009
static void
Packit 6c4009
hol_append (struct hol *hol, struct hol *more)
Packit 6c4009
{
Packit 6c4009
  struct hol_cluster **cl_end = &hol->clusters;
Packit 6c4009
Packit 6c4009
  /* Steal MORE's cluster list, and add it to the end of HOL's.  */
Packit 6c4009
  while (*cl_end)
Packit 6c4009
    cl_end = &(*cl_end)->next;
Packit 6c4009
  *cl_end = more->clusters;
Packit 6c4009
  more->clusters = 0;
Packit 6c4009
Packit 6c4009
  /* Merge entries.  */
Packit 6c4009
  if (more->num_entries > 0)
Packit 6c4009
    {
Packit 6c4009
      if (hol->num_entries == 0)
Packit 6c4009
	{
Packit 6c4009
	  hol->num_entries = more->num_entries;
Packit 6c4009
	  hol->entries = more->entries;
Packit 6c4009
	  hol->short_options = more->short_options;
Packit 6c4009
	  more->num_entries = 0;	/* Mark MORE's fields as invalid.  */
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	/* Append the entries in MORE to those in HOL, taking care to only add
Packit 6c4009
	   non-shadowed SHORT_OPTIONS values.  */
Packit 6c4009
	{
Packit 6c4009
	  unsigned left;
Packit 6c4009
	  char *so, *more_so;
Packit 6c4009
	  struct hol_entry *e;
Packit 6c4009
	  unsigned num_entries = hol->num_entries + more->num_entries;
Packit 6c4009
	  struct hol_entry *entries =
Packit 6c4009
	    malloc (num_entries * sizeof (struct hol_entry));
Packit 6c4009
	  unsigned hol_so_len = strlen (hol->short_options);
Packit 6c4009
	  char *short_options =
Packit 6c4009
	    malloc (hol_so_len + strlen (more->short_options) + 1);
Packit 6c4009
Packit 6c4009
	  assert (entries && short_options);
Packit 6c4009
#if SIZE_MAX <= UINT_MAX
Packit 6c4009
	  assert (num_entries <= SIZE_MAX / sizeof (struct hol_entry));
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  __mempcpy (__mempcpy (entries, hol->entries,
Packit 6c4009
				hol->num_entries * sizeof (struct hol_entry)),
Packit 6c4009
		     more->entries,
Packit 6c4009
		     more->num_entries * sizeof (struct hol_entry));
Packit 6c4009
Packit 6c4009
	  __mempcpy (short_options, hol->short_options, hol_so_len);
Packit 6c4009
Packit 6c4009
	  /* Fix up the short options pointers from HOL.  */
Packit 6c4009
	  for (e = entries, left = hol->num_entries; left > 0; e++, left--)
Packit 6c4009
	    e->short_options += (short_options - hol->short_options);
Packit 6c4009
Packit 6c4009
	  /* Now add the short options from MORE, fixing up its entries
Packit 6c4009
	     too.  */
Packit 6c4009
	  so = short_options + hol_so_len;
Packit 6c4009
	  more_so = more->short_options;
Packit 6c4009
	  for (left = more->num_entries; left > 0; e++, left--)
Packit 6c4009
	    {
Packit 6c4009
	      int opts_left;
Packit 6c4009
	      const struct argp_option *opt;
Packit 6c4009
Packit 6c4009
	      e->short_options = so;
Packit 6c4009
Packit 6c4009
	      for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--)
Packit 6c4009
		{
Packit 6c4009
		  int ch = *more_so;
Packit 6c4009
		  if (oshort (opt) && ch == opt->key)
Packit 6c4009
		    /* The next short option in MORE_SO, CH, is from OPT.  */
Packit 6c4009
		    {
Packit 6c4009
		      if (! find_char (ch, short_options,
Packit 6c4009
				       short_options + hol_so_len))
Packit 6c4009
			/* The short option CH isn't shadowed by HOL's options,
Packit 6c4009
			   so add it to the sum.  */
Packit 6c4009
			*so++ = ch;
Packit 6c4009
		      more_so++;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  *so = '\0';
Packit 6c4009
Packit 6c4009
	  free (hol->entries);
Packit 6c4009
	  free (hol->short_options);
Packit 6c4009
Packit 6c4009
	  hol->entries = entries;
Packit 6c4009
	  hol->num_entries = num_entries;
Packit 6c4009
	  hol->short_options = short_options;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  hol_free (more);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Inserts enough spaces to make sure STREAM is at column COL.  */
Packit 6c4009
static void
Packit 6c4009
indent_to (argp_fmtstream_t stream, unsigned col)
Packit 6c4009
{
Packit 6c4009
  int needed = col - __argp_fmtstream_point (stream);
Packit 6c4009
  while (needed-- > 0)
Packit 6c4009
    __argp_fmtstream_putc (stream, ' ');
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Output to STREAM either a space, or a newline if there isn't room for at
Packit 6c4009
   least ENSURE characters before the right margin.  */
Packit 6c4009
static void
Packit 6c4009
space (argp_fmtstream_t stream, size_t ensure)
Packit 6c4009
{
Packit 6c4009
  if (__argp_fmtstream_point (stream) + ensure
Packit 6c4009
      >= __argp_fmtstream_rmargin (stream))
Packit 6c4009
    __argp_fmtstream_putc (stream, '\n');
Packit 6c4009
  else
Packit 6c4009
    __argp_fmtstream_putc (stream, ' ');
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* If the option REAL has an argument, we print it in using the printf
Packit 6c4009
   format REQ_FMT or OPT_FMT depending on whether it's a required or
Packit 6c4009
   optional argument.  */
Packit 6c4009
static void
Packit 6c4009
arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt,
Packit 6c4009
     const char *domain, argp_fmtstream_t stream)
Packit 6c4009
{
Packit 6c4009
  if (real->arg)
Packit 6c4009
    {
Packit 6c4009
      if (real->flags & OPTION_ARG_OPTIONAL)
Packit 6c4009
	__argp_fmtstream_printf (stream, opt_fmt,
Packit 6c4009
				 dgettext (domain, real->arg));
Packit 6c4009
      else
Packit 6c4009
	__argp_fmtstream_printf (stream, req_fmt,
Packit 6c4009
				 dgettext (domain, real->arg));
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Helper functions for hol_entry_help.  */
Packit 6c4009
Packit 6c4009
/* State used during the execution of hol_help.  */
Packit 6c4009
struct hol_help_state
Packit 6c4009
{
Packit 6c4009
  /* PREV_ENTRY should contain the previous entry printed, or 0.  */
Packit 6c4009
  struct hol_entry *prev_entry;
Packit 6c4009
Packit 6c4009
  /* If an entry is in a different group from the previous one, and SEP_GROUPS
Packit 6c4009
     is true, then a blank line will be printed before any output. */
Packit 6c4009
  int sep_groups;
Packit 6c4009
Packit 6c4009
  /* True if a duplicate option argument was suppressed (only ever set if
Packit 6c4009
     UPARAMS.dup_args is false).  */
Packit 6c4009
  int suppressed_dup_arg;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Some state used while printing a help entry (used to communicate with
Packit 6c4009
   helper functions).  See the doc for hol_entry_help for more info, as most
Packit 6c4009
   of the fields are copied from its arguments.  */
Packit 6c4009
struct pentry_state
Packit 6c4009
{
Packit 6c4009
  const struct hol_entry *entry;
Packit 6c4009
  argp_fmtstream_t stream;
Packit 6c4009
  struct hol_help_state *hhstate;
Packit 6c4009
Packit 6c4009
  /* True if nothing's been printed so far.  */
Packit 6c4009
  int first;
Packit 6c4009
Packit 6c4009
  /* If non-zero, the state that was used to print this help.  */
Packit 6c4009
  const struct argp_state *state;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* If a user doc filter should be applied to DOC, do so.  */
Packit 6c4009
static const char *
Packit 6c4009
filter_doc (const char *doc, int key, const struct argp *argp,
Packit 6c4009
	    const struct argp_state *state)
Packit 6c4009
{
Packit 6c4009
  if (argp && argp->help_filter)
Packit 6c4009
    /* We must apply a user filter to this output.  */
Packit 6c4009
    {
Packit 6c4009
      void *input = __argp_input (argp, state);
Packit 6c4009
      return (*argp->help_filter) (key, doc, input);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    /* No filter.  */
Packit 6c4009
    return doc;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Prints STR as a header line, with the margin lines set appropriately, and
Packit 6c4009
   notes the fact that groups should be separated with a blank line.  ARGP is
Packit 6c4009
   the argp that should dictate any user doc filtering to take place.  Note
Packit 6c4009
   that the previous wrap margin isn't restored, but the left margin is reset
Packit 6c4009
   to 0.  */
Packit 6c4009
static void
Packit 6c4009
print_header (const char *str, const struct argp *argp,
Packit 6c4009
	      struct pentry_state *pest)
Packit 6c4009
{
Packit 6c4009
  const char *tstr = dgettext (argp->argp_domain, str);
Packit 6c4009
  const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state);
Packit 6c4009
Packit 6c4009
  if (fstr)
Packit 6c4009
    {
Packit 6c4009
      if (*fstr)
Packit 6c4009
	{
Packit 6c4009
	  if (pest->hhstate->prev_entry)
Packit 6c4009
	    /* Precede with a blank line.  */
Packit 6c4009
	    __argp_fmtstream_putc (pest->stream, '\n');
Packit 6c4009
	  indent_to (pest->stream, uparams.header_col);
Packit 6c4009
	  __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col);
Packit 6c4009
	  __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col);
Packit 6c4009
	  __argp_fmtstream_puts (pest->stream, fstr);
Packit 6c4009
	  __argp_fmtstream_set_lmargin (pest->stream, 0);
Packit 6c4009
	  __argp_fmtstream_putc (pest->stream, '\n');
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (fstr != tstr)
Packit 6c4009
    free ((char *) fstr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Inserts a comma if this isn't the first item on the line, and then makes
Packit 6c4009
   sure we're at least to column COL.  If this *is* the first item on a line,
Packit 6c4009
   prints any pending whitespace/headers that should precede this line. Also
Packit 6c4009
   clears FIRST.  */
Packit 6c4009
static void
Packit 6c4009
comma (unsigned col, struct pentry_state *pest)
Packit 6c4009
{
Packit 6c4009
  if (pest->first)
Packit 6c4009
    {
Packit 6c4009
      const struct hol_entry *pe = pest->hhstate->prev_entry;
Packit 6c4009
      const struct hol_cluster *cl = pest->entry->cluster;
Packit 6c4009
Packit 6c4009
      if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group)
Packit 6c4009
	__argp_fmtstream_putc (pest->stream, '\n');
Packit 6c4009
Packit 6c4009
      if (cl && cl->header && *cl->header
Packit 6c4009
	  && (!pe
Packit 6c4009
	      || (pe->cluster != cl
Packit 6c4009
		  && !hol_cluster_is_child (pe->cluster, cl))))
Packit 6c4009
	/* If we're changing clusters, then this must be the start of the
Packit 6c4009
	   ENTRY's cluster unless that is an ancestor of the previous one
Packit 6c4009
	   (in which case we had just popped into a sub-cluster for a bit).
Packit 6c4009
	   If so, then print the cluster's header line.  */
Packit 6c4009
	{
Packit 6c4009
	  int old_wm = __argp_fmtstream_wmargin (pest->stream);
Packit 6c4009
	  print_header (cl->header, cl->argp, pest);
Packit 6c4009
	  __argp_fmtstream_set_wmargin (pest->stream, old_wm);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      pest->first = 0;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    __argp_fmtstream_puts (pest->stream, ", ");
Packit 6c4009
Packit 6c4009
  indent_to (pest->stream, col);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Print help for ENTRY to STREAM.  */
Packit 6c4009
static void
Packit 6c4009
hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
Packit 6c4009
		argp_fmtstream_t stream, struct hol_help_state *hhstate)
Packit 6c4009
{
Packit 6c4009
  unsigned num;
Packit 6c4009
  const struct argp_option *real = entry->opt, *opt;
Packit 6c4009
  char *so = entry->short_options;
Packit 6c4009
  int have_long_opt = 0;	/* We have any long options.  */
Packit 6c4009
  /* Saved margins.  */
Packit 6c4009
  int old_lm = __argp_fmtstream_set_lmargin (stream, 0);
Packit 6c4009
  int old_wm = __argp_fmtstream_wmargin (stream);
Packit 6c4009
  /* PEST is a state block holding some of our variables that we'd like to
Packit 6c4009
     share with helper functions.  */
Packit 6c4009
  struct pentry_state pest = { entry, stream, hhstate, 1, state };
Packit 6c4009
Packit 6c4009
  if (! odoc (real))
Packit 6c4009
    for (opt = real, num = entry->num; num > 0; opt++, num--)
Packit 6c4009
      if (opt->name && ovisible (opt))
Packit 6c4009
	{
Packit 6c4009
	  have_long_opt = 1;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
  /* First emit short options.  */
Packit 6c4009
  __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col); /* For truly bizarre cases. */
Packit 6c4009
  for (opt = real, num = entry->num; num > 0; opt++, num--)
Packit 6c4009
    if (oshort (opt) && opt->key == *so)
Packit 6c4009
      /* OPT has a valid (non shadowed) short option.  */
Packit 6c4009
      {
Packit 6c4009
	if (ovisible (opt))
Packit 6c4009
	  {
Packit 6c4009
	    comma (uparams.short_opt_col, &pest);
Packit 6c4009
	    __argp_fmtstream_putc (stream, '-');
Packit 6c4009
	    __argp_fmtstream_putc (stream, *so);
Packit 6c4009
	    if (!have_long_opt || uparams.dup_args)
Packit 6c4009
	      arg (real, " %s", "[%s]",
Packit 6c4009
		   state == NULL ? NULL : state->root_argp->argp_domain,
Packit 6c4009
		   stream);
Packit 6c4009
	    else if (real->arg)
Packit 6c4009
	      hhstate->suppressed_dup_arg = 1;
Packit 6c4009
	  }
Packit 6c4009
	so++;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  /* Now, long options.  */
Packit 6c4009
  if (odoc (real))
Packit 6c4009
    /* A `documentation' option.  */
Packit 6c4009
    {
Packit 6c4009
      __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col);
Packit 6c4009
      for (opt = real, num = entry->num; num > 0; opt++, num--)
Packit 6c4009
	if (opt->name && ovisible (opt))
Packit 6c4009
	  {
Packit 6c4009
	    comma (uparams.doc_opt_col, &pest);
Packit 6c4009
	    /* Calling gettext here isn't quite right, since sorting will
Packit 6c4009
	       have been done on the original; but documentation options
Packit 6c4009
	       should be pretty rare anyway...  */
Packit 6c4009
	    __argp_fmtstream_puts (stream,
Packit 6c4009
				   dgettext (state == NULL ? NULL
Packit 6c4009
					     : state->root_argp->argp_domain,
Packit 6c4009
					     opt->name));
Packit 6c4009
	  }
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    /* A real long option.  */
Packit 6c4009
    {
Packit 6c4009
      __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col);
Packit 6c4009
      for (opt = real, num = entry->num; num > 0; opt++, num--)
Packit 6c4009
	if (opt->name && ovisible (opt))
Packit 6c4009
	  {
Packit 6c4009
	    comma (uparams.long_opt_col, &pest);
Packit 6c4009
	    __argp_fmtstream_printf (stream, "--%s", opt->name);
Packit 6c4009
	    arg (real, "=%s", "[=%s]",
Packit 6c4009
		 state == NULL ? NULL : state->root_argp->argp_domain, stream);
Packit 6c4009
	  }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Next, documentation strings.  */
Packit 6c4009
  __argp_fmtstream_set_lmargin (stream, 0);
Packit 6c4009
Packit 6c4009
  if (pest.first)
Packit 6c4009
    {
Packit 6c4009
      /* Didn't print any switches, what's up?  */
Packit 6c4009
      if (!oshort (real) && !real->name)
Packit 6c4009
	/* This is a group header, print it nicely.  */
Packit 6c4009
	print_header (real->doc, entry->argp, &pest);
Packit 6c4009
      else
Packit 6c4009
	/* Just a totally shadowed option or null header; print nothing.  */
Packit 6c4009
	goto cleanup;		/* Just return, after cleaning up.  */
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      const char *tstr = real->doc ? dgettext (state == NULL ? NULL
Packit 6c4009
					       : state->root_argp->argp_domain,
Packit 6c4009
					       real->doc) : 0;
Packit 6c4009
      const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
Packit 6c4009
      if (fstr && *fstr)
Packit 6c4009
	{
Packit 6c4009
	  unsigned int col = __argp_fmtstream_point (stream);
Packit 6c4009
Packit 6c4009
	  __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col);
Packit 6c4009
	  __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col);
Packit 6c4009
Packit 6c4009
	  if (col > (unsigned int) (uparams.opt_doc_col + 3))
Packit 6c4009
	    __argp_fmtstream_putc (stream, '\n');
Packit 6c4009
	  else if (col >= (unsigned int) uparams.opt_doc_col)
Packit 6c4009
	    __argp_fmtstream_puts (stream, "   ");
Packit 6c4009
	  else
Packit 6c4009
	    indent_to (stream, uparams.opt_doc_col);
Packit 6c4009
Packit 6c4009
	  __argp_fmtstream_puts (stream, fstr);
Packit 6c4009
	}
Packit 6c4009
      if (fstr && fstr != tstr)
Packit 6c4009
	free ((char *) fstr);
Packit 6c4009
Packit 6c4009
      /* Reset the left margin.  */
Packit 6c4009
      __argp_fmtstream_set_lmargin (stream, 0);
Packit 6c4009
      __argp_fmtstream_putc (stream, '\n');
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  hhstate->prev_entry = entry;
Packit 6c4009
Packit 6c4009
cleanup:
Packit 6c4009
  __argp_fmtstream_set_lmargin (stream, old_lm);
Packit 6c4009
  __argp_fmtstream_set_wmargin (stream, old_wm);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Output a long help message about the options in HOL to STREAM.  */
Packit 6c4009
static void
Packit 6c4009
hol_help (struct hol *hol, const struct argp_state *state,
Packit 6c4009
	  argp_fmtstream_t stream)
Packit 6c4009
{
Packit 6c4009
  unsigned num;
Packit 6c4009
  struct hol_entry *entry;
Packit 6c4009
  struct hol_help_state hhstate = { 0, 0, 0 };
Packit 6c4009
Packit 6c4009
  for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--)
Packit 6c4009
    hol_entry_help (entry, state, stream, &hhstate);
Packit 6c4009
Packit 6c4009
  if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
Packit 6c4009
    {
Packit 6c4009
      const char *tstr = dgettext (state == NULL ? NULL
Packit 6c4009
				   : state->root_argp->argp_domain, "\
Packit 6c4009
Mandatory or optional arguments to long options are also mandatory or \
Packit 6c4009
optional for any corresponding short options.");
Packit 6c4009
      const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
Packit 6c4009
				     state ? state->root_argp : 0, state);
Packit 6c4009
      if (fstr && *fstr)
Packit 6c4009
	{
Packit 6c4009
	  __argp_fmtstream_putc (stream, '\n');
Packit 6c4009
	  __argp_fmtstream_puts (stream, fstr);
Packit 6c4009
	  __argp_fmtstream_putc (stream, '\n');
Packit 6c4009
	}
Packit 6c4009
      if (fstr && fstr != tstr)
Packit 6c4009
	free ((char *) fstr);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Helper functions for hol_usage.  */
Packit 6c4009
Packit 6c4009
/* If OPT is a short option without an arg, append its key to the string
Packit 6c4009
   pointer pointer to by COOKIE, and advance the pointer.  */
Packit 6c4009
static int
Packit 6c4009
add_argless_short_opt (const struct argp_option *opt,
Packit 6c4009
		       const struct argp_option *real,
Packit 6c4009
		       const char *domain, void *cookie)
Packit 6c4009
{
Packit 6c4009
  char **snao_end = cookie;
Packit 6c4009
  if (!(opt->arg || real->arg)
Packit 6c4009
      && !((opt->flags | real->flags) & OPTION_NO_USAGE))
Packit 6c4009
    *(*snao_end)++ = opt->key;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* If OPT is a short option with an arg, output a usage entry for it to the
Packit 6c4009
   stream pointed at by COOKIE.  */
Packit 6c4009
static int
Packit 6c4009
usage_argful_short_opt (const struct argp_option *opt,
Packit 6c4009
			const struct argp_option *real,
Packit 6c4009
			const char *domain, void *cookie)
Packit 6c4009
{
Packit 6c4009
  argp_fmtstream_t stream = cookie;
Packit 6c4009
  const char *arg = opt->arg;
Packit 6c4009
  int flags = opt->flags | real->flags;
Packit 6c4009
Packit 6c4009
  if (! arg)
Packit 6c4009
    arg = real->arg;
Packit 6c4009
Packit 6c4009
  if (arg && !(flags & OPTION_NO_USAGE))
Packit 6c4009
    {
Packit 6c4009
      arg = dgettext (domain, arg);
Packit 6c4009
Packit 6c4009
      if (flags & OPTION_ARG_OPTIONAL)
Packit 6c4009
	__argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* Manually do line wrapping so that it (probably) won't
Packit 6c4009
	     get wrapped at the embedded space.  */
Packit 6c4009
	  space (stream, 6 + strlen (arg));
Packit 6c4009
	  __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Output a usage entry for the long option opt to the stream pointed at by
Packit 6c4009
   COOKIE.  */
Packit 6c4009
static int
Packit 6c4009
usage_long_opt (const struct argp_option *opt,
Packit 6c4009
		const struct argp_option *real,
Packit 6c4009
		const char *domain, void *cookie)
Packit 6c4009
{
Packit 6c4009
  argp_fmtstream_t stream = cookie;
Packit 6c4009
  const char *arg = opt->arg;
Packit 6c4009
  int flags = opt->flags | real->flags;
Packit 6c4009
Packit 6c4009
  if (! arg)
Packit 6c4009
    arg = real->arg;
Packit 6c4009
Packit 6c4009
  if (! (flags & OPTION_NO_USAGE))
Packit 6c4009
    {
Packit 6c4009
      if (arg)
Packit 6c4009
	{
Packit 6c4009
	  arg = dgettext (domain, arg);
Packit 6c4009
	  if (flags & OPTION_ARG_OPTIONAL)
Packit 6c4009
	    __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg);
Packit 6c4009
	  else
Packit 6c4009
	    __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	__argp_fmtstream_printf (stream, " [--%s]", opt->name);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Print a short usage description for the arguments in HOL to STREAM.  */
Packit 6c4009
static void
Packit 6c4009
hol_usage (struct hol *hol, argp_fmtstream_t stream)
Packit 6c4009
{
Packit 6c4009
  if (hol->num_entries > 0)
Packit 6c4009
    {
Packit 6c4009
      unsigned nentries;
Packit 6c4009
      struct hol_entry *entry;
Packit 6c4009
      char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1);
Packit 6c4009
      char *snao_end = short_no_arg_opts;
Packit 6c4009
Packit 6c4009
      /* First we put a list of short options without arguments.  */
Packit 6c4009
      for (entry = hol->entries, nentries = hol->num_entries
Packit 6c4009
	   ; nentries > 0
Packit 6c4009
	   ; entry++, nentries--)
Packit 6c4009
	hol_entry_short_iterate (entry, add_argless_short_opt,
Packit 6c4009
				 entry->argp->argp_domain, &snao_end);
Packit 6c4009
      if (snao_end > short_no_arg_opts)
Packit 6c4009
	{
Packit 6c4009
	  *snao_end++ = 0;
Packit 6c4009
	  __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Now a list of short options *with* arguments.  */
Packit 6c4009
      for (entry = hol->entries, nentries = hol->num_entries
Packit 6c4009
	   ; nentries > 0
Packit 6c4009
	   ; entry++, nentries--)
Packit 6c4009
	hol_entry_short_iterate (entry, usage_argful_short_opt,
Packit 6c4009
				 entry->argp->argp_domain, stream);
Packit 6c4009
Packit 6c4009
      /* Finally, a list of long options (whew!).  */
Packit 6c4009
      for (entry = hol->entries, nentries = hol->num_entries
Packit 6c4009
	   ; nentries > 0
Packit 6c4009
	   ; entry++, nentries--)
Packit 6c4009
	hol_entry_long_iterate (entry, usage_long_opt,
Packit 6c4009
				entry->argp->argp_domain, stream);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Make a HOL containing all levels of options in ARGP.  CLUSTER is the
Packit 6c4009
   cluster in which ARGP's entries should be clustered, or 0.  */
Packit 6c4009
static struct hol *
Packit 6c4009
argp_hol (const struct argp *argp, struct hol_cluster *cluster)
Packit 6c4009
{
Packit 6c4009
  const struct argp_child *child = argp->children;
Packit 6c4009
  struct hol *hol = make_hol (argp, cluster);
Packit 6c4009
  if (child)
Packit 6c4009
    while (child->argp)
Packit 6c4009
      {
Packit 6c4009
	struct hol_cluster *child_cluster =
Packit 6c4009
	  ((child->group || child->header)
Packit 6c4009
	   /* Put CHILD->argp within its own cluster.  */
Packit 6c4009
	   ? hol_add_cluster (hol, child->group, child->header,
Packit 6c4009
			      child - argp->children, cluster, argp)
Packit 6c4009
	   /* Just merge it into the parent's cluster.  */
Packit 6c4009
	   : cluster);
Packit 6c4009
	hol_append (hol, argp_hol (child->argp, child_cluster)) ;
Packit 6c4009
	child++;
Packit 6c4009
      }
Packit 6c4009
  return hol;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Calculate how many different levels with alternative args strings exist in
Packit 6c4009
   ARGP.  */
Packit 6c4009
static size_t
Packit 6c4009
argp_args_levels (const struct argp *argp)
Packit 6c4009
{
Packit 6c4009
  size_t levels = 0;
Packit 6c4009
  const struct argp_child *child = argp->children;
Packit 6c4009
Packit 6c4009
  if (argp->args_doc && strchr (argp->args_doc, '\n'))
Packit 6c4009
    levels++;
Packit 6c4009
Packit 6c4009
  if (child)
Packit 6c4009
    while (child->argp)
Packit 6c4009
      levels += argp_args_levels ((child++)->argp);
Packit 6c4009
Packit 6c4009
  return levels;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Print all the non-option args documented in ARGP to STREAM.  Any output is
Packit 6c4009
   preceded by a space.  LEVELS is a pointer to a byte vector the length
Packit 6c4009
   returned by argp_args_levels; it should be initialized to zero, and
Packit 6c4009
   updated by this routine for the next call if ADVANCE is true.  True is
Packit 6c4009
   returned as long as there are more patterns to output.  */
Packit 6c4009
static int
Packit 6c4009
argp_args_usage (const struct argp *argp, const struct argp_state *state,
Packit 6c4009
		 char **levels, int advance, argp_fmtstream_t stream)
Packit 6c4009
{
Packit 6c4009
  char *our_level = *levels;
Packit 6c4009
  int multiple = 0;
Packit 6c4009
  const struct argp_child *child = argp->children;
Packit 6c4009
  const char *tdoc = dgettext (argp->argp_domain, argp->args_doc), *nl = 0;
Packit 6c4009
  const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state);
Packit 6c4009
Packit 6c4009
  if (fdoc)
Packit 6c4009
    {
Packit 6c4009
      const char *cp = fdoc;
Packit 6c4009
      nl = __strchrnul (cp, '\n');
Packit 6c4009
      if (*nl != '\0')
Packit 6c4009
	/* This is a `multi-level' args doc; advance to the correct position
Packit 6c4009
	   as determined by our state in LEVELS, and update LEVELS.  */
Packit 6c4009
	{
Packit 6c4009
	  int i;
Packit 6c4009
	  multiple = 1;
Packit 6c4009
	  for (i = 0; i < *our_level; i++)
Packit 6c4009
	    cp = nl + 1, nl = __strchrnul (cp, '\n');
Packit 6c4009
	  (*levels)++;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Manually do line wrapping so that it (probably) won't get wrapped at
Packit 6c4009
	 any embedded spaces.  */
Packit 6c4009
      space (stream, 1 + nl - cp);
Packit 6c4009
Packit 6c4009
      __argp_fmtstream_write (stream, cp, nl - cp);
Packit 6c4009
    }
Packit 6c4009
  if (fdoc && fdoc != tdoc)
Packit 6c4009
    free ((char *)fdoc);	/* Free user's modified doc string.  */
Packit 6c4009
Packit 6c4009
  if (child)
Packit 6c4009
    while (child->argp)
Packit 6c4009
      advance = !argp_args_usage ((child++)->argp, state, levels, advance, stream);
Packit 6c4009
Packit 6c4009
  if (advance && multiple)
Packit 6c4009
    {
Packit 6c4009
      /* Need to increment our level.  */
Packit 6c4009
      if (*nl)
Packit 6c4009
	/* There's more we can do here.  */
Packit 6c4009
	{
Packit 6c4009
	  (*our_level)++;
Packit 6c4009
	  advance = 0;		/* Our parent shouldn't advance also. */
Packit 6c4009
	}
Packit 6c4009
      else if (*our_level > 0)
Packit 6c4009
	/* We had multiple levels, but used them up; reset to zero.  */
Packit 6c4009
	*our_level = 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return !advance;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Print the documentation for ARGP to STREAM; if POST is false, then
Packit 6c4009
   everything preceeding a `\v' character in the documentation strings (or
Packit 6c4009
   the whole string, for those with none) is printed, otherwise, everything
Packit 6c4009
   following the `\v' character (nothing for strings without).  Each separate
Packit 6c4009
   bit of documentation is separated a blank line, and if PRE_BLANK is true,
Packit 6c4009
   then the first is as well.  If FIRST_ONLY is true, only the first
Packit 6c4009
   occurrence is output.  Returns true if anything was output.  */
Packit 6c4009
static int
Packit 6c4009
argp_doc (const struct argp *argp, const struct argp_state *state,
Packit 6c4009
	  int post, int pre_blank, int first_only,
Packit 6c4009
	  argp_fmtstream_t stream)
Packit 6c4009
{
Packit 6c4009
  const char *text;
Packit 6c4009
  const char *inp_text;
Packit 6c4009
  void *input = 0;
Packit 6c4009
  int anything = 0;
Packit 6c4009
  size_t inp_text_limit = 0;
Packit 6c4009
  const char *doc = dgettext (argp->argp_domain, argp->doc);
Packit 6c4009
  const struct argp_child *child = argp->children;
Packit 6c4009
Packit 6c4009
  if (doc)
Packit 6c4009
    {
Packit 6c4009
      char *vt = strchr (doc, '\v');
Packit 6c4009
      inp_text = post ? (vt ? vt + 1 : 0) : doc;
Packit 6c4009
      inp_text_limit = (!post && vt) ? (vt - doc) : 0;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    inp_text = 0;
Packit 6c4009
Packit 6c4009
  if (argp->help_filter)
Packit 6c4009
    /* We have to filter the doc strings.  */
Packit 6c4009
    {
Packit 6c4009
      if (inp_text_limit)
Packit 6c4009
	/* Copy INP_TEXT so that it's nul-terminated.  */
Packit 6c4009
	inp_text = __strndup (inp_text, inp_text_limit);
Packit 6c4009
      input = __argp_input (argp, state);
Packit 6c4009
      text =
Packit 6c4009
	(*argp->help_filter) (post
Packit 6c4009
			      ? ARGP_KEY_HELP_POST_DOC
Packit 6c4009
			      : ARGP_KEY_HELP_PRE_DOC,
Packit 6c4009
			      inp_text, input);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    text = (const char *) inp_text;
Packit 6c4009
Packit 6c4009
  if (text)
Packit 6c4009
    {
Packit 6c4009
      if (pre_blank)
Packit 6c4009
	__argp_fmtstream_putc (stream, '\n');
Packit 6c4009
Packit 6c4009
      if (text == inp_text && inp_text_limit)
Packit 6c4009
	__argp_fmtstream_write (stream, inp_text, inp_text_limit);
Packit 6c4009
      else
Packit 6c4009
	__argp_fmtstream_puts (stream, text);
Packit 6c4009
Packit 6c4009
      if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream))
Packit 6c4009
	__argp_fmtstream_putc (stream, '\n');
Packit 6c4009
Packit 6c4009
      anything = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (text && text != inp_text)
Packit 6c4009
    free ((char *) text);	/* Free TEXT returned from the help filter.  */
Packit 6c4009
  if (inp_text && inp_text_limit && argp->help_filter)
Packit 6c4009
    free ((char *) inp_text);	/* We copied INP_TEXT, so free it now.  */
Packit 6c4009
Packit 6c4009
  if (post && argp->help_filter)
Packit 6c4009
    /* Now see if we have to output a ARGP_KEY_HELP_EXTRA text.  */
Packit 6c4009
    {
Packit 6c4009
      text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input);
Packit 6c4009
      if (text)
Packit 6c4009
	{
Packit 6c4009
	  if (anything || pre_blank)
Packit 6c4009
	    __argp_fmtstream_putc (stream, '\n');
Packit 6c4009
	  __argp_fmtstream_puts (stream, text);
Packit 6c4009
	  free ((char *) text);
Packit 6c4009
	  if (__argp_fmtstream_point (stream)
Packit 6c4009
	      > __argp_fmtstream_lmargin (stream))
Packit 6c4009
	    __argp_fmtstream_putc (stream, '\n');
Packit 6c4009
	  anything = 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (child)
Packit 6c4009
    while (child->argp && !(first_only && anything))
Packit 6c4009
      anything |=
Packit 6c4009
	argp_doc ((child++)->argp, state,
Packit 6c4009
		  post, anything || pre_blank, first_only,
Packit 6c4009
		  stream);
Packit 6c4009
Packit 6c4009
  return anything;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Output a usage message for ARGP to STREAM.  If called from
Packit 6c4009
   argp_state_help, STATE is the relevent parsing state.  FLAGS are from the
Packit 6c4009
   set ARGP_HELP_*.  NAME is what to use wherever a `program name' is
Packit 6c4009
   needed. */
Packit 6c4009
static void
Packit 6c4009
_help (const struct argp *argp, const struct argp_state *state, FILE *stream,
Packit 6c4009
       unsigned flags, char *name)
Packit 6c4009
{
Packit 6c4009
  int anything = 0;		/* Whether we've output anything.  */
Packit 6c4009
  struct hol *hol = 0;
Packit 6c4009
  argp_fmtstream_t fs;
Packit 6c4009
Packit 6c4009
  if (! stream)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Packit 6c4009
  __flockfile (stream);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  fill_in_uparams (state);
Packit 6c4009
Packit 6c4009
  fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0);
Packit 6c4009
  if (! fs)
Packit 6c4009
    {
Packit 6c4009
#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Packit 6c4009
      __funlockfile (stream);
Packit 6c4009
#endif
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG))
Packit 6c4009
    {
Packit 6c4009
      hol = argp_hol (argp, 0);
Packit 6c4009
Packit 6c4009
      /* If present, these options always come last.  */
Packit 6c4009
      hol_set_group (hol, "help", -1);
Packit 6c4009
      hol_set_group (hol, "version", -1);
Packit 6c4009
Packit 6c4009
      hol_sort (hol);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE))
Packit 6c4009
    /* Print a short `Usage:' message.  */
Packit 6c4009
    {
Packit 6c4009
      int first_pattern = 1, more_patterns;
Packit 6c4009
      size_t num_pattern_levels = argp_args_levels (argp);
Packit 6c4009
      char *pattern_levels = alloca (num_pattern_levels);
Packit 6c4009
Packit 6c4009
      memset (pattern_levels, 0, num_pattern_levels);
Packit 6c4009
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  int old_lm;
Packit 6c4009
	  int old_wm = __argp_fmtstream_set_wmargin (fs, uparams.usage_indent);
Packit 6c4009
	  char *levels = pattern_levels;
Packit 6c4009
Packit 6c4009
	  if (first_pattern)
Packit 6c4009
	    __argp_fmtstream_printf (fs, "%s %s",
Packit 6c4009
				     dgettext (argp->argp_domain, "Usage:"),
Packit 6c4009
				     name);
Packit 6c4009
	  else
Packit 6c4009
	    __argp_fmtstream_printf (fs, "%s %s",
Packit 6c4009
				     dgettext (argp->argp_domain, "  or: "),
Packit 6c4009
				     name);
Packit 6c4009
Packit 6c4009
	  /* We set the lmargin as well as the wmargin, because hol_usage
Packit 6c4009
	     manually wraps options with newline to avoid annoying breaks.  */
Packit 6c4009
	  old_lm = __argp_fmtstream_set_lmargin (fs, uparams.usage_indent);
Packit 6c4009
Packit 6c4009
	  if (flags & ARGP_HELP_SHORT_USAGE)
Packit 6c4009
	    /* Just show where the options go.  */
Packit 6c4009
	    {
Packit 6c4009
	      if (hol->num_entries > 0)
Packit 6c4009
		__argp_fmtstream_puts (fs, dgettext (argp->argp_domain,
Packit 6c4009
						     " [OPTION...]"));
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    /* Actually print the options.  */
Packit 6c4009
	    {
Packit 6c4009
	      hol_usage (hol, fs);
Packit 6c4009
	      flags |= ARGP_HELP_SHORT_USAGE; /* But only do so once.  */
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  more_patterns = argp_args_usage (argp, state, &levels, 1, fs);
Packit 6c4009
Packit 6c4009
	  __argp_fmtstream_set_wmargin (fs, old_wm);
Packit 6c4009
	  __argp_fmtstream_set_lmargin (fs, old_lm);
Packit 6c4009
Packit 6c4009
	  __argp_fmtstream_putc (fs, '\n');
Packit 6c4009
	  anything = 1;
Packit 6c4009
Packit 6c4009
	  first_pattern = 0;
Packit 6c4009
	}
Packit 6c4009
      while (more_patterns);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (flags & ARGP_HELP_PRE_DOC)
Packit 6c4009
    anything |= argp_doc (argp, state, 0, 0, 1, fs);
Packit 6c4009
Packit 6c4009
  if (flags & ARGP_HELP_SEE)
Packit 6c4009
    {
Packit 6c4009
      __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\
Packit 6c4009
Try `%s --help' or `%s --usage' for more information.\n"),
Packit 6c4009
			       name, name);
Packit 6c4009
      anything = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (flags & ARGP_HELP_LONG)
Packit 6c4009
    /* Print a long, detailed help message.  */
Packit 6c4009
    {
Packit 6c4009
      /* Print info about all the options.  */
Packit 6c4009
      if (hol->num_entries > 0)
Packit 6c4009
	{
Packit 6c4009
	  if (anything)
Packit 6c4009
	    __argp_fmtstream_putc (fs, '\n');
Packit 6c4009
	  hol_help (hol, state, fs);
Packit 6c4009
	  anything = 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (flags & ARGP_HELP_POST_DOC)
Packit 6c4009
    /* Print any documentation strings at the end.  */
Packit 6c4009
    anything |= argp_doc (argp, state, 1, anything, 0, fs);
Packit 6c4009
Packit 6c4009
  if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address)
Packit 6c4009
    {
Packit 6c4009
      if (anything)
Packit 6c4009
	__argp_fmtstream_putc (fs, '\n');
Packit 6c4009
      __argp_fmtstream_printf (fs, dgettext (argp->argp_domain,
Packit 6c4009
					     "Report bugs to %s.\n"),
Packit 6c4009
 			       argp_program_bug_address);
Packit 6c4009
      anything = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Packit 6c4009
  __funlockfile (stream);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (hol)
Packit 6c4009
    hol_free (hol);
Packit 6c4009
Packit 6c4009
  __argp_fmtstream_free (fs);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Output a usage message for ARGP to STREAM.  FLAGS are from the set
Packit 6c4009
   ARGP_HELP_*.  NAME is what to use wherever a `program name' is needed. */
Packit 6c4009
void __argp_help (const struct argp *argp, FILE *stream,
Packit 6c4009
		  unsigned flags, char *name)
Packit 6c4009
{
Packit 6c4009
  _help (argp, 0, stream, flags, name);
Packit 6c4009
}
Packit 6c4009
#ifdef weak_alias
Packit 6c4009
weak_alias (__argp_help, argp_help)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef _LIBC
Packit 6c4009
char *__argp_basename (char *name)
Packit 6c4009
{
Packit 6c4009
  char *short_name = strrchr (name, '/');
Packit 6c4009
  return short_name ? short_name + 1 : name;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
char *
Packit 6c4009
__argp_short_program_name (void)
Packit 6c4009
{
Packit 6c4009
# if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
Packit 6c4009
  return program_invocation_short_name;
Packit 6c4009
# elif HAVE_DECL_PROGRAM_INVOCATION_NAME
Packit 6c4009
  return __argp_basename (program_invocation_name);
Packit 6c4009
# else
Packit 6c4009
  /* FIXME: What now? Miles suggests that it is better to use NULL,
Packit 6c4009
     but currently the value is passed on directly to fputs_unlocked,
Packit 6c4009
     so that requires more changes. */
Packit 6c4009
# if __GNUC__
Packit 6c4009
#  warning No reasonable value to return
Packit 6c4009
# endif /* __GNUC__ */
Packit 6c4009
  return "";
Packit 6c4009
# endif
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Output, if appropriate, a usage message for STATE to STREAM.  FLAGS are
Packit 6c4009
   from the set ARGP_HELP_*.  */
Packit 6c4009
void
Packit 6c4009
__argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags)
Packit 6c4009
{
Packit 6c4009
  if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream)
Packit 6c4009
    {
Packit 6c4009
      if (state && (state->flags & ARGP_LONG_ONLY))
Packit 6c4009
	flags |= ARGP_HELP_LONG_ONLY;
Packit 6c4009
Packit 6c4009
      _help (state ? state->root_argp : 0, state, stream, flags,
Packit 6c4009
	     state ? state->name : __argp_short_program_name ());
Packit 6c4009
Packit 6c4009
      if (!state || ! (state->flags & ARGP_NO_EXIT))
Packit 6c4009
	{
Packit 6c4009
	  if (flags & ARGP_HELP_EXIT_ERR)
Packit 6c4009
	    exit (argp_err_exit_status);
Packit 6c4009
	  if (flags & ARGP_HELP_EXIT_OK)
Packit 6c4009
	    exit (0);
Packit 6c4009
	}
Packit 6c4009
  }
Packit 6c4009
}
Packit 6c4009
#ifdef weak_alias
Packit 6c4009
weak_alias (__argp_state_help, argp_state_help)
Packit 6c4009
#endif
Packit 6c4009

Packit 6c4009
/* If appropriate, print the printf string FMT and following args, preceded
Packit 6c4009
   by the program name and `:', to stderr, and followed by a `Try ... --help'
Packit 6c4009
   message, then exit (1).  */
Packit 6c4009
void
Packit 6c4009
__argp_error (const struct argp_state *state, const char *fmt, ...)
Packit 6c4009
{
Packit 6c4009
  if (!state || !(state->flags & ARGP_NO_ERRS))
Packit 6c4009
    {
Packit 6c4009
      FILE *stream = state ? state->err_stream : stderr;
Packit 6c4009
Packit 6c4009
      if (stream)
Packit 6c4009
	{
Packit 6c4009
	  va_list ap;
Packit 6c4009
Packit 6c4009
#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Packit 6c4009
	  __flockfile (stream);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  va_start (ap, fmt);
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
	  char *buf;
Packit 6c4009
Packit 6c4009
	  if (_IO_vasprintf (&buf, fmt, ap) < 0)
Packit 6c4009
	    buf = NULL;
Packit 6c4009
Packit 6c4009
	  __fxprintf (stream, "%s: %s\n",
Packit 6c4009
		      state ? state->name : __argp_short_program_name (), buf);
Packit 6c4009
Packit 6c4009
	  free (buf);
Packit 6c4009
#else
Packit 6c4009
	  fputs_unlocked (state ? state->name : __argp_short_program_name (),
Packit 6c4009
			  stream);
Packit 6c4009
	  putc_unlocked (':', stream);
Packit 6c4009
	  putc_unlocked (' ', stream);
Packit 6c4009
Packit 6c4009
	  vfprintf (stream, fmt, ap);
Packit 6c4009
Packit 6c4009
	  putc_unlocked ('\n', stream);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  __argp_state_help (state, stream, ARGP_HELP_STD_ERR);
Packit 6c4009
Packit 6c4009
	  va_end (ap);
Packit 6c4009
Packit 6c4009
#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Packit 6c4009
	  __funlockfile (stream);
Packit 6c4009
#endif
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
#ifdef weak_alias
Packit 6c4009
weak_alias (__argp_error, argp_error)
Packit 6c4009
#endif
Packit 6c4009

Packit 6c4009
/* Similar to the standard gnu error-reporting function error(), but will
Packit 6c4009
   respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print
Packit 6c4009
   to STATE->err_stream.  This is useful for argument parsing code that is
Packit 6c4009
   shared between program startup (when exiting is desired) and runtime
Packit 6c4009
   option parsing (when typically an error code is returned instead).  The
Packit 6c4009
   difference between this function and argp_error is that the latter is for
Packit 6c4009
   *parsing errors*, and the former is for other problems that occur during
Packit 6c4009
   parsing but don't reflect a (syntactic) problem with the input.  */
Packit 6c4009
void
Packit 6c4009
__argp_failure (const struct argp_state *state, int status, int errnum,
Packit 6c4009
		const char *fmt, ...)
Packit 6c4009
{
Packit 6c4009
  if (!state || !(state->flags & ARGP_NO_ERRS))
Packit 6c4009
    {
Packit 6c4009
      FILE *stream = state ? state->err_stream : stderr;
Packit 6c4009
Packit 6c4009
      if (stream)
Packit 6c4009
	{
Packit 6c4009
#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Packit 6c4009
	  __flockfile (stream);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
	  __fxprintf (stream, "%s",
Packit 6c4009
		      state ? state->name : __argp_short_program_name ());
Packit 6c4009
#else
Packit 6c4009
	  fputs_unlocked (state ? state->name : __argp_short_program_name (),
Packit 6c4009
			  stream);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  if (fmt)
Packit 6c4009
	    {
Packit 6c4009
	      va_list ap;
Packit 6c4009
Packit 6c4009
	      va_start (ap, fmt);
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
	      char *buf;
Packit 6c4009
Packit 6c4009
	      if (_IO_vasprintf (&buf, fmt, ap) < 0)
Packit 6c4009
		buf = NULL;
Packit 6c4009
Packit 6c4009
	      __fxprintf (stream, ": %s", buf);
Packit 6c4009
Packit 6c4009
	      free (buf);
Packit 6c4009
#else
Packit 6c4009
	      putc_unlocked (':', stream);
Packit 6c4009
	      putc_unlocked (' ', stream);
Packit 6c4009
Packit 6c4009
	      vfprintf (stream, fmt, ap);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	      va_end (ap);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (errnum)
Packit 6c4009
	    {
Packit 6c4009
	      char buf[200];
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
	      __fxprintf (stream, ": %s",
Packit 6c4009
			  __strerror_r (errnum, buf, sizeof (buf)));
Packit 6c4009
#else
Packit 6c4009
	      putc_unlocked (':', stream);
Packit 6c4009
	      putc_unlocked (' ', stream);
Packit 6c4009
# ifdef HAVE_STRERROR_R
Packit 6c4009
	      fputs (__strerror_r (errnum, buf, sizeof (buf)), stream);
Packit 6c4009
# else
Packit 6c4009
	      fputs (strerror (errnum), stream);
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (_IO_fwide (stream, 0) > 0)
Packit 6c4009
	    putwc_unlocked (L'\n', stream);
Packit 6c4009
	  else
Packit 6c4009
	    putc_unlocked ('\n', stream);
Packit 6c4009
Packit 6c4009
#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Packit 6c4009
	  __funlockfile (stream);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  if (status && (!state || !(state->flags & ARGP_NO_EXIT)))
Packit 6c4009
	    exit (status);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
#ifdef weak_alias
Packit 6c4009
weak_alias (__argp_failure, argp_failure)
Packit 6c4009
#endif