Blame gettext-tools/gnulib-lib/argmatch.c

Packit Bot 06c835
/* argmatch.c -- find a match for a string in an array
Packit Bot 06c835
Packit Bot 06c835
   Copyright (C) 1990, 1998-1999, 2001-2007, 2009-2015 Free Software
Packit Bot 06c835
   Foundation, Inc.
Packit Bot 06c835
Packit Bot 06c835
   This program is free software: you can redistribute it and/or modify
Packit Bot 06c835
   it under the terms of the GNU General Public License as published by
Packit Bot 06c835
   the Free Software Foundation; either version 3 of the License, or
Packit Bot 06c835
   (at your option) any later version.
Packit Bot 06c835
Packit Bot 06c835
   This program is distributed in the hope that it will be useful,
Packit Bot 06c835
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot 06c835
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Bot 06c835
   GNU General Public License for more details.
Packit Bot 06c835
Packit Bot 06c835
   You should have received a copy of the GNU General Public License
Packit Bot 06c835
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Bot 06c835
Packit Bot 06c835
/* Written by David MacKenzie <djm@ai.mit.edu>
Packit Bot 06c835
   Modified by Akim Demaille <demaille@inf.enst.fr> */
Packit Bot 06c835
Packit Bot 06c835
#include <config.h>
Packit Bot 06c835
Packit Bot 06c835
/* Specification.  */
Packit Bot 06c835
#include "argmatch.h"
Packit Bot 06c835
Packit Bot 06c835
#include <stdbool.h>
Packit Bot 06c835
#include <stdio.h>
Packit Bot 06c835
#include <stdlib.h>
Packit Bot 06c835
#include <string.h>
Packit Bot 06c835
Packit Bot 06c835
#include "gettext.h"
Packit Bot 06c835
#define _(msgid) gettext (msgid)
Packit Bot 06c835
Packit Bot 06c835
#include "error.h"
Packit Bot 06c835
#include "quotearg.h"
Packit Bot 06c835
#include "quote.h"
Packit Bot 06c835
Packit Bot 06c835
#if USE_UNLOCKED_IO
Packit Bot 06c835
# include "unlocked-io.h"
Packit Bot 06c835
#endif
Packit Bot 06c835
Packit Bot 06c835
/* When reporting an invalid argument, show nonprinting characters
Packit Bot 06c835
   by using the quoting style ARGMATCH_QUOTING_STYLE.  Do not use
Packit Bot 06c835
   literal_quoting_style.  */
Packit Bot 06c835
#ifndef ARGMATCH_QUOTING_STYLE
Packit Bot 06c835
# define ARGMATCH_QUOTING_STYLE locale_quoting_style
Packit Bot 06c835
#endif
Packit Bot 06c835
Packit Bot 06c835
/* Non failing version of argmatch call this function after failing. */
Packit Bot 06c835
#ifndef ARGMATCH_DIE
Packit Bot 06c835
# include "exitfail.h"
Packit Bot 06c835
# define ARGMATCH_DIE exit (exit_failure)
Packit Bot 06c835
#endif
Packit Bot 06c835
Packit Bot 06c835
#ifdef ARGMATCH_DIE_DECL
Packit Bot 06c835
ARGMATCH_DIE_DECL;
Packit Bot 06c835
#endif
Packit Bot 06c835
Packit Bot 06c835
static void
Packit Bot 06c835
__argmatch_die (void)
Packit Bot 06c835
{
Packit Bot 06c835
  ARGMATCH_DIE;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/* Used by XARGMATCH and XARGCASEMATCH.  See description in argmatch.h.
Packit Bot 06c835
   Default to __argmatch_die, but allow caller to change this at run-time. */
Packit Bot 06c835
argmatch_exit_fn argmatch_die = __argmatch_die;
Packit Bot 06c835
Packit Bot 06c835

Packit Bot 06c835
/* If ARG is an unambiguous match for an element of the
Packit Bot 06c835
   NULL-terminated array ARGLIST, return the index in ARGLIST
Packit Bot 06c835
   of the matched element, else -1 if it does not match any element
Packit Bot 06c835
   or -2 if it is ambiguous (is a prefix of more than one element).
Packit Bot 06c835
Packit Bot 06c835
   If VALLIST is none null, use it to resolve ambiguities limited to
Packit Bot 06c835
   synonyms, i.e., for
Packit Bot 06c835
     "yes", "yop" -> 0
Packit Bot 06c835
     "no", "nope" -> 1
Packit Bot 06c835
   "y" is a valid argument, for 0, and "n" for 1.  */
Packit Bot 06c835
Packit Bot 06c835
ptrdiff_t
Packit Bot 06c835
argmatch (const char *arg, const char *const *arglist,
Packit Bot 06c835
          const char *vallist, size_t valsize)
Packit Bot 06c835
{
Packit Bot 06c835
  size_t i;                     /* Temporary index in ARGLIST.  */
Packit Bot 06c835
  size_t arglen;                /* Length of ARG.  */
Packit Bot 06c835
  ptrdiff_t matchind = -1;      /* Index of first nonexact match.  */
Packit Bot 06c835
  bool ambiguous = false;       /* If true, multiple nonexact match(es).  */
Packit Bot 06c835
Packit Bot 06c835
  arglen = strlen (arg);
Packit Bot 06c835
Packit Bot 06c835
  /* Test all elements for either exact match or abbreviated matches.  */
Packit Bot 06c835
  for (i = 0; arglist[i]; i++)
Packit Bot 06c835
    {
Packit Bot 06c835
      if (!strncmp (arglist[i], arg, arglen))
Packit Bot 06c835
        {
Packit Bot 06c835
          if (strlen (arglist[i]) == arglen)
Packit Bot 06c835
            /* Exact match found.  */
Packit Bot 06c835
            return i;
Packit Bot 06c835
          else if (matchind == -1)
Packit Bot 06c835
            /* First nonexact match found.  */
Packit Bot 06c835
            matchind = i;
Packit Bot 06c835
          else
Packit Bot 06c835
            {
Packit Bot 06c835
              /* Second nonexact match found.  */
Packit Bot 06c835
              if (vallist == NULL
Packit Bot 06c835
                  || memcmp (vallist + valsize * matchind,
Packit Bot 06c835
                             vallist + valsize * i, valsize))
Packit Bot 06c835
                {
Packit Bot 06c835
                  /* There is a real ambiguity, or we could not
Packit Bot 06c835
                     disambiguate. */
Packit Bot 06c835
                  ambiguous = true;
Packit Bot 06c835
                }
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
  if (ambiguous)
Packit Bot 06c835
    return -2;
Packit Bot 06c835
  else
Packit Bot 06c835
    return matchind;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/* Error reporting for argmatch.
Packit Bot 06c835
   CONTEXT is a description of the type of entity that was being matched.
Packit Bot 06c835
   VALUE is the invalid value that was given.
Packit Bot 06c835
   PROBLEM is the return value from argmatch.  */
Packit Bot 06c835
Packit Bot 06c835
void
Packit Bot 06c835
argmatch_invalid (const char *context, const char *value, ptrdiff_t problem)
Packit Bot 06c835
{
Packit Bot 06c835
  char const *format = (problem == -1
Packit Bot 06c835
                        ? _("invalid argument %s for %s")
Packit Bot 06c835
                        : _("ambiguous argument %s for %s"));
Packit Bot 06c835
Packit Bot 06c835
  error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value),
Packit Bot 06c835
         quote_n (1, context));
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/* List the valid arguments for argmatch.
Packit Bot 06c835
   ARGLIST is the same as in argmatch.
Packit Bot 06c835
   VALLIST is a pointer to an array of values.
Packit Bot 06c835
   VALSIZE is the size of the elements of VALLIST */
Packit Bot 06c835
void
Packit Bot 06c835
argmatch_valid (const char *const *arglist,
Packit Bot 06c835
                const char *vallist, size_t valsize)
Packit Bot 06c835
{
Packit Bot 06c835
  size_t i;
Packit Bot 06c835
  const char *last_val = NULL;
Packit Bot 06c835
Packit Bot 06c835
  /* We try to put synonyms on the same line.  The assumption is that
Packit Bot 06c835
     synonyms follow each other */
Packit Bot 06c835
  fputs (_("Valid arguments are:"), stderr);
Packit Bot 06c835
  for (i = 0; arglist[i]; i++)
Packit Bot 06c835
    if ((i == 0)
Packit Bot 06c835
        || memcmp (last_val, vallist + valsize * i, valsize))
Packit Bot 06c835
      {
Packit Bot 06c835
        fprintf (stderr, "\n  - %s", quote (arglist[i]));
Packit Bot 06c835
        last_val = vallist + valsize * i;
Packit Bot 06c835
      }
Packit Bot 06c835
    else
Packit Bot 06c835
      {
Packit Bot 06c835
        fprintf (stderr, ", %s", quote (arglist[i]));
Packit Bot 06c835
      }
Packit Bot 06c835
  putc ('\n', stderr);
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/* Never failing versions of the previous functions.
Packit Bot 06c835
Packit Bot 06c835
   CONTEXT is the context for which argmatch is called (e.g.,
Packit Bot 06c835
   "--version-control", or "$VERSION_CONTROL" etc.).  Upon failure,
Packit Bot 06c835
   calls the (supposed never to return) function EXIT_FN. */
Packit Bot 06c835
Packit Bot 06c835
ptrdiff_t
Packit Bot 06c835
__xargmatch_internal (const char *context,
Packit Bot 06c835
                      const char *arg, const char *const *arglist,
Packit Bot 06c835
                      const char *vallist, size_t valsize,
Packit Bot 06c835
                      argmatch_exit_fn exit_fn)
Packit Bot 06c835
{
Packit Bot 06c835
  ptrdiff_t res = argmatch (arg, arglist, vallist, valsize);
Packit Bot 06c835
  if (res >= 0)
Packit Bot 06c835
    /* Success. */
Packit Bot 06c835
    return res;
Packit Bot 06c835
Packit Bot 06c835
  /* We failed.  Explain why. */
Packit Bot 06c835
  argmatch_invalid (context, arg, res);
Packit Bot 06c835
  argmatch_valid (arglist, vallist, valsize);
Packit Bot 06c835
  (*exit_fn) ();
Packit Bot 06c835
Packit Bot 06c835
  return -1; /* To please the compilers. */
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
Packit Bot 06c835
   return the first corresponding argument in ARGLIST */
Packit Bot 06c835
const char *
Packit Bot 06c835
argmatch_to_argument (const char *value,
Packit Bot 06c835
                      const char *const *arglist,
Packit Bot 06c835
                      const char *vallist, size_t valsize)
Packit Bot 06c835
{
Packit Bot 06c835
  size_t i;
Packit Bot 06c835
Packit Bot 06c835
  for (i = 0; arglist[i]; i++)
Packit Bot 06c835
    if (!memcmp (value, vallist + valsize * i, valsize))
Packit Bot 06c835
      return arglist[i];
Packit Bot 06c835
  return NULL;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
#ifdef TEST
Packit Bot 06c835
/*
Packit Bot 06c835
 * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
Packit Bot 06c835
 */
Packit Bot 06c835
char *program_name;
Packit Bot 06c835
Packit Bot 06c835
/* When to make backup files.  */
Packit Bot 06c835
enum backup_type
Packit Bot 06c835
{
Packit Bot 06c835
  /* Never make backups.  */
Packit Bot 06c835
  no_backups,
Packit Bot 06c835
Packit Bot 06c835
  /* Make simple backups of every file.  */
Packit Bot 06c835
  simple_backups,
Packit Bot 06c835
Packit Bot 06c835
  /* Make numbered backups of files that already have numbered backups,
Packit Bot 06c835
     and simple backups of the others.  */
Packit Bot 06c835
  numbered_existing_backups,
Packit Bot 06c835
Packit Bot 06c835
  /* Make numbered backups of every file.  */
Packit Bot 06c835
  numbered_backups
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
/* Two tables describing arguments (keys) and their corresponding
Packit Bot 06c835
   values */
Packit Bot 06c835
static const char *const backup_args[] =
Packit Bot 06c835
{
Packit Bot 06c835
  "no", "none", "off",
Packit Bot 06c835
  "simple", "never",
Packit Bot 06c835
  "existing", "nil",
Packit Bot 06c835
  "numbered", "t",
Packit Bot 06c835
  0
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
static const enum backup_type backup_vals[] =
Packit Bot 06c835
{
Packit Bot 06c835
  no_backups, no_backups, no_backups,
Packit Bot 06c835
  simple_backups, simple_backups,
Packit Bot 06c835
  numbered_existing_backups, numbered_existing_backups,
Packit Bot 06c835
  numbered_backups, numbered_backups
Packit Bot 06c835
};
Packit Bot 06c835
Packit Bot 06c835
int
Packit Bot 06c835
main (int argc, const char *const *argv)
Packit Bot 06c835
{
Packit Bot 06c835
  const char *cp;
Packit Bot 06c835
  enum backup_type backup_type = no_backups;
Packit Bot 06c835
Packit Bot 06c835
  program_name = (char *) argv[0];
Packit Bot 06c835
Packit Bot 06c835
  if (argc > 2)
Packit Bot 06c835
    {
Packit Bot 06c835
      fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
Packit Bot 06c835
      exit (1);
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  if ((cp = getenv ("VERSION_CONTROL")))
Packit Bot 06c835
    backup_type = XARGMATCH ("$VERSION_CONTROL", cp,
Packit Bot 06c835
                             backup_args, backup_vals);
Packit Bot 06c835
Packit Bot 06c835
  if (argc == 2)
Packit Bot 06c835
    backup_type = XARGMATCH (program_name, argv[1],
Packit Bot 06c835
                             backup_args, backup_vals);
Packit Bot 06c835
Packit Bot 06c835
  printf ("The version control is '%s'\n",
Packit Bot 06c835
          ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
Packit Bot 06c835
Packit Bot 06c835
  return 0;
Packit Bot 06c835
}
Packit Bot 06c835
#endif