Blame src/argparse.c

Packit fc043f
/* argparse.c - Argument Parser for option handling
Packit fc043f
 * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch
Packit fc043f
 * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
Packit fc043f
 * Copyright (C) 2015-2018 g10 Code GmbH
Packit fc043f
 *
Packit fc043f
 * This file is part of Libgpg-error.
Packit fc043f
 *
Packit fc043f
 * This file is free software; you can redistribute it and/or modify
Packit fc043f
 * it under the terms of the GNU Lesser General Public License as
Packit fc043f
 * published by the Free Software Foundation; either version 2.1 of
Packit fc043f
 * the License, or (at your option) any later version.
Packit fc043f
 *
Packit fc043f
 * This file is distributed in the hope that it will be useful,
Packit fc043f
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fc043f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit fc043f
 * GNU General Public License for more details.
Packit fc043f
 *
Packit fc043f
 * You should have received a copy of the GNU Lesser General Public License
Packit fc043f
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit fc043f
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit fc043f
 *
Packit fc043f
 * This file was originally a part of GnuPG.
Packit fc043f
 */
Packit fc043f
Packit fc043f
#ifdef HAVE_CONFIG_H
Packit fc043f
#include <config.h>
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#include <stdio.h>
Packit fc043f
#include <stdlib.h>
Packit fc043f
#include <ctype.h>
Packit fc043f
#include <string.h>
Packit fc043f
#include <stdarg.h>
Packit fc043f
#include <limits.h>
Packit fc043f
#include <errno.h>
Packit fc043f
Packit fc043f
#include "gpgrt-int.h"
Packit fc043f
Packit fc043f
/* Special short options which are auto-inserterd.  */
Packit fc043f
#define ARGPARSE_SHORTOPT_HELP 32768
Packit fc043f
#define ARGPARSE_SHORTOPT_VERSION 32769
Packit fc043f
#define ARGPARSE_SHORTOPT_WARRANTY 32770
Packit fc043f
#define ARGPARSE_SHORTOPT_DUMP_OPTIONS 32771
Packit fc043f
Packit fc043f
/* A mask for the types.  */
Packit fc043f
#define ARGPARSE_TYPE_MASK  7  /* Mask for the type values.  */
Packit fc043f
Packit fc043f
/* Internal object of the public gpgrt_argparse_t object.  */
Packit fc043f
struct _gpgrt_argparse_internal_s
Packit fc043f
{
Packit fc043f
  int idx;
Packit fc043f
  int inarg;
Packit fc043f
  int stopped;
Packit fc043f
  const char *last;
Packit fc043f
  void *aliases;
Packit fc043f
  const void *cur_alias;
Packit fc043f
  void *iio_list;
Packit fc043f
  gpgrt_opt_t **opts;  /* Malloced array of pointer to user provided opts.  */
Packit fc043f
};
Packit fc043f
Packit fc043f
Packit fc043f
typedef struct alias_def_s *ALIAS_DEF;
Packit fc043f
struct alias_def_s {
Packit fc043f
    ALIAS_DEF next;
Packit fc043f
    char *name;   /* malloced buffer with name, \0, value */
Packit fc043f
    const char *value; /* ptr into name */
Packit fc043f
};
Packit fc043f
Packit fc043f
Packit fc043f
/* Object to store the names for the --ignore-invalid-option option.
Packit fc043f
   This is a simple linked list.  */
Packit fc043f
typedef struct iio_item_def_s *IIO_ITEM_DEF;
Packit fc043f
struct iio_item_def_s
Packit fc043f
{
Packit fc043f
  IIO_ITEM_DEF next;
Packit fc043f
  char name[1];      /* String with the long option name.  */
Packit fc043f
};
Packit fc043f
Packit fc043f
Packit fc043f
/* The almost always needed user handler for strusage.  */
Packit fc043f
static const char *(*strusage_handler)( int ) = NULL;
Packit fc043f
/* Optional handler to write strings.  See _gpgrt_set_usage_outfnc.  */
Packit fc043f
static int (*custom_outfnc) (int, const char *);
Packit fc043f
/* Optional handler to map strings.  See _gpgrt_set_fixed_string_mapper.  */
Packit fc043f
static const char *(*fixed_string_mapper)(const char*);
Packit fc043f
Packit fc043f
static int  set_opt_arg (gpgrt_argparse_t *arg, unsigned int flags, char *s);
Packit fc043f
static void show_help (gpgrt_opt_t **opts, unsigned int flags);
Packit fc043f
static void show_version (void);
Packit fc043f
static int writestrings (int is_error, const char *string,
Packit fc043f
                         ...) GPGRT_ATTR_SENTINEL(0);
Packit fc043f
static int arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts);
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
Packit fc043f
/* Return true if the native charset is utf-8.  */
Packit fc043f
static int
Packit fc043f
is_native_utf8 (void)
Packit fc043f
{
Packit fc043f
  static char result;
Packit fc043f
Packit fc043f
  if (!result)
Packit fc043f
    {
Packit fc043f
      const char *p = _gpgrt_strusage (8);
Packit fc043f
      if (!p || !*p || !strcmp (p, "utf-8"))
Packit fc043f
        result = 1;
Packit fc043f
      result |= 128;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return (result & 1);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static char *
Packit fc043f
trim_spaces (char *str)
Packit fc043f
{
Packit fc043f
  char *string, *p, *mark;
Packit fc043f
Packit fc043f
  string = str;
Packit fc043f
  /* Find first non space character. */
Packit fc043f
  for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
Packit fc043f
    ;
Packit fc043f
  /* Move characters. */
Packit fc043f
  for ((mark = NULL); (*string = *p); string++, p++)
Packit fc043f
    if (isspace (*(unsigned char*)p))
Packit fc043f
      {
Packit fc043f
        if (!mark)
Packit fc043f
          mark = string;
Packit fc043f
      }
Packit fc043f
    else
Packit fc043f
      mark = NULL;
Packit fc043f
  if (mark)
Packit fc043f
    *mark = '\0' ;  /* Remove trailing spaces. */
Packit fc043f
Packit fc043f
  return str ;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static const char *
Packit fc043f
map_fixed_string (const char *string)
Packit fc043f
{
Packit fc043f
  return fixed_string_mapper? fixed_string_mapper (string) : string;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Write STRING and all following const char * arguments either to
Packit fc043f
   stdout or, if IS_ERROR is set, to stderr.  The list of strings must
Packit fc043f
   be terminated by a NULL.  */
Packit fc043f
static int
Packit fc043f
writestrings (int is_error, const char *string, ...)
Packit fc043f
{
Packit fc043f
  va_list arg_ptr;
Packit fc043f
  const char *s;
Packit fc043f
  int count = 0;
Packit fc043f
Packit fc043f
  if (string)
Packit fc043f
    {
Packit fc043f
      s = string;
Packit fc043f
      va_start (arg_ptr, string);
Packit fc043f
      do
Packit fc043f
        {
Packit fc043f
          if (custom_outfnc)
Packit fc043f
            custom_outfnc (is_error? 2:1, s);
Packit fc043f
          else
Packit fc043f
            fputs (s, is_error? stderr : stdout);
Packit fc043f
          count += strlen (s);
Packit fc043f
        }
Packit fc043f
      while ((s = va_arg (arg_ptr, const char *)));
Packit fc043f
      va_end (arg_ptr);
Packit fc043f
    }
Packit fc043f
  return count;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
flushstrings (int is_error)
Packit fc043f
{
Packit fc043f
  if (custom_outfnc)
Packit fc043f
    custom_outfnc (is_error? 2:1, NULL);
Packit fc043f
  else
Packit fc043f
    _gpgrt_fflush (is_error? es_stderr : es_stdout);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
deinitialize (gpgrt_argparse_t *arg)
Packit fc043f
{
Packit fc043f
  if (arg->internal)
Packit fc043f
    {
Packit fc043f
      xfree (arg->internal->opts);
Packit fc043f
      xfree (arg->internal);
Packit fc043f
      arg->internal = NULL;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  arg->lineno = 0;
Packit fc043f
  arg->err = 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
/* Our own exit handler to clean up used memory.  */
Packit fc043f
static void
Packit fc043f
my_exit (gpgrt_argparse_t *arg, int code)
Packit fc043f
{
Packit fc043f
  deinitialize (arg);
Packit fc043f
  exit (code);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static gpg_err_code_t
Packit fc043f
initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp)
Packit fc043f
{
Packit fc043f
  if (!arg->internal || (arg->flags & ARGPARSE_FLAG_RESET))
Packit fc043f
    {
Packit fc043f
      /* Allocate internal data.  */
Packit fc043f
      if (!arg->internal)
Packit fc043f
        {
Packit fc043f
          arg->internal = xtrymalloc (sizeof *arg->internal);
Packit fc043f
          if (!arg->internal)
Packit fc043f
            return _gpg_err_code_from_syserror ();
Packit fc043f
        }
Packit fc043f
      else if (arg->internal->opts)
Packit fc043f
        xfree (arg->internal->opts);
Packit fc043f
      arg->internal->opts = NULL;
Packit fc043f
Packit fc043f
      /* Initialize this instance. */
Packit fc043f
      arg->internal->idx = 0;
Packit fc043f
      arg->internal->last = NULL;
Packit fc043f
      arg->internal->inarg = 0;
Packit fc043f
      arg->internal->stopped = 0;
Packit fc043f
      arg->internal->aliases = NULL;
Packit fc043f
      arg->internal->cur_alias = NULL;
Packit fc043f
      arg->internal->iio_list = NULL;
Packit fc043f
Packit fc043f
      /* Clear the copy of the option list.  */
Packit fc043f
      /* Clear the error indicator.  */
Packit fc043f
      arg->err = 0;
Packit fc043f
Packit fc043f
      /* Usually an option file will be parsed from the start.
Packit fc043f
       * However, we do not open the stream and thus we have no way to
Packit fc043f
       * know the current lineno.  Using this flag we can allow the
Packit fc043f
       * user to provide a lineno which we don't reset.  */
Packit fc043f
      if (fp || !(arg->flags & ARGPARSE_FLAG_NOLINENO))
Packit fc043f
        arg->lineno = 0;
Packit fc043f
Packit fc043f
      /* Need to clear the reset request.  */
Packit fc043f
      arg->flags &= ~ARGPARSE_FLAG_RESET;
Packit fc043f
Packit fc043f
      /* Check initial args.  */
Packit fc043f
      if ( *arg->argc < 0 )
Packit fc043f
        _gpgrt_log_bug ("invalid argument passed to gpgrt_argparse\n");
Packit fc043f
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* Create an array with pointers to the provided list of options.
Packit fc043f
   * Keeping a copy is useful to sort that array and thus do a binary
Packit fc043f
   * search and to allow for extra space at the end to insert the
Packit fc043f
   * hidden options.  An ARGPARSE_FLAG_RESET can be used to reinit
Packit fc043f
   * this array.  */
Packit fc043f
  if (!arg->internal->opts)
Packit fc043f
    {
Packit fc043f
      static gpgrt_opt_t help_opt
Packit fc043f
        = ARGPARSE_s_n (ARGPARSE_SHORTOPT_HELP, "help", "@");
Packit fc043f
      static gpgrt_opt_t version_opt
Packit fc043f
        = ARGPARSE_s_n (ARGPARSE_SHORTOPT_VERSION, "version", "@");
Packit fc043f
      static gpgrt_opt_t warranty_opt
Packit fc043f
        = ARGPARSE_s_n (ARGPARSE_SHORTOPT_WARRANTY, "warranty", "@");
Packit fc043f
      static gpgrt_opt_t dump_options_opt
Packit fc043f
        = ARGPARSE_s_n(ARGPARSE_SHORTOPT_DUMP_OPTIONS, "dump-options", "@");
Packit fc043f
      static gpgrt_opt_t end_marker
Packit fc043f
        = ARGPARSE_end ();
Packit fc043f
      int seen_help = 0;
Packit fc043f
      int seen_version = 0;
Packit fc043f
      int seen_warranty = 0;
Packit fc043f
      int seen_dump_options = 0;
Packit fc043f
      int i;
Packit fc043f
Packit fc043f
      for (i=0; opts[i].short_opt; i++)
Packit fc043f
        {
Packit fc043f
          if (opts[i].long_opt)
Packit fc043f
            {
Packit fc043f
              if (!strcmp(opts[i].long_opt, help_opt.long_opt))
Packit fc043f
                seen_help = 1;
Packit fc043f
              else if (!strcmp(opts[i].long_opt, version_opt.long_opt))
Packit fc043f
                seen_version = 1;
Packit fc043f
              else if (!strcmp(opts[i].long_opt, warranty_opt.long_opt))
Packit fc043f
                seen_warranty = 1;
Packit fc043f
              else if (!strcmp(opts[i].long_opt, dump_options_opt.long_opt))
Packit fc043f
                seen_dump_options = 1;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      i += 4; /* The number of the above internal options.  */
Packit fc043f
      i++;    /* End of list marker.  */
Packit fc043f
      arg->internal->opts = xtrycalloc (i, sizeof *arg->internal->opts);
Packit fc043f
      if (!arg->internal->opts)
Packit fc043f
        return _gpg_err_code_from_syserror ();
Packit fc043f
      for(i=0; opts[i].short_opt; i++)
Packit fc043f
        arg->internal->opts[i] = opts + i;
Packit fc043f
      if (!seen_help)
Packit fc043f
        arg->internal->opts[i++] = &help_opt;
Packit fc043f
      if (!seen_version)
Packit fc043f
        arg->internal->opts[i++] = &version_opt;
Packit fc043f
      if (!seen_warranty)
Packit fc043f
        arg->internal->opts[i++] = &warranty_opt;
Packit fc043f
      if (!seen_dump_options)
Packit fc043f
        arg->internal->opts[i++] = &dump_options_opt;
Packit fc043f
      arg->internal->opts[i] = &end_marker;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (arg->err)
Packit fc043f
    {
Packit fc043f
      /* Last option was erroneous.  */
Packit fc043f
      const char *s;
Packit fc043f
Packit fc043f
      if (fp)
Packit fc043f
        {
Packit fc043f
          if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
Packit fc043f
            s = _("argument not expected");
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_READ_ERROR )
Packit fc043f
            s = _("read error");
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
Packit fc043f
            s = _("keyword too long");
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
Packit fc043f
            s = _("missing argument");
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
Packit fc043f
            s = _("invalid argument");
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
Packit fc043f
            s = _("invalid command");
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
Packit fc043f
            s = _("invalid alias definition");
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
Packit fc043f
            s = _("out of core");
Packit fc043f
          else
Packit fc043f
            s = _("invalid option");
Packit fc043f
          _gpgrt_log_error ("%s:%u: %s\n",
Packit fc043f
                            _gpgrt_fname_get (fp), arg->lineno, s);
Packit fc043f
	}
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          s = arg->internal->last? arg->internal->last:"[??]";
Packit fc043f
Packit fc043f
          if ( arg->r_opt == ARGPARSE_MISSING_ARG )
Packit fc043f
            _gpgrt_log_error (_("missing argument for option \"%.50s\"\n"), s);
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
Packit fc043f
            _gpgrt_log_error (_("invalid argument for option \"%.50s\"\n"), s);
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
Packit fc043f
            _gpgrt_log_error (_("option \"%.50s\" does not expect "
Packit fc043f
                                "an argument\n"), s);
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
Packit fc043f
            _gpgrt_log_error (_("invalid command \"%.50s\"\n"), s);
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
Packit fc043f
            _gpgrt_log_error (_("option \"%.50s\" is ambiguous\n"), s);
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
Packit fc043f
            _gpgrt_log_error (_("command \"%.50s\" is ambiguous\n"),s );
Packit fc043f
          else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
Packit fc043f
            _gpgrt_log_error ("%s\n", _("out of core\n"));
Packit fc043f
          else
Packit fc043f
            _gpgrt_log_error (_("invalid option \"%.50s\"\n"), s);
Packit fc043f
	}
Packit fc043f
      if (arg->err != ARGPARSE_PRINT_WARNING)
Packit fc043f
        my_exit (arg, 2);
Packit fc043f
      arg->err = 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* Zero out the return value union.  */
Packit fc043f
  arg->r.ret_str = NULL;
Packit fc043f
  arg->r.ret_long = 0;
Packit fc043f
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
store_alias( gpgrt_argparse_t *arg, char *name, char *value )
Packit fc043f
{
Packit fc043f
    /* TODO: replace this dummy function with a rea one
Packit fc043f
     * and fix the probelms IRIX has with (ALIAS_DEV)arg..
Packit fc043f
     * used as lvalue
Packit fc043f
     */
Packit fc043f
  (void)arg;
Packit fc043f
  (void)name;
Packit fc043f
  (void)value;
Packit fc043f
#if 0
Packit fc043f
    ALIAS_DEF a = xmalloc( sizeof *a );
Packit fc043f
    a->name = name;
Packit fc043f
    a->value = value;
Packit fc043f
    a->next = (ALIAS_DEF)arg->internal->aliases;
Packit fc043f
    (ALIAS_DEF)arg->internal->aliases = a;
Packit fc043f
#endif
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Return true if KEYWORD is in the ignore-invalid-option list.  */
Packit fc043f
static int
Packit fc043f
ignore_invalid_option_p (gpgrt_argparse_t *arg, const char *keyword)
Packit fc043f
{
Packit fc043f
  IIO_ITEM_DEF item = arg->internal->iio_list;
Packit fc043f
Packit fc043f
  for (; item; item = item->next)
Packit fc043f
    if (!strcmp (item->name, keyword))
Packit fc043f
      return 1;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Add the keywords up to the next LF to the list of to be ignored
Packit fc043f
   options.  After returning FP will either be at EOF or the next
Packit fc043f
   character read wll be the first of a new line.  The function
Packit fc043f
   returns 0 on success or true on malloc failure.  */
Packit fc043f
static int
Packit fc043f
ignore_invalid_option_add (gpgrt_argparse_t *arg, estream_t fp)
Packit fc043f
{
Packit fc043f
  IIO_ITEM_DEF item;
Packit fc043f
  int c;
Packit fc043f
  char name[100];
Packit fc043f
  int namelen = 0;
Packit fc043f
  int ready = 0;
Packit fc043f
  enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
Packit fc043f
Packit fc043f
  while (!ready)
Packit fc043f
    {
Packit fc043f
      c = _gpgrt_fgetc (fp);
Packit fc043f
      if (c == '\n')
Packit fc043f
        ready = 1;
Packit fc043f
      else if (c == EOF)
Packit fc043f
        {
Packit fc043f
          c = '\n';
Packit fc043f
          ready = 1;
Packit fc043f
        }
Packit fc043f
    again:
Packit fc043f
      switch (state)
Packit fc043f
        {
Packit fc043f
        case skipWS:
Packit fc043f
          if (!isascii (c) || !isspace(c))
Packit fc043f
            {
Packit fc043f
              namelen = 0;
Packit fc043f
              state = collectNAME;
Packit fc043f
              goto again;
Packit fc043f
            }
Packit fc043f
          break;
Packit fc043f
Packit fc043f
        case collectNAME:
Packit fc043f
          if (isspace (c))
Packit fc043f
            {
Packit fc043f
              state = addNAME;
Packit fc043f
              goto again;
Packit fc043f
            }
Packit fc043f
          else if (namelen < DIM(name)-1)
Packit fc043f
            name[namelen++] = c;
Packit fc043f
          else /* Too long.  */
Packit fc043f
            state = skipNAME;
Packit fc043f
          break;
Packit fc043f
Packit fc043f
        case skipNAME:
Packit fc043f
          if (isspace (c))
Packit fc043f
            {
Packit fc043f
              state = skipWS;
Packit fc043f
              goto again;
Packit fc043f
            }
Packit fc043f
          break;
Packit fc043f
Packit fc043f
        case addNAME:
Packit fc043f
          name[namelen] = 0;
Packit fc043f
          if (!ignore_invalid_option_p (arg, name))
Packit fc043f
            {
Packit fc043f
              item = xtrymalloc (sizeof *item + namelen);
Packit fc043f
              if (!item)
Packit fc043f
                return 1;
Packit fc043f
              strcpy (item->name, name);
Packit fc043f
              item->next = (IIO_ITEM_DEF)arg->internal->iio_list;
Packit fc043f
              arg->internal->iio_list = item;
Packit fc043f
            }
Packit fc043f
          state = skipWS;
Packit fc043f
          goto again;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Clear the entire ignore-invalid-option list.  */
Packit fc043f
static void
Packit fc043f
ignore_invalid_option_clear (gpgrt_argparse_t *arg)
Packit fc043f
{
Packit fc043f
  IIO_ITEM_DEF item, tmpitem;
Packit fc043f
Packit fc043f
  for (item = arg->internal->iio_list; item; item = tmpitem)
Packit fc043f
    {
Packit fc043f
      tmpitem = item->next;
Packit fc043f
      xfree (item);
Packit fc043f
    }
Packit fc043f
  arg->internal->iio_list = NULL;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
/****************
Packit fc043f
 * Get options from a file.
Packit fc043f
 * Lines starting with '#' are comment lines.
Packit fc043f
 * Syntax is simply a keyword and the argument.
Packit fc043f
 * Valid keywords are all keywords from the long_opt list without
Packit fc043f
 * the leading dashes. The special keywords "help", "warranty" and "version"
Packit fc043f
 * are not valid here.
Packit fc043f
 * The special keyword "alias" may be used to store alias definitions,
Packit fc043f
 * which are later expanded like long options.
Packit fc043f
 * The option
Packit fc043f
 *   ignore-invalid-option OPTIONNAMEs
Packit fc043f
 * is recognized and updates a list of option which should be ignored if they
Packit fc043f
 * are not defined.
Packit fc043f
 * Caller must free returned strings.
Packit fc043f
 * If called with FP set to NULL command line args are parse instead.
Packit fc043f
 *
Packit fc043f
 * Q: Should we allow the syntax
Packit fc043f
 *     keyword = value
Packit fc043f
 *    and accept for boolean options a value of 1/0, yes/no or true/false?
Packit fc043f
 * Note: Abbreviation of options is here not allowed.
Packit fc043f
 */
Packit fc043f
int
Packit fc043f
_gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig)
Packit fc043f
{
Packit fc043f
  gpgrt_opt_t **opts;
Packit fc043f
  int state, i, c;
Packit fc043f
  int idx = 0;
Packit fc043f
  char keyword[100];
Packit fc043f
  char *buffer = NULL;
Packit fc043f
  size_t buflen = 0;
Packit fc043f
  int in_alias=0;
Packit fc043f
  int unread_buf[3];  /* We use an int so that we can store EOF.  */
Packit fc043f
  int unread_buf_count = 0;
Packit fc043f
Packit fc043f
  if (arg && !opts_orig)
Packit fc043f
    {
Packit fc043f
      deinitialize (arg);
Packit fc043f
      return 0;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (!fp) /* Divert to arg_parse() in this case.  */
Packit fc043f
    return arg_parse (arg, opts_orig);
Packit fc043f
Packit fc043f
  if (initialize (arg, opts_orig, fp))
Packit fc043f
    return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
Packit fc043f
Packit fc043f
  opts = arg->internal->opts;
Packit fc043f
Packit fc043f
  /* If the LINENO is zero we assume that we are at the start of a
Packit fc043f
   * file and we skip over a possible Byte Order Mark.  */
Packit fc043f
  if (!arg->lineno)
Packit fc043f
    {
Packit fc043f
      unread_buf[0] = _gpgrt_fgetc (fp);
Packit fc043f
      unread_buf[1] = _gpgrt_fgetc (fp);
Packit fc043f
      unread_buf[2] = _gpgrt_fgetc (fp);
Packit fc043f
      if (unread_buf[0] != 0xef
Packit fc043f
          || unread_buf[1] != 0xbb
Packit fc043f
          || unread_buf[2] != 0xbf)
Packit fc043f
        unread_buf_count = 3;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* Find the next keyword.  */
Packit fc043f
  state = i = 0;
Packit fc043f
  for (;;)
Packit fc043f
    {
Packit fc043f
      if (unread_buf_count)
Packit fc043f
        c = unread_buf[3 - unread_buf_count--];
Packit fc043f
      else
Packit fc043f
        c = _gpgrt_fgetc (fp);
Packit fc043f
      if (c == '\n' || c== EOF )
Packit fc043f
        {
Packit fc043f
          if ( c != EOF )
Packit fc043f
            arg->lineno++;
Packit fc043f
          if (state == -1)
Packit fc043f
            break;
Packit fc043f
          else if (state == 2)
Packit fc043f
            {
Packit fc043f
              keyword[i] = 0;
Packit fc043f
              for (i=0; opts[i]->short_opt; i++ )
Packit fc043f
                {
Packit fc043f
                  if (opts[i]->long_opt && !strcmp (opts[i]->long_opt, keyword))
Packit fc043f
                    break;
Packit fc043f
                }
Packit fc043f
              idx = i;
Packit fc043f
              arg->r_opt = opts[idx]->short_opt;
Packit fc043f
              if ((opts[idx]->flags & ARGPARSE_OPT_IGNORE))
Packit fc043f
                {
Packit fc043f
                  state = i = 0;
Packit fc043f
                  continue;
Packit fc043f
                }
Packit fc043f
              else if (!opts[idx]->short_opt )
Packit fc043f
                {
Packit fc043f
                  if (!strcmp (keyword, "ignore-invalid-option"))
Packit fc043f
                    {
Packit fc043f
                      /* No argument - ignore this meta option.  */
Packit fc043f
                      state = i = 0;
Packit fc043f
                      continue;
Packit fc043f
                    }
Packit fc043f
                  else if (ignore_invalid_option_p (arg, keyword))
Packit fc043f
                    {
Packit fc043f
                      /* This invalid option is in the iio list.  */
Packit fc043f
                      state = i = 0;
Packit fc043f
                      continue;
Packit fc043f
                    }
Packit fc043f
                  arg->r_opt = ((opts[idx]->flags & ARGPARSE_OPT_COMMAND)
Packit fc043f
                                ? ARGPARSE_INVALID_COMMAND
Packit fc043f
                                : ARGPARSE_INVALID_OPTION);
Packit fc043f
                }
Packit fc043f
              else if (!(opts[idx]->flags & ARGPARSE_TYPE_MASK))
Packit fc043f
                arg->r_type = 0; /* Does not take an arg. */
Packit fc043f
              else if ((opts[idx]->flags & ARGPARSE_OPT_OPTIONAL) )
Packit fc043f
                arg->r_type = 0; /* Arg is optional.  */
Packit fc043f
              else
Packit fc043f
                arg->r_opt = ARGPARSE_MISSING_ARG;
Packit fc043f
Packit fc043f
              break;
Packit fc043f
	    }
Packit fc043f
          else if (state == 3)
Packit fc043f
            {
Packit fc043f
              /* No argument found.  */
Packit fc043f
              if (in_alias)
Packit fc043f
                arg->r_opt = ARGPARSE_MISSING_ARG;
Packit fc043f
              else if (!(opts[idx]->flags & ARGPARSE_TYPE_MASK))
Packit fc043f
                arg->r_type = 0; /* Does not take an arg. */
Packit fc043f
              else if ((opts[idx]->flags & ARGPARSE_OPT_OPTIONAL))
Packit fc043f
                arg->r_type = 0; /* No optional argument. */
Packit fc043f
              else
Packit fc043f
                arg->r_opt = ARGPARSE_MISSING_ARG;
Packit fc043f
Packit fc043f
              break;
Packit fc043f
	    }
Packit fc043f
          else if (state == 4)
Packit fc043f
            {
Packit fc043f
              /* Has an argument. */
Packit fc043f
              if (in_alias)
Packit fc043f
                {
Packit fc043f
                  if (!buffer)
Packit fc043f
                    arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
Packit fc043f
                  else
Packit fc043f
                    {
Packit fc043f
                      char *p;
Packit fc043f
Packit fc043f
                      buffer[i] = 0;
Packit fc043f
                      p = strpbrk (buffer, " \t");
Packit fc043f
                      if (p)
Packit fc043f
                        {
Packit fc043f
                          *p++ = 0;
Packit fc043f
                          trim_spaces (p);
Packit fc043f
			}
Packit fc043f
                      if (!p || !*p)
Packit fc043f
                        {
Packit fc043f
                          xfree (buffer);
Packit fc043f
                          arg->r_opt = ARGPARSE_INVALID_ALIAS;
Packit fc043f
                        }
Packit fc043f
                      else
Packit fc043f
                        {
Packit fc043f
                          store_alias (arg, buffer, p);
Packit fc043f
                        }
Packit fc043f
		    }
Packit fc043f
		}
Packit fc043f
              else if (!(opts[idx]->flags & ARGPARSE_TYPE_MASK))
Packit fc043f
                arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  char *p;
Packit fc043f
Packit fc043f
                  if (!buffer)
Packit fc043f
                    {
Packit fc043f
                      keyword[i] = 0;
Packit fc043f
                      buffer = xtrystrdup (keyword);
Packit fc043f
                      if (!buffer)
Packit fc043f
                        arg->r_opt = ARGPARSE_OUT_OF_CORE;
Packit fc043f
		    }
Packit fc043f
                  else
Packit fc043f
                    buffer[i] = 0;
Packit fc043f
Packit fc043f
                  if (buffer)
Packit fc043f
                    {
Packit fc043f
                      trim_spaces (buffer);
Packit fc043f
                      p = buffer;
Packit fc043f
                      if (*p == '"')
Packit fc043f
                        {
Packit fc043f
                          /* Remove quotes. */
Packit fc043f
                          p++;
Packit fc043f
                          if (*p && p[strlen(p)-1] == '\"' )
Packit fc043f
                            p[strlen(p)-1] = 0;
Packit fc043f
                        }
Packit fc043f
                      if (!set_opt_arg (arg, opts[idx]->flags, p))
Packit fc043f
                        xfree (buffer);
Packit fc043f
                      else
Packit fc043f
                        gpgrt_annotate_leaked_object (buffer);
Packit fc043f
                    }
Packit fc043f
                }
Packit fc043f
              break;
Packit fc043f
            }
Packit fc043f
          else if (c == EOF)
Packit fc043f
            {
Packit fc043f
              ignore_invalid_option_clear (arg);
Packit fc043f
              if (_gpgrt_ferror (fp))
Packit fc043f
                arg->r_opt = ARGPARSE_READ_ERROR;
Packit fc043f
              else
Packit fc043f
                arg->r_opt = 0; /* EOF. */
Packit fc043f
              break;
Packit fc043f
            }
Packit fc043f
          state = 0;
Packit fc043f
          i = 0;
Packit fc043f
        }
Packit fc043f
      else if (state == -1)
Packit fc043f
        ; /* Skip. */
Packit fc043f
      else if (state == 0 && isascii (c) && isspace(c))
Packit fc043f
        ; /* Skip leading white space.  */
Packit fc043f
      else if (state == 0 && c == '#' )
Packit fc043f
        state = 1;	/* Start of a comment.  */
Packit fc043f
      else if (state == 1)
Packit fc043f
        ; /* Skip comments. */
Packit fc043f
      else if (state == 2 && isascii (c) && isspace(c))
Packit fc043f
        {
Packit fc043f
          /* Check keyword.  */
Packit fc043f
          keyword[i] = 0;
Packit fc043f
          for (i=0; opts[i]->short_opt; i++ )
Packit fc043f
            if (opts[i]->long_opt && !strcmp (opts[i]->long_opt, keyword))
Packit fc043f
              break;
Packit fc043f
          idx = i;
Packit fc043f
          arg->r_opt = opts[idx]->short_opt;
Packit fc043f
          if ((opts[idx]->flags & ARGPARSE_OPT_IGNORE))
Packit fc043f
            {
Packit fc043f
              state = 1; /* Process like a comment.  */
Packit fc043f
            }
Packit fc043f
          else if (!opts[idx]->short_opt)
Packit fc043f
            {
Packit fc043f
              if (!strcmp (keyword, "alias"))
Packit fc043f
                {
Packit fc043f
                  in_alias = 1;
Packit fc043f
                  state = 3;
Packit fc043f
                }
Packit fc043f
              else if (!strcmp (keyword, "ignore-invalid-option"))
Packit fc043f
                {
Packit fc043f
                  if (ignore_invalid_option_add (arg, fp))
Packit fc043f
                    {
Packit fc043f
                      arg->r_opt = ARGPARSE_OUT_OF_CORE;
Packit fc043f
                      break;
Packit fc043f
                    }
Packit fc043f
                  state = i = 0;
Packit fc043f
                  arg->lineno++;
Packit fc043f
                }
Packit fc043f
              else if (ignore_invalid_option_p (arg, keyword))
Packit fc043f
                state = 1; /* Process like a comment.  */
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  arg->r_opt = ((opts[idx]->flags & ARGPARSE_OPT_COMMAND)
Packit fc043f
                                ? ARGPARSE_INVALID_COMMAND
Packit fc043f
                                : ARGPARSE_INVALID_OPTION);
Packit fc043f
                  state = -1; /* Skip rest of line and leave.  */
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
          else
Packit fc043f
            state = 3;
Packit fc043f
        }
Packit fc043f
      else if (state == 3)
Packit fc043f
        {
Packit fc043f
          /* Skip leading spaces of the argument.  */
Packit fc043f
          if (!isascii (c) || !isspace(c))
Packit fc043f
            {
Packit fc043f
              i = 0;
Packit fc043f
              keyword[i++] = c;
Packit fc043f
              state = 4;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (state == 4)
Packit fc043f
        {
Packit fc043f
          /* Collect the argument. */
Packit fc043f
          if (buffer)
Packit fc043f
            {
Packit fc043f
              if (i < buflen-1)
Packit fc043f
                buffer[i++] = c;
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  char *tmp;
Packit fc043f
                  size_t tmplen = buflen + 50;
Packit fc043f
Packit fc043f
                  tmp = xtryrealloc (buffer, tmplen);
Packit fc043f
                  if (tmp)
Packit fc043f
                    {
Packit fc043f
                      buflen = tmplen;
Packit fc043f
                      buffer = tmp;
Packit fc043f
                      buffer[i++] = c;
Packit fc043f
                    }
Packit fc043f
                  else
Packit fc043f
                    {
Packit fc043f
                      xfree (buffer);
Packit fc043f
                      arg->r_opt = ARGPARSE_OUT_OF_CORE;
Packit fc043f
                      break;
Packit fc043f
                    }
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
          else if (i < DIM(keyword)-1)
Packit fc043f
            keyword[i++] = c;
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              size_t tmplen = DIM(keyword) + 50;
Packit fc043f
              buffer = xtrymalloc (tmplen);
Packit fc043f
              if (buffer)
Packit fc043f
                {
Packit fc043f
                  buflen = tmplen;
Packit fc043f
                  memcpy(buffer, keyword, i);
Packit fc043f
                  buffer[i++] = c;
Packit fc043f
                }
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  arg->r_opt = ARGPARSE_OUT_OF_CORE;
Packit fc043f
                  break;
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (i >= DIM(keyword)-1)
Packit fc043f
        {
Packit fc043f
          arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
Packit fc043f
          state = -1; /* Skip rest of line and leave.  */
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          keyword[i++] = c;
Packit fc043f
          state = 2;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return arg->r_opt;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Given the list of options OPTS and a keyword, return the index of
Packit fc043f
 * the long option macthing KEYWORD.  On error -1 is retruned for not
Packit fc043f
 * found or -2 for ambigious keyword.  */
Packit fc043f
static int
Packit fc043f
find_long_option (gpgrt_argparse_t *arg, gpgrt_opt_t **opts,
Packit fc043f
                  const char *keyword)
Packit fc043f
{
Packit fc043f
  int i;
Packit fc043f
  size_t n;
Packit fc043f
Packit fc043f
  (void)arg;  /* Not yet required.  */
Packit fc043f
Packit fc043f
  /* Would be better if we can do a binary search, but it is not
Packit fc043f
   * possible to reorder our option table because we would mess up our
Packit fc043f
   * help strings.  What we can do is: Build an option lookup table
Packit fc043f
   * when this function is first invoked.  */
Packit fc043f
  if (!*keyword)
Packit fc043f
    return -1;
Packit fc043f
  for (i=0; opts[i]->short_opt; i++ )
Packit fc043f
    if (opts[i]->long_opt && !strcmp (opts[i]->long_opt, keyword))
Packit fc043f
      return i;
Packit fc043f
#if 0
Packit fc043f
  {
Packit fc043f
    ALIAS_DEF a;
Packit fc043f
    /* see whether it is an alias */
Packit fc043f
    for (a = args->internal->aliases; a; a = a->next)
Packit fc043f
      {
Packit fc043f
        if (!strcmp( a->name, keyword))
Packit fc043f
          {
Packit fc043f
            /* todo: must parse the alias here */
Packit fc043f
            args->internal->cur_alias = a;
Packit fc043f
            return -3; /* alias available */
Packit fc043f
          }
Packit fc043f
      }
Packit fc043f
  }
Packit fc043f
#endif
Packit fc043f
  /* Not found.  See whether it is an abbreviation.  Aliases may not
Packit fc043f
   * be abbreviated, though. */
Packit fc043f
  n = strlen (keyword);
Packit fc043f
  for (i=0; opts[i]->short_opt; i++)
Packit fc043f
    {
Packit fc043f
      if (opts[i]->long_opt && !strncmp (opts[i]->long_opt, keyword, n))
Packit fc043f
        {
Packit fc043f
          int j;
Packit fc043f
          for (j=i+1; opts[j]->short_opt; j++)
Packit fc043f
            {
Packit fc043f
              if (opts[j]->long_opt
Packit fc043f
                  && !strncmp (opts[j]->long_opt, keyword, n)
Packit fc043f
                  && !(opts[j]->short_opt == opts[i]->short_opt
Packit fc043f
                       && opts[j]->flags == opts[i]->flags ) )
Packit fc043f
                return -2;  /* Abbreviation is ambiguous.  */
Packit fc043f
	    }
Packit fc043f
          return i;
Packit fc043f
	}
Packit fc043f
    }
Packit fc043f
  return -1;  /* Not found.  */
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* The option parser for command line options.  */
Packit fc043f
static int
Packit fc043f
arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig)
Packit fc043f
{
Packit fc043f
  int idx;
Packit fc043f
  gpgrt_opt_t **opts;
Packit fc043f
  int argc;
Packit fc043f
  char **argv;
Packit fc043f
  char *s, *s2;
Packit fc043f
  int i;
Packit fc043f
Packit fc043f
  if (initialize (arg, opts_orig, NULL))
Packit fc043f
    return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
Packit fc043f
Packit fc043f
  opts = arg->internal->opts;
Packit fc043f
  argc = *arg->argc;
Packit fc043f
  argv = *arg->argv;
Packit fc043f
  idx = arg->internal->idx;
Packit fc043f
Packit fc043f
  if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
Packit fc043f
    {
Packit fc043f
      /* Skip the first argument.  */
Packit fc043f
      argc--; argv++; idx++;
Packit fc043f
    }
Packit fc043f
Packit fc043f
 next_one:
Packit fc043f
  if (!argc)
Packit fc043f
    {
Packit fc043f
      /* No more args.  */
Packit fc043f
      arg->r_opt = 0;
Packit fc043f
      goto leave; /* Ready. */
Packit fc043f
    }
Packit fc043f
Packit fc043f
  s = *argv;
Packit fc043f
  arg->internal->last = s;
Packit fc043f
Packit fc043f
  if (arg->internal->stopped && (arg->flags & ARGPARSE_FLAG_ALL))
Packit fc043f
    {
Packit fc043f
      arg->r_opt = ARGPARSE_IS_ARG;  /* Not an option but an argument.  */
Packit fc043f
      arg->r_type = 2;
Packit fc043f
      arg->r.ret_str = s;
Packit fc043f
      argc--; argv++; idx++; /* set to next one */
Packit fc043f
    }
Packit fc043f
  else if( arg->internal->stopped )
Packit fc043f
    {
Packit fc043f
      arg->r_opt = 0;
Packit fc043f
      goto leave; /* Ready.  */
Packit fc043f
    }
Packit fc043f
  else if ( *s == '-' && s[1] == '-' )
Packit fc043f
    {
Packit fc043f
      /* Long option.  */
Packit fc043f
      char *argpos;
Packit fc043f
Packit fc043f
      arg->internal->inarg = 0;
Packit fc043f
      if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
Packit fc043f
        {
Packit fc043f
          /* Stop option processing.  */
Packit fc043f
          arg->internal->stopped = 1;
Packit fc043f
          arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
Packit fc043f
          argc--; argv++; idx++;
Packit fc043f
          goto next_one;
Packit fc043f
	}
Packit fc043f
Packit fc043f
      argpos = strchr( s+2, '=' );
Packit fc043f
      if ( argpos )
Packit fc043f
        *argpos = 0;
Packit fc043f
      i = find_long_option ( arg, opts, s+2 );
Packit fc043f
      if ( argpos )
Packit fc043f
        *argpos = '=';
Packit fc043f
Packit fc043f
      if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_HELP)
Packit fc043f
        show_help (opts, arg->flags);
Packit fc043f
      else if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_VERSION)
Packit fc043f
        {
Packit fc043f
          if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
Packit fc043f
            {
Packit fc043f
              show_version ();
Packit fc043f
              my_exit (arg, 0);
Packit fc043f
            }
Packit fc043f
	}
Packit fc043f
      else if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_WARRANTY)
Packit fc043f
        {
Packit fc043f
          writestrings (0, _gpgrt_strusage (16), "\n", NULL);
Packit fc043f
          my_exit (arg, 0);
Packit fc043f
	}
Packit fc043f
      else if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS)
Packit fc043f
        {
Packit fc043f
          for (i=0; opts[i]->short_opt; i++ )
Packit fc043f
            {
Packit fc043f
              if (opts[i]->long_opt && !(opts[i]->flags & ARGPARSE_OPT_IGNORE))
Packit fc043f
                writestrings (0, "--", opts[i]->long_opt, "\n", NULL);
Packit fc043f
	    }
Packit fc043f
          my_exit (arg, 0);
Packit fc043f
	}
Packit fc043f
Packit fc043f
      if ( i == -2 )
Packit fc043f
        arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
Packit fc043f
      else if ( i == -1 )
Packit fc043f
        {
Packit fc043f
          arg->r_opt = ARGPARSE_INVALID_OPTION;
Packit fc043f
          arg->r.ret_str = s+2;
Packit fc043f
	}
Packit fc043f
      else
Packit fc043f
        arg->r_opt = opts[i]->short_opt;
Packit fc043f
      if ( i < 0 )
Packit fc043f
        ;
Packit fc043f
      else if ( (opts[i]->flags & ARGPARSE_TYPE_MASK) )
Packit fc043f
        {
Packit fc043f
          if ( argpos )
Packit fc043f
            {
Packit fc043f
              s2 = argpos+1;
Packit fc043f
              if ( !*s2 )
Packit fc043f
                s2 = NULL;
Packit fc043f
	    }
Packit fc043f
          else
Packit fc043f
            s2 = argv[1];
Packit fc043f
          if ( !s2 && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) )
Packit fc043f
            {
Packit fc043f
              arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional.  */
Packit fc043f
	    }
Packit fc043f
          else if ( !s2 )
Packit fc043f
            {
Packit fc043f
              arg->r_opt = ARGPARSE_MISSING_ARG;
Packit fc043f
	    }
Packit fc043f
          else if ( !argpos && *s2 == '-'
Packit fc043f
                    && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) )
Packit fc043f
            {
Packit fc043f
              /* The argument is optional and the next seems to be an
Packit fc043f
                 option.  We do not check this possible option but
Packit fc043f
                 assume no argument */
Packit fc043f
              arg->r_type = ARGPARSE_TYPE_NONE;
Packit fc043f
	    }
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              set_opt_arg (arg, opts[i]->flags, s2);
Packit fc043f
              if ( !argpos )
Packit fc043f
                {
Packit fc043f
                  argc--; argv++; idx++; /* Skip one.  */
Packit fc043f
		}
Packit fc043f
	    }
Packit fc043f
	}
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          /* Does not take an argument. */
Packit fc043f
          if ( argpos )
Packit fc043f
            arg->r_type = ARGPARSE_UNEXPECTED_ARG;
Packit fc043f
          else
Packit fc043f
            arg->r_type = 0;
Packit fc043f
	}
Packit fc043f
      argc--; argv++; idx++; /* Set to next one.  */
Packit fc043f
    }
Packit fc043f
    else if ( (*s == '-' && s[1]) || arg->internal->inarg )
Packit fc043f
      {
Packit fc043f
        /* Short option.  */
Packit fc043f
	int dash_kludge = 0;
Packit fc043f
Packit fc043f
	i = 0;
Packit fc043f
	if ( !arg->internal->inarg )
Packit fc043f
          {
Packit fc043f
	    arg->internal->inarg++;
Packit fc043f
	    if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
Packit fc043f
              {
Packit fc043f
                for (i=0; opts[i]->short_opt; i++ )
Packit fc043f
                  if ( opts[i]->long_opt && !strcmp (opts[i]->long_opt, s+1))
Packit fc043f
                    {
Packit fc043f
                      dash_kludge = 1;
Packit fc043f
                      break;
Packit fc043f
		    }
Packit fc043f
              }
Packit fc043f
          }
Packit fc043f
	s += arg->internal->inarg;
Packit fc043f
Packit fc043f
	if (!dash_kludge )
Packit fc043f
          {
Packit fc043f
	    for (i=0; opts[i]->short_opt; i++ )
Packit fc043f
              if ( opts[i]->short_opt == *s )
Packit fc043f
                break;
Packit fc043f
          }
Packit fc043f
Packit fc043f
	if ( !opts[i]->short_opt && ( *s == 'h' || *s == '?' ) )
Packit fc043f
          show_help (opts, arg->flags);
Packit fc043f
Packit fc043f
	arg->r_opt = opts[i]->short_opt;
Packit fc043f
	if (!opts[i]->short_opt )
Packit fc043f
          {
Packit fc043f
	    arg->r_opt = (opts[i]->flags & ARGPARSE_OPT_COMMAND)?
Packit fc043f
              ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
Packit fc043f
	    arg->internal->inarg++; /* Point to the next arg.  */
Packit fc043f
	    arg->r.ret_str = s;
Packit fc043f
          }
Packit fc043f
	else if ( (opts[i]->flags & ARGPARSE_TYPE_MASK) )
Packit fc043f
          {
Packit fc043f
	    if ( s[1] && !dash_kludge )
Packit fc043f
              {
Packit fc043f
		s2 = s+1;
Packit fc043f
		set_opt_arg (arg, opts[i]->flags, s2);
Packit fc043f
              }
Packit fc043f
	    else
Packit fc043f
              {
Packit fc043f
		s2 = argv[1];
Packit fc043f
		if ( !s2 && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) )
Packit fc043f
                  {
Packit fc043f
		    arg->r_type = ARGPARSE_TYPE_NONE;
Packit fc043f
                  }
Packit fc043f
		else if ( !s2 )
Packit fc043f
                  {
Packit fc043f
		    arg->r_opt = ARGPARSE_MISSING_ARG;
Packit fc043f
                  }
Packit fc043f
		else if ( *s2 == '-' && s2[1]
Packit fc043f
                          && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) )
Packit fc043f
                  {
Packit fc043f
		    /* The argument is optional and the next seems to
Packit fc043f
	               be an option.  We do not check this possible
Packit fc043f
	               option but assume no argument.  */
Packit fc043f
		    arg->r_type = ARGPARSE_TYPE_NONE;
Packit fc043f
                  }
Packit fc043f
		else
Packit fc043f
                  {
Packit fc043f
		    set_opt_arg (arg, opts[i]->flags, s2);
Packit fc043f
		    argc--; argv++; idx++; /* Skip one.  */
Packit fc043f
                  }
Packit fc043f
              }
Packit fc043f
	    s = "x"; /* This is so that !s[1] yields false.  */
Packit fc043f
          }
Packit fc043f
	else
Packit fc043f
          {
Packit fc043f
            /* Does not take an argument.  */
Packit fc043f
	    arg->r_type = ARGPARSE_TYPE_NONE;
Packit fc043f
	    arg->internal->inarg++; /* Point to the next arg.  */
Packit fc043f
          }
Packit fc043f
	if ( !s[1] || dash_kludge )
Packit fc043f
          {
Packit fc043f
            /* No more concatenated short options.  */
Packit fc043f
	    arg->internal->inarg = 0;
Packit fc043f
	    argc--; argv++; idx++;
Packit fc043f
          }
Packit fc043f
      }
Packit fc043f
  else if ( arg->flags & ARGPARSE_FLAG_MIXED )
Packit fc043f
    {
Packit fc043f
      arg->r_opt = ARGPARSE_IS_ARG;
Packit fc043f
      arg->r_type = 2;
Packit fc043f
      arg->r.ret_str = s;
Packit fc043f
      argc--; argv++; idx++; /* Set to next one.  */
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      arg->internal->stopped = 1; /* Stop option processing.  */
Packit fc043f
      goto next_one;
Packit fc043f
    }
Packit fc043f
Packit fc043f
 leave:
Packit fc043f
  *arg->argc = argc;
Packit fc043f
  *arg->argv = argv;
Packit fc043f
  arg->internal->idx = idx;
Packit fc043f
  return arg->r_opt;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Returns: -1 on error, 0 for an integer type and 1 for a non integer
Packit fc043f
   type argument.  */
Packit fc043f
static int
Packit fc043f
set_opt_arg (gpgrt_argparse_t *arg, unsigned flags, char *s)
Packit fc043f
{
Packit fc043f
  int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
Packit fc043f
  long l;
Packit fc043f
Packit fc043f
  switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
Packit fc043f
    {
Packit fc043f
    case ARGPARSE_TYPE_LONG:
Packit fc043f
    case ARGPARSE_TYPE_INT:
Packit fc043f
      errno = 0;
Packit fc043f
      l = strtol (s, NULL, base);
Packit fc043f
      if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
Packit fc043f
        {
Packit fc043f
          arg->r_opt = ARGPARSE_INVALID_ARG;
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
      if (arg->r_type == ARGPARSE_TYPE_LONG)
Packit fc043f
        arg->r.ret_long = l;
Packit fc043f
      else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
Packit fc043f
        {
Packit fc043f
          arg->r_opt = ARGPARSE_INVALID_ARG;
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        arg->r.ret_int = (int)l;
Packit fc043f
      return 0;
Packit fc043f
Packit fc043f
    case ARGPARSE_TYPE_ULONG:
Packit fc043f
      while (isascii (*s) && isspace(*s))
Packit fc043f
        s++;
Packit fc043f
      if (*s == '-')
Packit fc043f
        {
Packit fc043f
          arg->r.ret_ulong = 0;
Packit fc043f
          arg->r_opt = ARGPARSE_INVALID_ARG;
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
      errno = 0;
Packit fc043f
      arg->r.ret_ulong = strtoul (s, NULL, base);
Packit fc043f
      if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
Packit fc043f
        {
Packit fc043f
          arg->r_opt = ARGPARSE_INVALID_ARG;
Packit fc043f
          return -1;
Packit fc043f
        }
Packit fc043f
      return 0;
Packit fc043f
Packit fc043f
    case ARGPARSE_TYPE_STRING:
Packit fc043f
    default:
Packit fc043f
      arg->r.ret_str = s;
Packit fc043f
      return 1;
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Return the length of the option O.  This needs to consider the
Packit fc043f
 * description as weel as the option name.  */
Packit fc043f
static size_t
Packit fc043f
long_opt_strlen (gpgrt_opt_t *o)
Packit fc043f
{
Packit fc043f
  size_t n = strlen (o->long_opt);
Packit fc043f
Packit fc043f
  if ( o->description && *o->description == '|' )
Packit fc043f
    {
Packit fc043f
      const char *s;
Packit fc043f
      int is_utf8 = is_native_utf8 ();
Packit fc043f
Packit fc043f
      s=o->description+1;
Packit fc043f
      if ( *s != '=' )
Packit fc043f
        n++;
Packit fc043f
      /* For a (mostly) correct length calculation we exclude
Packit fc043f
       * continuation bytes (10xxxxxx) if we are on a native utf8
Packit fc043f
       * terminal. */
Packit fc043f
      for (; *s && *s != '|'; s++ )
Packit fc043f
        if ( is_utf8 && (*s&0xc0) != 0x80 )
Packit fc043f
          n++;
Packit fc043f
    }
Packit fc043f
  return n;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/****************
Packit fc043f
 * Print formatted help. The description string has some special
Packit fc043f
 * meanings:
Packit fc043f
 *  - A description string which is "@" suppresses help output for
Packit fc043f
 *    this option
Packit fc043f
 *  - a description,ine which starts with a '@' and is followed by
Packit fc043f
 *    any other characters is printed as is; this may be used for examples
Packit fc043f
 *    ans such.
Packit fc043f
 *  - A description which starts with a '|' outputs the string between this
Packit fc043f
 *    bar and the next one as arguments of the long option.
Packit fc043f
 */
Packit fc043f
static void
Packit fc043f
show_help (gpgrt_opt_t **opts, unsigned int flags)
Packit fc043f
{
Packit fc043f
  const char *s;
Packit fc043f
  char tmp[2];
Packit fc043f
Packit fc043f
  show_version ();
Packit fc043f
  writestrings (0, "\n", NULL);
Packit fc043f
  s = _gpgrt_strusage (42);
Packit fc043f
  if (s && *s == '1')
Packit fc043f
    {
Packit fc043f
      s = _gpgrt_strusage (40);
Packit fc043f
      writestrings (1, s, NULL);
Packit fc043f
      if (*s && s[strlen(s)] != '\n')
Packit fc043f
        writestrings (1, "\n", NULL);
Packit fc043f
    }
Packit fc043f
  s = _gpgrt_strusage(41);
Packit fc043f
  writestrings (0, s, "\n", NULL);
Packit fc043f
  if ( opts[0]->description )
Packit fc043f
    {
Packit fc043f
      /* Auto format the option description.  */
Packit fc043f
      int i,j, indent;
Packit fc043f
Packit fc043f
      /* Get max. length of long options.  */
Packit fc043f
      for (i=indent=0; opts[i]->short_opt; i++ )
Packit fc043f
        {
Packit fc043f
          if ( opts[i]->long_opt )
Packit fc043f
            if ( !opts[i]->description || *opts[i]->description != '@' )
Packit fc043f
              if ( (j=long_opt_strlen(opts[i])) > indent && j < 35 )
Packit fc043f
                indent = j;
Packit fc043f
	}
Packit fc043f
Packit fc043f
      /* Example: " -v, --verbose   Viele Sachen ausgeben" */
Packit fc043f
      indent += 10;
Packit fc043f
      if ( *opts[0]->description != '@' )
Packit fc043f
        writestrings (0, "Options:", "\n", NULL);
Packit fc043f
      for (i=0; opts[i]->short_opt; i++ )
Packit fc043f
        {
Packit fc043f
          s = map_fixed_string (_( opts[i]->description ));
Packit fc043f
          if ( s && *s== '@' && !s[1] ) /* Hide this line.  */
Packit fc043f
            continue;
Packit fc043f
          if ( s && *s == '@' )  /* Unindented comment only line.  */
Packit fc043f
            {
Packit fc043f
              for (s++; *s; s++ )
Packit fc043f
                {
Packit fc043f
                  if ( *s == '\n' )
Packit fc043f
                    {
Packit fc043f
                      if( s[1] )
Packit fc043f
                        writestrings (0, "\n", NULL);
Packit fc043f
		    }
Packit fc043f
                  else
Packit fc043f
                    {
Packit fc043f
                      tmp[0] = *s;
Packit fc043f
                      tmp[1] = 0;
Packit fc043f
                      writestrings (0, tmp, NULL);
Packit fc043f
                    }
Packit fc043f
                }
Packit fc043f
              writestrings (0, "\n", NULL);
Packit fc043f
              continue;
Packit fc043f
	    }
Packit fc043f
Packit fc043f
          j = 3;
Packit fc043f
          if ( opts[i]->short_opt < 256 )
Packit fc043f
            {
Packit fc043f
              tmp[0] = opts[i]->short_opt;
Packit fc043f
              tmp[1] = 0;
Packit fc043f
              writestrings (0, " -", tmp, NULL );
Packit fc043f
              if ( !opts[i]->long_opt )
Packit fc043f
                {
Packit fc043f
                  if (s && *s == '|' )
Packit fc043f
                    {
Packit fc043f
                      writestrings (0, " ", NULL); j++;
Packit fc043f
                      for (s++ ; *s && *s != '|'; s++, j++ )
Packit fc043f
                        {
Packit fc043f
                          tmp[0] = *s;
Packit fc043f
                          tmp[1] = 0;
Packit fc043f
                          writestrings (0, tmp, NULL);
Packit fc043f
                        }
Packit fc043f
                      if ( *s )
Packit fc043f
                        s++;
Packit fc043f
		    }
Packit fc043f
		}
Packit fc043f
	    }
Packit fc043f
          else
Packit fc043f
            writestrings (0, "   ", NULL);
Packit fc043f
          if ( opts[i]->long_opt )
Packit fc043f
            {
Packit fc043f
              tmp[0] = opts[i]->short_opt < 256?',':' ';
Packit fc043f
              tmp[1] = 0;
Packit fc043f
              j += writestrings (0, tmp, " --", opts[i]->long_opt, NULL);
Packit fc043f
              if (s && *s == '|' )
Packit fc043f
                {
Packit fc043f
                  if ( *++s != '=' )
Packit fc043f
                    {
Packit fc043f
                      writestrings (0, " ", NULL);
Packit fc043f
                      j++;
Packit fc043f
		    }
Packit fc043f
                  for ( ; *s && *s != '|'; s++, j++ )
Packit fc043f
                    {
Packit fc043f
                      tmp[0] = *s;
Packit fc043f
                      tmp[1] = 0;
Packit fc043f
                      writestrings (0, tmp, NULL);
Packit fc043f
                    }
Packit fc043f
                  if ( *s )
Packit fc043f
                    s++;
Packit fc043f
		}
Packit fc043f
              writestrings (0, "   ", NULL);
Packit fc043f
              j += 3;
Packit fc043f
	    }
Packit fc043f
          for (;j < indent; j++ )
Packit fc043f
            writestrings (0, " ", NULL);
Packit fc043f
          if ( s )
Packit fc043f
            {
Packit fc043f
              if ( *s && j > indent )
Packit fc043f
                {
Packit fc043f
                  writestrings (0, "\n", NULL);
Packit fc043f
                  for (j=0;j < indent; j++ )
Packit fc043f
                    writestrings (0, " ", NULL);
Packit fc043f
		}
Packit fc043f
              for (; *s; s++ )
Packit fc043f
                {
Packit fc043f
                  if ( *s == '\n' )
Packit fc043f
                    {
Packit fc043f
                      if ( s[1] )
Packit fc043f
                        {
Packit fc043f
                          writestrings (0, "\n", NULL);
Packit fc043f
                          for (j=0; j < indent; j++ )
Packit fc043f
                            writestrings (0, " ", NULL);
Packit fc043f
			}
Packit fc043f
		    }
Packit fc043f
                  else
Packit fc043f
                    {
Packit fc043f
                      tmp[0] = *s;
Packit fc043f
                      tmp[1] = 0;
Packit fc043f
                      writestrings (0, tmp, NULL);
Packit fc043f
                    }
Packit fc043f
		}
Packit fc043f
	    }
Packit fc043f
          writestrings (0, "\n", NULL);
Packit fc043f
	}
Packit fc043f
	if ( (flags & ARGPARSE_FLAG_ONEDASH) )
Packit fc043f
          writestrings (0, "\n(A single dash may be used "
Packit fc043f
                        "instead of the double ones)\n", NULL);
Packit fc043f
    }
Packit fc043f
  if ( (s=_gpgrt_strusage(19)) )
Packit fc043f
    {
Packit fc043f
      writestrings (0, "\n", NULL);
Packit fc043f
      writestrings (0, s, NULL);
Packit fc043f
    }
Packit fc043f
  flushstrings (0);
Packit fc043f
  exit (0);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
show_version ()
Packit fc043f
{
Packit fc043f
  const char *s;
Packit fc043f
  int i;
Packit fc043f
Packit fc043f
  /* Version line.  */
Packit fc043f
  writestrings (0, _gpgrt_strusage (11), NULL);
Packit fc043f
  if ((s=_gpgrt_strusage (12)))
Packit fc043f
    writestrings (0, " (", s, ")", NULL);
Packit fc043f
  writestrings (0, " ", _gpgrt_strusage (13), "\n", NULL);
Packit fc043f
  /* Additional version lines. */
Packit fc043f
  for (i=20; i < 30; i++)
Packit fc043f
    if ((s=_gpgrt_strusage (i)))
Packit fc043f
      writestrings (0, s, "\n", NULL);
Packit fc043f
  /* Copyright string.  */
Packit fc043f
  if ((s=_gpgrt_strusage (14)))
Packit fc043f
    writestrings (0, s, "\n", NULL);
Packit fc043f
  /* Licence string.  */
Packit fc043f
  if( (s=_gpgrt_strusage (10)) )
Packit fc043f
    writestrings (0, s, "\n", NULL);
Packit fc043f
  /* Copying conditions. */
Packit fc043f
  if ( (s=_gpgrt_strusage(15)) )
Packit fc043f
    writestrings (0, s, NULL);
Packit fc043f
  /* Thanks. */
Packit fc043f
  if ((s=_gpgrt_strusage(18)))
Packit fc043f
    writestrings (0, s, NULL);
Packit fc043f
  /* Additional program info. */
Packit fc043f
  for (i=30; i < 40; i++ )
Packit fc043f
    if ( (s=_gpgrt_strusage (i)) )
Packit fc043f
      writestrings (0, s, NULL);
Packit fc043f
  flushstrings (0);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
void
Packit fc043f
_gpgrt_usage (int level)
Packit fc043f
{
Packit fc043f
  const char *p;
Packit fc043f
Packit fc043f
  if (!level)
Packit fc043f
    {
Packit fc043f
      writestrings (1, _gpgrt_strusage(11), " ", _gpgrt_strusage(13), "; ",
Packit fc043f
                    _gpgrt_strusage (14), "\n", NULL);
Packit fc043f
      flushstrings (1);
Packit fc043f
    }
Packit fc043f
  else if (level == 1)
Packit fc043f
    {
Packit fc043f
      p = _gpgrt_strusage (40);
Packit fc043f
      writestrings (1, p, NULL);
Packit fc043f
      if (*p && p[strlen(p)] != '\n')
Packit fc043f
        writestrings (1, "\n", NULL);
Packit fc043f
      exit (2);
Packit fc043f
    }
Packit fc043f
  else if (level == 2)
Packit fc043f
    {
Packit fc043f
      p = _gpgrt_strusage (42);
Packit fc043f
      if (p && *p == '1')
Packit fc043f
        {
Packit fc043f
          p = _gpgrt_strusage (40);
Packit fc043f
          writestrings (1, p, NULL);
Packit fc043f
          if (*p && p[strlen(p)] != '\n')
Packit fc043f
            writestrings (1, "\n", NULL);
Packit fc043f
        }
Packit fc043f
      writestrings (0, _gpgrt_strusage(41), "\n", NULL);
Packit fc043f
      exit (0);
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
/* Level
Packit fc043f
 *     0: Print copyright string to stderr
Packit fc043f
 *     1: Print a short usage hint to stderr and terminate
Packit fc043f
 *     2: Print a long usage hint to stdout and terminate
Packit fc043f
 *     8: Return NULL for UTF-8 or string with the native charset.
Packit fc043f
 *     9: Return the SPDX License tag.
Packit fc043f
 *    10: Return license info string
Packit fc043f
 *    11: Return the name of the program
Packit fc043f
 *    12: Return optional name of package which includes this program.
Packit fc043f
 *    13: version  string
Packit fc043f
 *    14: copyright string
Packit fc043f
 *    15: Short copying conditions (with LFs)
Packit fc043f
 *    16: Long copying conditions (with LFs)
Packit fc043f
 *    17: Optional printable OS name
Packit fc043f
 *    18: Optional thanks list (with LFs)
Packit fc043f
 *    19: Bug report info
Packit fc043f
 *20..29: Additional lib version strings.
Packit fc043f
 *30..39: Additional program info (with LFs)
Packit fc043f
 *    40: short usage note (with LF)
Packit fc043f
 *    41: long usage note (with LF)
Packit fc043f
 *    42: Flag string:
Packit fc043f
 *          First char is '1':
Packit fc043f
 *             The short usage notes needs to be printed
Packit fc043f
 *             before the long usage note.
Packit fc043f
 */
Packit fc043f
const char *
Packit fc043f
_gpgrt_strusage (int level)
Packit fc043f
{
Packit fc043f
  const char *p = strusage_handler? strusage_handler(level) : NULL;
Packit fc043f
  const char *tmp;
Packit fc043f
Packit fc043f
  if ( p )
Packit fc043f
    return map_fixed_string (p);
Packit fc043f
Packit fc043f
  switch ( level )
Packit fc043f
    {
Packit fc043f
Packit fc043f
    case 8: break; /* Default to utf-8.  */
Packit fc043f
    case 9:
Packit fc043f
      p = "GPL-3.0-or-later"; /* Suggested license.  */
Packit fc043f
      break;
Packit fc043f
Packit fc043f
    case 10:
Packit fc043f
      tmp = _gpgrt_strusage (9);
Packit fc043f
      if (tmp && !strcmp (tmp, "GPL-2.0-or-later"))
Packit fc043f
        p = ("License GPL-2.0-or-later <https://gnu.org/licenses/>");
Packit fc043f
      else if (tmp && !strcmp (tmp, "LGPL-2.1-or-later"))
Packit fc043f
        p = ("License LGPL-2.1-or-later <https://gnu.org/licenses/>");
Packit fc043f
      else /* Default to GPLv3+.  */
Packit fc043f
        p = ("License GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>");
Packit fc043f
      break;
Packit fc043f
    case 11: p = "foo"; break;
Packit fc043f
    case 13: p = "0.0"; break;
Packit fc043f
    case 14: p = "Copyright (C) YEAR NAME"; break;
Packit fc043f
    case 15: p =
Packit fc043f
"This is free software: you are free to change and redistribute it.\n"
Packit fc043f
"There is NO WARRANTY, to the extent permitted by law.\n";
Packit fc043f
      break;
Packit fc043f
    case 16:
Packit fc043f
      tmp = _gpgrt_strusage (9);
Packit fc043f
      if (tmp && !strcmp (tmp, "GPL-2.0-or-later"))
Packit fc043f
        p =
Packit fc043f
"This is free software; you can redistribute it and/or modify\n"
Packit fc043f
"it under the terms of the GNU General Public License as published by\n"
Packit fc043f
"the Free Software Foundation; either version 2 of the License, or\n"
Packit fc043f
"(at your option) any later version.\n\n"
Packit fc043f
"It is distributed in the hope that it will be useful,\n"
Packit fc043f
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
Packit fc043f
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
Packit fc043f
"GNU General Public License for more details.\n\n"
Packit fc043f
"You should have received a copy of the GNU General Public License\n"
Packit fc043f
"along with this software.  If not, see <https://gnu.org/licenses/>.\n";
Packit fc043f
      else if (tmp && !strcmp (tmp, "LGPL-2.1-or-later"))
Packit fc043f
        p =
Packit fc043f
"This is free software; you can redistribute it and/or modify\n"
Packit fc043f
"it under the terms of the GNU Lesser General Public License as\n"
Packit fc043f
"published by the Free Software Foundation; either version 2.1 of\n"
Packit fc043f
"the License, or (at your option) any later version.\n\n"
Packit fc043f
"It is distributed in the hope that it will be useful,\n"
Packit fc043f
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
Packit fc043f
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
Packit fc043f
"GNU Lesser General Public License for more details.\n\n"
Packit fc043f
"You should have received a copy of the GNU General Public License\n"
Packit fc043f
"along with this software.  If not, see <https://gnu.org/licenses/>.\n";
Packit fc043f
      else /* Default */
Packit fc043f
        p =
Packit fc043f
"This is free software; you can redistribute it and/or modify\n"
Packit fc043f
"it under the terms of the GNU General Public License as published by\n"
Packit fc043f
"the Free Software Foundation; either version 3 of the License, or\n"
Packit fc043f
"(at your option) any later version.\n\n"
Packit fc043f
"It is distributed in the hope that it will be useful,\n"
Packit fc043f
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
Packit fc043f
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
Packit fc043f
"GNU General Public License for more details.\n\n"
Packit fc043f
"You should have received a copy of the GNU General Public License\n"
Packit fc043f
"along with this software.  If not, see <https://gnu.org/licenses/>.\n";
Packit fc043f
      break;
Packit fc043f
    case 40: /* short and long usage */
Packit fc043f
    case 41: p = ""; break;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  return p;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Set the usage handler.  This function is basically a constructor.  */
Packit fc043f
void
Packit fc043f
_gpgrt_set_strusage (const char *(*f)(int) )
Packit fc043f
{
Packit fc043f
  strusage_handler = f;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Set a function to write strings which is the used instead of
Packit fc043f
 * estream.  The first arg of that function is MODE and the second the
Packit fc043f
 * STRING to write.  A mode of 1 is used for writing to stdout and a
Packit fc043f
 * mode of 2 to write to stderr.  Other modes are reserved and should
Packit fc043f
 * not output anything.  A NULL for STRING requests a flush.  */
Packit fc043f
void
Packit fc043f
_gpgrt_set_usage_outfnc (int (*f)(int, const char *))
Packit fc043f
{
Packit fc043f
  custom_outfnc = f;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Register function F as a string mapper which takes a string as
Packit fc043f
 * argument, replaces known "@FOO@" style macros and returns a new
Packit fc043f
 * fixed string.  Warning: The input STRING must have been allocated
Packit fc043f
 * statically.  */
Packit fc043f
void
Packit fc043f
_gpgrt_set_fixed_string_mapper (const char *(*f)(const char*))
Packit fc043f
{
Packit fc043f
  fixed_string_mapper = f;
Packit fc043f
}