]> Savannah Git Hosting - gnulib.git/commitdiff
localeinfo: record whether locale is simple
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 16 Dec 2019 08:27:15 +0000 (00:27 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 16 Dec 2019 08:56:46 +0000 (00:56 -0800)
* lib/localeinfo.c (using_simple_locale): New function,
copied here from lib/dfa.c but with a change: it uses
strcoll for its heuristic, instead of using setlocale.
This lets it be thread-safe.
* lib/localeinfo.h (struct localeinfo): New member ‘simple’.

ChangeLog
lib/localeinfo.c
lib/localeinfo.h

index 4f46f01a4eac9d090e0674f2c17269905a6950f2..e59323a3ed75267bba3974c227bb9b8be51cb5f1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2019-12-16  Paul Eggert  <eggert@cs.ucla.edu>
+
+       localeinfo: record whether locale is simple
+       * lib/localeinfo.c (using_simple_locale): New function,
+       copied here from lib/dfa.c but with a change: it uses
+       strcoll for its heuristic, instead of using setlocale.
+       This lets it be thread-safe.
+       * lib/localeinfo.h (struct localeinfo): New member ‘simple’.
+
 2019-12-15  Bruno Haible  <bruno@clisp.org>
 
        duplocale: Fix multithread-safety bug on AIX.
index 65b6c5e6de06060eed7e01d39b049d927f64d80c..372530e014bbe66c4da04a802846a044cd356907 100644 (file)
@@ -44,17 +44,55 @@ is_using_utf8 (void)
   return mbrtowc (&wc, "\xc4\x80", 2, &mbs) == 2 && wc == 0x100;
 }
 
+/* Return true if the locale is compatible enough with the C locale so
+   that the locale is single-byte, bytes are in collating-sequence
+   order, and there are no multi-character collating elements.  */
+
+static bool
+using_simple_locale (bool multibyte)
+{
+  /* The native character set is known to be compatible with
+     the C locale.  The following test isn't perfect, but it's good
+     enough in practice, as only ASCII and EBCDIC are in common use
+     and this test correctly accepts ASCII and rejects EBCDIC.  */
+  enum { native_c_charset =
+    ('\b' == 8 && '\t' == 9 && '\n' == 10 && '\v' == 11 && '\f' == 12
+     && '\r' == 13 && ' ' == 32 && '!' == 33 && '"' == 34 && '#' == 35
+     && '%' == 37 && '&' == 38 && '\'' == 39 && '(' == 40 && ')' == 41
+     && '*' == 42 && '+' == 43 && ',' == 44 && '-' == 45 && '.' == 46
+     && '/' == 47 && '0' == 48 && '9' == 57 && ':' == 58 && ';' == 59
+     && '<' == 60 && '=' == 61 && '>' == 62 && '?' == 63 && 'A' == 65
+     && 'Z' == 90 && '[' == 91 && '\\' == 92 && ']' == 93 && '^' == 94
+     && '_' == 95 && 'a' == 97 && 'z' == 122 && '{' == 123 && '|' == 124
+     && '}' == 125 && '~' == 126)
+  };
+
+  if (!native_c_charset || multibyte)
+    return false;
+
+  /* As a heuristic, use strcoll to compare native character order.
+     If this agrees with byte order the locale should be simple.
+     This heuristic should work for all known practical locales,
+     although it would be invalid for artificially-constructed locales
+     where the native order is the collating-sequence order but there
+     are multi-character collating elements.  */
+  for (int i = 0; i < UCHAR_MAX; i++)
+    if (strcoll (((char []) {i, 0}), ((char []) {i + 1, 0})) <= 0)
+      return false;
+
+  return true;
+}
+
 /* Initialize *LOCALEINFO from the current locale.  */
 
 void
 init_localeinfo (struct localeinfo *localeinfo)
 {
-  int i;
-
   localeinfo->multibyte = MB_CUR_MAX > 1;
+  localeinfo->simple = using_simple_locale (localeinfo->multibyte);
   localeinfo->using_utf8 = is_using_utf8 ();
 
-  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+  for (int i = CHAR_MIN; i <= CHAR_MAX; i++)
     {
       char c = i;
       unsigned char uc = i;
index a5140164fde34840b95d2d399eb5471b65551891..c827a2bfd25477f49f38b3fb5a5212d2ef68d3e9 100644 (file)
@@ -28,6 +28,12 @@ struct localeinfo
   /* MB_CUR_MAX > 1.  */
   bool multibyte;
 
+  /* The locale is simple, like the C locale.  These locales can be
+     processed more efficiently, as they are single-byte, their native
+     character set is in collating-sequence order, and they do not
+     have multi-character collating elements.  */
+  bool simple;
+
   /* The locale uses UTF-8.  */
   bool using_utf8;