[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: yesno module and i18n
From: |
Bruno Haible |
Subject: |
Re: yesno module and i18n |
Date: |
Sat, 18 Aug 2007 21:25:31 +0200 |
User-agent: |
KMail/1.5.4 |
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 <address@hidden>
* 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
! ])
- yesno module consumes too much input, Eric Blake-1, 2007/08/17
- Re: yesno module consumes too much input, Eric Blake-1, 2007/08/17
- Re: yesno module and i18n, Bruno Haible, 2007/08/18
- Re: yesno module and i18n, Paul Eggert, 2007/08/19
- Re: yesno module and i18n, Bruno Haible, 2007/08/19
- Re: yesno module and i18n, Eric Blake, 2007/08/19
- Re: yesno module and i18n, Paul Eggert, 2007/08/23
Re: yesno module consumes too much input, Jim Meyering, 2007/08/17
Re: yesno module consumes too much input, Paul Eggert, 2007/08/17