Eric Blake wrote: > > + translated_pattern = nl_langinfo (nl_index); > > Not reliable. nl_langinfo is entitled to use static storage that can be > overwritten by later calls to nl_langinfo or by subsequent changes to the > locale. You will need to do something like strdup to avoid problems with > nl_langinfo's storage; then properly clean up to avoid memory leaks.
Oh, indeed. How about this? 2007-08-18 Bruno Haible <[EMAIL PROTECTED]> * lib/rpmatch.c: Include langinfo.h. (N_): New macro. (try): Copy the pattern into safe memory before caching it. (localized_pattern): New function/macro. (rpmatch): Use it. Add translator comments. * m4/rpmatch.m4 (gl_PREREQ_RPMATCH): Test for nl_langinfo and YESEXPR. Suggested by Eric Blake. *** lib/rpmatch.c 13 Sep 2006 22:38:14 -0000 1.20 --- lib/rpmatch.c 18 Aug 2007 19:24:04 -0000 *************** *** 1,7 **** /* Determine whether string value is affirmation or negative response according to current locale's data. ! Copyright (C) 1996, 1998, 2000, 2002, 2003, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify --- 1,7 ---- /* Determine whether string value is affirmation or negative response according to current locale's data. ! Copyright (C) 1996, 1998, 2000, 2002-2003, 2006-2007 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify *************** *** 27,60 **** # include <sys/types.h> # include <limits.h> # include <regex.h> # include "gettext.h" # define _(msgid) gettext (msgid) static int try (const char *response, const char *pattern, const int match, ! const int nomatch, const char **lastp, regex_t *re) { ! if (pattern != *lastp) { /* The pattern has changed. */ ! if (*lastp) { /* Free the old compiled pattern. */ regfree (re); *lastp = NULL; } /* Compile the pattern and cache it for future runs. */ ! if (regcomp (re, pattern, REG_EXTENDED) != 0) return -1; ! *lastp = pattern; } /* See if the regular expression matches RESPONSE. */ return regexec (re, response, 0, NULL, 0) == 0 ? match : nomatch; } #endif int rpmatch (const char *response) { --- 27,100 ---- # include <sys/types.h> # include <limits.h> # include <regex.h> + # include <string.h> + # if HAVE_LANGINFO_YESEXPR + # include <langinfo.h> + # endif # include "gettext.h" # define _(msgid) gettext (msgid) + # define N_(msgid) gettext_noop (msgid) static int try (const char *response, const char *pattern, const int match, ! const int nomatch, char **lastp, regex_t *re) { ! if (*lastp == NULL || strcmp (pattern, *lastp) != 0) { + char *safe_pattern; + /* The pattern has changed. */ ! 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, 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; } + + # 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) + { + /* First, look in the gnulib message catalog. */ + const char *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); + if (translated_pattern == NULL || translated_pattern[0] == '\0') + /* Broken system. */ + translated_pattern = english_pattern; + } + return translated_pattern; + } + # else + # define localized_pattern(english_pattern,nl_index) _(english_pattern) + # endif + #endif + /* Test a user response to a question. + Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear. */ int rpmatch (const char *response) { *************** *** 63,76 **** first if necessary. */ /* We cache the response patterns and compiled regexps here. */ ! static const char *yesexpr, *noexpr; static regex_t yesre, nore; int result; ! return ((result = try (response, _("^[yY]"), 1, 0, ! &yesexpr, &yesre)) ? result ! : try (response, _("^[nN]"), 0, -1, &noexpr, &nore)); #else /* Test against "^[yY]" and "^[nN]", hardcoded to avoid requiring regex */ return (*response == 'y' || *response == 'Y' ? 1 --- 103,133 ---- first if necessary. */ /* We cache the response patterns and compiled regexps here. */ ! static char *yesexpr, *noexpr; static regex_t yesre, nore; int result; ! return ((result = try (response, ! /* 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=' */ ! localized_pattern (N_("^[yY]"), YESEXPR), ! 1, 0, &yesexpr, &yesre)) ? result ! : try (response, ! /* 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=' */ ! localized_pattern (N_("^[nN]"), NOEXPR), ! 0, -1, &noexpr, &nore)); #else /* Test against "^[yY]" and "^[nN]", hardcoded to avoid requiring regex */ return (*response == 'y' || *response == 'Y' ? 1 *** m4/rpmatch.m4 23 Jan 2005 08:06:57 -0000 1.5 --- m4/rpmatch.m4 18 Aug 2007 19:24:04 -0000 *************** *** 1,5 **** ! # rpmatch.m4 serial 5 ! dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. --- 1,5 ---- ! # rpmatch.m4 serial 6 ! dnl Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. *************** *** 13,16 **** ]) # Prerequisites of lib/rpmatch.c. ! AC_DEFUN([gl_PREREQ_RPMATCH], [:]) --- 13,27 ---- ]) # Prerequisites of lib/rpmatch.c. ! AC_DEFUN([gl_PREREQ_RPMATCH], [ ! AC_CACHE_CHECK([for nl_langinfo and YESEXPR], gl_cv_langinfo_yesexpr, ! [AC_TRY_LINK([#include <langinfo.h>], ! [char* cs = nl_langinfo(YESEXPR); return !cs;], ! gl_cv_langinfo_yesexpr=yes, ! gl_cv_langinfo_yesexpr=no) ! ]) ! if test $gl_cv_langinfo_yesexpr = yes; then ! AC_DEFINE([HAVE_LANGINFO_YESEXPR], 1, ! [Define if you have <langinfo.h> and nl_langinfo(YESEXPR).]) ! fi ! ])