root/maint/gnulib/lib/rpmatch.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. localized_pattern
  2. try
  3. rpmatch

   1 /* Determine whether string value is affirmation or negative response
   2    according to current locale's data.
   3 
   4    Copyright (C) 1996, 1998, 2000, 2002-2003, 2006-2021 Free Software
   5    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 #include <config.h>
  21 
  22 /* Specification.  */
  23 #include <stdlib.h>
  24 
  25 #include <stdbool.h>
  26 #include <stddef.h>
  27 
  28 #if ENABLE_NLS
  29 # include <sys/types.h>
  30 # include <limits.h>
  31 # include <string.h>
  32 # if HAVE_LANGINFO_YESEXPR
  33 #  include <langinfo.h>
  34 # endif
  35 # include <regex.h>
  36 # include "gettext.h"
  37 # define _(msgid) gettext (msgid)
  38 # define N_(msgid) gettext_noop (msgid)
  39 
  40 # if HAVE_LANGINFO_YESEXPR
  41 /* Return the localized regular expression pattern corresponding to
  42    ENGLISH_PATTERN.  NL_INDEX can be used with nl_langinfo.
  43    The resulting string may only be used until the next nl_langinfo call.  */
  44 static const char *
  45 localized_pattern (const char *english_pattern, nl_item nl_index,
     /* [previous][next][first][last][top][bottom][index][help] */
  46                    bool posixly_correct)
  47 {
  48   const char *translated_pattern;
  49 
  50   /* We prefer to get the patterns from a PO file.  It would be possible to
  51      always use nl_langinfo (YESEXPR) instead of _("^[yY]"), and
  52      nl_langinfo (NOEXPR) instead of _("^[nN]"), if we could assume that the
  53      system's locale support is good.  But this is not the case e.g. on Cygwin.
  54      The localizations of gnulib.pot are of better quality in general.
  55      Also, if we use locale info from non-free systems that don't have a
  56      'localedef' command, we deprive the users of the freedom to localize
  57      this pattern for their preferred language.
  58      But some programs, such as 'cp', 'mv', 'rm', 'find', 'xargs', are
  59      specified by POSIX to use nl_langinfo (YESEXPR).  We implement this
  60      behaviour if POSIXLY_CORRECT is set, for the sake of these programs.  */
  61 
  62   /* If the user wants strict POSIX compliance, use nl_langinfo.  */
  63   if (posixly_correct)
  64     {
  65       translated_pattern = nl_langinfo (nl_index);
  66       /* Check against a broken system return value.  */
  67       if (translated_pattern != NULL && translated_pattern[0] != '\0')
  68         return translated_pattern;
  69    }
  70 
  71   /* Look in the gnulib message catalog.  */
  72   translated_pattern = _(english_pattern);
  73   if (translated_pattern == english_pattern)
  74     {
  75       /* The gnulib message catalog provides no translation.
  76          Try the system's message catalog.  */
  77       translated_pattern = nl_langinfo (nl_index);
  78       /* Check against a broken system return value.  */
  79       if (translated_pattern != NULL && translated_pattern[0] != '\0')
  80         return translated_pattern;
  81       /* Fall back to English.  */
  82       translated_pattern = english_pattern;
  83     }
  84   return translated_pattern;
  85 }
  86 # else
  87 #  define localized_pattern(english_pattern,nl_index,posixly_correct) \
  88      _(english_pattern)
  89 # endif
  90 
  91 static int
  92 try (const char *response, const char *pattern, char **lastp, regex_t *re)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94   if (*lastp == NULL || strcmp (pattern, *lastp) != 0)
  95     {
  96       char *safe_pattern;
  97 
  98       /* The pattern has changed.  */
  99       if (*lastp != NULL)
 100         {
 101           /* Free the old compiled pattern.  */
 102           regfree (re);
 103           free (*lastp);
 104           *lastp = NULL;
 105         }
 106       /* Put the PATTERN into safe memory before calling regcomp.
 107          (regcomp may call nl_langinfo, overwriting PATTERN's storage.  */
 108       safe_pattern = strdup (pattern);
 109       if (safe_pattern == NULL)
 110         return -1;
 111       /* Compile the pattern and cache it for future runs.  */
 112       if (regcomp (re, safe_pattern, REG_EXTENDED) != 0)
 113         {
 114           free (safe_pattern);
 115           return -1;
 116         }
 117       *lastp = safe_pattern;
 118     }
 119 
 120   /* See if the regular expression matches RESPONSE.  */
 121   return regexec (re, response, 0, NULL, 0) == 0;
 122 }
 123 #endif
 124 
 125 
 126 int
 127 rpmatch (const char *response)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129 #if ENABLE_NLS
 130   /* Match against one of the response patterns, compiling the pattern
 131      first if necessary.  */
 132 
 133   /* We cache the response patterns and compiled regexps here.  */
 134   static char *last_yesexpr, *last_noexpr;
 135   static regex_t cached_yesre, cached_nore;
 136 
 137 # if HAVE_LANGINFO_YESEXPR
 138   bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
 139 # endif
 140 
 141   const char *yesexpr, *noexpr;
 142   int result;
 143 
 144   /* TRANSLATORS: A regular expression testing for an affirmative answer
 145      (english: "yes").  Testing the first character may be sufficient.
 146      Take care to consider upper and lower case.
 147      To enquire the regular expression that your system uses for this
 148      purpose, you can use the command
 149        locale -k LC_MESSAGES | grep '^yesexpr='  */
 150   yesexpr = localized_pattern (N_("^[yY]"), YESEXPR, posixly_correct);
 151   result = try (response, yesexpr, &last_yesexpr, &cached_yesre);
 152   if (result < 0)
 153     return -1;
 154   if (result)
 155     return 1;
 156 
 157   /* TRANSLATORS: A regular expression testing for a negative answer
 158      (english: "no").  Testing the first character may be sufficient.
 159      Take care to consider upper and lower case.
 160      To enquire the regular expression that your system uses for this
 161      purpose, you can use the command
 162        locale -k LC_MESSAGES | grep '^noexpr='  */
 163   noexpr = localized_pattern (N_("^[nN]"), NOEXPR, posixly_correct);
 164   result = try (response, noexpr, &last_noexpr, &cached_nore);
 165   if (result < 0)
 166     return -1;
 167   if (result)
 168     return 0;
 169 
 170   return -1;
 171 #else
 172   /* Test against "^[yY]" and "^[nN]", hardcoded to avoid requiring regex */
 173   return (*response == 'y' || *response == 'Y' ? 1
 174           : *response == 'n' || *response == 'N' ? 0 : -1);
 175 #endif
 176 }

/* [previous][next][first][last][top][bottom][index][help] */