X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Frpmatch.c;h=cf1252381a4476637e3a10d35066f6a753cef5e9;hb=9fc81090f6c5590bd1b0e0fa5087577a2ee43a3e;hp=65674b6ab3095a0d5cc2408719926b602cad4086;hpb=a2232307a099e1e49f5438a96ac4fed1c46e4078;p=gnulib.git diff --git a/lib/rpmatch.c b/lib/rpmatch.c index 65674b6ab..cf1252381 100644 --- a/lib/rpmatch.c +++ b/lib/rpmatch.c @@ -1,87 +1,173 @@ -/* rpmatch - determine whether string value is affirmation or negative - response according to current locale's data -Copyright (C) 1996 Free Software Foundation, Inc. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif +/* Determine whether string value is affirmation or negative response + according to current locale's data. -#if STDC_HEADERS || _LIBC -# include -# include -#else -# ifndef NULL -# define NULL 0 -# endif -#endif + Copyright (C) 1996, 1998, 2000, 2002-2003, 2006-2013 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include -#include -#include +/* Specification. */ +#include + +#include +#include #if ENABLE_NLS -# include -# define _(Text) gettext (Text) -#else -# define _(Text) Text -#endif +# include +# include +# include +# if HAVE_LANGINFO_YESEXPR +# include +# endif +# include +# include "gettext.h" +# define _(msgid) gettext (msgid) +# define N_(msgid) gettext_noop (msgid) + +# if HAVE_LANGINFO_YESEXPR +/* Return the localized regular expression pattern corresponding to + ENGLISH_PATTERN. NL_INDEX can be used with nl_langinfo. + The resulting string may only be used until the next nl_langinfo call. */ +static const char * +localized_pattern (const char *english_pattern, nl_item nl_index, + bool posixly_correct) +{ + const char *translated_pattern; + + /* We prefer to get the patterns from a PO file. It would be possible to + always use nl_langinfo (YESEXPR) instead of _("^[yY]"), and + nl_langinfo (NOEXPR) instead of _("^[nN]"), if we could assume that the + system's locale support is good. But this is not the case e.g. on Cygwin. + The localizations of gnulib.pot are of better quality in general. + Also, if we use locale info from non-free systems that don't have a + 'localedef' command, we deprive the users of the freedom to localize + this pattern for their preferred language. + But some programs, such as 'cp', 'mv', 'rm', 'find', 'xargs', are + specified by POSIX to use nl_langinfo (YESEXPR). We implement this + behaviour if POSIXLY_CORRECT is set, for the sake of these programs. */ + + /* If the user wants strict POSIX compliance, use nl_langinfo. */ + if (posixly_correct) + { + translated_pattern = nl_langinfo (nl_index); + /* Check against a broken system return value. */ + if (translated_pattern != NULL && translated_pattern[0] != '\0') + return translated_pattern; + } + + /* Look in the gnulib message catalog. */ + translated_pattern = _(english_pattern); + if (translated_pattern == english_pattern) + { + /* The gnulib message catalog provides no translation. + Try the system's message catalog. */ + translated_pattern = nl_langinfo (nl_index); + /* Check against a broken system return value. */ + if (translated_pattern != NULL && translated_pattern[0] != '\0') + return translated_pattern; + /* Fall back to English. */ + translated_pattern = english_pattern; + } + return translated_pattern; +} +# else +# define localized_pattern(english_pattern,nl_index,posixly_correct) \ + _(english_pattern) +# endif static int -try (response, pattern, match, nomatch, lastp, re) - const char *response; - const char *pattern; - const int match; - const int nomatch; - const char **lastp; - regex_t *re; +try (const char *response, const char *pattern, char **lastp, regex_t *re) { - if (pattern != *lastp) + if (*lastp == NULL || strcmp (pattern, *lastp) != 0) { + char *safe_pattern; + /* The pattern has changed. */ - if (*lastp) - { - /* Free the old compiled pattern. */ - regfree (re); - *lastp = NULL; - } + if (*lastp != NULL) + { + /* Free the old compiled pattern. */ + regfree (re); + free (*lastp); + *lastp = NULL; + } + /* Put the PATTERN into safe memory before calling regcomp. + (regcomp may call nl_langinfo, overwriting PATTERN's storage. */ + safe_pattern = strdup (pattern); + if (safe_pattern == NULL) + return -1; /* Compile the pattern and cache it for future runs. */ - if (regcomp (re, pattern, REG_EXTENDED) != 0) - return -1; - *lastp = pattern; + if (regcomp (re, safe_pattern, REG_EXTENDED) != 0) + return -1; + *lastp = safe_pattern; } /* See if the regular expression matches RESPONSE. */ - return regexec (re, response, 0, NULL, 0) == 0 ? match : nomatch; + return regexec (re, response, 0, NULL, 0) == 0; } +#endif int -rpmatch (response) - const char *response; +rpmatch (const char *response) { +#if ENABLE_NLS /* Match against one of the response patterns, compiling the pattern first if necessary. */ /* We cache the response patterns and compiled regexps here. */ - static const char *yesexpr, *noexpr; - static regex_t yesre, nore; + static char *last_yesexpr, *last_noexpr; + static regex_t cached_yesre, cached_nore; + +# if HAVE_LANGINFO_YESEXPR + bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL); +# endif + + const char *yesexpr, *noexpr; int result; - return ((result = try (response, _("^[yY]"), 1, 0, - &yesexpr, &yesre)) - ? result - : try (response, _("^[nN]"), 0, -1, &noexpr, &nore)); + /* TRANSLATORS: A regular expression testing for an affirmative answer + (english: "yes"). Testing the first character may be sufficient. + Take care to consider upper and lower case. + To enquire the regular expression that your system uses for this + purpose, you can use the command + locale -k LC_MESSAGES | grep '^yesexpr=' */ + yesexpr = localized_pattern (N_("^[yY]"), YESEXPR, posixly_correct); + result = try (response, yesexpr, &last_yesexpr, &cached_yesre); + if (result < 0) + return -1; + if (result) + return 1; + + /* TRANSLATORS: A regular expression testing for a negative answer + (english: "no"). Testing the first character may be sufficient. + Take care to consider upper and lower case. + To enquire the regular expression that your system uses for this + purpose, you can use the command + locale -k LC_MESSAGES | grep '^noexpr=' */ + noexpr = localized_pattern (N_("^[nN]"), NOEXPR, posixly_correct); + result = try (response, noexpr, &last_noexpr, &cached_nore); + if (result < 0) + return -1; + if (result) + return 0; + + return -1; +#else + /* Test against "^[yY]" and "^[nN]", hardcoded to avoid requiring regex */ + return (*response == 'y' || *response == 'Y' ? 1 + : *response == 'n' || *response == 'N' ? 0 : -1); +#endif }