bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Describe which environment variables really control the inte


From: Bruno Haible
Subject: Re: [PATCH] Describe which environment variables really control the interpretation of the response to -ok.
Date: Mon, 28 Apr 2008 01:27:15 +0200
User-agent: KMail/1.5.4

Hi Jim,

> The only non-POSIX behaviour is that it fetches the yesexpr and noexpr from
> a compiled PO file rather than from the system's nl_langinfo function.

Here is a proposed compromise that enables the strict POSIX behaviour when
POSIXLY_CORRECT is set. This is a POSIX compliance fix for the programs
'cp', 'mv', 'rm', 'find', 'xargs'.

This is a continuation of the approach presented last year in
  http://lists.gnu.org/archive/html/bug-gnulib/2007-08/msg00075.html
Paul replied with the argument of POSIX compliance here:
  http://lists.gnu.org/archive/html/bug-gnulib/2007-08/msg00093.html
I think testing POSIXLY_CORRECT should address this argument.

Tested with the 'yesno' module. (Why does the 'rpmatch' module not have a
unit test? Why does it not even have an include file that declares the
rpmatch function?)

Jim, Eric, is this ok to apply?


2007-08-18  Bruno Haible  <address@hidden>

        * lib/rpmatch.c: Include stdbool.h, string.h, langinfo.h.
        (N_): New macro.
        (localized_pattern): New function/macro.
        (try): Remove match, nomatch arguments. Copy the pattern into safe
        memory before caching it.
        (rpmatch): Use localized_pattern. Add translator comments.
        * m4/rpmatch.m4 (gl_PREREQ_RPMATCH): Test for nl_langinfo and YESEXPR.
        Suggested by Eric Blake.
        * modules/rpmatch (Depends-on): Add stdbool.

*** lib/rpmatch.c.orig  2008-04-28 01:25:41.000000000 +0200
--- lib/rpmatch.c       2008-04-28 01:02:12.000000000 +0200
***************
*** 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, 2008 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-2008 Free Software
     Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
***************
*** 19,59 ****
  
  #include <config.h>
  
  #include <stddef.h>
  #include <stdlib.h>
  
  #if ENABLE_NLS
  # 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)
  {
--- 19,126 ----
  
  #include <config.h>
  
+ #include <stdbool.h>
  #include <stddef.h>
  #include <stdlib.h>
  
  #if ENABLE_NLS
  # include <sys/types.h>
  # include <limits.h>
+ # include <string.h>
+ # if HAVE_LANGINFO_YESEXPR
+ #  include <langinfo.h>
+ # endif
  # include <regex.h>
  # 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 (const char *response, const char *pattern, 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;
  }
  #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)
  {
***************
*** 61,84 ****
    /* Match against one of the response patterns, compiling the pattern
       first if necessary.  */
  
-   /* We get the patterns from a PO file.  It would be possible to 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 used locale info from non-free systems that don't have a
-      'localedef' command, we would deprive the users of the freedom to
-      localize this pattern for their preferred language.  */
- 
    /* 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
--- 128,171 ----
    /* Match against one of the response patterns, compiling the pattern
       first if necessary.  */
  
    /* We cache the response patterns and compiled regexps here.  */
!   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;
  
!   /* 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
*** m4/rpmatch.m4.orig  2008-04-28 01:25:41.000000000 +0200
--- m4/rpmatch.m4       2008-04-28 00:24:03.000000000 +0200
***************
*** 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-2008 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
! ])
*** modules/rpmatch.orig        2008-04-28 01:25:41.000000000 +0200
--- modules/rpmatch     2008-04-27 23:49:28.000000000 +0200
***************
*** 6,11 ****
--- 6,12 ----
  m4/rpmatch.m4
  
  Depends-on:
+ stdbool
  gettext-h
  regex
  





reply via email to

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