unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Text collation
@ 2006-09-19  9:23 Ludovic Courtès
  2006-09-19 22:38 ` Kevin Ryde
  0 siblings, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-09-19  9:23 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 3190 bytes --]

Hi,

Guile doesn't provide any locale-dependent string comparison primitive.
`string<?' et al., from SRFI-13 (also found in R5.91RS), are required to
be locale-independent:

  These procedures are the lexicographic extensions to strings of the
  corresponding orderings on characters. For example, string< is the
  lexicographic ordering on strings induced by the ordering char<? on
  characters.

  [...]

  Comparison is simply done on individual code-points of the
  string. True text collation is not handled by this SRFI.

R5.91RS, about `char<?' et al., adds:

  These procedures impose a total ordering on the set of characters
  according to their scalar values.

Thus, for proper locale-dependent "text collation", we need a separate
API.  The patch below provides preliminary support for this.  Here is a
sample session showing how the API can be used:

  guile> (define l (make-locale LC_COLLATE_MASK "fr_FR"))
  guile> l
  #<locale 300a74d0>
  guile> (string-locale<? "été" "hiver") ;; using the "C" locale
  #f
  guile> (string-locale<? "été" "hiver" l)
  #t
  guile> (char-locale<? #\é #\h)         ;; using the "C" locale
  #f
  guile> (char-locale<? #\é #\h l)
  #t
  guile> (setlocale LC_COLLATE "fr_FR")
  "fr_FR"
  guile> (string-locale<? "été" "hiver") ;; using the "fr_FR" locale
  #t

The cool thing is that it's a "clean" API in that the locale settings
can be passed explicitly as a third parameter.  The (potentially)
controversial part is that this wraps a non-standard GNU extension.

I don't think this should be seen as a problem, first because this GNU
extension can be emulated on non-GNU platforms by controlling
invocations of `setlocale' (via a mutex) and by using that to create
"critical locale sections" within the `-locale<?' functions:

  /* Save the current locale settings and install LOCALE_SETTINGS.  */
  scm_being_locked_locale_section (locale_settings);

  result = strcoll (c_s1, c_s2);
  /* ... */

  /* Restore the previous locale settings.  */
  scm_end_locked_locale_section ();

Emulation of the locale category mask that is passed to `make-locale'
may turn out to be quite inelegant, but it can be implemented in terms
of `setlocale ()' (as many calls as bits set in the mask).

Second, it is likely that this or a similar API will be adopted by OSes
and may eventually be standardized.  The C++ standard already includes a
similar locale API (ISO C++ 14882, see the `locale_classes.h' header
that ships with GCC).

The GNU C library also provides `strcasecmp_l ()' which would be nice to
have but since this would be hard or even impossible to "emulate" on
other platforms, it may be preferable not to include it at the moment.

If all this sounds like a reasonable plan to you, then I can implement
locked locale sections (for non-GNU platforms), augment the docs, and
eventually merge it in both 1.8 and HEAD.

Thanks,
Ludovic.

PS: I would be happier if this was part of an `(ice-9 i18n)' module but
    since it's already too late for `gettext', `bindtextdomain' and
    friends to go there, maybe we should just keep using the root
    module...


[-- Attachment #2: The patch --]
[-- Type: text/plain, Size: 8378 bytes --]

--- orig/configure.in
+++ mod/configure.in
@@ -599,8 +599,9 @@
 #   stat64 - SuS largefile stuff, not on old systems
 #   sysconf - not on old systems
 #   _NSGetEnviron - Darwin specific
+#   strcoll_l, newlocale - GNU extensions (glibc)
 #
-AC_CHECK_FUNCS([DINFINITY DQNAN ctermid fesetround ftime fchown getcwd geteuid gettimeofday gmtime_r ioctl lstat mkdir mknod nice readdir_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex unsetenv _NSGetEnviron])
+AC_CHECK_FUNCS([DINFINITY DQNAN ctermid fesetround ftime fchown getcwd geteuid gettimeofday gmtime_r ioctl lstat mkdir mknod nice readdir_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex unsetenv _NSGetEnviron strcoll strcoll_l newlocale])
 
 # Reasons for testing:
 #   netdb.h - not in mingw


--- orig/libguile/i18n.c
+++ mod/libguile/i18n.c
@@ -15,6 +15,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#define _GNU_SOURCE /* Ask for glibc's `newlocale' API */
 
 #if HAVE_CONFIG_H
 # include <config.h>
@@ -24,10 +25,13 @@
 #include "libguile/feature.h"
 #include "libguile/i18n.h"
 #include "libguile/strings.h"
+#include "libguile/chars.h"
 #include "libguile/dynwind.h"
+#include "libguile/validate.h"
 
 #include "gettext.h"
 #include <locale.h>
+#include <string.h> /* `strcoll ()' */
 
 
 int
@@ -312,10 +316,206 @@
 }
 #undef FUNC_NAME
 
-void 
+\f
+/* Locale objects, string and character collation.  */
+
+SCM_SMOB (scm_tc16_locale_smob_type, "locale", 0);
+
+SCM_SMOB_FREE (scm_tc16_locale_smob_type, smob_locale_free, locale)
+{
+#ifdef __GNU_LIBRARY__
+  freelocale ((locale_t)SCM_SMOB_DATA (locale));
+#endif
+
+  return 0;
+}
+
+#ifndef __GNU_LIBRARY__
+
+/* Provide the locale category masks as found in glibc (copied from
+   <locale.h> as found in glibc 2.3.6).  */
+
+# define LC_CTYPE_MASK		(1 << LC_CTYPE)
+# define LC_NUMERIC_MASK	(1 << LC_NUMERIC)
+# define LC_TIME_MASK		(1 << LC_TIME)
+# define LC_COLLATE_MASK	(1 << LC_COLLATE)
+# define LC_MONETARY_MASK	(1 << LC_MONETARY)
+# define LC_MESSAGES_MASK	(1 << LC_MESSAGES)
+# define LC_PAPER_MASK		(1 << LC_PAPER)
+# define LC_NAME_MASK		(1 << LC_NAME)
+# define LC_ADDRESS_MASK	(1 << LC_ADDRESS)
+# define LC_TELEPHONE_MASK	(1 << LC_TELEPHONE)
+# define LC_MEASUREMENT_MASK	(1 << LC_MEASUREMENT)
+# define LC_IDENTIFICATION_MASK	(1 << LC_IDENTIFICATION)
+# define LC_ALL_MASK		(LC_CTYPE_MASK \
+				 | LC_NUMERIC_MASK \
+				 | LC_TIME_MASK \
+				 | LC_COLLATE_MASK \
+				 | LC_MONETARY_MASK \
+				 | LC_MESSAGES_MASK \
+				 | LC_PAPER_MASK \
+				 | LC_NAME_MASK \
+				 | LC_ADDRESS_MASK \
+				 | LC_TELEPHONE_MASK \
+				 | LC_MEASUREMENT_MASK \
+				 | LC_IDENTIFICATION_MASK \
+				 )
+
+#endif
+
+
+SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0,
+	    (SCM category_mask, SCM locale_name, SCM base_locale),
+	    "Return a reference to a data structure representing a set of "
+	    "locale datasets.  Unlike for the @var{category} parameter for "
+	    "@code{setlocale}, the @var{category_mask} parameter here uses "
+	    "a single bit for each category, made by OR'ing together "
+	    "@code{LC_*_MASK} bits.")
+#define FUNC_NAME s_scm_make_locale
+{
+#ifdef __GNU_LIBRARY__
+  SCM locale;
+  int c_category_mask;
+  char *c_locale_name;
+  locale_t c_base_locale, c_locale;
+
+  SCM_VALIDATE_INT_COPY (1, category_mask, c_category_mask);
+  SCM_VALIDATE_STRING (2, locale_name);
+  c_locale_name = scm_to_locale_string (locale_name);
+
+  if (base_locale != SCM_UNDEFINED)
+    {
+      SCM_VALIDATE_SMOB (3, base_locale, locale_smob_type);
+      c_base_locale = (locale_t)SCM_SMOB_DATA (base_locale);
+    }
+  else
+    c_base_locale = NULL;
+
+  c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale);
+  free (c_base_locale);
+
+  if (!c_locale)
+    locale = SCM_BOOL_F;
+  else
+    SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
+
+  return locale;
+#else
+  /* FIXME: Handle this situation, for instance:
+     SCM_RETURN_NEWSMOB (scm_tc16_locale_smob_type,
+                         scm_list_3 (category_mask, locale_name,
+			             base_locale));  */
+  return SCM_BOOL_F;
+#endif
+}
+#undef FUNC_NAME
+
+
+/* Compare null-terminated strings C_S1 and C_S2 according to LOCALE.  Return
+   an integer whose sign is the same as the difference between C_S1 and
+   C_S2.  */
+static inline int
+compare_strings (const char *c_s1, const char *c_s2, SCM locale,
+		 const char *func_name)
+#define FUNC_NAME func_name
+{
+#ifdef __GNU_LIBRARY__
+  locale_t c_locale;
+#endif
+  int result;
+
+#ifdef __GNU_LIBRARY__
+  if (locale != SCM_UNDEFINED)
+    {
+      SCM_VALIDATE_SMOB (3, locale, locale_smob_type);
+      c_locale = (locale_t)SCM_SMOB_DATA (locale);
+    }
+  else
+    c_locale = NULL;
+
+  if (c_locale)
+    result = strcoll_l (c_s1, c_s2, c_locale);
+  else
+#endif
+
+#if HAVE_STRCOLL
+    result = strcoll (c_s1, c_s2);
+#else
+    result = strcmp (c_s1, c_s2);
+#endif
+
+  return result;
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_string_locale_lt, "string-locale<?", 2, 1, 0,
+	    (SCM s1, SCM s2, SCM locale),
+	    "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
+	    "If @var{locale} is provided, it should be locale object (as "
+	    "returned by @code{make-locale}) and will be used to perform the "
+	    "comparison; otherwise, the current system locale is used.")
+#define FUNC_NAME s_scm_string_locale_lt
+{
+  int result;
+  const char *c_s1, *c_s2;
+
+  SCM_VALIDATE_STRING (1, s1);
+  SCM_VALIDATE_STRING (2, s2);
+
+  c_s1 = scm_i_string_chars (s1);
+  c_s2 = scm_i_string_chars (s2);
+
+  result = compare_strings (c_s1, c_s2, locale, FUNC_NAME);
+
+  scm_remember_upto_here_2 (s1, s2);
+
+  return scm_from_bool (result < 0);
+}
+#undef FUNC_NAME
+
+/* XXX: Wrap GNU's `strcasecmp_l ()'?  */
+
+
+SCM_DEFINE (scm_char_locale_lt, "char-locale<?", 2, 1, 0,
+	    (SCM c1, SCM c2, SCM locale),
+	    "Return true if character @var{c1} is lower than @var{c2} "
+	    "according to @var{locale} or to the current locale.")
+#define FUNC_NAME s_scm_char_locale_lt
+{
+  char c_c1[2], c_c2[2];
+
+  SCM_VALIDATE_CHAR (1, c1);
+  SCM_VALIDATE_CHAR (2, c2);
+
+  c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
+  c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
+
+  return scm_from_bool (compare_strings (c_c1, c_c2, locale, FUNC_NAME) < 0);
+}
+#undef FUNC_NAME
+
+
+\f
+void
 scm_init_i18n ()
 {
   scm_add_feature ("i18n");
+
+  scm_c_define ("LC_CTYPE_MASK", SCM_I_MAKINUM (LC_CTYPE_MASK));
+  scm_c_define ("LC_NUMERIC_MASK", SCM_I_MAKINUM (LC_NUMERIC_MASK));
+  scm_c_define ("LC_TIME_MASK", SCM_I_MAKINUM (LC_TIME_MASK));
+  scm_c_define ("LC_COLLATE_MASK", SCM_I_MAKINUM (LC_COLLATE_MASK));
+  scm_c_define ("LC_MONETARY_MASK", SCM_I_MAKINUM (LC_MONETARY_MASK));
+  scm_c_define ("LC_MESSAGES_MASK", SCM_I_MAKINUM (LC_MESSAGES_MASK));
+  scm_c_define ("LC_PAPER_MASK", SCM_I_MAKINUM (LC_PAPER_MASK));
+  scm_c_define ("LC_NAME_MASK", SCM_I_MAKINUM (LC_NAME_MASK));
+  scm_c_define ("LC_ADDRESS_MASK", SCM_I_MAKINUM (LC_ADDRESS_MASK));
+  scm_c_define ("LC_TELEPHONE_MASK", SCM_I_MAKINUM (LC_TELEPHONE_MASK));
+  scm_c_define ("LC_MEASUREMENT_MASK", SCM_I_MAKINUM (LC_MEASUREMENT_MASK));
+  scm_c_define ("LC_IDENTIFICATION_MASK", SCM_I_MAKINUM (LC_IDENTIFICATION_MASK));
+  scm_c_define ("LC_ALL_MASK", SCM_I_MAKINUM (LC_ALL_MASK));
+
 #include "libguile/i18n.x"
 }
 


--- orig/libguile/i18n.h
+++ mod/libguile/i18n.h
@@ -30,6 +30,10 @@
 
 SCM_API int scm_i_to_lc_category (SCM category, int allow_lc_all);
 
+SCM_API SCM scm_make_locale (SCM category_mask, SCM locale_name, SCM base_locale);
+SCM_API SCM scm_string_locale_lt (SCM s1, SCM s2, SCM locale);
+SCM_API SCM scm_char_locale_lt (SCM c1, SCM c2, SCM locale);
+
 SCM_API void scm_init_i18n (void);
 
 #endif  /* SCM_I18N_H */




[-- Attachment #3: Type: text/plain, Size: 143 bytes --]

_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-09-19  9:23 Text collation Ludovic Courtès
@ 2006-09-19 22:38 ` Kevin Ryde
  2006-10-22 18:33   ` Ludovic Courtès
  0 siblings, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-09-19 22:38 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> The cool thing is that it's a "clean" API in that the locale settings
> can be passed explicitly as a third parameter.  The (potentially)
> controversial part is that this wraps a non-standard GNU extension.

/usr/include/locale.h has

	Attention: all these functions are *not* standardized in any form.
	This is a proof-of-concept implementation.

which is not confidence inspiring :(.

> If all this sounds like a reasonable plan to you, then I can implement
> locked locale sections (for non-GNU platforms), augment the docs, and
> eventually merge it in both 1.8 and HEAD.

I wonder if the unicode of r6rs might make the implementation
difficult later.

> PS: I would be happier if this was part of an `(ice-9 i18n)' module but
>     since it's already too late for `gettext', `bindtextdomain' and
>     friends to go there, maybe we should just keep using the root
>     module...

If it doesn't drag in extra libraries then it doesn't hurt much.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-09-19 22:38 ` Kevin Ryde
@ 2006-10-22 18:33   ` Ludovic Courtès
  2006-10-23  2:01     ` Rob Browning
                       ` (5 more replies)
  0 siblings, 6 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-10-22 18:33 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 3698 bytes --]

Hi,

I have come up with an `(ice-9 i18n)' module that contains
locale-dependent text collation functions and also character case
mapping and functions to read numbers.  There would be a lot more things
to add, like `strfmon ()', but I think that's a good start.

Here are the key points that may deserve further discussion:

1. Use of a glibc-specific reentrant API (the `_l' functions).  As I
   mentioned in my previous post, the idea here is to provide the option
   to pass locale information as an additional argument, as in:

     (string-locale<? "hello" "world" my-locale)

   That last argument may be omitted, in which case the current process
   locale is used (and the "regular" C function is used behind the
   scenes).  Note that in cases where this optional argument is not
   used, the implementation is exactly the same on both GNU and non-GNU
   systems.

   For non-GNU systems, I implemented this (dealing with the LOCALE
   argument) by serializing calls to `setlocale', and performing as many
   `setlocale' calls as needed to install the locale specified by this
   third argument (details in `i18n.c' below).  This is not efficient
   nor very elegant, but at least, it provides users with the same
   semantics across all systems.

   There's one difference, though, between the behavior on GNU and
   non-GNU systems: on GNU, passing a wrong locale name to `make-locale'
   immediately yields an exception, while on non-GNU that exception will
   only be raised when the locale object is actually used.

   Kevin mentioned the argument in glibc's <locale.h> stating that the
   `locale_t' API was a "proof-of-concept".  It seems, however, that
   it's built to stay [0].

2. Kevin said: "I wonder if the unicode of r6rs might make the
   implementation difficult later."  When we support Unicode, `i18n.c'
   "just" has to be changed to use the wide-character variants of the
   various functions (e.g., `wstrcoll' instead of `strcoll', etc.).  So
   I don't think there's much to worry about here.

3. I've put those functions in `(ice-9 i18n)' but they are actually
   implemented in C so `i18n.scm' simply `dynamic-link's a new library,
   `libguile-i18n-v0', that is compiled from within the `libguile'
   directory.

   The rationale for doing it was the following:

   * Reduce startup time.  The approach that consists in initializing
     _everything_ at startup is not scalable.

   * Optionally, reduce memory footprint when the module is not used,
     although that's arguably not a major concern.

   On IRC, Rob identified a number of issues with this approach:

   * It would be the first `ice-9' module that does a `dynamic-link', so
     we may want to think twice before doing it.

   * The C programmer willing to use those functions would have to link
     against `libguile-i18n' additionally.

   There's another (small) issue:

   * The online help is a bit confused because the doc of the i18n.c
     functions is include in libguile's `guile-procedure.txt'.  Thus,
     `(help make-locale)' always works, even when `(ice-9 i18n)' is not
     loaded.

Personally, I'm not worried about issues (1) and (2).  As for item (3),
I'd be tempted to leave the thing in a separate shared library.  While I
agree that this practically precludes use of those functions by C
programmers (as is the case for those SRFIs that are implemented in C),
I believe that this module is more targeted towards Scheme programmers
and, consequently, I see more value in keeping the module's code in a
separate shared lib than in providing access to the C functions.

What do you think?

Thanks,
Ludovic.

[0] http://sources.redhat.com/ml/libc-alpha/2006-09/msg00033.html


[-- Attachment #2: The patch --]
[-- Type: text/x-patch, Size: 67843 bytes --]

--- orig/configure.in
+++ mod/configure.in
@@ -613,8 +613,9 @@ AC_CHECK_HEADERS([assert.h crt_externs.h
 #   truncate - not in mingw
 #   isblank - available as a GNU extension or in C99
 #   _NSGetEnviron - Darwin specific
+#   strcoll_l, newlocale - GNU extensions (glibc)
 #
-AC_CHECK_FUNCS([DINFINITY DQNAN chsize clog10 ctermid fesetround ftime ftruncate fchown getcwd geteuid gettimeofday gmtime_r ioctl lstat mkdir mknod nice readdir_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex truncate unsetenv isblank _NSGetEnviron])
+AC_CHECK_FUNCS([DINFINITY DQNAN chsize clog10 ctermid fesetround ftime ftruncate fchown getcwd geteuid gettimeofday gmtime_r ioctl lstat mkdir mknod nice readdir_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex truncate unsetenv isblank _NSGetEnviron strcoll strcoll_l newlocale])
 
 # Reasons for testing:
 #   netdb.h - not in mingw
--- orig/doc/ref/api-i18n.texi
+++ mod/doc/ref/api-i18n.texi
@@ -1,6 +1,6 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
+@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006
 @c   Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
@@ -8,6 +8,266 @@
 @node Internationalization
 @section Support for Internationalization
 
+@cindex internationalization
+@cindex i18n
+
+Guile provides internationalization support for Scheme programs in two
+ways.  First, procedures to manipulate text and data in a way that
+conforms to particular cultural conventions (i.e., in a
+``locale-dependent'' way) are provided in the @code{(ice-9 i18n)}.
+Second, Guile allows the use of GNU @code{gettext} to translate
+program message strings.
+
+@menu
+* The ice-9 i18n Module::            Honoring cultural conventions.
+* Gettext Support::                  Translating message strings.
+@end menu
+
+
+@node The ice-9 i18n Module
+@subsection The @code{(ice-9 i18n)} Module
+
+In order to make use of the following functions, one must import the
+@code{(ice-9 i18n)} module in the usual way:
+
+@example
+(use-modules (ice-9 i18n))
+@end example
+
+@cindex cultural conventions
+
+The @code{(ice-9 i18n)} module provides procedures to manipulate text
+and other data in a way that conforms to the cultural conventions
+chosen by the user.  Each region of the world or language has its own
+customs to, for instance, represent real numbers, classify characters,
+collate text, etc.  All these aspects comprise the so-called
+``cultural conventions'' of that region or language.
+
+@cindex locale
+@cindex locale category
+
+Computer systems typically refer to a set of cultural conventions as a
+@dfn{locale}.  For each particular aspect that comprise those cultural
+conventions, a @dfn{locale category} is defined.  For instance, the
+way characters are classified is defined by the @code{LC_CTYPE}
+category, while the language in which program messages are issued to
+the user is defined by the @code{LC_MESSAGES} category
+(@pxref{Locales, General Locale Information} for details).
+
+@cindex locale object
+
+The procedures provided by this module allow the development of
+programs that adapt automatically to any locale setting.  As we will
+see later, many of the locale-dependent procedures provided by this
+module can optionally take a @dfn{locale object} argument.  This
+additional argument defines the locale settings that must be followed
+by the invoked procedure.  When it is omitted, then the current locale
+settings of the process are followed (@pxref{Locales,
+@code{setlocale}}).
+
+The following procedures allow the manipulation of such locale
+objects.
+
+@deffn {Scheme Procedure} make-locale category_mask locale_name [base_locale]
+Return a reference to a data structure representing a set of locale
+datasets.  Unlike for the @var{category} parameter for
+@code{setlocale}, the @var{category_mask} parameter here uses a single
+bit for each category, made by OR'ing together @code{LC_*_MASK} bits.
+The optional @var{base_locale} argument can be used to specify a
+locale object whose settings are to be used as a basis for the locale
+object being returned.
+
+The available locale category masks are the following:
+
+@defvar LC_COLLATE_MASK
+Represents the collation locale category.
+@end defvar
+@defvar LC_CTYPE_MASK
+Represents the character classification locale category.
+@end defvar
+@defvar LC_MESSAGES_MASK
+Represents the messages locale category.
+@end defvar
+@defvar LC_MONETARY_MASK
+Represents the monetary locale category.
+@end defvar
+@defvar LC_NUMERIC_MASK
+Represents the way numbers are displayed.
+@end defvar
+@defvar LC_TIME_MASK
+Represents the way date and time are displayed
+@end defvar
+
+The following category masks are also available but will not have any
+effect on systems that do not support them:
+
+@defvar LC_PAPER_MASK
+@defvarx LC_NAME_MASK
+@defvarx LC_ADDRESS_MASK
+@defvarx LC_TELEPHONE_MASK
+@defvarx LC_MEASUREMENT_MASK
+@defvarx LC_IDENTIFICATION_MASK
+@end defvar
+
+Finally, there is also:
+
+@defvar LC_ALL_MASK
+This represents all the locale categories supported by the system.
+@end defvar
+
+The @code{LC_*_MASK} variables are bound to integers which may be OR'd
+together using @code{logior} (@pxref{Primitive Numerics,
+@code{logior}}).  For instance, the following invocation creates a
+locale object that combines the use of Esperanto for messages and
+character classification with the default settings for the other
+categories (i.e., the settings of the default @code{C} locale which
+usually represents conventions in use in the USA):
+
+@example
+(make-locale (logior LC_MESSAGE_MASK LC_CTYPE_MASK) "eo_EO")
+@end example
+
+The following example combines the use of Swedish conventions with
+monetary conventions from Croatia:
+
+@example
+(make-locale LC_MONETARY_MASK "hr_HR"
+             (make-locale LC_ALL_MASK "sv_SE"))
+@end example
+
+A @code{system-error} exception (@pxref{Handling Errors}) is raised by
+@code{make-locale} when @var{locale_name} does not match any of the
+locales compiled on the system.
+
+@end deffn
+
+@deffn {Scheme Procedure} locale? obj
+Return true if @var{obj} is a locale object.
+@end deffn
+
+The following procedures provide support for text collation.
+
+@deffn {Scheme Procedure} string-locale<? s1 s2 [locale]
+Compare strings @var{s1} and @var{s2} in a locale-dependent way.  If
+@var{locale} is provided, it should be locale object (as returned by
+@code{make-locale}) and will be used to perform the comparison;
+otherwise, the current system locale is used.
+@end deffn
+
+@deffn {Scheme Procedure} string-locale>? s1 s2 [locale]
+Compare strings @var{s1} and @var{s2} in a locale-dependent way.  If
+@var{locale} is provided, it should be locale object (as returned by
+@code{make-locale}) and will be used to perform the comparison;
+otherwise, the current system locale is used.
+@end deffn
+
+@deffn {Scheme Procedure} string-locale-ci<? s1 s2 [locale]
+Compare strings @var{s1} and @var{s2} in a case-insensitive, and
+locale-dependent way.  If @var{locale} is provided, it should be
+locale object (as returned by @code{make-locale}) and will be used to
+perform the comparison; otherwise, the current system locale is used.
+@end deffn
+
+@deffn {Scheme Procedure} string-locale-ci>? s1 s2 [locale]
+Compare strings @var{s1} and @var{s2} in a case-insensitive, and
+locale-dependent way.  If @var{locale} is provided, it should be
+locale object (as returned by @code{make-locale}) and will be used to
+perform the comparison; otherwise, the current system locale is used.
+@end deffn
+
+@deffn {Scheme Procedure} string-locale-ci=? s1 s2 [locale]
+Compare strings @var{s1} and @var{s2} in a case-insensitive, and
+locale-dependent way.  If @var{locale} is provided, it should be
+locale object (as returned by @code{make-locale}) and will be used to
+perform the comparison; otherwise, the current system locale is used.
+@end deffn
+
+@deffn {Scheme Procedure} char-locale<? c1 c2 [locale]
+Return true if character @var{c1} is lower than @var{c2} according to
+@var{locale} or to the current locale.
+@end deffn
+
+@deffn {Scheme Procedure} char-locale>? c1 c2 [locale]
+Return true if character @var{c1} is greater than @var{c2} according
+to @var{locale} or to the current locale.
+@end deffn
+
+@deffn {Scheme Procedure} char-locale-ci<? c1 c2 [locale]
+Return true if character @var{c1} is lower than @var{c2}, in a case
+insensitive way according to @var{locale} or to the current locale.
+@end deffn
+
+@deffn {Scheme Procedure} char-locale-ci>? c1 c2 [locale]
+Return true if character @var{c1} is greater than @var{c2}, in a case
+insensitive way according to @var{locale} or to the current locale.
+@end deffn
+
+@deffn {Scheme Procedure} char-locale-ci=? c1 c2 [locale]
+Return true if character @var{c1} is equal to @var{c2}, in a case
+insensitive way according to @var{locale} or to the current locale.
+@end deffn
+
+The procedures below provide support for ``character case mapping'',
+i.e., to convert characters or strings to their upper-case or
+lower-case equivalent.  Note that SRFI-13 provides procedures that
+look similar (@pxref{Alphabetic Case Mapping}).  However, the SRFI-13
+procedures are locale-independent.  Therefore, they do not take into
+account specificities of the customs in use in a particular language
+or region of the world.  For instance, while most languages using the
+Latin alphabet map lower-case letter ``i'' to upper-case letter ``I'',
+Turkish maps lower-case ``i'' to ``Latin capital letter I with dot
+above''.  The following procedures allow to provide idiomatic
+character mapping.
+
+@deffn {Scheme Procedure} char-locale-downcase chr [locale]
+Return the lowercase character that corresponds to @var{chr} according
+to either @var{locale} or the current locale.
+@end deffn
+
+@deffn {Scheme Procedure} char-locale-upcase chr [locale]
+Return the uppercase character that corresponds to @var{chr} according
+to either @var{locale} or the current locale.
+@end deffn
+
+@deffn {Scheme Procedure} string-locale-upcase str [locale]
+Return a new string that is the uppercase version of @var{str}
+according to either @var{locale} or the current locale.
+@end deffn
+
+@deffn {Scheme Procedure} string-locale-downcase str [locale]
+Return a new string that is the down-case version of @var{str}
+according to either @var{locale} or the current locale.
+@end deffn
+
+Finally, the following procedures allow programs to read numbers
+written according to a particular locale.  As an example, in English,
+``ten thousand and a half'' is usually written @code{10,000.5} while
+in French it is written @code{10000,5}.  These procedures allow to
+account for this differences.
+
+@deffn {Scheme Procedure} locale-string->integer str [base [locale]]
+Convert string @var{str} into an integer according to either
+@var{locale} (a locale object as returned by @code{make-locale}) or
+the current process locale.  If @var{base} is specified, then it
+determines the base of the integer being read (e.g., @code{16} for an
+hexadecimal number, @code{10} for a decimal number); by default,
+decimal numbers are read.  Return two values: an integer (on success)
+or @code{#f}, and the number of characters read from @var{str}
+(@code{0} on failure).
+@end deffn
+
+@deffn {Scheme Procedure} locale-string->inexact str [locale]
+Convert string @var{str} into an inexact number according to either
+@var{locale} (a locale object as returned by @code{make-locale}) or
+the current process locale.  Return two values: an inexact number (on
+success) or @code{#f}, and the number of characters read from
+@var{str} (@code{0} on failure).
+@end deffn
+
+
+@node Gettext Support
+@subsection Gettext Support
+
 Guile provides an interface to GNU @code{gettext} for translating
 message strings (@pxref{Introduction,,, gettext, GNU @code{gettext}
 utilities}).
@@ -155,4 +415,5 @@ future.
 
 @c Local Variables:
 @c TeX-master: "guile.texi"
+@c ispell-local-dictionary: "american"
 @c End:
--- orig/doc/ref/posix.texi
+++ mod/doc/ref/posix.texi
@@ -1,6 +1,6 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
+@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006
 @c   Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
@@ -3159,6 +3159,10 @@ categories based on standard environment
 For full details on categories and locale names @pxref{Locales,,
 Locales and Internationalization, libc, The GNU C Library Reference
 Manual}.
+
+Note that @code{setlocale} affects locale settings for the whole
+process.  For a safer, thread-safe and reentrant alternative,
+@xref{The ice-9 i18n Module, Locale Objects and @code{make-locale}}.
 @end deffn
 
 @node Encryption
--- orig/libguile/Makefile.am
+++ mod/libguile/Makefile.am
@@ -31,7 +31,7 @@ INCLUDES = -I.. -I$(top_srcdir)
 ETAGS_ARGS = --regex='/SCM_\(GLOBAL_\)?\(G?PROC\|G?PROC1\|SYMBOL\|VCELL\|CONST_LONG\).*\"\([^\"]\)*\"/\3/' \
    --regex='/[ \t]*SCM_[G]?DEFINE1?[ \t]*(\([^,]*\),[^,]*/\1/'
 
-lib_LTLIBRARIES = libguile.la
+lib_LTLIBRARIES = libguile.la libguile-i18n-v0.la
 bin_PROGRAMS = guile
 
 noinst_PROGRAMS = guile_filter_doc_snarfage gen-scmconfig
@@ -97,9 +97,10 @@ libguile_la_SOURCES = alist.c arbiters.c
     deprecated.c discouraged.c dynwind.c environments.c eq.c error.c	\
     eval.c evalext.c extensions.c feature.c fluids.c fports.c		\
     futures.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c		\
-    gc-freelist.c gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c	\
+    gc-freelist.c gc_os_dep.c gdbint.c gettext.c			\
+    gh_data.c gh_eval.c gh_funcs.c					\
     gh_init.c gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c		\
-    guardians.c hash.c hashtab.c hooks.c i18n.c init.c inline.c		\
+    guardians.c hash.c hashtab.c hooks.c init.c inline.c		\
     ioext.c keywords.c lang.c list.c load.c macros.c mallocs.c		\
     modules.c numbers.c objects.c objprop.c options.c pairs.c ports.c	\
     print.c procprop.c procs.c properties.c random.c rdelim.c read.c	\
@@ -109,11 +110,16 @@ libguile_la_SOURCES = alist.c arbiters.c
     throw.c values.c variable.c vectors.c version.c vports.c weaks.c	\
     ramap.c unif.c
 
+libguile_i18n_v0_la_SOURCES = i18n.c
+libguile_i18n_v0_la_CFLAGS = $(libguile_la_CFLAGS)
+libguile_i18n_v0_la_LDFLAGS = -module -L$(builddir) -lguile
+
 DOT_X_FILES = alist.x arbiters.x async.x backtrace.x boolean.x chars.x	\
     continuations.x debug.x deprecation.x deprecated.x discouraged.x	\
     dynl.x dynwind.x environments.x eq.x error.x eval.x evalext.x	\
     extensions.x feature.x fluids.x fports.x futures.x gc.x gc-mark.x	\
-    gc-segment.x gc-malloc.x gc-card.x goops.x gsubr.x guardians.x	\
+    gc-segment.x gc-malloc.x gc-card.x gettext.x goops.x		\
+    gsubr.x guardians.x							\
     hash.x hashtab.x hooks.x i18n.x init.x ioext.x keywords.x lang.x	\
     list.x load.x macros.x mallocs.x modules.x numbers.x objects.x	\
     objprop.x options.x pairs.x ports.x print.x procprop.x procs.x	\
@@ -131,7 +137,8 @@ DOT_DOC_FILES = alist.doc arbiters.doc a
     environments.doc eq.doc error.doc eval.doc evalext.doc		\
     extensions.doc feature.doc fluids.doc fports.doc futures.doc	\
     gc.doc goops.doc gsubr.doc gc-mark.doc gc-segment.doc		\
-    gc-malloc.doc gc-card.doc guardians.doc hash.doc hashtab.doc	\
+    gc-malloc.doc gc-card.doc gettext.doc				\
+    guardians.doc hash.doc hashtab.doc					\
     hooks.doc i18n.doc init.doc ioext.doc keywords.doc lang.doc		\
     list.doc load.doc macros.doc mallocs.doc modules.doc numbers.doc	\
     objects.doc objprop.doc options.doc pairs.doc ports.doc print.doc	\
@@ -153,8 +160,9 @@ EXTRA_libguile_la_SOURCES = _scm.h		\
     inet_aton.c memmove.c putenv.c strerror.c	\
     dynl.c regex-posix.c			\
     filesys.c posix.c net_db.c socket.c		\
-    debug-malloc.c mkstemp.c	\
-    win32-uname.c win32-dirent.c win32-socket.c
+    debug-malloc.c mkstemp.c			\
+    win32-uname.c win32-dirent.c win32-socket.c	\
+    locale-categories.h
 
 ## delete guile-snarf.awk from the installation bindir, in case it's
 ## lingering there due to an earlier guile version not having been
@@ -187,7 +195,8 @@ modinclude_HEADERS = __scm.h alist.h arb
     deprecation.h deprecated.h discouraged.h dynl.h dynwind.h		\
     environments.h eq.h error.h eval.h evalext.h extensions.h		\
     feature.h filesys.h fluids.h fports.h futures.h gc.h		\
-    gdb_interface.h gdbint.h goops.h gsubr.h guardians.h hash.h		\
+    gdb_interface.h gdbint.h gettext.h goops.h				\
+    gsubr.h guardians.h hash.h						\
     hashtab.h hooks.h i18n.h init.h inline.h ioext.h iselect.h		\
     keywords.h lang.h list.h load.h macros.h mallocs.h modules.h	\
     net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h	\
@@ -212,7 +221,7 @@ EXTRA_DIST = ChangeLog-gh ChangeLog-scm 
     cpp_errno.c cpp_err_symbols.in cpp_err_symbols.c		\
     cpp_sig_symbols.c cpp_sig_symbols.in cpp_cnvt.awk	\
     c-tokenize.lex version.h.in \
-    scmconfig.h.top gettext.h
+    scmconfig.h.top libgettext.h
 #    $(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES) \
 #    guile-procedures.txt guile.texi
 
--- orig/libguile/i18n.c
+++ mod/libguile/gettext.c
@@ -22,11 +22,11 @@
 
 #include "libguile/_scm.h"
 #include "libguile/feature.h"
-#include "libguile/i18n.h"
 #include "libguile/strings.h"
 #include "libguile/dynwind.h"
 
-#include "gettext.h"
+#include "libguile/gettext.h"
+#include "libgettext.h"
 #include <locale.h>
 
 
@@ -312,11 +312,15 @@ SCM_DEFINE (scm_bind_textdomain_codeset,
 }
 #undef FUNC_NAME
 
-void 
-scm_init_i18n ()
+void
+scm_init_gettext ()
 {
+  /* When gettext support was first added (in 1.8.0), it provided feature
+     `i18n'.  We keep this as is although the name is a bit misleading
+     now.  */
   scm_add_feature ("i18n");
-#include "libguile/i18n.x"
+
+#include "libguile/gettext.x"
 }
 
 
--- orig/libguile/i18n.h
+++ mod/libguile/gettext.h
@@ -1,7 +1,7 @@
 /* classes: h_files */
 
-#ifndef SCM_I18N_H
-#define SCM_I18N_H
+#ifndef SCM_GETTEXT_H
+#define SCM_GETTEXT_H
 
 /* Copyright (C) 2004, 2006 Free Software Foundation, Inc.
  *
@@ -30,9 +30,9 @@ SCM_API SCM scm_bind_textdomain_codeset 
 
 SCM_API int scm_i_to_lc_category (SCM category, int allow_lc_all);
 
-SCM_API void scm_init_i18n (void);
+SCM_API void scm_init_gettext (void);
 
-#endif  /* SCM_I18N_H */
+#endif  /* SCM_GETTEXT_H */
 
 /*
   Local Variables:
--- orig/libguile/init.c
+++ mod/libguile/init.c
@@ -63,7 +63,7 @@
 #include "libguile/hash.h"
 #include "libguile/hashtab.h"
 #include "libguile/hooks.h"
-#include "libguile/i18n.h"
+#include "libguile/gettext.h"
 #include "libguile/iselect.h"
 #include "libguile/ioext.h"
 #include "libguile/keywords.h"
@@ -473,7 +473,7 @@ scm_i_init_guile (SCM_STACKITEM *base)
   scm_init_properties ();
   scm_init_hooks ();            /* Requires smob_prehistory */
   scm_init_gc ();		/* Requires hooks, async */
-  scm_init_i18n ();
+  scm_init_gettext ();
   scm_init_ioext ();
   scm_init_keywords ();
   scm_init_list ();
--- orig/libguile/posix.c
+++ mod/libguile/posix.c
@@ -40,7 +40,7 @@
 
 #include "libguile/validate.h"
 #include "libguile/posix.h"
-#include "libguile/i18n.h"
+#include "libguile/gettext.h"
 #include "libguile/threads.h"
 \f
 
@@ -115,6 +115,10 @@ extern char ** environ;
 #include <locale.h>
 #endif
 
+#if (defined HAVE_NEWLOCALE) && (defined HAVE_STRCOLL_L)
+# define USE_GNU_LOCALE_API
+#endif
+
 #if HAVE_CRYPT_H
 #  include <crypt.h>
 #endif
@@ -1380,7 +1384,15 @@ SCM_DEFINE (scm_putenv, "putenv", 1, 0, 
 }
 #undef FUNC_NAME
 
+#ifndef USE_GNU_LOCALE_API
+/* This mutex is used to serialize invocations of `setlocale ()' on non-GNU
+   systems (i.e., systems where a reentrant locale API is not available).
+   See `i18n.c' for details.  */
+scm_i_pthread_mutex_t scm_i_locale_mutex;
+#endif
+
 #ifdef HAVE_SETLOCALE
+
 SCM_DEFINE (scm_setlocale, "setlocale", 1, 1, 0,
             (SCM category, SCM locale),
 	    "If @var{locale} is omitted, return the current value of the\n"
@@ -1409,7 +1421,14 @@ SCM_DEFINE (scm_setlocale, "setlocale", 
       scm_dynwind_free (clocale);
     }
 
+#ifndef USE_GNU_LOCALE_API
+  scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
+#endif
   rv = setlocale (scm_i_to_lc_category (category, 1), clocale);
+#ifndef USE_GNU_LOCALE_API
+  scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
+#endif
+
   if (rv == NULL)
     {
       /* POSIX and C99 don't say anything about setlocale setting errno, so
@@ -1943,9 +1962,13 @@ SCM_DEFINE (scm_gethostname, "gethostnam
 #endif /* HAVE_GETHOSTNAME */
 
 
-void 
+void
 scm_init_posix ()
 {
+#ifndef USE_GNU_LOCALE_API
+  scm_i_pthread_mutex_init (&scm_i_locale_mutex, NULL);
+#endif
+
   scm_add_feature ("posix");
 #ifdef HAVE_GETEUID
   scm_add_feature ("EIDs");
--- orig/libguile/posix.h
+++ mod/libguile/posix.h
@@ -23,8 +23,7 @@
 \f
 
 #include "libguile/__scm.h"
-
-\f
+#include "libguile/threads.h"
 
 
 \f
@@ -87,6 +86,8 @@ SCM_API SCM scm_sethostname (SCM name);
 SCM_API SCM scm_gethostname (void);
 SCM_API void scm_init_posix (void);
 
+SCM_API scm_i_pthread_mutex_t scm_i_locale_mutex;
+
 #endif  /* SCM_POSIX_H */
 
 /*
--- orig/test-suite/Makefile.am
+++ mod/test-suite/Makefile.am
@@ -43,6 +43,7 @@ SCM_TESTS = tests/alist.test			\
 	    tests/guardians.test		\
 	    tests/hash.test			\
 	    tests/hooks.test			\
+	    tests/i18n.test			\
 	    tests/import.test			\
 	    tests/interp.test			\
 	    tests/list.test			\

* added files

--- /dev/null
+++ mod/ice-9/.arch-ids/i18n.scm.id
@@ -0,0 +1 @@
+Ludovic Courtes <ludovic.courtes@laas.fr> Sat Oct 21 16:12:32 2006 29433.0
--- /dev/null
+++ mod/ice-9/i18n.scm
@@ -0,0 +1,68 @@
+;;;; i18n.scm --- internationalization support
+
+;;;;	Copyright (C) 2006 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 2.1 of the License, or (at your option) any later version.
+;;;;
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+;;; Author: Ludovic Courtès <ludovic.courtes@laas.fr>
+
+;;; Commentary:
+;;;
+;;; This module provides a number of routines that support
+;;; internationalization (e.g., locale-dependent text collation, character
+;;; mapping, etc.).  It also defines `locale' objects, representing locale
+;;; settings, that may be passed around to most of these procedures.
+;;;
+
+;;; Code:
+
+(define-module (ice-9 i18n)
+  :export (;; `locale' type
+           make-locale locale?
+
+           ;; locale category masks (standard)
+           LC_ALL_MASK
+           LC_COLLATE_MASK LC_CTYPE_MASK LC_MESSAGES_MASK
+           LC_MONETARY_MASK LC_NUMERIC_MASK LC_TIME_MASK
+
+           ;; locale category masks (non-standard)
+           LC_PAPER_MASK LC_NAME_MASK LC_ADDRESS_MASK
+           LC_TELEPHONE_MASK LC_MEASUREMENT_MASK
+           LC_IDENTIFICATION_MASK
+
+           ;; text collation
+           string-locale<? string-locale>?
+           string-locale-ci<? string-locale-ci>? string-locale-ci=?
+
+           char-locale<? char-locale>?
+           char-locale-ci<? char-locale-ci>? char-locale-ci=?
+
+           ;; character mapping
+           char-locale-downcase char-locale-upcase
+           string-locale-downcase string-locale-upcase
+
+           ;; reading numbers
+           locale-string->integer locale-string->inexact))
+
+
+(dynamic-call "scm_init_i18n"
+              (dynamic-link "libguile-i18n-v0"))
+
+
+;;; Local Variables:
+;;; coding: latin-1
+;;; End:
+
+;;; i18n.scm ends here
--- /dev/null
+++ mod/libguile/.arch-ids/i18n.c.id
@@ -0,0 +1 @@
+Ludovic Courtes <ludovic.courtes@laas.fr> Sat Oct 21 17:24:34 2006 11178.0
--- /dev/null
+++ mod/libguile/.arch-ids/i18n.h.id
@@ -0,0 +1 @@
+Ludovic Courtes <ludovic.courtes@laas.fr> Sat Oct 21 17:24:44 2006 11192.0
--- /dev/null
+++ mod/libguile/.arch-ids/locale-categories.h.id
@@ -0,0 +1 @@
+Ludovic Courtes <ludovic.courtes@laas.fr> Sat Oct 14 17:20:45 2006 6695.0
--- /dev/null
+++ mod/libguile/i18n.c
@@ -0,0 +1,1161 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE /* Ask for glibc's `newlocale' API */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include "libguile/_scm.h"
+#include "libguile/feature.h"
+#include "libguile/i18n.h"
+#include "libguile/strings.h"
+#include "libguile/chars.h"
+#include "libguile/dynwind.h"
+#include "libguile/validate.h"
+#include "libguile/values.h"
+
+#include <locale.h>
+#include <string.h> /* `strcoll ()' */
+#include <ctype.h>  /* `toupper ()' et al. */
+#include <errno.h>
+
+#if (defined HAVE_NEWLOCALE) && (defined HAVE_STRCOLL_L)
+# define USE_GNU_LOCALE_API
+#endif
+
+#ifndef USE_GNU_LOCALE_API
+# include "libguile/posix.h"  /* for `scm_i_locale_mutex' */
+#endif
+
+#ifndef HAVE_SETLOCALE
+static inline char *
+setlocale (int category, const char *name)
+{
+  errno = ENOSYS;
+  return NULL;
+}
+#endif
+
+
+\f
+/* Locale objects, string and character collation, and other locale-dependent
+   string operations.
+
+   A large part of the code here deals with emulating glibc's reentrant
+   locale API on non-GNU systems.  The emulation is a bit "brute-force":
+   Whenever a `-locale<?' procedure is passed a locale object, then:
+
+   1. The `scm_t_locale_mutex' is locked.
+   2. A series of `setlocale ()' call is performed to store the current
+      locale for each category in an `scm_t_locale_settings' object.
+   3. A series of `setlocale ()' call is made to install each of the locale
+      categories of each of the base locales of each locale object,
+      recursively, starting from the last locale object of the chain.
+   4. The settings captured in step (2) are restored.
+   5. The `scm_t_locale_mutex' is released.
+
+   Hopefully, some smart standard will make that hack useless someday...
+   A similar API can be found in MzScheme starting from version 200:
+   http://download.plt-scheme.org/chronology/mzmr200alpha14.html .
+
+   Note: We don't wrap glibc's `uselocale ()' call because it sets the locale
+   of the current _thread_ (unlike `setlocale ()') and doing so would require
+   maintaining per-thread locale information on non-GNU systems and always
+   re-installing this locale upon locale-dependent calls.  */
+
+
+#ifndef USE_GNU_LOCALE_API
+
+/* Provide the locale category masks as found in glibc (copied from
+   <locale.h> as found in glibc 2.3.6).  This must be kept in sync with
+   `locale-categories.h'.  */
+
+# define LC_CTYPE_MASK		(1 << LC_CTYPE)
+# define LC_COLLATE_MASK	(1 << LC_COLLATE)
+# define LC_MESSAGES_MASK	(1 << LC_MESSAGES)
+# define LC_MONETARY_MASK	(1 << LC_MONETARY)
+# define LC_NUMERIC_MASK	(1 << LC_NUMERIC)
+# define LC_TIME_MASK		(1 << LC_TIME)
+
+# ifdef LC_PAPER
+#   define LC_PAPER_MASK	(1 << LC_PAPER)
+# else
+#   define LC_PAPER_MASK	0
+# endif
+# ifdef LC_NAME
+#   define LC_NAME_MASK		(1 << LC_NAME)
+# else
+#   define LC_NAME_MASK		0
+# endif
+# ifdef LC_ADDRESS
+#   define LC_ADDRESS_MASK	(1 << LC_ADDRESS)
+# else
+#   define LC_ADDRESS_MASK	0
+# endif
+# ifdef LC_TELEPHONE
+#   define LC_TELEPHONE_MASK	(1 << LC_TELEPHONE)
+# else
+#   define LC_TELEPHONE_MASK	0
+# endif
+# ifdef LC_MEASUREMENT
+#   define LC_MEASUREMENT_MASK	(1 << LC_MEASUREMENT)
+# else
+#   define LC_MEASUREMENT_MASK	0
+# endif
+# ifdef LC_IDENTIFICATION
+#   define LC_IDENTIFICATION_MASK (1 << LC_IDENTIFICATION)
+# else
+#   define LC_IDENTIFICATION_MASK 0
+# endif
+
+# define LC_ALL_MASK		(LC_CTYPE_MASK \
+				 | LC_NUMERIC_MASK \
+				 | LC_TIME_MASK \
+				 | LC_COLLATE_MASK \
+				 | LC_MONETARY_MASK \
+				 | LC_MESSAGES_MASK \
+				 | LC_PAPER_MASK \
+				 | LC_NAME_MASK \
+				 | LC_ADDRESS_MASK \
+				 | LC_TELEPHONE_MASK \
+				 | LC_MEASUREMENT_MASK \
+				 | LC_IDENTIFICATION_MASK \
+				 )
+
+/* Locale objects as returned by `make-locale' on non-GNU systems.  */
+typedef struct scm_locale
+{
+  SCM   base_locale; /* a `locale' object */
+  char *locale_name;
+  int   category_mask;
+} *scm_t_locale;
+
+#else
+
+/* Alias for glibc's locale type.  */
+typedef locale_t scm_t_locale;
+
+#endif
+
+/* Validate parameter ARG as a locale object and set C_LOCALE to the
+   corresponding C locale object.  */
+#define SCM_VALIDATE_LOCALE_COPY(_pos, _arg, _c_locale)		\
+  do								\
+    {								\
+      SCM_VALIDATE_SMOB ((_pos), (_arg), locale_smob_type);	\
+      (_c_locale) = (scm_t_locale)SCM_SMOB_DATA (_arg);		\
+    }								\
+  while (0)
+
+/* Validate optional parameter ARG as either undefined or bound to a locale
+   object.  Set C_LOCALE to the corresponding C locale object or NULL.  */
+#define SCM_VALIDATE_OPTIONAL_LOCALE_COPY(_pos, _arg, _c_locale)	\
+  do									\
+    {									\
+      if ((_arg) != SCM_UNDEFINED)					\
+	SCM_VALIDATE_LOCALE_COPY (_pos, _arg, _c_locale);		\
+      else								\
+	(_c_locale) = NULL;						\
+    }									\
+  while (0)
+
+
+SCM_SMOB (scm_tc16_locale_smob_type, "locale", 0);
+
+SCM_SMOB_FREE (scm_tc16_locale_smob_type, smob_locale_free, locale)
+{
+  scm_t_locale c_locale;
+
+  c_locale = (scm_t_locale)SCM_SMOB_DATA (locale);
+
+#ifdef USE_GNU_LOCALE_API
+  freelocale ((locale_t)c_locale);
+#else
+  c_locale->base_locale = SCM_UNDEFINED;
+  free (c_locale->locale_name);
+
+  scm_gc_free (c_locale, sizeof (* c_locale), "locale");
+#endif
+
+  return 0;
+}
+
+#ifndef USE_GNU_LOCALE_API
+static SCM
+smob_locale_mark (SCM locale)
+{
+  scm_t_locale c_locale;
+
+  c_locale = (scm_t_locale)SCM_SMOB_DATA (locale);
+  return (c_locale->base_locale);
+}
+#endif
+
+
+SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0,
+	    (SCM category_mask, SCM locale_name, SCM base_locale),
+	    "Return a reference to a data structure representing a set of "
+	    "locale datasets.  Unlike for the @var{category} parameter for "
+	    "@code{setlocale}, the @var{category_mask} parameter here uses "
+	    "a single bit for each category, made by OR'ing together "
+	    "@code{LC_*_MASK} bits.")
+#define FUNC_NAME s_scm_make_locale
+{
+  SCM locale = SCM_BOOL_F;
+  int c_category_mask;
+  char *c_locale_name;
+  scm_t_locale c_base_locale, c_locale;
+
+  SCM_VALIDATE_INT_COPY (1, category_mask, c_category_mask);
+  SCM_VALIDATE_STRING (2, locale_name);
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, base_locale, c_base_locale);
+
+  c_locale_name = scm_to_locale_string (locale_name);
+
+#ifdef USE_GNU_LOCALE_API
+
+  c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale);
+
+  if (!c_locale)
+    locale = SCM_BOOL_F;
+  else
+    SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
+
+  free (c_locale_name);
+
+#else
+
+  c_locale = scm_gc_malloc (sizeof (* c_locale), "locale");
+  c_locale->base_locale = base_locale;
+
+  c_locale->category_mask = c_category_mask;
+  c_locale->locale_name = c_locale_name;
+
+  SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
+
+#endif
+
+  return locale;
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_locale_p, "locale?", 1, 0, 0,
+	    (SCM obj),
+	    "Return true if @var{obj} is a locale object.")
+#define FUNC_NAME s_scm_locale_p
+{
+  if (SCM_SMOB_PREDICATE (scm_tc16_locale_smob_type, obj))
+    return SCM_BOOL_T;
+
+  return SCM_BOOL_F;
+}
+#undef FUNC_NAME
+
+
+\f
+#ifndef USE_GNU_LOCALE_API  /* Emulate GNU's reentrant locale API.  */
+
+
+/* Maximum number of chained locales (via `base_locale').  */
+#define LOCALE_STACK_SIZE_MAX  256
+
+typedef struct
+{
+#define SCM_DEFINE_LOCALE_CATEGORY(_name)  char * _name;
+#include "locale-categories.h"
+#undef SCM_DEFINE_LOCALE_CATEGORY
+} scm_t_locale_settings;
+
+/* Fill out SETTINGS according to the current locale settings.  On success
+   zero is returned and SETTINGS is properly initialized.  */
+static int
+get_current_locale_settings (scm_t_locale_settings *settings)
+{
+  const char *locale_name;
+
+#define SCM_DEFINE_LOCALE_CATEGORY(_name)			\
+  {								\
+    SCM_SYSCALL (locale_name = setlocale (LC_ ## _name, NULL));	\
+    if (!locale_name)						\
+      goto handle_error;					\
+								\
+    settings-> _name = strdup (locale_name);			\
+    if (settings-> _name == NULL)				\
+      goto handle_oom;						\
+  }
+
+#include "locale-categories.h"
+#undef SCM_DEFINE_LOCALE_CATEGORY
+
+  return 0;
+
+ handle_error:
+  return errno;
+
+ handle_oom:
+  return ENOMEM;
+}
+
+/* Restore locale settings SETTINGS.  On success, return zero.  */
+static int
+restore_locale_settings (const scm_t_locale_settings *settings)
+{
+  const char *result;
+
+#define SCM_DEFINE_LOCALE_CATEGORY(_name)				\
+  SCM_SYSCALL (result = setlocale (LC_ ## _name, settings-> _name));	\
+  if (result == NULL)							\
+    goto handle_error;
+
+#include "locale-categories.h"
+#undef SCM_DEFINE_LOCALE_CATEGORY
+
+  return 0;
+
+ handle_error:
+  return errno;
+}
+
+/* Free memory associated with SETTINGS.  */
+static void
+free_locale_settings (scm_t_locale_settings *settings)
+{
+#define SCM_DEFINE_LOCALE_CATEGORY(_name)	\
+  free (settings-> _name);			\
+  settings->_name = NULL;
+#include  "locale-categories.h"
+#undef SCM_DEFINE_LOCALE_CATEGORY
+}
+
+/* Install the locale named LOCALE_NAME for all the categories listed in
+   CATEGORY_MASK.  */
+static int
+install_locale_categories (const char *locale_name, int category_mask)
+{
+  const char *result;
+
+  if (category_mask == LC_ALL_MASK)
+    {
+      SCM_SYSCALL (result = setlocale (LC_ALL, locale_name));
+      if (result == NULL)
+	goto handle_error;
+    }
+  else
+    {
+#define SCM_DEFINE_LOCALE_CATEGORY(_name)				\
+  if (category_mask & LC_ ## _name ## _MASK)				\
+    {									\
+      SCM_SYSCALL (result = setlocale (LC_ ## _name, locale_name));	\
+      if (result == NULL)						\
+	goto handle_error;						\
+    }
+#include "locale-categories.h"
+#undef SCM_DEFINE_LOCALE_CATEGORY
+    }
+
+  return 0;
+
+ handle_error:
+  return errno;
+}
+
+/* Install LOCALE, recursively installing its base locales first.  On
+   success, zero is returned.  */
+static int
+install_locale (scm_t_locale locale)
+{
+  scm_t_locale stack[LOCALE_STACK_SIZE_MAX];
+  size_t stack_size = 0;
+  int stack_offset = 0;
+  const char *result = NULL;
+
+  /* Build up a locale stack by traversing the `base_locale' link.  */
+  do
+    {
+      if (stack_size >= LOCALE_STACK_SIZE_MAX)
+	/* We cannot use `scm_error ()' here because otherwise the locale
+	   mutex may remain locked.  */
+	return EINVAL;
+
+      stack[stack_size++] = locale;
+
+      if (locale->base_locale != SCM_UNDEFINED)
+	locale = (scm_t_locale)SCM_SMOB_DATA (locale->base_locale);
+      else
+	locale = NULL;
+    }
+  while (locale != NULL);
+
+  /* Install the C locale to start from a pristine state.  */
+  SCM_SYSCALL (result = setlocale (LC_ALL, "C"));
+  if (result == NULL)
+    goto handle_error;
+
+  /* Install the locales in reverse order.  */
+  for (stack_offset = stack_size - 1;
+       stack_offset >= 0;
+       stack_offset--)
+    {
+      int err;
+      scm_t_locale locale;
+
+      locale = stack[stack_offset];
+      err = install_locale_categories (locale->locale_name,
+				       locale->category_mask);
+      if (err)
+	goto handle_error;
+    }
+
+  return 0;
+
+ handle_error:
+  return errno;
+}
+
+/* Leave the locked locale section.  */
+static inline void
+leave_locale_section (const scm_t_locale_settings *settings)
+{
+  /* Restore the previous locale settings.  */
+  (void)restore_locale_settings (settings);
+
+  scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
+}
+
+/* Enter a locked locale section.  */
+static inline int
+enter_locale_section (scm_t_locale locale,
+		      scm_t_locale_settings *prev_locale)
+{
+  int err;
+
+  scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
+
+  err = get_current_locale_settings (prev_locale);
+  if (err)
+    {
+      scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
+      return err;
+    }
+
+  err = install_locale (locale);
+  if (err)
+    {
+      leave_locale_section (prev_locale);
+      free_locale_settings (prev_locale);
+    }
+
+  return err;
+}
+
+/* Throw an exception corresponding to error ERR.  */
+static void inline
+scm_locale_error (const char *func_name, int err)
+{
+  SCM s_err;
+
+  s_err = scm_from_int (err);
+  scm_error (scm_system_error_key, func_name,
+	     "Failed to install locale",
+	     scm_cons (scm_strerror (s_err), SCM_EOL),
+	     scm_cons (s_err, SCM_EOL));
+}
+
+/* Convenient macro to run STATEMENT in the locale context of C_LOCALE.  */
+#define RUN_IN_LOCALE_SECTION(_c_locale, _statement)			\
+  do									\
+   {									\
+      int lsec_err;							\
+      scm_t_locale_settings lsec_prev_locale;				\
+									\
+      lsec_err = enter_locale_section ((_c_locale), &lsec_prev_locale);	\
+      if (lsec_err)							\
+	scm_locale_error (FUNC_NAME, lsec_err);				\
+      else								\
+	{								\
+	  _statement ;							\
+									\
+	  leave_locale_section (&lsec_prev_locale);			\
+	  free_locale_settings (&lsec_prev_locale);			\
+	}								\
+   }									\
+  while (0)
+
+#endif /* !USE_GNU_LOCALE_API */
+
+\f
+/* Locale-dependent string comparison.  */
+
+/* Compare null-terminated strings C_S1 and C_S2 according to LOCALE.  Return
+   an integer whose sign is the same as the difference between C_S1 and
+   C_S2.  */
+static inline int
+compare_strings (const char *c_s1, const char *c_s2, SCM locale,
+		 const char *func_name)
+#define FUNC_NAME func_name
+{
+  int result;
+  scm_t_locale c_locale;
+
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
+
+  if (c_locale)
+    {
+#ifdef USE_GNU_LOCALE_API
+      result = strcoll_l (c_s1, c_s2, c_locale);
+#else
+#ifdef HAVE_STRCOLL
+      RUN_IN_LOCALE_SECTION (c_locale, result = strcoll (c_s1, c_s2));
+#else
+      result = strcmp (c_s1, c_s2);
+#endif
+#endif /* !USE_GNU_LOCALE_API */
+    }
+  else
+
+#ifdef HAVE_STRCOLL
+    result = strcoll (c_s1, c_s2);
+#else
+    result = strcmp (c_s1, c_s2);
+#endif
+
+  return result;
+}
+#undef FUNC_NAME
+
+/* Store into DST an upper-case version of SRC.  */
+static inline void
+str_upcase (register char *dst, register const char *src)
+{
+  for (; *src != '\0'; src++, dst++)
+    *dst = toupper (*src);
+  *dst = '\0';
+}
+
+static inline void
+str_downcase (register char *dst, register const char *src)
+{
+  for (; *src != '\0'; src++, dst++)
+    *dst = tolower (*src);
+  *dst = '\0';
+}
+
+#ifdef USE_GNU_LOCALE_API
+static inline void
+str_upcase_l (register char *dst, register const char *src,
+	      scm_t_locale locale)
+{
+  for (; *src != '\0'; src++, dst++)
+    *dst = toupper_l (*src, locale);
+  *dst = '\0';
+}
+
+static inline void
+str_downcase_l (register char *dst, register const char *src,
+		scm_t_locale locale)
+{
+  for (; *src != '\0'; src++, dst++)
+    *dst = tolower_l (*src, locale);
+  *dst = '\0';
+}
+#endif
+
+
+/* Compare null-terminated strings C_S1 and C_S2 in a case-independent way
+   according to LOCALE.  Return an integer whose sign is the same as the
+   difference between C_S1 and C_S2.  */
+static inline int
+compare_strings_ci (const char *c_s1, const char *c_s2, SCM locale,
+		    const char *func_name)
+#define FUNC_NAME func_name
+{
+  int result;
+  scm_t_locale c_locale;
+  char *c_us1, *c_us2;
+
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
+
+  c_us1 = (char *) alloca (strlen (c_s1) + 1);
+  c_us2 = (char *) alloca (strlen (c_s2) + 1);
+
+  if (c_locale)
+    {
+#ifdef USE_GNU_LOCALE_API
+      str_upcase_l (c_us1, c_s1, c_locale);
+      str_upcase_l (c_us2, c_s2, c_locale);
+
+      result = strcoll_l (c_us1, c_us2, c_locale);
+#else
+      int err;
+      scm_t_locale_settings prev_locale;
+
+      err = enter_locale_section (c_locale, &prev_locale);
+      if (err)
+	{
+	  scm_locale_error (func_name, err);
+	  return 0;
+	}
+
+      str_upcase (c_us1, c_s1);
+      str_upcase (c_us2, c_s2);
+
+#ifdef HAVE_STRCOLL
+      result = strcoll (c_us1, c_us2);
+#else
+      result = strcmp (c_us1, c_us2);
+#endif /* !HAVE_STRCOLL */
+
+      leave_locale_section (&prev_locale);
+      free_locale_settings (&prev_locale);
+#endif /* !USE_GNU_LOCALE_API */
+    }
+  else
+    {
+      str_upcase (c_us1, c_s1);
+      str_upcase (c_us2, c_s2);
+
+#ifdef HAVE_STRCOLL
+      result = strcoll (c_us1, c_us2);
+#else
+      result = strcmp (c_us1, c_us2);
+#endif
+    }
+
+  return result;
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_string_locale_lt, "string-locale<?", 2, 1, 0,
+	    (SCM s1, SCM s2, SCM locale),
+	    "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
+	    "If @var{locale} is provided, it should be locale object (as "
+	    "returned by @code{make-locale}) and will be used to perform the "
+	    "comparison; otherwise, the current system locale is used.")
+#define FUNC_NAME s_scm_string_locale_lt
+{
+  int result;
+  const char *c_s1, *c_s2;
+
+  SCM_VALIDATE_STRING (1, s1);
+  SCM_VALIDATE_STRING (2, s2);
+
+  c_s1 = scm_i_string_chars (s1);
+  c_s2 = scm_i_string_chars (s2);
+
+  result = compare_strings (c_s1, c_s2, locale, FUNC_NAME);
+
+  scm_remember_upto_here_2 (s1, s2);
+
+  return scm_from_bool (result < 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_string_locale_gt, "string-locale>?", 2, 1, 0,
+	    (SCM s1, SCM s2, SCM locale),
+	    "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
+	    "If @var{locale} is provided, it should be locale object (as "
+	    "returned by @code{make-locale}) and will be used to perform the "
+	    "comparison; otherwise, the current system locale is used.")
+#define FUNC_NAME s_scm_string_locale_gt
+{
+  int result;
+  const char *c_s1, *c_s2;
+
+  SCM_VALIDATE_STRING (1, s1);
+  SCM_VALIDATE_STRING (2, s2);
+
+  c_s1 = scm_i_string_chars (s1);
+  c_s2 = scm_i_string_chars (s2);
+
+  result = compare_strings (c_s1, c_s2, locale, FUNC_NAME);
+
+  scm_remember_upto_here_2 (s1, s2);
+
+  return scm_from_bool (result > 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_string_locale_ci_lt, "string-locale-ci<?", 2, 1, 0,
+	    (SCM s1, SCM s2, SCM locale),
+	    "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
+	    "and locale-dependent way.  If @var{locale} is provided, it "
+	    "should be locale object (as returned by @code{make-locale}) "
+	    "and will be used to perform the comparison; otherwise, the "
+	    "current system locale is used.")
+#define FUNC_NAME s_scm_string_locale_ci_lt
+{
+  int result;
+  const char *c_s1, *c_s2;
+
+  SCM_VALIDATE_STRING (1, s1);
+  SCM_VALIDATE_STRING (2, s2);
+
+  c_s1 = scm_i_string_chars (s1);
+  c_s2 = scm_i_string_chars (s2);
+
+  result = compare_strings_ci (c_s1, c_s2, locale, FUNC_NAME);
+
+  scm_remember_upto_here_2 (s1, s2);
+
+  return scm_from_bool (result < 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_string_locale_ci_gt, "string-locale-ci>?", 2, 1, 0,
+	    (SCM s1, SCM s2, SCM locale),
+	    "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
+	    "and locale-dependent way.  If @var{locale} is provided, it "
+	    "should be locale object (as returned by @code{make-locale}) "
+	    "and will be used to perform the comparison; otherwise, the "
+	    "current system locale is used.")
+#define FUNC_NAME s_scm_string_locale_ci_gt
+{
+  int result;
+  const char *c_s1, *c_s2;
+
+  SCM_VALIDATE_STRING (1, s1);
+  SCM_VALIDATE_STRING (2, s2);
+
+  c_s1 = scm_i_string_chars (s1);
+  c_s2 = scm_i_string_chars (s2);
+
+  result = compare_strings_ci (c_s1, c_s2, locale, FUNC_NAME);
+
+  scm_remember_upto_here_2 (s1, s2);
+
+  return scm_from_bool (result > 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_string_locale_ci_eq, "string-locale-ci=?", 2, 1, 0,
+	    (SCM s1, SCM s2, SCM locale),
+	    "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
+	    "and locale-dependent way.  If @var{locale} is provided, it "
+	    "should be locale object (as returned by @code{make-locale}) "
+	    "and will be used to perform the comparison; otherwise, the "
+	    "current system locale is used.")
+#define FUNC_NAME s_scm_string_locale_ci_eq
+{
+  int result;
+  const char *c_s1, *c_s2;
+
+  SCM_VALIDATE_STRING (1, s1);
+  SCM_VALIDATE_STRING (2, s2);
+
+  c_s1 = scm_i_string_chars (s1);
+  c_s2 = scm_i_string_chars (s2);
+
+  result = compare_strings_ci (c_s1, c_s2, locale, FUNC_NAME);
+
+  scm_remember_upto_here_2 (s1, s2);
+
+  return scm_from_bool (result == 0);
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_char_locale_lt, "char-locale<?", 2, 1, 0,
+	    (SCM c1, SCM c2, SCM locale),
+	    "Return true if character @var{c1} is lower than @var{c2} "
+	    "according to @var{locale} or to the current locale.")
+#define FUNC_NAME s_scm_char_locale_lt
+{
+  char c_c1[2], c_c2[2];
+
+  SCM_VALIDATE_CHAR (1, c1);
+  SCM_VALIDATE_CHAR (2, c2);
+
+  c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
+  c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
+
+  return scm_from_bool (compare_strings (c_c1, c_c2, locale, FUNC_NAME) < 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_char_locale_gt, "char-locale>?", 2, 1, 0,
+	    (SCM c1, SCM c2, SCM locale),
+	    "Return true if character @var{c1} is greater than @var{c2} "
+	    "according to @var{locale} or to the current locale.")
+#define FUNC_NAME s_scm_char_locale_gt
+{
+  char c_c1[2], c_c2[2];
+
+  SCM_VALIDATE_CHAR (1, c1);
+  SCM_VALIDATE_CHAR (2, c2);
+
+  c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
+  c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
+
+  return scm_from_bool (compare_strings (c_c1, c_c2, locale, FUNC_NAME) > 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_char_locale_ci_lt, "char-locale-ci<?", 2, 1, 0,
+	    (SCM c1, SCM c2, SCM locale),
+	    "Return true if character @var{c1} is lower than @var{c2}, "
+	    "in a case insensitive way according to @var{locale} or to "
+	    "the current locale.")
+#define FUNC_NAME s_scm_char_locale_ci_lt
+{
+  int result;
+  char c_c1[2], c_c2[2];
+
+  SCM_VALIDATE_CHAR (1, c1);
+  SCM_VALIDATE_CHAR (2, c2);
+
+  c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
+  c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
+
+  result = compare_strings_ci (c_c1, c_c2, locale, FUNC_NAME);
+
+  return scm_from_bool (result < 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_char_locale_ci_gt, "char-locale-ci>?", 2, 1, 0,
+	    (SCM c1, SCM c2, SCM locale),
+	    "Return true if character @var{c1} is greater than @var{c2}, "
+	    "in a case insensitive way according to @var{locale} or to "
+	    "the current locale.")
+#define FUNC_NAME s_scm_char_locale_ci_gt
+{
+  int result;
+  char c_c1[2], c_c2[2];
+
+  SCM_VALIDATE_CHAR (1, c1);
+  SCM_VALIDATE_CHAR (2, c2);
+
+  c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
+  c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
+
+  result = compare_strings_ci (c_c1, c_c2, locale, FUNC_NAME);
+
+  return scm_from_bool (result > 0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_char_locale_ci_eq, "char-locale-ci=?", 2, 1, 0,
+	    (SCM c1, SCM c2, SCM locale),
+	    "Return true if character @var{c1} is equal to @var{c2}, "
+	    "in a case insensitive way according to @var{locale} or to "
+	    "the current locale.")
+#define FUNC_NAME s_scm_char_locale_ci_eq
+{
+  int result;
+  char c_c1[2], c_c2[2];
+
+  SCM_VALIDATE_CHAR (1, c1);
+  SCM_VALIDATE_CHAR (2, c2);
+
+  c_c1[0] = (char)SCM_CHAR (c1); c_c1[1] = '\0';
+  c_c2[0] = (char)SCM_CHAR (c2); c_c2[1] = '\0';
+
+  result = compare_strings_ci (c_c1, c_c2, locale, FUNC_NAME);
+
+  return scm_from_bool (result == 0);
+}
+#undef FUNC_NAME
+
+
+\f
+/* Locale-dependent alphabetic character mapping.  */
+
+SCM_DEFINE (scm_char_locale_downcase, "char-locale-downcase", 1, 1, 0,
+	    (SCM chr, SCM locale),
+	    "Return the lowercase character that corresponds to @var{chr} "
+	    "according to either @var{locale} or the current locale.")
+#define FUNC_NAME s_scm_char_locale_downcase
+{
+  char c_chr;
+  int c_result;
+  scm_t_locale c_locale;
+
+  SCM_VALIDATE_CHAR (1, chr);
+  c_chr = SCM_CHAR (chr);
+
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
+
+  if (c_locale != NULL)
+    {
+#ifdef USE_GNU_LOCALE_API
+      c_result = tolower_l (c_chr, c_locale);
+#else
+      RUN_IN_LOCALE_SECTION (c_locale, c_result = tolower (c_chr));
+#endif
+    }
+  else
+    c_result = tolower (c_chr);
+
+  return (SCM_MAKE_CHAR (c_result));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_char_locale_upcase, "char-locale-upcase", 1, 1, 0,
+	    (SCM chr, SCM locale),
+	    "Return the uppercase character that corresponds to @var{chr} "
+	    "according to either @var{locale} or the current locale.")
+#define FUNC_NAME s_scm_char_locale_upcase
+{
+  char c_chr;
+  int c_result;
+  scm_t_locale c_locale;
+
+  SCM_VALIDATE_CHAR (1, chr);
+  c_chr = SCM_CHAR (chr);
+
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
+
+  if (c_locale != NULL)
+    {
+#ifdef USE_GNU_LOCALE_API
+      c_result = toupper_l (c_chr, c_locale);
+#else
+      RUN_IN_LOCALE_SECTION (c_locale, c_result = toupper (c_chr));
+#endif
+    }
+  else
+    c_result = toupper (c_chr);
+
+  return (SCM_MAKE_CHAR (c_result));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_string_locale_upcase, "string-locale-upcase", 1, 1, 0,
+	    (SCM str, SCM locale),
+	    "Return a new string that is the uppercase version of "
+	    "@var{str} according to either @var{locale} or the current "
+	    "locale.")
+#define FUNC_NAME s_scm_string_locale_upcase
+{
+  const char *c_str;
+  char *c_ustr;
+  scm_t_locale c_locale;
+
+  SCM_VALIDATE_STRING (1, str);
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
+
+  c_str = scm_i_string_chars (str);
+  c_ustr = (char *) alloca (strlen (c_str) + 1);
+
+  if (c_locale)
+    {
+#ifdef USE_GNU_LOCALE_API
+      str_upcase_l (c_ustr, c_str, c_locale);
+#else
+      RUN_IN_LOCALE_SECTION (c_locale, str_upcase (c_ustr, c_str));
+#endif
+    }
+  else
+    str_upcase (c_ustr, c_str);
+
+  scm_remember_upto_here (str);
+
+  return (scm_from_locale_string (c_ustr));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_string_locale_downcase, "string-locale-downcase", 1, 1, 0,
+	    (SCM str, SCM locale),
+	    "Return a new string that is the down-case version of "
+	    "@var{str} according to either @var{locale} or the current "
+	    "locale.")
+#define FUNC_NAME s_scm_string_locale_downcase
+{
+  const char *c_str;
+  char *c_lstr;
+  scm_t_locale c_locale;
+
+  SCM_VALIDATE_STRING (1, str);
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
+
+  c_str = scm_i_string_chars (str);
+  c_lstr = (char *) alloca (strlen (c_str) + 1);
+
+  if (c_locale)
+    {
+#ifdef USE_GNU_LOCALE_API
+      str_downcase_l (c_lstr, c_str, c_locale);
+#else
+      RUN_IN_LOCALE_SECTION (c_locale, str_downcase (c_lstr, c_str));
+#endif
+    }
+  else
+    str_downcase (c_lstr, c_str);
+
+  scm_remember_upto_here (str);
+
+  return (scm_from_locale_string (c_lstr));
+}
+#undef FUNC_NAME
+
+/* Note: We don't provide mutative versions of `string-locale-(up|down)case'
+   because, in some languages, a single downcase character maps to a couple
+   of uppercase characters.  Read the SRFI-13 document for a detailed
+   discussion about this.  */
+
+
+\f
+/* Locale-dependent number parsing.  */
+
+SCM_DEFINE (scm_locale_string_to_integer, "locale-string->integer",
+	    1, 2, 0, (SCM str, SCM base, SCM locale),
+	    "Convert string @var{str} into an integer according to either "
+	    "@var{locale} (a locale object as returned by @code{make-locale}) "
+	    "or the current process locale.  Return two values: an integer "
+	    "(on success) or @code{#f}, and the number of characters read "
+	    "from @var{str} (@code{0} on failure).")
+#define FUNC_NAME s_scm_locale_string_to_integer
+{
+  SCM result;
+  long c_result;
+  int c_base;
+  const char *c_str;
+  char *c_endptr;
+  scm_t_locale c_locale;
+
+  SCM_VALIDATE_STRING (1, str);
+  c_str = scm_i_string_chars (str);
+
+  if (base != SCM_UNDEFINED)
+    SCM_VALIDATE_INT_COPY (2, base, c_base);
+  else
+    c_base = 10;
+
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
+
+  if (c_locale != NULL)
+    {
+#ifdef USE_GNU_LOCALE_API
+      c_result = strtol_l (c_str, &c_endptr, c_base, c_locale);
+#else
+      RUN_IN_LOCALE_SECTION (c_locale,
+			     c_result = strtol (c_str, &c_endptr, c_base));
+#endif
+    }
+  else
+    c_result = strtol (c_str, &c_endptr, c_base);
+
+  scm_remember_upto_here (str);
+
+  if (c_endptr == c_str)
+    result = SCM_BOOL_F;
+  else
+    result = scm_from_long (c_result);
+
+  return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_locale_string_to_inexact, "locale-string->inexact",
+	    1, 1, 0, (SCM str, SCM locale),
+	    "Convert string @var{str} into an inexact number according to "
+	    "either @var{locale} (a locale object as returned by "
+	    "@code{make-locale}) or the current process locale.  Return "
+	    "two values: an inexact number (on success) or @code{#f}, and "
+	    "the number of characters read from @var{str} (@code{0} on "
+	    "failure).")
+#define FUNC_NAME s_scm_locale_string_to_inexact
+{
+  SCM result;
+  double c_result;
+  const char *c_str;
+  char *c_endptr;
+  scm_t_locale c_locale;
+
+  SCM_VALIDATE_STRING (1, str);
+  c_str = scm_i_string_chars (str);
+
+  SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
+
+  if (c_locale != NULL)
+    {
+#ifdef USE_GNU_LOCALE_API
+      c_result = strtod_l (c_str, &c_endptr, c_locale);
+#else
+      RUN_IN_LOCALE_SECTION (c_locale,
+			     c_result = strtod (c_str, &c_endptr));
+#endif
+    }
+  else
+    c_result = strtod (c_str, &c_endptr);
+
+  scm_remember_upto_here (str);
+
+  if (c_endptr == c_str)
+    result = SCM_BOOL_F;
+  else
+    result = scm_from_double (c_result);
+
+  return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
+}
+#undef FUNC_NAME
+
+
+\f
+void
+scm_init_i18n ()
+{
+  scm_add_feature ("ice-9-i18n");
+
+#define _SCM_STRINGIFY_LC(_name)  # _name
+#define SCM_STRINGIFY_LC(_name)   _SCM_STRINGIFY_LC (_name)
+
+  /* Define all the relevant `_MASK' variables.  */
+#define SCM_DEFINE_LOCALE_CATEGORY(_name)		\
+  scm_c_define ("LC_" SCM_STRINGIFY_LC (_name) "_MASK",	\
+		SCM_I_MAKINUM (LC_ ## _name ## _MASK));
+#include "locale-categories.h"
+
+#undef SCM_DEFINE_LOCALE_CATEGORY
+#undef SCM_STRINGIFY_LC
+#undef _SCM_STRINGIFY_LC
+
+  scm_c_define ("LC_ALL_MASK", SCM_I_MAKINUM (LC_ALL_MASK));
+
+#include "libguile/i18n.x"
+
+#ifndef USE_GNU_LOCALE_API
+  scm_set_smob_mark (scm_tc16_locale_smob_type, smob_locale_mark);
+#endif
+}
+
+
+/*
+  Local Variables:
+  c-file-style: "gnu"
+  End:
+*/
--- /dev/null
+++ mod/libguile/i18n.h
@@ -0,0 +1,52 @@
+/* classes: h_files */
+
+#ifndef SCM_I18N_H
+#define SCM_I18N_H
+
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libguile/__scm.h"
+
+SCM_API SCM scm_make_locale (SCM category_mask, SCM locale_name, SCM base_locale);
+SCM_API SCM scm_locale_p (SCM obj);
+SCM_API SCM scm_string_locale_lt (SCM s1, SCM s2, SCM locale);
+SCM_API SCM scm_string_locale_gt (SCM s1, SCM s2, SCM locale);
+SCM_API SCM scm_string_locale_ci_lt (SCM s1, SCM s2, SCM locale);
+SCM_API SCM scm_string_locale_ci_gt (SCM s1, SCM s2, SCM locale);
+SCM_API SCM scm_string_locale_ci_eq (SCM s1, SCM s2, SCM locale);
+SCM_API SCM scm_char_locale_lt (SCM c1, SCM c2, SCM locale);
+SCM_API SCM scm_char_locale_gt (SCM c1, SCM c2, SCM locale);
+SCM_API SCM scm_char_locale_ci_lt (SCM c1, SCM c2, SCM locale);
+SCM_API SCM scm_char_locale_ci_gt (SCM c1, SCM c2, SCM locale);
+SCM_API SCM scm_char_locale_ci_eq (SCM c1, SCM c2, SCM locale);
+SCM_API SCM scm_char_locale_upcase (SCM chr, SCM locale);
+SCM_API SCM scm_char_locale_downcase (SCM chr, SCM locale);
+SCM_API SCM scm_string_locale_upcase (SCM chr, SCM locale);
+SCM_API SCM scm_string_locale_downcase (SCM chr, SCM locale);
+SCM_API SCM scm_locale_string_to_integer (SCM str, SCM base, SCM locale);
+SCM_API SCM scm_locale_string_to_inexact (SCM str, SCM locale);
+
+SCM_API void scm_init_i18n (void);
+
+#endif  /* SCM_I18N_H */
+
+/*
+  Local Variables:
+  c-file-style: "gnu"
+  End:
+*/
--- /dev/null
+++ mod/libguile/locale-categories.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* A list of all available locale categories, not including `ALL'.  */
+
+
+/* The six standard categories, as defined in IEEE Std 1003.1-2001.  */
+SCM_DEFINE_LOCALE_CATEGORY (COLLATE)
+SCM_DEFINE_LOCALE_CATEGORY (CTYPE)
+SCM_DEFINE_LOCALE_CATEGORY (MESSAGES)
+SCM_DEFINE_LOCALE_CATEGORY (MONETARY)
+SCM_DEFINE_LOCALE_CATEGORY (NUMERIC)
+SCM_DEFINE_LOCALE_CATEGORY (TIME)
+
+/* Additional non-standard categories.  */
+#ifdef LC_PAPER
+SCM_DEFINE_LOCALE_CATEGORY (PAPER)
+#endif
+#ifdef LC_NAME
+SCM_DEFINE_LOCALE_CATEGORY (NAME)
+#endif
+#ifdef LC_ADDRESS
+SCM_DEFINE_LOCALE_CATEGORY (ADDRESS)
+#endif
+#ifdef LC_TELEPHONE
+SCM_DEFINE_LOCALE_CATEGORY (TELEPHONE)
+#endif
+#ifdef LC_MEASUREMENT
+SCM_DEFINE_LOCALE_CATEGORY (MEASUREMENT)
+#endif
+#ifdef LC_IDENTIFICATION
+SCM_DEFINE_LOCALE_CATEGORY (IDENTIFICATION)
+#endif
--- /dev/null
+++ mod/test-suite/tests/.arch-ids/i18n.test.id
@@ -0,0 +1 @@
+Ludovic Courtes <ludovic.courtes@laas.fr> Thu Oct 19 01:46:26 2006 25287.0
--- /dev/null
+++ mod/test-suite/tests/i18n.test
@@ -0,0 +1,143 @@
+;;;; i18n.test --- Exercise the i18n API.
+;;;;
+;;;; Copyright (C) 2006 Free Software Foundation, Inc.
+;;;; Ludovic Courtès
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 2.1 of the License, or (at your option) any later version.
+;;;;
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (test-suite i18n)
+  :use-module (ice-9 i18n)
+  :use-module (test-suite lib))
+
+;; Start from a pristine locale state.
+(setlocale LC_ALL "C")
+
+\f
+(with-test-prefix "locale objects"
+
+  (pass-if "make-locale (2 args)"
+    (not (not (make-locale LC_ALL_MASK "C"))))
+
+  (pass-if "make-locale (3 args)"
+    (not (not (make-locale LC_COLLATE_MASK "C"
+                           (make-locale LC_MESSAGES_MASK "C")))))
+
+  (pass-if "locale?"
+    (and (locale? (make-locale LC_ALL_MASK "C"))
+         (locale? (make-locale (logior LC_MESSAGES_MASK LC_NUMERIC_MASK) "C"
+                               (make-locale LC_CTYPE_MASK "C"))))))
+
+
+\f
+(with-test-prefix "text collation (English)"
+
+  (pass-if "string-locale<?"
+    (and (string-locale<? "hello" "world")
+         (string-locale<? "hello" "world"
+                          (make-locale LC_COLLATE_MASK "C"))))
+
+  (pass-if "char-locale<?"
+    (and (char-locale<? #\a #\b)
+         (char-locale<? #\a #\b (make-locale LC_COLLATE_MASK "C"))))
+
+  (pass-if "string-locale-ci=?"
+    (and (string-locale-ci=? "Hello" "HELLO")
+         (string-locale-ci=? "Hello" "HELLO"
+                             (make-locale LC_COLLATE_MASK "C"))))
+
+  (pass-if "string-locale-ci<?"
+    (and (string-locale-ci<? "hello" "WORLD")
+         (string-locale-ci<? "hello" "WORLD"
+                             (make-locale LC_COLLATE_MASK "C")))))
+
+\f
+(define %french-locale
+  (false-if-exception
+   (make-locale (logior LC_CTYPE_MASK LC_COLLATE_MASK)
+                "fr_FR.ISO-8859-1")))
+
+(define (under-french-locale-or-unresolved thunk)
+  ;; On non-GNU systems, an exception may be raised only when the locale is
+  ;; actually used rather than at `make-locale'-time.  Thus, we must guard
+  ;; against both.
+  (if %french-locale
+      (catch 'system-error thunk
+             (lambda (key . args)
+               (throw 'unresolved)))
+      (throw 'unresolved)))
+
+(with-test-prefix "text collation (French)"
+
+  (pass-if "string-locale<?"
+    (under-french-locale-or-unresolved
+      (lambda ()
+        (string-locale<? "été" "hiver" %french-locale))))
+
+  (pass-if "char-locale<?"
+    (under-french-locale-or-unresolved
+      (lambda ()
+        (char-locale<? #\é #\h %french-locale))))
+
+  (pass-if "string-locale-ci=?"
+    (under-french-locale-or-unresolved
+      (lambda ()
+        (string-locale-ci=? "ÉTÉ" "été" %french-locale))))
+
+  (pass-if "string-locale-ci<>?"
+    (under-french-locale-or-unresolved
+      (lambda ()
+        (and (string-locale-ci<? "été" "Hiver" %french-locale)
+             (string-locale-ci>? "HiVeR" "été" %french-locale)))))
+
+  (pass-if "char-locale-ci<>?"
+     (under-french-locale-or-unresolved
+       (lambda ()
+         (and (char-locale-ci<? #\é #\H %french-locale)
+              (char-locale-ci>? #\h #\É %french-locale))))))
+
+\f
+(with-test-prefix "character mapping"
+
+  (pass-if "char-locale-downcase"
+    (and (eq? #\a (char-locale-downcase #\A))
+         (eq? #\a (char-locale-downcase #\A (make-locale LC_ALL_MASK "C")))))
+
+  (pass-if "char-locale-upcase"
+    (and (eq? #\Z (char-locale-upcase #\z))
+         (eq? #\Z (char-locale-upcase #\z (make-locale LC_ALL_MASK "C"))))))
+
+\f
+(with-test-prefix "number parsing"
+
+  (pass-if "locale-string->integer"
+    (call-with-values (lambda () (locale-string->integer "123"))
+      (lambda (result char-count)
+        (and (equal? result 123)
+             (equal? char-count 3)))))
+
+  (pass-if "locale-string->inexact"
+    (call-with-values
+        (lambda ()
+          (locale-string->inexact "123.456"
+                                  (make-locale LC_NUMERIC_MASK "C")))
+      (lambda (result char-count)
+        (and (equal? result 123.456)
+             (equal? char-count 7))))))
+
+
+;;; Local Variables:
+;;; coding: latin-1
+;;; mode: scheme
+;;; End:

[-- Attachment #3: Type: text/plain, Size: 143 bytes --]

_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-22 18:33   ` Ludovic Courtès
@ 2006-10-23  2:01     ` Rob Browning
  2006-10-23  7:56       ` Ludovic Courtès
  2006-10-25 18:33     ` Neil Jerram
                       ` (4 subsequent siblings)
  5 siblings, 1 reply; 46+ messages in thread
From: Rob Browning @ 2006-10-23  2:01 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

>    On IRC, Rob identified a number of issues with this approach:
>
>    * It would be the first `ice-9' module that does a `dynamic-link', so
>      we may want to think twice before doing it.
>
>    * The C programmer willing to use those functions would have to link
>      against `libguile-i18n' additionally.

Yes, the main question is to what extent we want people coding in C to
have to link aginst libraries other than -lguile.  Of course, this is
already the case for some of the SRFIs.

>    There's another (small) issue:
>
>    * The online help is a bit confused because the doc of the i18n.c
>      functions is include in libguile's `guile-procedure.txt'.  Thus,
>      `(help make-locale)' always works, even when `(ice-9 i18n)' is not
>      loaded.

Perhaps that's something we'll eventually want to fix in the
documentation system, but a really simple approach might be to just
mention the required module in the documentation for each function.

> While I agree that this practically precludes use of those functions
> by C programmers (as is the case for those SRFIs that are
> implemented in C)

Actually, if I understand you correctly, this isn't the case.  The
SRFIs (which provide C interfaces) are definitely intended for use by
C programmers.  The programmers just have to make sure to include the
correct -lguile-srfi-* for the SRFI in question.

Although I'm not sure it's a great idea, one other possibility would
be to put the C code in libguile, and to provide a C init function,
called from init.c, that doesn't do anything more than publish a
scheme-side init function that can handle the full initialization
later.

Then the startup process should be relatively unaffected, and
ice-9/i18n.scm would just do something like this:

  (define-module (ice-9 i18n) ...)
  (scm-init-i18n)

This would avoid the need to make it possible to use dynamic-link for
items that are already in libguile.  Of course, whether or not the
approach is a good idea is a different question.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-23  2:01     ` Rob Browning
@ 2006-10-23  7:56       ` Ludovic Courtès
  2006-10-24  8:37         ` Rob Browning
  0 siblings, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-10-23  7:56 UTC (permalink / raw)
  Cc: Guile-Devel

Hi,

Rob Browning <rlb@defaultvalue.org> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
>> While I agree that this practically precludes use of those functions
>> by C programmers (as is the case for those SRFIs that are
>> implemented in C)
>
> Actually, if I understand you correctly, this isn't the case.  The
> SRFIs (which provide C interfaces) are definitely intended for use by
> C programmers.  The programmers just have to make sure to include the
> correct -lguile-srfi-* for the SRFI in question.

I don't think this is actually the case: there are currently 4 shared
libraries in the `srfi' directory, but none of them is documented in the
manual and the C functions they export are not mentioned either (that's
what I meant by "practically preclude": it's technically possible to use
them but it's not documented).

I would expect it to be done on purpose: For instance, the contents of
`libguile-srfi-srfi-1' changed noticeably as some functions were
rewritten in C and this is not something we want users to be aware of.

> Then the startup process should be relatively unaffected, and
> ice-9/i18n.scm would just do something like this:
>
>   (define-module (ice-9 i18n) ...)
>   (scm-init-i18n)

Yes, I'm open to that if we consider it a better option than having
another shared lib.

The issue, IMO, is that this is not very "scalable" either: we still end
up adding one function call in `scm_i_init_guile ()' that systematically
gets in the way.

> This would avoid the need to make it possible to use dynamic-link for
> items that are already in libguile.  Of course, whether or not the
> approach is a good idea is a different question.

Right.  What I had in mind was to have, say, `(dynamic-link)' (with no
arguments) translate to `lt_dlopen (NULL)', so that we could access
symbols contained within the executable.  Now, I'm not sure this would
work in all cases, for instance when the executable is not `guile'
itself.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-23  7:56       ` Ludovic Courtès
@ 2006-10-24  8:37         ` Rob Browning
  2006-10-25  8:16           ` Ludovic Courtès
  2006-10-25 18:43           ` Neil Jerram
  0 siblings, 2 replies; 46+ messages in thread
From: Rob Browning @ 2006-10-24  8:37 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> I don't think this is actually the case: there are currently 4
> shared libraries in the `srfi' directory, but none of them is
> documented in the manual and the C functions they export are not
> mentioned either (that's what I meant by "practically preclude":
> it's technically possible to use them but it's not documented).

Actually, in general, the SRFI scm_* functions are intended for public
use.  If not, then all of the relevant scm_* functions would/should
have been named scm_i_*.

Also, you definitely can't judge by the presence or lack of
documentation.  Guile's documentation has often taken a while to catch
up with the code.

(BTW, does documentation snarfing work right for C functions in
libraries outside libguile?  If not, then that's just a bug.)

> I would expect it to be done on purpose: For instance, the contents
> of `libguile-srfi-srfi-1' changed noticeably as some functions were
> rewritten in C and this is not something we want users to be aware
> of.

Note that when Marius moved the SRFI-13 and SRFI-14 functions to
libguile, he still kept the C library for backward compatibility.  I
believe this was specifically so that people who were already using
those functions wouldn't be affected.

> Yes, I'm open to that if we consider it a better option than having
> another shared lib.
>
> The issue, IMO, is that this is not very "scalable" either: we still
> end up adding one function call in `scm_i_init_guile ()' that
> systematically gets in the way.

I'm actually not sure which (of the discussed approaches) I think is
best.  I suppose first we'd need to consider the extent to which we
want to move toward a more modular ice-9 (more modular core), and then
determine how we might want to implement that modularity.

> Right.  What I had in mind was to have, say, `(dynamic-link)' (with
> no arguments) translate to `lt_dlopen (NULL)', so that we could
> access symbols contained within the executable.  Now, I'm not sure
> this would work in all cases, for instance when the executable is
> not `guile' itself.

Well, if we wanted to take this approach, and if lt_dlopen(NULL)
wouldn't do what was intended, perhaps there is some other way to
accomplish the same thing (i.e. to make sure you get the current
libguile.so), but I don't know offhand.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-24  8:37         ` Rob Browning
@ 2006-10-25  8:16           ` Ludovic Courtès
  2006-10-25  8:46             ` Rob Browning
  2006-10-25 18:43           ` Neil Jerram
  1 sibling, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-10-25  8:16 UTC (permalink / raw)
  Cc: Guile-Devel

Hi,

Rob Browning <rlb@defaultvalue.org> writes:

> (BTW, does documentation snarfing work right for C functions in
> libraries outside libguile?  If not, then that's just a bug.)

No, it doesn't work.  In the latest `guile-reader', I have a couple of
modules that do (part of) what the Awk script in `libguile' does:
parsing the output of `cpp -DSCM_MAGIC_SNARF'.  I'd be in favor of
integrating such an approach in Guile core eventually.

>> The issue, IMO, is that this is not very "scalable" either: we still
>> end up adding one function call in `scm_i_init_guile ()' that
>> systematically gets in the way.
>
> I'm actually not sure which (of the discussed approaches) I think is
> best.  I suppose first we'd need to consider the extent to which we
> want to move toward a more modular ice-9 (more modular core), and then
> determine how we might want to implement that modularity.

Personally, I would like Guile "core" to be much more modular than what
it is now.  I believe many things in what we call "Guile core" are there
just because we want them to be part of the "standard Guile library",
but they certainly to not comprise the "core" or "kernel" of Guile.  For
instance, I believe the Gettext-related functions ought to be
distributed with Guile core but as a separate module.  Same for
SRFI-1[43].  Not to mention the bits and pieces that are in `boot-9' and
that happen to be visible to everyone.  ;-)

Basically, the logical separation among the R5.91RS standard libraries
has a level of granularity that looks appropriate to me.

Now, whether each module should load its own shared library is a
different issue.  This may depend on the module characteristics: size,
usefulness, C programmability.  We also have to find a balance between
lazy initialization (with `dynamic-link') and systematic initialization.


Getting back to `(ice-9 i18n)': I'm strongly in favor of keeping this as
a module; I am more inclined to having it in a separate shared library
(because it's not useful to everyone) but I wouldn't mind having it in
`libguile.so'.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-25  8:16           ` Ludovic Courtès
@ 2006-10-25  8:46             ` Rob Browning
  2006-10-25 18:40               ` Neil Jerram
  0 siblings, 1 reply; 46+ messages in thread
From: Rob Browning @ 2006-10-25  8:46 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> No, it doesn't work.  In the latest `guile-reader', I have a couple of
> modules that do (part of) what the Awk script in `libguile' does:
> parsing the output of `cpp -DSCM_MAGIC_SNARF'.  I'd be in favor of
> integrating such an approach in Guile core eventually.

Yes.  It would be nice to have a more comprehensive solution for
documentation, one that can be used both internally and externally.

> Personally, I would like Guile "core" to be much more modular than what
> it is now.  I believe many things in what we call "Guile core" are there
> just because we want them to be part of the "standard Guile library",
> but they certainly to not comprise the "core" or "kernel" of Guile.  For
> instance, I believe the Gettext-related functions ought to be
> distributed with Guile core but as a separate module.  Same for
> SRFI-1[43].  Not to mention the bits and pieces that are in `boot-9' and
> that happen to be visible to everyone.  ;-)

I don't really disagree.  In particular, I think this is something we
should definitely consider as we examine R6RS.

> Now, whether each module should load its own shared library is a
> different issue.  This may depend on the module characteristics:
> size, usefulness, C programmability.  We also have to find a balance
> between lazy initialization (with `dynamic-link') and systematic
> initialization.
>
> Getting back to `(ice-9 i18n)': I'm strongly in favor of keeping this as
> a module; I am more inclined to having it in a separate shared library
> (because it's not useful to everyone) but I wouldn't mind having it in
> `libguile.so'.

I'm somewhat inclined to think that the scheme-side module is a good
idea, though perhaps it begs more general organizational questions.
I'm less certain about whether or not adding small shared library is a
good idea.  However, in both cases, I need to think a bit more.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-22 18:33   ` Ludovic Courtès
  2006-10-23  2:01     ` Rob Browning
@ 2006-10-25 18:33     ` Neil Jerram
  2006-10-26  8:39       ` Ludovic Courtès
  2006-11-29 23:08     ` Kevin Ryde
                       ` (3 subsequent siblings)
  5 siblings, 1 reply; 46+ messages in thread
From: Neil Jerram @ 2006-10-25 18:33 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Hi,

Hi, and sorry for coming late to the discussion.  I think this whole
patch is great.  I've a few detailed comments below, and I'll comment
on some of the conceptual issues in response to emails further down
the thread.

>  @c Local Variables:
>  @c TeX-master: "guile.texi"
> +@c ispell-local-dictionary: "american"

Hmmm :-)  (I'm British.)  I guess Guile is an FSF project, and the FSF
is US, though, so OK.

> -void 
> -scm_init_i18n ()
> +void
> +scm_init_gettext ()
>  {
> +  /* When gettext support was first added (in 1.8.0), it provided feature
> +     `i18n'.  We keep this as is although the name is a bit misleading
> +     now.  */
>    scm_add_feature ("i18n");

OK, but how about (i) adding a "gettext" feature too, (ii) adding a
NEWS item to say that the "i18n" feature is deprecated and will be
removed in a future release, and that people should check "gettext"
instead.



> +(dynamic-call "scm_init_i18n"
> +              (dynamic-link "libguile-i18n-v0"))

You should use (load-extension ...) here instead.  Then if someone
wants to link the i18n lib statically, they can.

(Note that I haven't looked in detail at the C code yet; I might do
that if I get time in the next few days.)

Regards,
     Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-25  8:46             ` Rob Browning
@ 2006-10-25 18:40               ` Neil Jerram
  2006-10-25 19:55                 ` Rob Browning
  2006-10-26  8:47                 ` Ludovic Courtès
  0 siblings, 2 replies; 46+ messages in thread
From: Neil Jerram @ 2006-10-25 18:40 UTC (permalink / raw)
  Cc: Guile-Devel

Rob Browning <rlb@defaultvalue.org> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
>> No, it doesn't work.  In the latest `guile-reader', I have a couple of
>> modules that do (part of) what the Awk script in `libguile' does:
>> parsing the output of `cpp -DSCM_MAGIC_SNARF'.  I'd be in favor of
>> integrating such an approach in Guile core eventually.
>
> Yes.  It would be nice to have a more comprehensive solution for
> documentation, one that can be used both internally and externally.

FWIW, this is the next thing on my radar, once I'm done with debugging
stuff.

Not that that should stop anyone beating me to it!

>> Personally, I would like Guile "core" to be much more modular than what
>> it is now.

Me too.  And I think this should mean separate libraries.

> I don't really disagree.  In particular, I think this is something we
> should definitely consider as we examine R6RS.

Ah yes, R6RS.  I've been following r6rs-discuss just enough to feel
worried about this!  (My impression is that there's quite a lot of
change from R5RS, not just additions.)

>> Getting back to `(ice-9 i18n)': I'm strongly in favor of keeping this as
>> a module; I am more inclined to having it in a separate shared library
>> (because it's not useful to everyone) but I wouldn't mind having it in
>> `libguile.so'.
>
> I'm somewhat inclined to think that the scheme-side module is a good
> idea, though perhaps it begs more general organizational questions.
> I'm less certain about whether or not adding small shared library is a
> good idea.  However, in both cases, I need to think a bit more.

I agree with both separate module and separate library.  If having a
separate library throws up problems, this can motivate us to address
them.

Regards,
     Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-24  8:37         ` Rob Browning
  2006-10-25  8:16           ` Ludovic Courtès
@ 2006-10-25 18:43           ` Neil Jerram
  2006-10-25 19:31             ` Rob Browning
  1 sibling, 1 reply; 46+ messages in thread
From: Neil Jerram @ 2006-10-25 18:43 UTC (permalink / raw)
  Cc: Guile-Devel

Rob Browning <rlb@defaultvalue.org> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
>> I don't think this is actually the case: there are currently 4
>> shared libraries in the `srfi' directory, but none of them is
>> documented in the manual and the C functions they export are not
>> mentioned either (that's what I meant by "practically preclude":
>> it's technically possible to use them but it's not documented).
>
> Actually, in general, the SRFI scm_* functions are intended for public
> use.  If not, then all of the relevant scm_* functions would/should
> have been named scm_i_*.
>
> Also, you definitely can't judge by the presence or lack of
> documentation.  Guile's documentation has often taken a while to catch
> up with the code.

I'm not sure I agree with that.  I accept that documentation can
sometimes take a while to catch up (although it shouldn't, and
recently I think we've all been pretty good about writing doc at the
same time as developing something), but in principle I think "presence
in the manual" is a better way of indicating to users whether an API
is officially supported than a coding convention.

Regards,
     Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-25 18:43           ` Neil Jerram
@ 2006-10-25 19:31             ` Rob Browning
  0 siblings, 0 replies; 46+ messages in thread
From: Rob Browning @ 2006-10-25 19:31 UTC (permalink / raw)
  Cc: Guile-Devel

Neil Jerram <neil@ossau.uklinux.net> writes:

>> Also, you definitely can't judge by the presence or lack of
>> documentation.  Guile's documentation has often taken a while to
>> catch up with the code.
>
> I'm not sure I agree with that.  I accept that documentation can
> sometimes take a while to catch up (although it shouldn't, and
> recently I think we've all been pretty good about writing doc at the
> same time as developing something), but in principle I think
> "presence in the manual" is a better way of indicating to users
> whether an API is officially supported than a coding convention.

Well, if that's how we want to proceed, then I think we need to be
very clear about it.  My understanding has been that we promse that as
a default, any C feature that's prefixed with scm_ instead of scm_i_
is fair game for the C programmer and that they can expect us to
maintain it going forward (plus or minus deprecation, *major*
(i.e. 2.0) releases, etc.).

In the past (at least), this was important because there were a lot of
things not mentioned in the documentation.  Further, as with the SRFI
code, the automatic documentation mechanism hasn't included the C
documentation, even when it exists, and even if our documentation
becomes (has become) more or less comprehensive, I still feel like the
scm_ vs scm_i_ convention is a good one.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-25 18:40               ` Neil Jerram
@ 2006-10-25 19:55                 ` Rob Browning
  2006-10-26  8:47                 ` Ludovic Courtès
  1 sibling, 0 replies; 46+ messages in thread
From: Rob Browning @ 2006-10-25 19:55 UTC (permalink / raw)
  Cc: Guile-Devel

Neil Jerram <neil@ossau.uklinux.net> writes:

>>> Personally, I would like Guile "core" to be much more modular than
>>> what it is now.
>
> Me too.  And I think this should mean separate libraries.
>
>> I don't really disagree.  In particular, I think this is something we
>> should definitely consider as we examine R6RS.
>
> Ah yes, R6RS.  I've been following r6rs-discuss just enough to feel
> worried about this!  (My impression is that there's quite a lot of
> change from R5RS, not just additions.)

Although I still haven't looked at R6RS carefully yet, I've been
wondering if this might be an opportunity to think about a Guile 2.0
release, one where we give ourselves more latitude to make disruptive
changes, perhaps including R6RS support, the addition of any other
major features, and any appropriate reorganizations (ice-9?).

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-25 18:33     ` Neil Jerram
@ 2006-10-26  8:39       ` Ludovic Courtès
  0 siblings, 0 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-10-26  8:39 UTC (permalink / raw)
  Cc: Guile-Devel

Hi,

Neil Jerram <neil@ossau.uklinux.net> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>>
>>  @c Local Variables:
>>  @c TeX-master: "guile.texi"
>> +@c ispell-local-dictionary: "american"
>
> Hmmm :-)  (I'm British.)  I guess Guile is an FSF project, and the FSF
> is US, though, so OK.

:-)

OTOH, Guile does not target only US users---if it were, we wouldn't be
talking about i18n in the first place.  ;-)

>> -void 
>> -scm_init_i18n ()
>> +void
>> +scm_init_gettext ()
>>  {
>> +  /* When gettext support was first added (in 1.8.0), it provided feature
>> +     `i18n'.  We keep this as is although the name is a bit misleading
>> +     now.  */
>>    scm_add_feature ("i18n");
>
> OK, but how about (i) adding a "gettext" feature too, (ii) adding a
> NEWS item to say that the "i18n" feature is deprecated and will be
> removed in a future release, and that people should check "gettext"
> instead.

I was considering the inclusion of this patch in 1.8.  Thus, I initially
thought that within the 1.8 branch we shouldn't change feature names
_at all_, so we would keep using `i18n' for Gettext, and `ice-9-i18n'
for the other.

Now, I agree that we should change those names in HEAD.  But should we
also change them eventually in, say, 1.8.3?

>> +(dynamic-call "scm_init_i18n"
>> +              (dynamic-link "libguile-i18n-v0"))
>
> You should use (load-extension ...) here instead.  Then if someone
> wants to link the i18n lib statically, they can.

Ok, I'll do it.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-25 18:40               ` Neil Jerram
  2006-10-25 19:55                 ` Rob Browning
@ 2006-10-26  8:47                 ` Ludovic Courtès
  2006-11-09  7:44                   ` Ludovic Courtès
  1 sibling, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-10-26  8:47 UTC (permalink / raw)
  Cc: Guile-Devel, Rob Browning

Hi,

Neil Jerram <neil@ossau.uklinux.net> writes:

> I agree with both separate module and separate library.  If having a
> separate library throws up problems, this can motivate us to address
> them.

In particular, if we keep it this way for `(ice-9 i18n)', do you think
we should document both the existence of `libguile-i18n-vXX' and the C
functions that are in this library?

The patch I posted only documents the Scheme side, assuming that the C
side is "not very useful" (which is debatable).  Rob pointed out that
since we do have those C functions anyway, then there's no compelling
reason not to document them.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-26  8:47                 ` Ludovic Courtès
@ 2006-11-09  7:44                   ` Ludovic Courtès
  2006-11-09 17:43                     ` Rob Browning
  0 siblings, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-11-09  7:44 UTC (permalink / raw)
  Cc: Guile-Devel, Rob Browning

Hi,

If nobody disagrees, I would like to merge `(ice-9 i18n)' in HEAD and
1.8 within a few days "as is" (that is, using a separate shared library
and without documenting the C functions, as discussed earlier).

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-09  7:44                   ` Ludovic Courtès
@ 2006-11-09 17:43                     ` Rob Browning
  2006-11-10 13:39                       ` Ludovic Courtès
  0 siblings, 1 reply; 46+ messages in thread
From: Rob Browning @ 2006-11-09 17:43 UTC (permalink / raw)
  Cc: Guile-Devel

ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> If nobody disagrees, I would like to merge `(ice-9 i18n)' in HEAD
> and 1.8 within a few days "as is" (that is, using a separate shared
> library and without documenting the C functions, as discussed
> earlier).

I don't have a strong feeling about the shared library issue as long
as none of the versioning requirements are broken.  However, I'm still
opposed to the addition of new scm_ functions that aren't intended to
be public, but don't use the scm_i_ prefix.

For better or for worse, people have long been advised to look at the
Guile headers/source in addition to the documentation, especially when
the documentation wasn't as good, and they've also been told about the
scm_i_ convention.

I've assumed that convention myself when reading the source, and
whether we maintain a public/private distinction via a naming
convention or via public/private headers, I think it's a good idea.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-09 17:43                     ` Rob Browning
@ 2006-11-10 13:39                       ` Ludovic Courtès
  2006-11-11 15:17                         ` Neil Jerram
  2006-11-20 13:24                         ` Ludovic Courtès
  0 siblings, 2 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-11-10 13:39 UTC (permalink / raw)
  Cc: Guile-Devel, Neil Jerram

Hi,

Rob Browning <rlb@defaultvalue.org> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
>> If nobody disagrees, I would like to merge `(ice-9 i18n)' in HEAD
>> and 1.8 within a few days "as is" (that is, using a separate shared
>> library and without documenting the C functions, as discussed
>> earlier).
>
> I don't have a strong feeling about the shared library issue as long
> as none of the versioning requirements are broken.  However, I'm still
> opposed to the addition of new scm_ functions that aren't intended to
> be public, but don't use the scm_i_ prefix.

Fair enough.  Then I think I'll do the following:

  1. Keep the shared library (named `libguile-i18n-v-0' in the next 1.8
     release).

  2. Document its existence as well as the C functions.

I think it's a better plan than renaming the C functions to `scm_i_'.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-10 13:39                       ` Ludovic Courtès
@ 2006-11-11 15:17                         ` Neil Jerram
  2006-11-20 13:24                         ` Ludovic Courtès
  1 sibling, 0 replies; 46+ messages in thread
From: Neil Jerram @ 2006-11-11 15:17 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Fair enough.  Then I think I'll do the following:
>
>   1. Keep the shared library (named `libguile-i18n-v-0' in the next 1.8
>      release).
>
>   2. Document its existence as well as the C functions.
>
> I think it's a better plan than renaming the C functions to `scm_i_'.

FWIW I'm happy with that.

Regards,
     Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-10 13:39                       ` Ludovic Courtès
  2006-11-11 15:17                         ` Neil Jerram
@ 2006-11-20 13:24                         ` Ludovic Courtès
  2006-11-21 22:03                           ` Neil Jerram
  1 sibling, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-11-20 13:24 UTC (permalink / raw)
  Cc: Guile-Devel, Neil Jerram

Hi,

ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Fair enough.  Then I think I'll do the following:
>
>   1. Keep the shared library (named `libguile-i18n-v-0' in the next 1.8
>      release).
>
>   2. Document its existence as well as the C functions.

This is now in HEAD.  I'm planning to merge it in 1.8 some time soon.

Please report build/run-time problems, especially on non-GNU platforms.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-20 13:24                         ` Ludovic Courtès
@ 2006-11-21 22:03                           ` Neil Jerram
  2006-11-22 13:38                             ` Ludovic Courtès
  0 siblings, 1 reply; 46+ messages in thread
From: Neil Jerram @ 2006-11-21 22:03 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> This is now in HEAD.

Great!

>  I'm planning to merge it in 1.8 some time soon.

I'm not sure that's a good idea, as will be apparent from another
thread.  Can I suggest holding off until that other thread reaches a
consensus?

Regards,
     Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-21 22:03                           ` Neil Jerram
@ 2006-11-22 13:38                             ` Ludovic Courtès
  0 siblings, 0 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-11-22 13:38 UTC (permalink / raw)
  Cc: Guile-Devel

Neil Jerram <neil@ossau.uklinux.net> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:

>>  I'm planning to merge it in 1.8 some time soon.
>
> I'm not sure that's a good idea, as will be apparent from another
> thread.  Can I suggest holding off until that other thread reaches a
> consensus?

Sure.  ;-)

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-22 18:33   ` Ludovic Courtès
  2006-10-23  2:01     ` Rob Browning
  2006-10-25 18:33     ` Neil Jerram
@ 2006-11-29 23:08     ` Kevin Ryde
  2006-11-30 15:19       ` Ludovic Courtès
                         ` (2 more replies)
  2006-12-12 19:05     ` Kevin Ryde
                       ` (2 subsequent siblings)
  5 siblings, 3 replies; 46+ messages in thread
From: Kevin Ryde @ 2006-11-29 23:08 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> I have come up with an `(ice-9 i18n)' module that contains
> locale-dependent text collation functions and also character case
> mapping and functions to read numbers.  There would be a lot more things
> to add, like `strfmon ()', but I think that's a good start.

I would worry that r6rs may address these things too, leaving
guile-specifics as, well, a dead-end.  Though I can see this stuff is
of use now.

Myself I've been using a couple of bits from from localeconv and
nl_langinfo.  Some way to get at that would be a good addition (though
hopefully in a cleaner way than the C level).

> [0] http://sources.redhat.com/ml/libc-alpha/2006-09/msg00033.html

You could stick that link and perhaps the tllocale.ps.gz one in i18n.c
for reference, since it's not in the glibc manual.

> +@node The ice-9 i18n Module

See if you can think of a better section name.

> +@deffn {Scheme Procedure} make-locale category_mask locale_name [base_locale]
> ...
> +A @code{system-error} exception (@pxref{Handling Errors}) is raised by
> +@code{make-locale} when @var{locale_name} does not match any of the
> +locales compiled on the system.

This bit could be moved to earlier in the description.  And perhaps
something non-committal like "locale_name must be known to the
system".

> +@deffn {Scheme Procedure} string-locale<? s1 s2 [locale]
> +@deffn {Scheme Procedure} string-locale>? s1 s2 [locale]
> +@deffn {Scheme Procedure} string-locale-ci<? s1 s2 [locale]
> +@deffn {Scheme Procedure} string-locale-ci>? s1 s2 [locale]
> +@deffn {Scheme Procedure} string-locale-ci=? s1 s2 [locale]

These could be described in one block I think, to avoid five very
similar descriptions.  Likewise the char ones.

> +...  Note that SRFI-13 provides procedures that
> +look similar (@pxref{Alphabetic Case Mapping}).  However, the SRFI-13
> +procedures are locale-independent.

That's the intention of the srfi I guess, but it's not true currently
is it?  Don't they use toupper() and therefore get whatever nonsense
the current setlocale() gives.  Perhaps better leave the description
of srfi-13 to that section.

> +@deffn {Scheme Procedure} string-locale-upcase str [locale]
> +@deffn {Scheme Procedure} string-locale-downcase str [locale]

Do you need a caveat about multibyte characters there, for now?  Like
"Note that in the current implementation Guile has no notion of
multibyte characters and in a multibyte locale characters may not be
converted correctly."

> +@deffn {Scheme Procedure} locale-string->integer str [base [locale]]
> +@deffn {Scheme Procedure} locale-string->inexact str [locale]

I think you should cross-reference strtol and strtod here, since their
parsing is rather idiosyncratic.  I'd even be a bit tempted to name
them strtol and strtod in guile, to make it clear they're only one
possible way of parsing.  Except those names aren't very nice ...

> +...  Return two values:

Consider @pxref{Multiple Values}, since multi-values are (thankfully)
fairly rare.

>  @c Local Variables:
>  @c TeX-master: "guile.texi"
> +@c ispell-local-dictionary: "american"

Best leave that out please, it'll only annoy those of us who don't
have that dictionary installed.

> +Note that @code{setlocale} affects locale settings for the whole
> +process.  For a safer, thread-safe and reentrant alternative,

Go easy on the advertising! :)

> -    scmconfig.h.top gettext.h
> +    scmconfig.h.top libgettext.h

I don't think that's good.  Best leave gettext.h the gettext one, and
use another name for guile.  Gettext got there first, and it doesn't
really matter which guile header has which prototypes.

> +/* This mutex is used to serialize invocations of `setlocale ()' on non-GNU
> +   systems (i.e., systems where a reentrant locale API is not available).
> +   See `i18n.c' for details.  */
> +scm_i_pthread_mutex_t scm_i_locale_mutex;

There's an scm_i_misc_mutex for use when protection is (or should be)
rarely needed.

> +++ mod/libguile/i18n.c
> +
> +#ifndef USE_GNU_LOCALE_API
> +# include "libguile/posix.h"  /* for `scm_i_locale_mutex' */
> +#endif

No need to conditionalize that, it's ok if it's only used sometimes,
it does no harm.

> +/* Provide the locale category masks as found in glibc (copied from
> +   <locale.h> as found in glibc 2.3.6).  This must be kept in sync with
> +   `locale-categories.h'.  */
> +# define LC_CTYPE_MASK		(1 << LC_CTYPE)
> +# define LC_COLLATE_MASK	(1 << LC_COLLATE)
> +# define LC_MESSAGES_MASK	(1 << LC_MESSAGES)
> +# define LC_MONETARY_MASK	(1 << LC_MONETARY)
> +# define LC_NUMERIC_MASK	(1 << LC_NUMERIC)
> +# define LC_TIME_MASK		(1 << LC_TIME)

I think you should put some privately selected bits there, not depend
on LC_CTYPE etc being in range 0 to 31.

> +/* Alias for glibc's locale type.  */
> +typedef locale_t scm_t_locale;

I suppose the emulation could provide locale_t.  Might make it hard to
exercise on an actual gnu system.  A #define locale_t would likely be
ok.

> +SCM_DEFINE (scm_locale_p, "locale?", 1, 0, 0,
> ...
> +  if (SCM_SMOB_PREDICATE (scm_tc16_locale_smob_type, obj))
> +    return SCM_BOOL_T;
> +  return SCM_BOOL_F;

scm_from_bool perhaps.

> +#ifdef USE_GNU_LOCALE_API
> +  freelocale ((locale_t)c_locale);
> +#else
> +  c_locale->base_locale = SCM_UNDEFINED;
> +  free (c_locale->locale_name);
> +  scm_gc_free (c_locale, sizeof (* c_locale), "locale");
> +#endif

A possibility there, and with other funcs, would be to implement a
compatible freelocale(), instead of sticking conditionals in each
usage.

> +#ifdef USE_GNU_LOCALE_API
> +
> +  c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale);
> +  if (!c_locale)
> +    locale = SCM_BOOL_F;

Your docs call for an exception on unknown locale don't they?

And should you tell the gc something about the size of a locale_t, and
perhaps extra for its underlying data?  To approximate memory used,
for the gc triggers.

> +void
> +scm_init_i18n ()
> +{
> +  scm_add_feature ("ice-9-i18n");

Is there any point adding a feature after the module is loaded? :)
I expect a better name would be possible too.

> +(define (under-french-locale-or-unresolved thunk)
> +  ;; On non-GNU systems, an exception may be raised only when the locale is
> +  ;; actually used rather than at `make-locale'-time.  Thus, we must guard
> +  ;; against both.
> +  (if %french-locale
> +      (catch 'system-error thunk
> +             (lambda (key . args)
> +               (throw 'unresolved)))
> +      (throw 'unresolved)))

Do you mean 'unsupported rather than 'unresolved, when fr_FR isn't
available from the system?

> +(with-test-prefix "number parsing"

Some french number parsing too?  Just to show there's a point to
locale dependent parsing :).


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-29 23:08     ` Kevin Ryde
@ 2006-11-30 15:19       ` Ludovic Courtès
  2006-12-02 21:56         ` Kevin Ryde
  2006-12-05  0:38         ` Kevin Ryde
  2006-12-02 22:02       ` Kevin Ryde
  2006-12-10 12:30       ` Ludovic Courtès
  2 siblings, 2 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-11-30 15:19 UTC (permalink / raw)


Hi,

Kevin Ryde <user42@zip.com.au> writes:

> I would worry that r6rs may address these things too, leaving
> guile-specifics as, well, a dead-end.  Though I can see this stuff is
> of use now.

Don't worry, R5.91RS doesn't deal with locales and text collation [0],
and if it did, we'd just have to provide a wrapper for our API.
MzScheme has had a similar API for some time also [1].

> Myself I've been using a couple of bits from from localeconv and
> nl_langinfo.  Some way to get at that would be a good addition (though
> hopefully in a cleaner way than the C level).

I've written a wrapper for `nl_langinfo ()' as part of the `i18n' module
(it is necessary to internationalize SRFI-19 for instance).  This also
required the implementation of `scm_from_string ()', a generalized
version of `scm_from_locale_string ()' that uses `iconv ()'.

I'll write about this later and try to address the other issues you
raised at the same time.

Thanks,
Ludovic.

[0] http://lists.gnu.org/archive/html/guile-devel/2006-09/msg00052.html
[1] http://download.plt-scheme.org/chronology/mzmr200alpha14.html


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-30 15:19       ` Ludovic Courtès
@ 2006-12-02 21:56         ` Kevin Ryde
  2006-12-04  9:01           ` Ludovic Courtès
  2006-12-05  0:38         ` Kevin Ryde
  1 sibling, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-12-02 21:56 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> I've written a wrapper for `nl_langinfo ()' as part of the `i18n' module
> (it is necessary to internationalize SRFI-19 for instance).

I think the existing strftime is enough, it's just nobody has got
around to using it.  The only extra would be the decimal point for ~f.

If you're interested in srfi-19 then fixing the date conversion would
be the best thing to do (dates prior to 1582 use gregorian leap years,
where it should be julian; it gets for instance a wrong start point
for the julian day numbers).


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-29 23:08     ` Kevin Ryde
  2006-11-30 15:19       ` Ludovic Courtès
@ 2006-12-02 22:02       ` Kevin Ryde
  2006-12-10 12:30       ` Ludovic Courtès
  2 siblings, 0 replies; 46+ messages in thread
From: Kevin Ryde @ 2006-12-02 22:02 UTC (permalink / raw)


I wrote:
>
>> +@deffn {Scheme Procedure} locale-string->integer str [base [locale]]
>> +@deffn {Scheme Procedure} locale-string->inexact str [locale]
>
> I think you should cross-reference strtol and strtod here, since their
> parsing is rather idiosyncratic.  I'd even be a bit tempted to name
> them strtol and strtod in guile, to make it clear they're only one
> possible way of parsing.  Except those names aren't very nice ...

I'm now sure these should be called strtol and probably strtod,
because they're actually pretty awful functions.  The syntax they
recognise is C style, and the error return for overflow is not too
friendly.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-02 21:56         ` Kevin Ryde
@ 2006-12-04  9:01           ` Ludovic Courtès
  2006-12-05  0:20             ` Kevin Ryde
  0 siblings, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-12-04  9:01 UTC (permalink / raw)


Hi,

Kevin Ryde <user42@zip.com.au> writes:

> I think the existing strftime is enough, it's just nobody has got
> around to using it.  The only extra would be the decimal point for ~f.

I suspect that this would be suboptimal.  SRFI-19 has its own template
format for `date->string', and internally it uses primitives equivalent
to `nl_langinfo (DAY_1)' and the likes (the `priv:locale' functions).

> If you're interested in srfi-19 then fixing the date conversion would
> be the best thing to do (dates prior to 1582 use gregorian leap years,
> where it should be julian; it gets for instance a wrong start point
> for the julian day numbers).

I don't clearly understand.  Could you provide more details for the
novice (perhaps in another thread)?  :-)

Thanks,
Ludovic.



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-04  9:01           ` Ludovic Courtès
@ 2006-12-05  0:20             ` Kevin Ryde
  2006-12-05 18:42               ` Carl Witty
  0 siblings, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-12-05  0:20 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> I suspect that this would be suboptimal.  SRFI-19 has its own template
> format for `date->string', and internally it uses primitives equivalent
> to `nl_langinfo (DAY_1)' and the likes (the `priv:locale' functions).

No need to worry about the existing internals.  strftime may be
necessary (at some level) on systems with only localeconv (ie. not
nl_langinfo), though I don't know how common that would be or if it's
worth taking trouble over.

> I don't clearly understand.  Could you provide more details for the
> novice (perhaps in another thread)?  :-)

The note in the manual:

	*Caution*: The current code in this module incorrectly extends
	the Gregorian calendar leap year rule back prior to the
	introduction of those reforms in 1582 (or the appropriate year
	in various countries).  The Julian calendar was used prior to
	1582, and there were 10 days skipped for the reform, but the
	code doesn't implement that.

So for instance the year 1500 should be a leap year, but isn't in the
current code.  (If I've got that right off the top of my head ... :-)


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-30 15:19       ` Ludovic Courtès
  2006-12-02 21:56         ` Kevin Ryde
@ 2006-12-05  0:38         ` Kevin Ryde
  1 sibling, 0 replies; 46+ messages in thread
From: Kevin Ryde @ 2006-12-05  0:38 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 833 bytes --]

ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> I've written a wrapper for `nl_langinfo ()' as part of the `i18n' module

What do other schemes or lisps do?  I had an idea one of the srfis had
some bits but they weren't great.  I started a localeconv bit (below)
using a vector for all info, though I'm now inclined to think a
function with a symbol arg would be friendlier than a big object
return.

	(langinfo 'thousands-sep) => ","

Or "localeinfo" or "localeconv" or something.

In my charting program I made a separate function for each of the few
bits I wanted,

	(locale-decimal-point) => "."
	(locale-d-fmt)         => "%d/%m/%y"

One cute thing about that is that the user can override to personal
preferences by `set!'ing in a new function, like having "%b" for the
month in the date format.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: localeconv.c --]
[-- Type: text/x-csrc, Size: 2416 bytes --]

#define _GNU_SOURCE  /* ask glibc for C99 lconv fields */

#include <locale.h>




SCM_DEFINE (scm_localeconv, "localeconv", 0, 0, 0,
            (),
	    "Return an ``lconv'' object representing current locale specific\n"
	    "information.")
#define FUNC_NAME s_scm_localtime
{
  SCM result;
  const struct lconv *l;

#define LCONV_STR(idx, field)                                   \
  SCM_VECTOR_SET (result, idx, scm_makfrom0str (l->field))

#define LCONV_INT(idx, field)                           \
  SCM_VECTOR_SET (result, idx, SCM_MAKINUM (l->field))

  /* group array ends with either 0 or CHAR_MAX */
#define LCONV_GRP(idx, field)                                           \
  do {                                                                  \
    SCM  vec;                                                           \
    int  n, i;                                                          \
    for (i = 0; l->field[i] != 0 && l->field[i] != CHAR_MAX; i++)       \
      ;                                                                 \
    n = i + 1;  /* number of elements */                                \
    vec = scm_c_make_vector (n, SCM_BOOL_F);                            \
    for (i = 0; i < n; i++)                                             \
      SCM_VECTOR_SET (result, idx, SCM_MAKINUM (l->field[i]));          \
    SCM_VECTOR_SET (result, idx, vec);                                  \
  } while (0)

  result = scm_c_make_vector (11, SCM_BOOL_F);

  SCM_DEFER_INTS;
  LCONV_STR ( 0, decimal_point);
  LCONV_STR ( 1, thousands_sep);
  LCONV_GRP ( 2, grouping);
  LCONV_STR ( 3, int_curr_symbol);
  LCONV_STR ( 4, currency_symbol);
  LCONV_STR ( 5, mon_decimal_point);
  LCONV_STR ( 6, mon_thousands_sep);
  LCONV_GRP ( 7, mon_grouping);
  LCONV_STR ( 8, positive_sign);
  LCONV_STR ( 9, negative_sign);
  LCONV_INT (10, int_frac_digits);
  LCONV_INT (11, frac_digits);
  LCONV_INT (12, p_cs_precedes);
  LCONV_INT (13, p_sep_by_space);
  LCONV_INT (14, n_cs_precedes);
  LCONV_INT (15, n_sep_by_space);
  LCONV_INT (16, p_sign_posn);
  LCONV_INT (17, n_sign_posn);

  /* C99 extras, apparently */
#if HAVE_LCONV_INT_P_CS_PRECEDES
  LCONV_INT (18, int_p_cs_precedes);
  LCONV_INT (19, int_p_sep_by_space);
  LCONV_INT (20, int_n_cs_precedes);
  LCONV_INT (21, int_n_sep_by_space);
  LCONV_INT (22, int_p_sign_posn);
  LCONV_INT (23, int_n_sign_posn);
#endif

  return result;
}

[-- Attachment #3: Type: text/plain, Size: 143 bytes --]

_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-05  0:20             ` Kevin Ryde
@ 2006-12-05 18:42               ` Carl Witty
  2006-12-05 20:41                 ` Kevin Ryde
  0 siblings, 1 reply; 46+ messages in thread
From: Carl Witty @ 2006-12-05 18:42 UTC (permalink / raw)
  Cc: Guile-Devel

On Tue, 2006-12-05 at 11:20 +1100, Kevin Ryde wrote:
> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
> > I don't clearly understand.  Could you provide more details for the
> > novice (perhaps in another thread)?  :-)
> 
> The note in the manual:
> 
> 	*Caution*: The current code in this module incorrectly extends
> 	the Gregorian calendar leap year rule back prior to the
> 	introduction of those reforms in 1582 (or the appropriate year
> 	in various countries).  The Julian calendar was used prior to
> 	1582, and there were 10 days skipped for the reform, but the
> 	code doesn't implement that.
> 
> So for instance the year 1500 should be a leap year, but isn't in the
> current code.  (If I've got that right off the top of my head ... :-)

If I understand correctly, this would make date->julian-day (for
instance) convert from Julian calendar dates before 1582 and Gregorian
calendar dates after 1582.  This is cute, but I don't think it's
particularly useful; the problem is that the Julian to Gregorian switch
lasted for hundreds of years around the world (and, indeed, some
churches still use the Julian calendar to determine religious dates), so
you can't tell if a date is Julian or Gregorian just by looking at the
year.  I would propose leaving the code the way it is now, and changing
the note to something like "Note: Dates in this module use the proleptic
Gregorian calendar, which means that it extends the Gregorian calendar
leap year rule back prior to the introduction of these reforms in 1582."
(See http://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar for more
information on the proleptic Gregorian calendar.)

If people need to use Julian dates, then there should be a separate
julian-date type with separate converters.

Carl Witty




_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-05 18:42               ` Carl Witty
@ 2006-12-05 20:41                 ` Kevin Ryde
  2006-12-05 22:29                   ` Carl Witty
  0 siblings, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-12-05 20:41 UTC (permalink / raw)
  Cc: Guile-Devel

Carl Witty <cwitty@newtonlabs.com> writes:
>
> If I understand correctly, this would make date->julian-day (for
> instance) convert from Julian calendar dates before 1582 and Gregorian
> calendar dates after 1582.

Yes.

> This is cute, but I don't think it's particularly useful;

Apart from being what people actually used then!

> the problem is that the Julian to Gregorian switch
> lasted for hundreds of years around the world (and, indeed, some
> churches still use the Julian calendar to determine religious dates), so
> you can't tell if a date is Julian or Gregorian just by looking at the
> year.

Yes, the switch happened at different times, but if you're calling it
gregorian then it makes some sense to go with the date pope gregory
signed off on :).  It could get some localization perhaps, though that
sounds like hard work.  I think the gnu "cal" program does that.

> I would propose leaving the code the way it is now, and changing
> the note to something like "Note: Dates in this module use the proleptic
> Gregorian calendar,

If the srfi author wanted to clarify that then it'd be ok, otherwise
surely a calendar with at least some sort of historical basis is more
use.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-05 20:41                 ` Kevin Ryde
@ 2006-12-05 22:29                   ` Carl Witty
  0 siblings, 0 replies; 46+ messages in thread
From: Carl Witty @ 2006-12-05 22:29 UTC (permalink / raw)
  Cc: Guile-Devel

On Wed, 2006-12-06 at 07:41 +1100, Kevin Ryde wrote:
> Carl Witty <cwitty@newtonlabs.com> writes:
> >
> > If I understand correctly, this would make date->julian-day (for
> > instance) convert from Julian calendar dates before 1582 and Gregorian
> > calendar dates after 1582.
> 
> Yes.
> 
> > This is cute, but I don't think it's particularly useful;
> 
> Apart from being what people actually used then!
> 
> > the problem is that the Julian to Gregorian switch
> > lasted for hundreds of years around the world (and, indeed, some
> > churches still use the Julian calendar to determine religious dates), so
> > you can't tell if a date is Julian or Gregorian just by looking at the
> > year.
> 
> Yes, the switch happened at different times, but if you're calling it
> gregorian then it makes some sense to go with the date pope gregory
> signed off on :).  It could get some localization perhaps, though that
> sounds like hard work.  I think the gnu "cal" program does that.

I believe that virtually any program that needs to do date computations
on historical dates will need more support than SRFI-19 provides, no
matter what meaning we assign to "date"s with years before 1582.  If you
consider the small set of Guile users who need to do date computation
for historical dates, and the even smaller set for which "before 1582 is
Julian, after 1582 is Gregorian" is exactly the date semantics they
want, I think it is quite possible that this smaller set is empty: that
nobody would ever correctly use the SRFI-19 "date" type for historical
dates.  (My totally-made-up estimate is that the likelihood of wanting a
split in October 1582  is about the same as the likelihood of wanting
the proleptic Gregorian calendar, which is at least used for ISO 8601;
and that both of these are far more likely than wanting a split which is
automatically computed based on the locale of the user running the
program.)

If it is indeed true that nobody would ever correctly use a
split-at-1582 date type, then the decision should be made on the basis
of the difficulty of implementing, testing, and documenting.  It seems
like implementing and testing the proleptic Gregorian calendar is far
easier than the split-at-1582 calendar, and the difficulty of
documenting either is about even.

> > I would propose leaving the code the way it is now, and changing
> > the note to something like "Note: Dates in this module use the proleptic
> > Gregorian calendar,
> 
> If the srfi author wanted to clarify that then it'd be ok, otherwise
> surely a calendar with at least some sort of historical basis is more
> use.

I note that the SRFI does say "A date is a representation of a point in
time in the Gregorian calendar..."

Carl Witty




_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-11-29 23:08     ` Kevin Ryde
  2006-11-30 15:19       ` Ludovic Courtès
  2006-12-02 22:02       ` Kevin Ryde
@ 2006-12-10 12:30       ` Ludovic Courtès
  2006-12-11 22:32         ` Kevin Ryde
  2 siblings, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-12-10 12:30 UTC (permalink / raw)


Hi,

Just a few notes about your remarks regarding `(ice-9 i18n)'.  A patch
will follow soon.

Kevin Ryde <user42@zip.com.au> writes:

>> +@node The ice-9 i18n Module
>
> See if you can think of a better section name.

Actually, since we're not going to include this module in 1.8, I think
I'd be in favor of moving the `gettext'-related functions in `(ice-9
i18n)'.  Then the doc would have to be rearranged accordingly.

>> +@deffn {Scheme Procedure} string-locale<? s1 s2 [locale]
>> +@deffn {Scheme Procedure} string-locale>? s1 s2 [locale]
>> +@deffn {Scheme Procedure} string-locale-ci<? s1 s2 [locale]
>> +@deffn {Scheme Procedure} string-locale-ci>? s1 s2 [locale]
>> +@deffn {Scheme Procedure} string-locale-ci=? s1 s2 [locale]
>
> These could be described in one block I think, to avoid five very
> similar descriptions.  Likewise the char ones.

Yes, done.

>> +...  Note that SRFI-13 provides procedures that
>> +look similar (@pxref{Alphabetic Case Mapping}).  However, the SRFI-13
>> +procedures are locale-independent.
>
> That's the intention of the srfi I guess, but it's not true currently
> is it?  Don't they use toupper() and therefore get whatever nonsense
> the current setlocale() gives.  Perhaps better leave the description
> of srfi-13 to that section.

Perhaps, but this is undocumented behavior.  :-)

> Do you need a caveat about multibyte characters there, for now?  Like
> "Note that in the current implementation Guile has no notion of
> multibyte characters and in a multibyte locale characters may not be
> converted correctly."

Yes.

>> +@deffn {Scheme Procedure} locale-string->integer str [base [locale]]
>> +@deffn {Scheme Procedure} locale-string->inexact str [locale]
>
> I think you should cross-reference strtol and strtod here, since their
> parsing is rather idiosyncratic.  I'd even be a bit tempted to name
> them strtol and strtod in guile, to make it clear they're only one
> possible way of parsing.  Except those names aren't very nice ...

I added a cross-ref to glibc's `strto{dl}', but I'm not willing to
change the names to the C library names (I'm not sure that's what you
were suggesting though).

>> +...  Return two values:
>
> Consider @pxref{Multiple Values}, since multi-values are (thankfully)
> fairly rare.

Yes, done.

>> -    scmconfig.h.top gettext.h
>> +    scmconfig.h.top libgettext.h
>
> I don't think that's good.  Best leave gettext.h the gettext one, and
> use another name for guile.  Gettext got there first, and it doesn't
> really matter which guile header has which prototypes.

The former `i18n.c' (which contained only `gettext'-related code) was
renamed to `gettext.c' which seems more appropriate.  Thus, for
consistency, the corresponding header file had to be renamed from
`i18n.h' to `gettext.h'.  Since `gettext.h' was already used for the one
coming from Gettext, it had to be renamed.  `libgettext.h' doesn't seem
such a bad name to me.

>> +/* This mutex is used to serialize invocations of `setlocale ()' on non-GNU
>> +   systems (i.e., systems where a reentrant locale API is not available).
>> +   See `i18n.c' for details.  */
>> +scm_i_pthread_mutex_t scm_i_locale_mutex;
>
> There's an scm_i_misc_mutex for use when protection is (or should be)
> rarely needed.

It seems more robust to use a dedicated mutex.

>> +/* Provide the locale category masks as found in glibc (copied from
>> +   <locale.h> as found in glibc 2.3.6).  This must be kept in sync with
>> +   `locale-categories.h'.  */
>> +# define LC_CTYPE_MASK		(1 << LC_CTYPE)
>> +# define LC_COLLATE_MASK	(1 << LC_COLLATE)
>> +# define LC_MESSAGES_MASK	(1 << LC_MESSAGES)
>> +# define LC_MONETARY_MASK	(1 << LC_MONETARY)
>> +# define LC_NUMERIC_MASK	(1 << LC_NUMERIC)
>> +# define LC_TIME_MASK		(1 << LC_TIME)
>
> I think you should put some privately selected bits there, not depend
> on LC_CTYPE etc being in range 0 to 31.

Good point, done.

>> +/* Alias for glibc's locale type.  */
>> +typedef locale_t scm_t_locale;
>
> I suppose the emulation could provide locale_t.  Might make it hard to
> exercise on an actual gnu system.  A #define locale_t would likely be
> ok.

It seems safer to make changes only in the `scm_' name space.  As a
matter of fact, I just discovered that Darwin now implements the
`locale_t' "GNU" API (I suppose that change is quite recent):

  http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/newlocale.3.html

Thus, defining `locale_t', `newlocale', et al. internally would have
been a potential source of problems when building on that platform.

>> +#ifdef USE_GNU_LOCALE_API
>> +  freelocale ((locale_t)c_locale);
>> +#else
>> +  c_locale->base_locale = SCM_UNDEFINED;
>> +  free (c_locale->locale_name);
>> +  scm_gc_free (c_locale, sizeof (* c_locale), "locale");
>> +#endif
>
> A possibility there, and with other funcs, would be to implement a
> compatible freelocale(), instead of sticking conditionals in each
> usage.

(See above).

>> +#ifdef USE_GNU_LOCALE_API
>> +
>> +  c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale);
>> +  if (!c_locale)
>> +    locale = SCM_BOOL_F;
>
> Your docs call for an exception on unknown locale don't they?

Indeed, fixed.

> And should you tell the gc something about the size of a locale_t, and
> perhaps extra for its underlying data?  To approximate memory used,
> for the gc triggers.

Yes, but `locale_t' is typically a pointer type, and the size of the
struct pointed to by `locale_t' could be opaque (although that is
currently not the case with glibc).  So we could provide a guess for the
underlying object size, but maybe we can also just safely ignore it?

>> +void
>> +scm_init_i18n ()
>> +{
>> +  scm_add_feature ("ice-9-i18n");
>
> Is there any point adding a feature after the module is loaded? :)

Indeed, removed.  :-)

>> +(define (under-french-locale-or-unresolved thunk)
>> +  ;; On non-GNU systems, an exception may be raised only when the locale is
>> +  ;; actually used rather than at `make-locale'-time.  Thus, we must guard
>> +  ;; against both.
>> +  (if %french-locale
>> +      (catch 'system-error thunk
>> +             (lambda (key . args)
>> +               (throw 'unresolved)))
>> +      (throw 'unresolved)))
>
> Do you mean 'unsupported rather than 'unresolved, when fr_FR isn't
> available from the system?

I really meant "unresolved", in the sense that the test cannot be run
when `fr_FR' isn't available.

>> +(with-test-prefix "number parsing"
>
> Some french number parsing too?  Just to show there's a point to
> locale dependent parsing :).

Done.

Thanks for your detailed review!

Ludovic.



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-10 12:30       ` Ludovic Courtès
@ 2006-12-11 22:32         ` Kevin Ryde
  2006-12-12  8:38           ` Ludovic Courtès
  0 siblings, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-12-11 22:32 UTC (permalink / raw)
  Cc: guile-devel

ludo@chbouib.org (Ludovic Courtès) writes:
>
> I'd be in favor of moving the `gettext'-related functions in `(ice-9
> i18n)'.

They'll be used by the core to translate various core messages at some
stage, that's why they're there.

[srfi-13]
> Perhaps, but this is undocumented behavior.  :-)

Keep to a minimum what you say about a function in a separate part of
the manual.

> strto{dl}

The reason those funcs are hardly used is that they're not very good.
Traditionally strtol had no overflow checking, and even now c99
doesn't guarantee localized forms for either.  Also strtod may or may
not have the helpful "p" format, and its rounding isn't guaranteed
(only "recommended practice").

There's no particular virtue in the C library.  If you want to hook
onto it then name functions accordingly, so everyone knows what to
expect.  If you want better semantics, hopefully more scheme-like,
then use names reflecting that betterness.

> The former `i18n.c' (which contained only `gettext'-related code) was
> renamed to `gettext.c' which seems more appropriate.

Please try to resist the temptation to make non-changes.

> It seems more robust to use a dedicated mutex.

If you say you're concerned about speed of startup and size of
modules :-), then you don't want to create a new mutex.  The common one
is specifically there for miscellaneous uses.

> I really meant "unresolved", in the sense that the test cannot be run
> when `fr_FR' isn't available.

"unresolved" is for bugs not yet addressed, or long-standing
misfeatures not easily fixed.  I'm pretty sure "unsupported" is
intended for things not available on account of the system
environment.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-11 22:32         ` Kevin Ryde
@ 2006-12-12  8:38           ` Ludovic Courtès
  2006-12-12 20:04             ` Kevin Ryde
  2006-12-15 20:52             ` Kevin Ryde
  0 siblings, 2 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-12-12  8:38 UTC (permalink / raw)


Hi,

Kevin Ryde <user42@zip.com.au> writes:

>> strto{dl}
>
> The reason those funcs are hardly used is that they're not very good.
> Traditionally strtol had no overflow checking, and even now c99
> doesn't guarantee localized forms for either.  Also strtod may or may
> not have the helpful "p" format, and its rounding isn't guaranteed
> (only "recommended practice").

Ok, I wasn't aware of this.

> There's no particular virtue in the C library.  If you want to hook
> onto it then name functions accordingly, so everyone knows what to
> expect.  If you want better semantics, hopefully more scheme-like,
> then use names reflecting that betterness.

That makes sense, but OTOH, we want to avoid silly names I guess.  ;-)

So, do you think we should rename them to `strto{d,l}' or documenting
this dependence is enough?

>> The former `i18n.c' (which contained only `gettext'-related code) was
>> renamed to `gettext.c' which seems more appropriate.
>
> Please try to resist the temptation to make non-changes.

I couldn't think of any other option that would retain consistency.

> If you say you're concerned about speed of startup and size of
> modules :-), then you don't want to create a new mutex.  The common one
> is specifically there for miscellaneous uses.

The mutex is statically initialized, how can it impact startup time?

More importantly: what's the semantics of a "misc" mutex?  Suppose
function `foo' invokes `bar', which in turn invokes `string-locale<?'.
What if both `foo' and `string-locale<?' turn out to lock the "misc"
mutex upon entry?

>> I really meant "unresolved", in the sense that the test cannot be run
>> when `fr_FR' isn't available.
>
> "unresolved" is for bugs not yet addressed, or long-standing
> misfeatures not easily fixed.  I'm pretty sure "unsupported" is
> intended for things not available on account of the system
> environment.

Hmm, I thought `unresolved' was for cases where a test cannot be run for
some reason.  See, e.g., `guardians.test', `socket.test'.  OTOH,
`unsupported' seems to be used when a feature cannot be tested because
it wasn't compiled in (e.g., `alist.test').  Well, there's admittedly
not a huge difference.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-22 18:33   ` Ludovic Courtès
                       ` (2 preceding siblings ...)
  2006-11-29 23:08     ` Kevin Ryde
@ 2006-12-12 19:05     ` Kevin Ryde
  2006-12-13  9:14       ` Ludovic Courtès
  2006-12-12 19:16     ` Kevin Ryde
  2006-12-12 21:37     ` Kevin Ryde
  5 siblings, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-12-12 19:05 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> +++ mod/libguile/posix.c
>...  
> +#ifndef USE_GNU_LOCALE_API
> +  scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
> +#endif
>    rv = setlocale (scm_i_to_lc_category (category, 1), clocale);
> +#ifndef USE_GNU_LOCALE_API
> +  scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
> +#endif

Looks like a mutex leak here if scm_i_to_lc_category throws an error.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-22 18:33   ` Ludovic Courtès
                       ` (3 preceding siblings ...)
  2006-12-12 19:05     ` Kevin Ryde
@ 2006-12-12 19:16     ` Kevin Ryde
  2006-12-13  9:20       ` Ludovic Courtès
  2006-12-12 21:37     ` Kevin Ryde
  5 siblings, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-12-12 19:16 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> +@defvar LC_ALL_MASK
> +This represents all the locale categories supported by the system.

How about having make-locale take the existing LC_MESSAGES etc.  I'm
thinking either a single LC value, or a list of them for multiple
categories.

I'm pretty sure there's no need for a second parallel set of values,
and that it's a good chance of being confusing.  Someone's bound to
write

	(make-locale LC_ALL ...

and wonder why it doesn't work (and doesn't give an error either).


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-12  8:38           ` Ludovic Courtès
@ 2006-12-12 20:04             ` Kevin Ryde
  2006-12-13  9:41               ` Ludovic Courtès
  2006-12-31 17:10               ` Neil Jerram
  2006-12-15 20:52             ` Kevin Ryde
  1 sibling, 2 replies; 46+ messages in thread
From: Kevin Ryde @ 2006-12-12 20:04 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> So, do you think we should rename them to `strto{d,l}' or documenting
> this dependence is enough?

Number parsing on the whole always seems very application-specific to
me.  I don't think I've ever seen a style that could recommended
whole-heartedly for all user input :-(.

I'd think about something modest like a string->number that stripped
thousands seps and transformed the decimal point (if necessary).  I
think that'd find a use.

> Hmm, I thought `unresolved' was for cases where a test cannot be run for
> some reason.  See, e.g., `guardians.test',

Not sure about those, were they actually unresolved issues for a time?

> `socket.test'

Hang on, that's your work isn't it! :)

> Well, there's admittedly not a huge difference.

Yes, though hopefully the difference is that "unsupported" bits can be
safely ignored, assuming you know those features are not supposed to
be available.  But the author of this stuff must be lurking here ...


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-10-22 18:33   ` Ludovic Courtès
                       ` (4 preceding siblings ...)
  2006-12-12 19:16     ` Kevin Ryde
@ 2006-12-12 21:37     ` Kevin Ryde
  2006-12-13  9:28       ` Ludovic Courtès
  5 siblings, 1 reply; 46+ messages in thread
From: Kevin Ryde @ 2006-12-12 21:37 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> +/* Throw an exception corresponding to error ERR.  */
> +static void inline
> +scm_locale_error (const char *func_name, int err)
> +{
> +  SCM s_err;
> +
> +  s_err = scm_from_int (err);
> +  scm_error (scm_system_error_key, func_name,
> +	     "Failed to install locale",
> +	     scm_cons (scm_strerror (s_err), SCM_EOL),
> +	     scm_cons (s_err, SCM_EOL));
> +}

This doesn't display,

    <unnamed port>:3:1: In procedure string-locale<? in expression (string-locale<?
    "x" "y" ...):
    <unnamed port>:3:1: Failed to install locale
    Exception during displaying of error: misc-error
    ABORT: (system-error)

It'd be good if it was a standard SCM_SYSERROR and was detected on
creating a locale.

Incidentally, in the fallback code there seems to be something fishy
after a failed install.  If you try to use the offending locale object
a second time it succeeds.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-12 19:05     ` Kevin Ryde
@ 2006-12-13  9:14       ` Ludovic Courtès
  0 siblings, 0 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-12-13  9:14 UTC (permalink / raw)


Hi,

Kevin Ryde <user42@zip.com.au> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>>
>> +++ mod/libguile/posix.c
>>...  
>> +#ifndef USE_GNU_LOCALE_API
>> +  scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
>> +#endif
>>    rv = setlocale (scm_i_to_lc_category (category, 1), clocale);
>> +#ifndef USE_GNU_LOCALE_API
>> +  scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
>> +#endif
>
> Looks like a mutex leak here if scm_i_to_lc_category throws an error.

Indeed!  I'll fix it in a while.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-12 19:16     ` Kevin Ryde
@ 2006-12-13  9:20       ` Ludovic Courtès
  0 siblings, 0 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-12-13  9:20 UTC (permalink / raw)


Hi,

Kevin Ryde <user42@zip.com.au> writes:

> How about having make-locale take the existing LC_MESSAGES etc.  I'm
> thinking either a single LC value, or a list of them for multiple
> categories.

I considered this option at some point but then thought lists were a too
high-level construct.  ;-)

Seriously, one could argue that lists are more "expensive" (to store and
process), but that's not big deal anyway since the list is likely to
contain only a couple of values.

So I'll make this change.

Thanks!

Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-12 21:37     ` Kevin Ryde
@ 2006-12-13  9:28       ` Ludovic Courtès
  2006-12-13 20:10         ` Kevin Ryde
  0 siblings, 1 reply; 46+ messages in thread
From: Ludovic Courtès @ 2006-12-13  9:28 UTC (permalink / raw)


Kevin Ryde <user42@zip.com.au> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>>
>> +/* Throw an exception corresponding to error ERR.  */
>> +static void inline
>> +scm_locale_error (const char *func_name, int err)
>> +{
>> +  SCM s_err;
>> +
>> +  s_err = scm_from_int (err);
>> +  scm_error (scm_system_error_key, func_name,
>> +	     "Failed to install locale",
>> +	     scm_cons (scm_strerror (s_err), SCM_EOL),
>> +	     scm_cons (s_err, SCM_EOL));
>> +}
>
> This doesn't display,
>
>     <unnamed port>:3:1: In procedure string-locale<? in expression (string-locale<?
>     "x" "y" ...):
>     <unnamed port>:3:1: Failed to install locale
>     Exception during displaying of error: misc-error
>     ABORT: (system-error)

That's on a system where `USE_GNU_LOCALE_API' is not defined, right?

> It'd be good if it was a standard SCM_SYSERROR and was detected on
> creating a locale.

It's not an `SCM_SYSERROR' because the error code is provided by
variable ERR, not by ERRNO.  That said, it could use `SCM_SYSERROR_MSG'.

In order to detect locale unavailability upon locale create on non-GNU
systems, it would have to try to actually install the locale first.  I
guess we can do it, although that adds a bit of overhead.

> Incidentally, in the fallback code there seems to be something fishy
> after a failed install.  If you try to use the offending locale object
> a second time it succeeds.

Hmm, weird.  Is the locale in question available on your system?  I'll
give it a try.

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-12 20:04             ` Kevin Ryde
@ 2006-12-13  9:41               ` Ludovic Courtès
  2006-12-31 17:10               ` Neil Jerram
  1 sibling, 0 replies; 46+ messages in thread
From: Ludovic Courtès @ 2006-12-13  9:41 UTC (permalink / raw)


Kevin Ryde <user42@zip.com.au> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>>
>> So, do you think we should rename them to `strto{d,l}' or documenting
>> this dependence is enough?
>
> Number parsing on the whole always seems very application-specific to
> me.  I don't think I've ever seen a style that could recommended
> whole-heartedly for all user input :-(.

Right.

> I'd think about something modest like a string->number that stripped
> thousands seps and transformed the decimal point (if necessary).  I
> think that'd find a use.

Sure.

>> Hmm, I thought `unresolved' was for cases where a test cannot be run for
>> some reason.  See, e.g., `guardians.test',
>
> Not sure about those, were they actually unresolved issues for a time?

The idea (I think) is that, for instance, when SEEN-G3-GARBAGE is false,
you can't decide if that's because the guardian code is actually buggy
or if that's because the GC is somehow rightfully retaining G3.  IOW,
you can't decide whether the test case passes or not, so you throw
`unresolved'.

>> `socket.test'
>
> Hang on, that's your work isn't it! :)

Oh, right.  :-)

Thanks,
Ludo'.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-13  9:28       ` Ludovic Courtès
@ 2006-12-13 20:10         ` Kevin Ryde
  0 siblings, 0 replies; 46+ messages in thread
From: Kevin Ryde @ 2006-12-13 20:10 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> That's on a system where `USE_GNU_LOCALE_API' is not defined, right?

Yes, faked out.

> In order to detect locale unavailability upon locale create on non-GNU
> systems, it would have to try to actually install the locale first.  I
> guess we can do it, although that adds a bit of overhead.

Worth doing, to make the fallback work like the real thing.

> Hmm, weird.  Is the locale in question available on your system?

No, a bogus name deliberately trying to provoke.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-12  8:38           ` Ludovic Courtès
  2006-12-12 20:04             ` Kevin Ryde
@ 2006-12-15 20:52             ` Kevin Ryde
  1 sibling, 0 replies; 46+ messages in thread
From: Kevin Ryde @ 2006-12-15 20:52 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> mutex

If you want to think about mutexes, the timezone swapping in stime.c
could stand some attention.  When changing the "environ" global
variable it uses the old SCM_CRITICAL_SECTION_START business, which is
a secret mutex.  It, and probably your locale bits, should expose
something so C code (including wrappers around external libraries) can
lock down afflicted bits when necessary.

There's no need for a separate mutex for each thing.  When an
operation like time conversion or locale query is fast then no
important parallelism is lost by sharing.  And if you've got multiple
mutexes that might be acquired all at once then you have to think
about the sequence to do that in, otherwise there's risk of a deadly
embrace.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Text collation
  2006-12-12 20:04             ` Kevin Ryde
  2006-12-13  9:41               ` Ludovic Courtès
@ 2006-12-31 17:10               ` Neil Jerram
  1 sibling, 0 replies; 46+ messages in thread
From: Neil Jerram @ 2006-12-31 17:10 UTC (permalink / raw)


Kevin Ryde <user42@zip.com.au> writes:

> Yes, though hopefully the difference is that "unsupported" bits can be
> safely ignored, assuming you know those features are not supposed to
> be available.  But the author of this stuff must be lurking here ...

That would be Jim Blandy.  He might be lurking, but I think it's
unlikely, as he hasn't posted anything for ages.

Regards,
     Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2006-12-31 17:10 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-19  9:23 Text collation Ludovic Courtès
2006-09-19 22:38 ` Kevin Ryde
2006-10-22 18:33   ` Ludovic Courtès
2006-10-23  2:01     ` Rob Browning
2006-10-23  7:56       ` Ludovic Courtès
2006-10-24  8:37         ` Rob Browning
2006-10-25  8:16           ` Ludovic Courtès
2006-10-25  8:46             ` Rob Browning
2006-10-25 18:40               ` Neil Jerram
2006-10-25 19:55                 ` Rob Browning
2006-10-26  8:47                 ` Ludovic Courtès
2006-11-09  7:44                   ` Ludovic Courtès
2006-11-09 17:43                     ` Rob Browning
2006-11-10 13:39                       ` Ludovic Courtès
2006-11-11 15:17                         ` Neil Jerram
2006-11-20 13:24                         ` Ludovic Courtès
2006-11-21 22:03                           ` Neil Jerram
2006-11-22 13:38                             ` Ludovic Courtès
2006-10-25 18:43           ` Neil Jerram
2006-10-25 19:31             ` Rob Browning
2006-10-25 18:33     ` Neil Jerram
2006-10-26  8:39       ` Ludovic Courtès
2006-11-29 23:08     ` Kevin Ryde
2006-11-30 15:19       ` Ludovic Courtès
2006-12-02 21:56         ` Kevin Ryde
2006-12-04  9:01           ` Ludovic Courtès
2006-12-05  0:20             ` Kevin Ryde
2006-12-05 18:42               ` Carl Witty
2006-12-05 20:41                 ` Kevin Ryde
2006-12-05 22:29                   ` Carl Witty
2006-12-05  0:38         ` Kevin Ryde
2006-12-02 22:02       ` Kevin Ryde
2006-12-10 12:30       ` Ludovic Courtès
2006-12-11 22:32         ` Kevin Ryde
2006-12-12  8:38           ` Ludovic Courtès
2006-12-12 20:04             ` Kevin Ryde
2006-12-13  9:41               ` Ludovic Courtès
2006-12-31 17:10               ` Neil Jerram
2006-12-15 20:52             ` Kevin Ryde
2006-12-12 19:05     ` Kevin Ryde
2006-12-13  9:14       ` Ludovic Courtès
2006-12-12 19:16     ` Kevin Ryde
2006-12-13  9:20       ` Ludovic Courtès
2006-12-12 21:37     ` Kevin Ryde
2006-12-13  9:28       ` Ludovic Courtès
2006-12-13 20:10         ` Kevin Ryde

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).