xref: /dragonfly/contrib/grep/lib/argmatch.c (revision 09d4459f)
195b7b453SJohn Marino /* argmatch.c -- find a match for a string in an array
295b7b453SJohn Marino 
3*09d4459fSDaniel Fojt    Copyright (C) 1990, 1998-1999, 2001-2007, 2009-2020 Free Software
4200fbe8dSJohn Marino    Foundation, Inc.
595b7b453SJohn Marino 
695b7b453SJohn Marino    This program is free software: you can redistribute it and/or modify
795b7b453SJohn Marino    it under the terms of the GNU General Public License as published by
895b7b453SJohn Marino    the Free Software Foundation; either version 3 of the License, or
995b7b453SJohn Marino    (at your option) any later version.
1095b7b453SJohn Marino 
1195b7b453SJohn Marino    This program is distributed in the hope that it will be useful,
1295b7b453SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1395b7b453SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1495b7b453SJohn Marino    GNU General Public License for more details.
1595b7b453SJohn Marino 
1695b7b453SJohn Marino    You should have received a copy of the GNU General Public License
17*09d4459fSDaniel Fojt    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
1895b7b453SJohn Marino 
1995b7b453SJohn Marino /* Written by David MacKenzie <djm@ai.mit.edu>
2095b7b453SJohn Marino    Modified by Akim Demaille <demaille@inf.enst.fr> */
2195b7b453SJohn Marino 
2295b7b453SJohn Marino #include <config.h>
2395b7b453SJohn Marino 
2495b7b453SJohn Marino /* Specification.  */
2595b7b453SJohn Marino #include "argmatch.h"
2695b7b453SJohn Marino 
2795b7b453SJohn Marino #include <stdbool.h>
2895b7b453SJohn Marino #include <stdio.h>
2995b7b453SJohn Marino #include <stdlib.h>
3095b7b453SJohn Marino #include <string.h>
3195b7b453SJohn Marino 
3295b7b453SJohn Marino #define _(msgid) gettext (msgid)
3395b7b453SJohn Marino 
3495b7b453SJohn Marino #include "error.h"
3595b7b453SJohn Marino #include "quotearg.h"
36*09d4459fSDaniel Fojt #include "getprogname.h"
3795b7b453SJohn Marino 
3895b7b453SJohn Marino #if USE_UNLOCKED_IO
3995b7b453SJohn Marino # include "unlocked-io.h"
4095b7b453SJohn Marino #endif
4195b7b453SJohn Marino 
4295b7b453SJohn Marino /* When reporting an invalid argument, show nonprinting characters
4395b7b453SJohn Marino    by using the quoting style ARGMATCH_QUOTING_STYLE.  Do not use
4495b7b453SJohn Marino    literal_quoting_style.  */
4595b7b453SJohn Marino #ifndef ARGMATCH_QUOTING_STYLE
4695b7b453SJohn Marino # define ARGMATCH_QUOTING_STYLE locale_quoting_style
4795b7b453SJohn Marino #endif
4895b7b453SJohn Marino 
4995b7b453SJohn Marino /* Non failing version of argmatch call this function after failing. */
5095b7b453SJohn Marino #ifndef ARGMATCH_DIE
5195b7b453SJohn Marino # include "exitfail.h"
5295b7b453SJohn Marino # define ARGMATCH_DIE exit (exit_failure)
5395b7b453SJohn Marino #endif
5495b7b453SJohn Marino 
5595b7b453SJohn Marino #ifdef ARGMATCH_DIE_DECL
5695b7b453SJohn Marino ARGMATCH_DIE_DECL;
5795b7b453SJohn Marino #endif
5895b7b453SJohn Marino 
5995b7b453SJohn Marino static void
__argmatch_die(void)6095b7b453SJohn Marino __argmatch_die (void)
6195b7b453SJohn Marino {
6295b7b453SJohn Marino   ARGMATCH_DIE;
6395b7b453SJohn Marino }
6495b7b453SJohn Marino 
6595b7b453SJohn Marino /* Used by XARGMATCH and XARGCASEMATCH.  See description in argmatch.h.
6695b7b453SJohn Marino    Default to __argmatch_die, but allow caller to change this at run-time. */
6795b7b453SJohn Marino argmatch_exit_fn argmatch_die = __argmatch_die;
6895b7b453SJohn Marino 
6995b7b453SJohn Marino 
7095b7b453SJohn Marino /* If ARG is an unambiguous match for an element of the
7195b7b453SJohn Marino    NULL-terminated array ARGLIST, return the index in ARGLIST
7295b7b453SJohn Marino    of the matched element, else -1 if it does not match any element
7395b7b453SJohn Marino    or -2 if it is ambiguous (is a prefix of more than one element).
7495b7b453SJohn Marino 
7595b7b453SJohn Marino    If VALLIST is none null, use it to resolve ambiguities limited to
7695b7b453SJohn Marino    synonyms, i.e., for
7795b7b453SJohn Marino      "yes", "yop" -> 0
7895b7b453SJohn Marino      "no", "nope" -> 1
79cf28ed85SJohn Marino    "y" is a valid argument, for 0, and "n" for 1.  */
8095b7b453SJohn Marino 
8195b7b453SJohn Marino ptrdiff_t
argmatch(const char * arg,const char * const * arglist,const void * vallist,size_t valsize)8295b7b453SJohn Marino argmatch (const char *arg, const char *const *arglist,
83*09d4459fSDaniel Fojt           const void *vallist, size_t valsize)
8495b7b453SJohn Marino {
8595b7b453SJohn Marino   size_t i;                     /* Temporary index in ARGLIST.  */
8695b7b453SJohn Marino   size_t arglen;                /* Length of ARG.  */
8795b7b453SJohn Marino   ptrdiff_t matchind = -1;      /* Index of first nonexact match.  */
8895b7b453SJohn Marino   bool ambiguous = false;       /* If true, multiple nonexact match(es).  */
8995b7b453SJohn Marino 
9095b7b453SJohn Marino   arglen = strlen (arg);
9195b7b453SJohn Marino 
9295b7b453SJohn Marino   /* Test all elements for either exact match or abbreviated matches.  */
9395b7b453SJohn Marino   for (i = 0; arglist[i]; i++)
9495b7b453SJohn Marino     {
9595b7b453SJohn Marino       if (!strncmp (arglist[i], arg, arglen))
9695b7b453SJohn Marino         {
9795b7b453SJohn Marino           if (strlen (arglist[i]) == arglen)
9895b7b453SJohn Marino             /* Exact match found.  */
9995b7b453SJohn Marino             return i;
10095b7b453SJohn Marino           else if (matchind == -1)
10195b7b453SJohn Marino             /* First nonexact match found.  */
10295b7b453SJohn Marino             matchind = i;
10395b7b453SJohn Marino           else
10495b7b453SJohn Marino             {
10595b7b453SJohn Marino               /* Second nonexact match found.  */
10695b7b453SJohn Marino               if (vallist == NULL
107*09d4459fSDaniel Fojt                   || memcmp ((char const *) vallist + valsize * matchind,
108*09d4459fSDaniel Fojt                              (char const *) vallist + valsize * i, valsize))
10995b7b453SJohn Marino                 {
11095b7b453SJohn Marino                   /* There is a real ambiguity, or we could not
11195b7b453SJohn Marino                      disambiguate. */
11295b7b453SJohn Marino                   ambiguous = true;
11395b7b453SJohn Marino                 }
11495b7b453SJohn Marino             }
11595b7b453SJohn Marino         }
11695b7b453SJohn Marino     }
11795b7b453SJohn Marino   if (ambiguous)
11895b7b453SJohn Marino     return -2;
11995b7b453SJohn Marino   else
12095b7b453SJohn Marino     return matchind;
12195b7b453SJohn Marino }
12295b7b453SJohn Marino 
12395b7b453SJohn Marino /* Error reporting for argmatch.
12495b7b453SJohn Marino    CONTEXT is a description of the type of entity that was being matched.
12595b7b453SJohn Marino    VALUE is the invalid value that was given.
12695b7b453SJohn Marino    PROBLEM is the return value from argmatch.  */
12795b7b453SJohn Marino 
12895b7b453SJohn Marino void
argmatch_invalid(const char * context,const char * value,ptrdiff_t problem)12995b7b453SJohn Marino argmatch_invalid (const char *context, const char *value, ptrdiff_t problem)
13095b7b453SJohn Marino {
13195b7b453SJohn Marino   char const *format = (problem == -1
13295b7b453SJohn Marino                         ? _("invalid argument %s for %s")
13395b7b453SJohn Marino                         : _("ambiguous argument %s for %s"));
13495b7b453SJohn Marino 
13595b7b453SJohn Marino   error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value),
13695b7b453SJohn Marino          quote_n (1, context));
13795b7b453SJohn Marino }
13895b7b453SJohn Marino 
13995b7b453SJohn Marino /* List the valid arguments for argmatch.
14095b7b453SJohn Marino    ARGLIST is the same as in argmatch.
14195b7b453SJohn Marino    VALLIST is a pointer to an array of values.
14295b7b453SJohn Marino    VALSIZE is the size of the elements of VALLIST */
14395b7b453SJohn Marino void
argmatch_valid(const char * const * arglist,const void * vallist,size_t valsize)14495b7b453SJohn Marino argmatch_valid (const char *const *arglist,
145*09d4459fSDaniel Fojt                 const void *vallist, size_t valsize)
14695b7b453SJohn Marino {
14795b7b453SJohn Marino   size_t i;
14895b7b453SJohn Marino   const char *last_val = NULL;
14995b7b453SJohn Marino 
15095b7b453SJohn Marino   /* We try to put synonyms on the same line.  The assumption is that
15195b7b453SJohn Marino      synonyms follow each other */
152cf28ed85SJohn Marino   fputs (_("Valid arguments are:"), stderr);
15395b7b453SJohn Marino   for (i = 0; arglist[i]; i++)
15495b7b453SJohn Marino     if ((i == 0)
155*09d4459fSDaniel Fojt         || memcmp (last_val, (char const *) vallist + valsize * i, valsize))
15695b7b453SJohn Marino       {
157cf28ed85SJohn Marino         fprintf (stderr, "\n  - %s", quote (arglist[i]));
158*09d4459fSDaniel Fojt         last_val = (char const *) vallist + valsize * i;
15995b7b453SJohn Marino       }
16095b7b453SJohn Marino     else
16195b7b453SJohn Marino       {
162cf28ed85SJohn Marino         fprintf (stderr, ", %s", quote (arglist[i]));
16395b7b453SJohn Marino       }
16495b7b453SJohn Marino   putc ('\n', stderr);
16595b7b453SJohn Marino }
16695b7b453SJohn Marino 
16795b7b453SJohn Marino /* Never failing versions of the previous functions.
16895b7b453SJohn Marino 
16995b7b453SJohn Marino    CONTEXT is the context for which argmatch is called (e.g.,
17095b7b453SJohn Marino    "--version-control", or "$VERSION_CONTROL" etc.).  Upon failure,
17195b7b453SJohn Marino    calls the (supposed never to return) function EXIT_FN. */
17295b7b453SJohn Marino 
17395b7b453SJohn Marino ptrdiff_t
__xargmatch_internal(const char * context,const char * arg,const char * const * arglist,const void * vallist,size_t valsize,argmatch_exit_fn exit_fn)17495b7b453SJohn Marino __xargmatch_internal (const char *context,
17595b7b453SJohn Marino                       const char *arg, const char *const *arglist,
176*09d4459fSDaniel Fojt                       const void *vallist, size_t valsize,
17795b7b453SJohn Marino                       argmatch_exit_fn exit_fn)
17895b7b453SJohn Marino {
17995b7b453SJohn Marino   ptrdiff_t res = argmatch (arg, arglist, vallist, valsize);
18095b7b453SJohn Marino   if (res >= 0)
18195b7b453SJohn Marino     /* Success. */
18295b7b453SJohn Marino     return res;
18395b7b453SJohn Marino 
18495b7b453SJohn Marino   /* We failed.  Explain why. */
18595b7b453SJohn Marino   argmatch_invalid (context, arg, res);
18695b7b453SJohn Marino   argmatch_valid (arglist, vallist, valsize);
18795b7b453SJohn Marino   (*exit_fn) ();
18895b7b453SJohn Marino 
18995b7b453SJohn Marino   return -1; /* To please the compilers. */
19095b7b453SJohn Marino }
19195b7b453SJohn Marino 
19295b7b453SJohn Marino /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
19395b7b453SJohn Marino    return the first corresponding argument in ARGLIST */
19495b7b453SJohn Marino const char *
argmatch_to_argument(const void * value,const char * const * arglist,const void * vallist,size_t valsize)195*09d4459fSDaniel Fojt argmatch_to_argument (const void *value,
19695b7b453SJohn Marino                       const char *const *arglist,
197*09d4459fSDaniel Fojt                       const void *vallist, size_t valsize)
19895b7b453SJohn Marino {
19995b7b453SJohn Marino   size_t i;
20095b7b453SJohn Marino 
20195b7b453SJohn Marino   for (i = 0; arglist[i]; i++)
202*09d4459fSDaniel Fojt     if (!memcmp (value, (char const *) vallist + valsize * i, valsize))
20395b7b453SJohn Marino       return arglist[i];
20495b7b453SJohn Marino   return NULL;
20595b7b453SJohn Marino }
20695b7b453SJohn Marino 
20795b7b453SJohn Marino #ifdef TEST
20895b7b453SJohn Marino /*
20995b7b453SJohn Marino  * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
21095b7b453SJohn Marino  */
21195b7b453SJohn Marino 
21295b7b453SJohn Marino /* When to make backup files.  */
21395b7b453SJohn Marino enum backup_type
21495b7b453SJohn Marino {
21595b7b453SJohn Marino   /* Never make backups.  */
21695b7b453SJohn Marino   no_backups,
21795b7b453SJohn Marino 
21895b7b453SJohn Marino   /* Make simple backups of every file.  */
21995b7b453SJohn Marino   simple_backups,
22095b7b453SJohn Marino 
22195b7b453SJohn Marino   /* Make numbered backups of files that already have numbered backups,
22295b7b453SJohn Marino      and simple backups of the others.  */
22395b7b453SJohn Marino   numbered_existing_backups,
22495b7b453SJohn Marino 
22595b7b453SJohn Marino   /* Make numbered backups of every file.  */
22695b7b453SJohn Marino   numbered_backups
22795b7b453SJohn Marino };
22895b7b453SJohn Marino 
22995b7b453SJohn Marino /* Two tables describing arguments (keys) and their corresponding
23095b7b453SJohn Marino    values */
23195b7b453SJohn Marino static const char *const backup_args[] =
23295b7b453SJohn Marino {
23395b7b453SJohn Marino   "no", "none", "off",
23495b7b453SJohn Marino   "simple", "never",
23595b7b453SJohn Marino   "existing", "nil",
23695b7b453SJohn Marino   "numbered", "t",
23795b7b453SJohn Marino   0
23895b7b453SJohn Marino };
23995b7b453SJohn Marino 
24095b7b453SJohn Marino static const enum backup_type backup_vals[] =
24195b7b453SJohn Marino {
24295b7b453SJohn Marino   no_backups, no_backups, no_backups,
24395b7b453SJohn Marino   simple_backups, simple_backups,
24495b7b453SJohn Marino   numbered_existing_backups, numbered_existing_backups,
24595b7b453SJohn Marino   numbered_backups, numbered_backups
24695b7b453SJohn Marino };
24795b7b453SJohn Marino 
24895b7b453SJohn Marino int
main(int argc,const char * const * argv)24995b7b453SJohn Marino main (int argc, const char *const *argv)
25095b7b453SJohn Marino {
25195b7b453SJohn Marino   const char *cp;
25295b7b453SJohn Marino   enum backup_type backup_type = no_backups;
25395b7b453SJohn Marino 
25495b7b453SJohn Marino   if (argc > 2)
25595b7b453SJohn Marino     {
256*09d4459fSDaniel Fojt       fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", getprogname ());
25795b7b453SJohn Marino       exit (1);
25895b7b453SJohn Marino     }
25995b7b453SJohn Marino 
26095b7b453SJohn Marino   if ((cp = getenv ("VERSION_CONTROL")))
26195b7b453SJohn Marino     backup_type = XARGMATCH ("$VERSION_CONTROL", cp,
26295b7b453SJohn Marino                              backup_args, backup_vals);
26395b7b453SJohn Marino 
26495b7b453SJohn Marino   if (argc == 2)
265*09d4459fSDaniel Fojt     backup_type = XARGMATCH (getprogname (), argv[1],
26695b7b453SJohn Marino                              backup_args, backup_vals);
26795b7b453SJohn Marino 
268cf28ed85SJohn Marino   printf ("The version control is '%s'\n",
26995b7b453SJohn Marino           ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
27095b7b453SJohn Marino 
27195b7b453SJohn Marino   return 0;
27295b7b453SJohn Marino }
27395b7b453SJohn Marino #endif
274