bug-gnulib
[Top][All Lists]
Advanced

[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
! ])





reply via email to

[Prev in Thread] Current Thread [Next in Thread]