(root)/
findutils-4.9.0/
lib/
regextype.c
       1  
       2  /* regextype.c -- Decode the name of a regular expression syntax into am
       3                    option name.
       4  
       5     Copyright (C) 2005-2022 Free Software Foundation, Inc.
       6  
       7     This program is free software: you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation, either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program.  If not, see <https://www.gnu.org/licenses/>.
      19  */
      20  /* Written by James Youngman, <jay@gnu.org>. */
      21  
      22  /* config.h must be included first. */
      23  #include <config.h>
      24  
      25  /* system headers. */
      26  #include <stdio.h>
      27  #include <stdlib.h>
      28  #include <string.h>
      29  
      30  /* gnulib headers. */
      31  #include "quote.h"
      32  #include "regex.h"
      33  #include "regextype.h"
      34  #include "xalloc.h"
      35  
      36  /* findutils headers */
      37  #include "system.h"
      38  #include "die.h"
      39  
      40  
      41  struct tagRegexTypeMap
      42  {
      43    const char *name;
      44    int  context;
      45    int  option_val;
      46  };
      47  
      48  static struct tagRegexTypeMap regex_map[] =
      49    {
      50     { "findutils-default",     CONTEXT_FINDUTILS, RE_SYNTAX_EMACS|RE_DOT_NEWLINE  },
      51     { "ed",                    CONTEXT_GENERIC,   RE_SYNTAX_ED                    },
      52     { "emacs",                 CONTEXT_ALL,       RE_SYNTAX_EMACS                 },
      53     { "gnu-awk",               CONTEXT_ALL,       RE_SYNTAX_GNU_AWK               },
      54     { "grep",                  CONTEXT_ALL,       RE_SYNTAX_GREP                  },
      55     { "posix-awk",             CONTEXT_ALL,       RE_SYNTAX_POSIX_AWK             },
      56     { "awk",                   CONTEXT_ALL,       RE_SYNTAX_AWK                   },
      57     { "posix-basic",           CONTEXT_ALL,       RE_SYNTAX_POSIX_BASIC           },
      58     { "posix-egrep",           CONTEXT_ALL,       RE_SYNTAX_POSIX_EGREP           },
      59     { "egrep",                 CONTEXT_ALL,       RE_SYNTAX_EGREP                 },
      60     { "posix-extended",        CONTEXT_ALL,       RE_SYNTAX_POSIX_EXTENDED        },
      61     { "posix-minimal-basic",   CONTEXT_GENERIC,   RE_SYNTAX_POSIX_MINIMAL_BASIC   },
      62     { "sed",                   CONTEXT_GENERIC,   RE_SYNTAX_SED                   },
      63     /*    ,{ "posix-common",   CONTEXT_GENERIC,  _RE_SYNTAX_POSIX_COMMON   } */
      64    };
      65  enum { N_REGEX_MAP_ENTRIES = sizeof (regex_map)/sizeof (regex_map[0]) };
      66  
      67  int
      68  get_regex_type (const char *s)
      69  {
      70    unsigned i;
      71    size_t msglen;
      72    char *buf, *p;
      73  
      74    msglen = 0u;
      75    for (i=0u; i<N_REGEX_MAP_ENTRIES; ++i)
      76      {
      77        if (0 == strcmp (regex_map[i].name, s))
      78  	return regex_map[i].option_val;
      79        else
      80  	msglen += strlen (quote (regex_map[i].name)) + 2u;
      81      }
      82  
      83    /* We didn't find a match for the type of regular expression that the
      84     * user indicated they wanted.  Tell them what the options are.
      85     */
      86    p = buf = xmalloc (1u + msglen);
      87    for (i=0u; i<N_REGEX_MAP_ENTRIES; ++i)
      88      {
      89        if (i > 0u)
      90  	{
      91  	  strcpy (p, ", ");
      92  	  p += 2;
      93  	}
      94        p += sprintf (p, "%s", quote (regex_map[i].name));
      95      }
      96  
      97    die (EXIT_FAILURE, 0,
      98         _("Unknown regular expression type %s; valid types are %s."),
      99         quote (s),
     100         buf);
     101    /*NOTREACHED*/
     102    return -1;
     103  }
     104  
     105  
     106  const char *
     107  get_regex_type_name (unsigned int ix)
     108  {
     109    if (ix < N_REGEX_MAP_ENTRIES)
     110      return regex_map[ix].name;
     111    else
     112      return NULL;
     113  }
     114  
     115  int
     116  get_regex_type_flags (unsigned int ix)
     117  {
     118    if (ix < N_REGEX_MAP_ENTRIES)
     119      return regex_map[ix].option_val;
     120    else
     121      return -1;
     122  }
     123  
     124  unsigned int get_regex_type_context (unsigned int ix)
     125  {
     126    if (ix < N_REGEX_MAP_ENTRIES)
     127      return regex_map[ix].context;
     128    else
     129      return 0u;
     130  }
     131  
     132  int
     133  get_regex_type_synonym (unsigned int ix, unsigned int context)
     134  {
     135    unsigned i;
     136    int flags;
     137  
     138    if (ix >= N_REGEX_MAP_ENTRIES)
     139      return -1;
     140    flags = regex_map[ix].option_val;
     141    /* Terminate the loop before we get to IX, so that we always
     142       consistently choose the same entry as a synonym (rather than
     143       stating that x and y are synonyms of each other). */
     144    for (i=0u; i<ix; ++i)
     145      {
     146        if ((regex_map[i].context & context) == 0)
     147  	{
     148  	  /* It is pointless to state that "x is a synonym of y" if we
     149  	     are not in fact going to include y. */
     150  	  continue;
     151  	}
     152        else if (flags == regex_map[i].option_val)
     153  	{
     154  	  return i;
     155  	}
     156      }
     157    return -1;
     158  }