1 /* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include "libguile/_scm.h"
26 #include "libguile/extensions.h"
27 #include "libguile/feature.h"
28 #include "libguile/i18n.h"
29 #include "libguile/strings.h"
30 #include "libguile/chars.h"
31 #include "libguile/dynwind.h"
32 #include "libguile/validate.h"
33 #include "libguile/values.h"
34 #include "libguile/threads.h"
37 #include <string.h> /* `strcoll ()' */
38 #include <ctype.h> /* `toupper ()' et al. */
43 #if (defined HAVE_NEWLOCALE) && (defined HAVE_STRCOLL_L)
44 /* The GNU thread-aware locale API is documented in ``Thread-Aware Locale
45 Model, a Proposal'', by Ulrich Drepper:
47 http://people.redhat.com/drepper/tllocale.ps.gz
49 It is now also implemented by Darwin:
51 http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/newlocale.3.html
53 The whole API was eventually standardized in the ``Open Group Base
54 Specifications Issue 7'' (aka. "POSIX 2008"):
56 http://www.opengroup.org/onlinepubs/9699919799/basedefs/locale.h.html */
57 # define USE_GNU_LOCALE_API
60 #include "libguile/posix.h" /* for `scm_i_locale_mutex' */
62 /* Use Gnulib's header, which also provides `nl_item' & co. */
65 #ifndef HAVE_SETLOCALE
67 setlocale (int category
, const char *name
)
74 /* Helper stringification macro. */
75 #define SCM_I18N_STRINGIFY(_name) # _name
77 /* Acquiring and releasing the locale lock. */
80 lock_locale_mutex (void)
83 scm_i_pthread_mutex_lock (&scm_i_locale_mutex
);
89 unlock_locale_mutex (void)
92 scm_i_pthread_mutex_unlock (&scm_i_locale_mutex
);
98 /* Locale objects, string and character collation, and other locale-dependent
101 A large part of the code here deals with emulating glibc's reentrant
102 locale API on non-GNU systems. The emulation is a bit "brute-force":
103 Whenever a `-locale<?' procedure is passed a locale object, then:
105 1. The `scm_i_locale_mutex' is locked.
106 2. A series of `setlocale ()' call is performed to store the current
107 locale for each category in an `scm_t_locale' object.
108 3. A series of `setlocale ()' call is made to install each of the locale
109 categories of each of the base locales of each locale object,
110 recursively, starting from the last locale object of the chain.
111 4. The settings captured in step (2) are restored.
112 5. The `scm_i_locale_mutex' is released.
114 Hopefully, the X/Open standard will eventually make this hack useless.
116 Note: We don't wrap glibc's `uselocale ()' call because it sets the locale
117 of the current _thread_ (unlike `setlocale ()') and doing so would require
118 maintaining per-thread locale information on non-GNU systems and always
119 re-installing this locale upon locale-dependent calls. */
122 /* Return the category mask corresponding to CAT. */
123 #define SCM_LOCALE_CATEGORY_MASK(_cat) LC_ ## _cat ## _MASK
126 #ifndef USE_GNU_LOCALE_API
128 /* Provide the locale category masks as found in glibc. This must be kept in
129 sync with `locale-categories.h'. */
131 # define LC_CTYPE_MASK 1
132 # define LC_COLLATE_MASK 2
133 # define LC_MESSAGES_MASK 4
134 # define LC_MONETARY_MASK 8
135 # define LC_NUMERIC_MASK 16
136 # define LC_TIME_MASK 32
139 # define LC_PAPER_MASK 64
141 # define LC_PAPER_MASK 0
144 # define LC_NAME_MASK 128
146 # define LC_NAME_MASK 0
149 # define LC_ADDRESS_MASK 256
151 # define LC_ADDRESS_MASK 0
154 # define LC_TELEPHONE_MASK 512
156 # define LC_TELEPHONE_MASK 0
158 # ifdef LC_MEASUREMENT
159 # define LC_MEASUREMENT_MASK 1024
161 # define LC_MEASUREMENT_MASK 0
163 # ifdef LC_IDENTIFICATION
164 # define LC_IDENTIFICATION_MASK 2048
166 # define LC_IDENTIFICATION_MASK 0
169 # define LC_ALL_MASK (LC_CTYPE_MASK \
178 | LC_TELEPHONE_MASK \
179 | LC_MEASUREMENT_MASK \
180 | LC_IDENTIFICATION_MASK \
183 /* Locale objects as returned by `make-locale' on non-GNU systems. */
184 typedef struct scm_locale
186 SCM base_locale
; /* a `locale' object */
191 #else /* USE_GNU_LOCALE_API */
193 /* Alias for glibc's locale type. */
194 typedef locale_t scm_t_locale
;
196 #endif /* USE_GNU_LOCALE_API */
199 /* A locale object denoting the global locale. */
200 SCM_GLOBAL_VARIABLE (scm_global_locale
, "%global-locale");
203 /* Validate parameter ARG as a locale object and set C_LOCALE to the
204 corresponding C locale object. */
205 #define SCM_VALIDATE_LOCALE_COPY(_pos, _arg, _c_locale) \
208 SCM_VALIDATE_SMOB ((_pos), (_arg), locale_smob_type); \
209 (_c_locale) = (scm_t_locale)SCM_SMOB_DATA (_arg); \
213 /* Validate optional parameter ARG as either undefined or bound to a locale
214 object. Set C_LOCALE to the corresponding C locale object or NULL. */
215 #define SCM_VALIDATE_OPTIONAL_LOCALE_COPY(_pos, _arg, _c_locale) \
218 if (!SCM_UNBNDP (_arg)) \
219 SCM_VALIDATE_LOCALE_COPY (_pos, _arg, _c_locale); \
221 (_c_locale) = NULL; \
226 SCM_SMOB (scm_tc16_locale_smob_type
, "locale", 0);
228 #ifdef USE_GNU_LOCALE_API
230 SCM_SMOB_FREE (scm_tc16_locale_smob_type
, smob_locale_free
, locale
)
232 scm_t_locale c_locale
;
234 c_locale
= (scm_t_locale
) SCM_SMOB_DATA (locale
);
235 freelocale (c_locale
);
240 #endif /* USE_GNU_LOCALE_API */
243 static void inline scm_locale_error (const char *, int) SCM_NORETURN
;
245 /* Throw an exception corresponding to error ERR. */
247 scm_locale_error (const char *func_name
, int err
)
249 scm_syserror_msg (func_name
,
250 "Failed to install locale",
256 /* Emulating GNU's reentrant locale API. */
257 #ifndef USE_GNU_LOCALE_API
260 /* Maximum number of chained locales (via `base_locale'). */
261 #define LOCALE_STACK_SIZE_MAX 256
265 #define SCM_DEFINE_LOCALE_CATEGORY(_name) char * _name;
266 #include "locale-categories.h"
267 #undef SCM_DEFINE_LOCALE_CATEGORY
268 } scm_t_locale_settings
;
270 /* Fill out SETTINGS according to the current locale settings. On success
271 zero is returned and SETTINGS is properly initialized. */
273 get_current_locale_settings (scm_t_locale_settings
*settings
)
275 const char *locale_name
;
277 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
279 SCM_SYSCALL (locale_name = setlocale (LC_ ## _name, NULL)); \
280 if (locale_name == NULL) \
283 settings-> _name = strdup (locale_name); \
284 if (settings-> _name == NULL) \
288 #include "locale-categories.h"
289 #undef SCM_DEFINE_LOCALE_CATEGORY
300 /* Restore locale settings SETTINGS. On success, return zero. */
302 restore_locale_settings (const scm_t_locale_settings
*settings
)
306 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
307 SCM_SYSCALL (result = setlocale (LC_ ## _name, settings-> _name)); \
308 if (result == NULL) \
311 #include "locale-categories.h"
312 #undef SCM_DEFINE_LOCALE_CATEGORY
320 /* Free memory associated with SETTINGS. */
322 free_locale_settings (scm_t_locale_settings
*settings
)
324 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
325 free (settings-> _name); \
326 settings->_name = NULL;
327 #include "locale-categories.h"
328 #undef SCM_DEFINE_LOCALE_CATEGORY
331 /* Install the locale named LOCALE_NAME for all the categories listed in
334 install_locale_categories (const char *locale_name
, int category_mask
)
338 if (category_mask
== LC_ALL_MASK
)
340 SCM_SYSCALL (result
= setlocale (LC_ALL
, locale_name
));
346 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
347 if (category_mask & SCM_LOCALE_CATEGORY_MASK (_name)) \
349 SCM_SYSCALL (result = setlocale (LC_ ## _name, locale_name)); \
350 if (result == NULL) \
353 #include "locale-categories.h"
354 #undef SCM_DEFINE_LOCALE_CATEGORY
363 /* Install LOCALE, recursively installing its base locales first. On
364 success, zero is returned. */
366 install_locale (scm_t_locale locale
)
368 scm_t_locale stack
[LOCALE_STACK_SIZE_MAX
];
369 int category_mask
= 0;
370 size_t stack_size
= 0;
371 int stack_offset
= 0;
372 const char *result
= NULL
;
374 /* Build up a locale stack by traversing the `base_locale' link. */
377 if (stack_size
>= LOCALE_STACK_SIZE_MAX
)
378 /* We cannot use `scm_error ()' here because otherwise the locale
379 mutex may remain locked. */
382 stack
[stack_size
++] = locale
;
384 /* Keep track of which categories have already been taken into
386 category_mask
|= locale
->category_mask
;
388 if (!SCM_UNBNDP (locale
->base_locale
))
389 locale
= (scm_t_locale
) SCM_SMOB_DATA (locale
->base_locale
);
393 while ((locale
!= NULL
) && (category_mask
!= LC_ALL_MASK
));
395 /* Install the C locale to start from a pristine state. */
396 SCM_SYSCALL (result
= setlocale (LC_ALL
, "C"));
400 /* Install the locales in reverse order. */
401 for (stack_offset
= stack_size
- 1;
408 locale
= stack
[stack_offset
];
409 err
= install_locale_categories (locale
->locale_name
,
410 locale
->category_mask
);
421 /* Leave the locked locale section. */
423 leave_locale_section (const scm_t_locale_settings
*settings
)
425 /* Restore the previous locale settings. */
426 (void)restore_locale_settings (settings
);
428 unlock_locale_mutex ();
431 /* Enter a locked locale section. */
433 enter_locale_section (scm_t_locale locale
,
434 scm_t_locale_settings
*prev_locale
)
438 lock_locale_mutex ();
440 err
= get_current_locale_settings (prev_locale
);
443 unlock_locale_mutex ();
447 err
= install_locale (locale
);
450 leave_locale_section (prev_locale
);
451 free_locale_settings (prev_locale
);
457 /* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
458 #define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
462 scm_t_locale_settings lsec_prev_locale; \
464 lsec_err = enter_locale_section ((_c_locale), &lsec_prev_locale); \
466 scm_locale_error (FUNC_NAME, lsec_err); \
471 leave_locale_section (&lsec_prev_locale); \
472 free_locale_settings (&lsec_prev_locale); \
477 /* Convert the current locale settings into a locale SMOB. On success, zero
478 is returned and RESULT points to the new SMOB. Otherwise, an error is
481 get_current_locale (SCM
*result
)
484 scm_t_locale c_locale
;
485 const char *current_locale
;
487 c_locale
= scm_gc_malloc (sizeof (* c_locale
), "locale");
489 lock_locale_mutex ();
491 c_locale
->category_mask
= LC_ALL_MASK
;
492 c_locale
->base_locale
= SCM_UNDEFINED
;
494 current_locale
= setlocale (LC_ALL
, NULL
);
495 if (current_locale
!= NULL
)
496 c_locale
->locale_name
= scm_gc_strdup (current_locale
, "locale");
500 unlock_locale_mutex ();
503 SCM_NEWSMOB (*result
, scm_tc16_locale_smob_type
, c_locale
);
505 *result
= SCM_BOOL_F
;
510 #else /* USE_GNU_LOCALE_API */
512 /* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
513 #define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
516 scm_t_locale old_loc; \
518 old_loc = uselocale (_c_locale); \
520 uselocale (old_loc); \
525 #endif /* USE_GNU_LOCALE_API */
529 /* `make-locale' can take either category lists or single categories (the
530 `LC_*' integer constants). */
531 #define SCM_LIST_OR_INTEGER_P(arg) \
532 (scm_is_integer (arg) || scm_is_true (scm_list_p (arg)))
535 /* Return the category mask corresponding to CATEGORY (an `LC_' integer
538 category_to_category_mask (SCM category
,
539 const char *func_name
, int pos
)
544 c_category
= scm_to_int (category
);
546 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
548 c_category_mask = SCM_LOCALE_CATEGORY_MASK (_name); \
553 #include "locale-categories.h"
556 c_category_mask
= LC_ALL_MASK
;
560 scm_wrong_type_arg_msg (func_name
, pos
, category
,
564 #undef SCM_DEFINE_LOCALE_CATEGORY
566 return c_category_mask
;
569 /* Convert CATEGORIES, a list of locale categories or a single category (an
570 integer), into a category mask. */
572 category_list_to_category_mask (SCM categories
,
573 const char *func_name
, int pos
)
575 int c_category_mask
= 0;
577 if (scm_is_integer (categories
))
578 c_category_mask
= category_to_category_mask (categories
,
581 for (; !scm_is_null (categories
); categories
= SCM_CDR (categories
))
583 SCM category
= SCM_CAR (categories
);
586 category_to_category_mask (category
, func_name
, pos
);
589 return c_category_mask
;
593 SCM_DEFINE (scm_make_locale
, "make-locale", 2, 1, 0,
594 (SCM category_list
, SCM locale_name
, SCM base_locale
),
595 "Return a reference to a data structure representing a set of "
596 "locale datasets. @var{category_list} should be either a list "
597 "of locale categories or a single category as used with "
598 "@code{setlocale} (@pxref{Locales, @code{setlocale}}) and "
599 "@var{locale_name} should be the name of the locale considered "
600 "(e.g., @code{\"sl_SI\"}). Optionally, if @code{base_locale} is "
601 "passed, it should be a locale object denoting settings for "
602 "categories not listed in @var{category_list}.")
603 #define FUNC_NAME s_scm_make_locale
605 SCM locale
= SCM_BOOL_F
;
609 scm_t_locale c_base_locale
, c_locale
;
611 SCM_MAKE_VALIDATE (1, category_list
, LIST_OR_INTEGER_P
);
612 SCM_VALIDATE_STRING (2, locale_name
);
613 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, base_locale
, c_base_locale
);
615 c_category_mask
= category_list_to_category_mask (category_list
,
617 c_locale_name
= scm_to_locale_string (locale_name
);
619 #ifdef USE_GNU_LOCALE_API
621 if (scm_is_eq (base_locale
, SCM_VARIABLE_REF (scm_global_locale
)))
622 c_base_locale
= LC_GLOBAL_LOCALE
;
624 if (c_base_locale
!= (locale_t
) 0)
626 /* C_BASE_LOCALE is to be consumed by `newlocale ()' so it needs to be
627 duplicated before. */
628 c_base_locale
= duplocale (c_base_locale
);
630 if (c_base_locale
== (locale_t
) 0)
637 c_locale
= newlocale (c_category_mask
, c_locale_name
, c_base_locale
);
639 free (c_locale_name
);
640 c_locale_name
= NULL
;
642 if (c_locale
== (locale_t
) 0)
644 if (c_base_locale
!= (locale_t
) 0)
645 freelocale (c_base_locale
);
646 scm_locale_error (FUNC_NAME
, errno
);
649 SCM_NEWSMOB (locale
, scm_tc16_locale_smob_type
, c_locale
);
653 c_locale
= scm_gc_malloc (sizeof (* c_locale
), "locale");
655 c_locale
->category_mask
= c_category_mask
;
656 c_locale
->locale_name
= scm_gc_strdup (c_locale_name
, "locale");
657 free (c_locale_name
);
658 c_locale_name
= NULL
;
660 if (scm_is_eq (base_locale
, SCM_VARIABLE_REF (scm_global_locale
)))
662 /* Get the current locale settings and turn them into a locale
664 err
= get_current_locale (&base_locale
);
669 c_locale
->base_locale
= base_locale
;
672 /* Try out the new locale and raise an exception if it doesn't work. */
674 scm_t_locale_settings prev_locale
;
676 err
= enter_locale_section (c_locale
, &prev_locale
);
682 leave_locale_section (&prev_locale
);
683 SCM_NEWSMOB (locale
, scm_tc16_locale_smob_type
, c_locale
);
692 #ifndef USE_GNU_LOCALE_API
693 scm_gc_free (c_locale
, sizeof (* c_locale
), "locale");
695 free (c_locale_name
);
696 scm_locale_error (FUNC_NAME
, err
);
702 SCM_DEFINE (scm_locale_p
, "locale?", 1, 0, 0,
704 "Return true if @var{obj} is a locale object.")
705 #define FUNC_NAME s_scm_locale_p
707 return scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_locale_smob_type
, obj
));
713 /* Locale-dependent string comparison.
715 A similar API can be found in MzScheme starting from version 200:
716 http://download.plt-scheme.org/chronology/mzmr200alpha14.html . */
718 #define SCM_STRING_TO_U32_BUF(s1, c_s1) \
721 if (scm_i_is_narrow_string (s1)) \
724 const char *buf = scm_i_string_chars (s1); \
726 len = scm_i_string_length (s1); \
727 c_s1 = alloca (sizeof (scm_t_wchar) * (len + 1)); \
729 for (i = 0; i < len; i ++) \
730 c_s1[i] = (unsigned char ) buf[i]; \
734 c_s1 = (scm_t_wchar *) scm_i_string_wide_chars (s1); \
738 /* Compare UTF-32 strings according to LOCALE. Returns a negative value if
739 S1 compares smaller than S2, a positive value if S1 compares larger than
740 S2, or 0 if they compare equal. */
742 compare_u32_strings (SCM s1
, SCM s2
, SCM locale
, const char *func_name
)
743 #define FUNC_NAME func_name
746 scm_t_locale c_locale
;
747 scm_t_wchar
*c_s1
, *c_s2
;
748 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale
, c_locale
);
750 SCM_STRING_TO_U32_BUF (s1
, c_s1
);
751 SCM_STRING_TO_U32_BUF (s2
, c_s2
);
754 RUN_IN_LOCALE_SECTION (c_locale
,
755 result
= u32_strcoll ((const scm_t_uint32
*) c_s1
,
756 (const scm_t_uint32
*) c_s2
));
758 result
= u32_strcoll ((const scm_t_uint32
*) c_s1
,
759 (const scm_t_uint32
*) c_s2
);
761 scm_remember_upto_here_2 (s1
, s2
);
762 scm_remember_upto_here (locale
);
767 /* Return the current language of the locale. */
771 /* Note: If the locale has been set with 'uselocale', uc_locale_language
772 from libunistring versions 0.9.1 and older will return the incorrect
773 (non-thread-specific) locale. This is fixed in versions 0.9.2 and
775 return uc_locale_language ();
779 u32_locale_casecoll (const char *func_name
, const scm_t_uint32
*c_s1
,
780 const scm_t_uint32
*c_s2
,
783 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must note
784 make any non-local exit. */
787 const char *loc
= locale_language ();
789 ret
= u32_casecoll (c_s1
, u32_strlen (c_s1
),
790 c_s2
, u32_strlen (c_s2
),
791 loc
, UNINORM_NFC
, result
);
793 return ret
== 0 ? ret
: errno
;
797 compare_u32_strings_ci (SCM s1
, SCM s2
, SCM locale
, const char *func_name
)
798 #define FUNC_NAME func_name
801 scm_t_locale c_locale
;
802 scm_t_wchar
*c_s1
, *c_s2
;
803 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale
, c_locale
);
805 SCM_STRING_TO_U32_BUF (s1
, c_s1
);
806 SCM_STRING_TO_U32_BUF (s2
, c_s2
);
809 RUN_IN_LOCALE_SECTION
811 ret
= u32_locale_casecoll (func_name
,
812 (const scm_t_uint32
*) c_s1
,
813 (const scm_t_uint32
*) c_s2
,
816 ret
= u32_locale_casecoll (func_name
,
817 (const scm_t_uint32
*) c_s1
,
818 (const scm_t_uint32
*) c_s2
,
821 if (SCM_UNLIKELY (ret
!= 0))
824 scm_syserror (FUNC_NAME
);
827 scm_remember_upto_here_2 (s1
, s2
);
828 scm_remember_upto_here (locale
);
834 /* Store into DST an upper-case version of SRC. */
836 str_upcase (register char *dst
, register const char *src
)
838 for (; *src
!= '\0'; src
++, dst
++)
839 *dst
= toupper ((int) *src
);
844 str_downcase (register char *dst
, register const char *src
)
846 for (; *src
!= '\0'; src
++, dst
++)
847 *dst
= tolower ((int) *src
);
851 #ifdef USE_GNU_LOCALE_API
853 str_upcase_l (register char *dst
, register const char *src
,
856 for (; *src
!= '\0'; src
++, dst
++)
857 *dst
= toupper_l (*src
, locale
);
862 str_downcase_l (register char *dst
, register const char *src
,
865 for (; *src
!= '\0'; src
++, dst
++)
866 *dst
= tolower_l (*src
, locale
);
872 SCM_DEFINE (scm_string_locale_lt
, "string-locale<?", 2, 1, 0,
873 (SCM s1
, SCM s2
, SCM locale
),
874 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
875 "If @var{locale} is provided, it should be locale object (as "
876 "returned by @code{make-locale}) and will be used to perform the "
877 "comparison; otherwise, the current system locale is used.")
878 #define FUNC_NAME s_scm_string_locale_lt
882 SCM_VALIDATE_STRING (1, s1
);
883 SCM_VALIDATE_STRING (2, s2
);
885 result
= compare_u32_strings (s1
, s2
, locale
, FUNC_NAME
);
887 return scm_from_bool (result
< 0);
891 SCM_DEFINE (scm_string_locale_gt
, "string-locale>?", 2, 1, 0,
892 (SCM s1
, SCM s2
, SCM locale
),
893 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
894 "If @var{locale} is provided, it should be locale object (as "
895 "returned by @code{make-locale}) and will be used to perform the "
896 "comparison; otherwise, the current system locale is used.")
897 #define FUNC_NAME s_scm_string_locale_gt
901 SCM_VALIDATE_STRING (1, s1
);
902 SCM_VALIDATE_STRING (2, s2
);
904 result
= compare_u32_strings (s1
, s2
, locale
, FUNC_NAME
);
906 return scm_from_bool (result
> 0);
910 SCM_DEFINE (scm_string_locale_ci_lt
, "string-locale-ci<?", 2, 1, 0,
911 (SCM s1
, SCM s2
, SCM locale
),
912 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
913 "and locale-dependent way. If @var{locale} is provided, it "
914 "should be locale object (as returned by @code{make-locale}) "
915 "and will be used to perform the comparison; otherwise, the "
916 "current system locale is used.")
917 #define FUNC_NAME s_scm_string_locale_ci_lt
921 SCM_VALIDATE_STRING (1, s1
);
922 SCM_VALIDATE_STRING (2, s2
);
924 result
= compare_u32_strings_ci (s1
, s2
, locale
, FUNC_NAME
);
926 return scm_from_bool (result
< 0);
930 SCM_DEFINE (scm_string_locale_ci_gt
, "string-locale-ci>?", 2, 1, 0,
931 (SCM s1
, SCM s2
, SCM locale
),
932 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
933 "and locale-dependent way. If @var{locale} is provided, it "
934 "should be locale object (as returned by @code{make-locale}) "
935 "and will be used to perform the comparison; otherwise, the "
936 "current system locale is used.")
937 #define FUNC_NAME s_scm_string_locale_ci_gt
941 SCM_VALIDATE_STRING (1, s1
);
942 SCM_VALIDATE_STRING (2, s2
);
944 result
= compare_u32_strings_ci (s1
, s2
, locale
, FUNC_NAME
);
946 return scm_from_bool (result
> 0);
950 SCM_DEFINE (scm_string_locale_ci_eq
, "string-locale-ci=?", 2, 1, 0,
951 (SCM s1
, SCM s2
, SCM locale
),
952 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
953 "and locale-dependent way. If @var{locale} is provided, it "
954 "should be locale object (as returned by @code{make-locale}) "
955 "and will be used to perform the comparison; otherwise, the "
956 "current system locale is used.")
957 #define FUNC_NAME s_scm_string_locale_ci_eq
961 SCM_VALIDATE_STRING (1, s1
);
962 SCM_VALIDATE_STRING (2, s2
);
964 result
= compare_u32_strings_ci (s1
, s2
, locale
, FUNC_NAME
);
966 return scm_from_bool (result
== 0);
971 SCM_DEFINE (scm_char_locale_lt
, "char-locale<?", 2, 1, 0,
972 (SCM c1
, SCM c2
, SCM locale
),
973 "Return true if character @var{c1} is lower than @var{c2} "
974 "according to @var{locale} or to the current locale.")
975 #define FUNC_NAME s_scm_char_locale_lt
979 SCM_VALIDATE_CHAR (1, c1
);
980 SCM_VALIDATE_CHAR (2, c2
);
982 result
= compare_u32_strings (scm_string (scm_list_1 (c1
)),
983 scm_string (scm_list_1 (c2
)),
986 return scm_from_bool (result
< 0);
990 SCM_DEFINE (scm_char_locale_gt
, "char-locale>?", 2, 1, 0,
991 (SCM c1
, SCM c2
, SCM locale
),
992 "Return true if character @var{c1} is greater than @var{c2} "
993 "according to @var{locale} or to the current locale.")
994 #define FUNC_NAME s_scm_char_locale_gt
998 SCM_VALIDATE_CHAR (1, c1
);
999 SCM_VALIDATE_CHAR (2, c2
);
1001 result
= compare_u32_strings (scm_string (scm_list_1 (c1
)),
1002 scm_string (scm_list_1 (c2
)),
1005 return scm_from_bool (result
> 0);
1009 SCM_DEFINE (scm_char_locale_ci_lt
, "char-locale-ci<?", 2, 1, 0,
1010 (SCM c1
, SCM c2
, SCM locale
),
1011 "Return true if character @var{c1} is lower than @var{c2}, "
1012 "in a case insensitive way according to @var{locale} or to "
1013 "the current locale.")
1014 #define FUNC_NAME s_scm_char_locale_ci_lt
1018 SCM_VALIDATE_CHAR (1, c1
);
1019 SCM_VALIDATE_CHAR (2, c2
);
1021 result
= compare_u32_strings_ci (scm_string (scm_list_1 (c1
)),
1022 scm_string (scm_list_1 (c2
)),
1025 return scm_from_bool (result
< 0);
1029 SCM_DEFINE (scm_char_locale_ci_gt
, "char-locale-ci>?", 2, 1, 0,
1030 (SCM c1
, SCM c2
, SCM locale
),
1031 "Return true if character @var{c1} is greater than @var{c2}, "
1032 "in a case insensitive way according to @var{locale} or to "
1033 "the current locale.")
1034 #define FUNC_NAME s_scm_char_locale_ci_gt
1038 SCM_VALIDATE_CHAR (1, c1
);
1039 SCM_VALIDATE_CHAR (2, c2
);
1041 result
= compare_u32_strings_ci (scm_string (scm_list_1 (c1
)),
1042 scm_string (scm_list_1 (c2
)),
1045 return scm_from_bool (result
> 0);
1049 SCM_DEFINE (scm_char_locale_ci_eq
, "char-locale-ci=?", 2, 1, 0,
1050 (SCM c1
, SCM c2
, SCM locale
),
1051 "Return true if character @var{c1} is equal to @var{c2}, "
1052 "in a case insensitive way according to @var{locale} or to "
1053 "the current locale.")
1054 #define FUNC_NAME s_scm_char_locale_ci_eq
1058 SCM_VALIDATE_CHAR (1, c1
);
1059 SCM_VALIDATE_CHAR (2, c2
);
1061 result
= compare_u32_strings_ci (scm_string (scm_list_1 (c1
)),
1062 scm_string (scm_list_1 (c2
)),
1065 return scm_from_bool (result
== 0);
1071 /* Locale-dependent alphabetic character mapping. */
1074 u32_locale_tocase (const scm_t_uint32
*c_s1
, size_t len
,
1075 scm_t_uint32
**p_c_s2
, size_t * p_len2
,
1076 scm_t_uint32
*(*func
) (const scm_t_uint32
*, size_t,
1077 const char *, uninorm_t
,
1078 scm_t_uint32
*, size_t *))
1080 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must not
1081 make any non-local exit. */
1084 const char *loc
= locale_language ();
1086 /* The first NULL here indicates that no NFC or NFKC normalization
1087 is done. The second NULL means the return buffer is
1089 ret
= func (c_s1
, len
, loc
, NULL
, NULL
, p_len2
);
1093 *p_c_s2
= (scm_t_uint32
*) NULL
;
1104 chr_to_case (SCM chr
, scm_t_locale c_locale
,
1105 scm_t_uint32
*(*func
) (const scm_t_uint32
*, size_t, const char *,
1106 uninorm_t
, scm_t_uint32
*, size_t *),
1107 const char *func_name
,
1109 #define FUNC_NAME func_name
1113 scm_t_uint32
*convbuf
;
1119 if (c_locale
!= NULL
)
1120 RUN_IN_LOCALE_SECTION (c_locale
, ret
=
1121 u32_locale_tocase (&c
, 1, &convbuf
, &convlen
, func
));
1124 u32_locale_tocase (&c
, 1, &convbuf
, &convlen
, func
);
1126 if (SCM_UNLIKELY (ret
!= 0))
1133 convchar
= SCM_MAKE_CHAR ((scm_t_wchar
) convbuf
[0]);
1142 SCM_DEFINE (scm_char_locale_downcase
, "char-locale-downcase", 1, 1, 0,
1143 (SCM chr
, SCM locale
),
1144 "Return the lowercase character that corresponds to @var{chr} "
1145 "according to either @var{locale} or the current locale.")
1146 #define FUNC_NAME s_scm_char_locale_downcase
1148 scm_t_locale c_locale
;
1152 SCM_VALIDATE_CHAR (1, chr
);
1153 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1155 ret
= chr_to_case (chr
, c_locale
, u32_tolower
, FUNC_NAME
, &err
);
1160 scm_syserror (FUNC_NAME
);
1166 SCM_DEFINE (scm_char_locale_upcase
, "char-locale-upcase", 1, 1, 0,
1167 (SCM chr
, SCM locale
),
1168 "Return the uppercase character that corresponds to @var{chr} "
1169 "according to either @var{locale} or the current locale.")
1170 #define FUNC_NAME s_scm_char_locale_upcase
1172 scm_t_locale c_locale
;
1176 SCM_VALIDATE_CHAR (1, chr
);
1177 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1179 ret
= chr_to_case (chr
, c_locale
, u32_toupper
, FUNC_NAME
, &err
);
1184 scm_syserror (FUNC_NAME
);
1190 SCM_DEFINE (scm_char_locale_titlecase
, "char-locale-titlecase", 1, 1, 0,
1191 (SCM chr
, SCM locale
),
1192 "Return the titlecase character that corresponds to @var{chr} "
1193 "according to either @var{locale} or the current locale.")
1194 #define FUNC_NAME s_scm_char_locale_titlecase
1196 scm_t_locale c_locale
;
1200 SCM_VALIDATE_CHAR (1, chr
);
1201 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1203 ret
= chr_to_case (chr
, c_locale
, u32_totitle
, FUNC_NAME
, &err
);
1208 scm_syserror (FUNC_NAME
);
1215 str_to_case (SCM str
, scm_t_locale c_locale
,
1216 scm_t_uint32
*(*func
) (const scm_t_uint32
*, size_t, const char *,
1217 uninorm_t
, scm_t_uint32
*, size_t *),
1218 const char *func_name
,
1220 #define FUNC_NAME func_name
1222 scm_t_wchar
*c_str
, *c_buf
;
1223 scm_t_uint32
*c_convstr
;
1224 size_t len
, convlen
;
1228 len
= scm_i_string_length (str
);
1231 SCM_STRING_TO_U32_BUF (str
, c_str
);
1234 RUN_IN_LOCALE_SECTION (c_locale
, ret
=
1235 u32_locale_tocase ((scm_t_uint32
*) c_str
, len
,
1240 u32_locale_tocase ((scm_t_uint32
*) c_str
, len
,
1241 &c_convstr
, &convlen
, func
);
1243 scm_remember_upto_here (str
);
1245 if (SCM_UNLIKELY (ret
!= 0))
1251 convstr
= scm_i_make_wide_string (convlen
, &c_buf
, 0);
1252 memcpy (c_buf
, c_convstr
, convlen
* sizeof (scm_t_wchar
));
1255 scm_i_try_narrow_string (convstr
);
1261 SCM_DEFINE (scm_string_locale_upcase
, "string-locale-upcase", 1, 1, 0,
1262 (SCM str
, SCM locale
),
1263 "Return a new string that is the uppercase version of "
1264 "@var{str} according to either @var{locale} or the current "
1266 #define FUNC_NAME s_scm_string_locale_upcase
1268 scm_t_locale c_locale
;
1272 SCM_VALIDATE_STRING (1, str
);
1273 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1275 ret
= str_to_case (str
, c_locale
, u32_toupper
, FUNC_NAME
, &err
);
1280 scm_syserror (FUNC_NAME
);
1286 SCM_DEFINE (scm_string_locale_downcase
, "string-locale-downcase", 1, 1, 0,
1287 (SCM str
, SCM locale
),
1288 "Return a new string that is the down-case version of "
1289 "@var{str} according to either @var{locale} or the current "
1291 #define FUNC_NAME s_scm_string_locale_downcase
1293 scm_t_locale c_locale
;
1297 SCM_VALIDATE_STRING (1, str
);
1298 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1300 ret
= str_to_case (str
, c_locale
, u32_tolower
, FUNC_NAME
, &err
);
1305 scm_syserror (FUNC_NAME
);
1311 SCM_DEFINE (scm_string_locale_titlecase
, "string-locale-titlecase", 1, 1, 0,
1312 (SCM str
, SCM locale
),
1313 "Return a new string that is the title-case version of "
1314 "@var{str} according to either @var{locale} or the current "
1316 #define FUNC_NAME s_scm_string_locale_titlecase
1318 scm_t_locale c_locale
;
1322 SCM_VALIDATE_STRING (1, str
);
1323 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1325 ret
= str_to_case (str
, c_locale
, u32_totitle
, FUNC_NAME
, &err
);
1330 scm_syserror (FUNC_NAME
);
1336 /* Note: We don't provide mutative versions of `string-locale-(up|down)case'
1337 because, in some languages, a single downcase character maps to a couple
1338 of uppercase characters. Read the SRFI-13 document for a detailed
1339 discussion about this. */
1343 /* Locale-dependent number parsing. */
1345 SCM_DEFINE (scm_locale_string_to_integer
, "locale-string->integer",
1346 1, 2, 0, (SCM str
, SCM base
, SCM locale
),
1347 "Convert string @var{str} into an integer according to either "
1348 "@var{locale} (a locale object as returned by @code{make-locale}) "
1349 "or the current process locale. Return two values: an integer "
1350 "(on success) or @code{#f}, and the number of characters read "
1351 "from @var{str} (@code{0} on failure).")
1352 #define FUNC_NAME s_scm_locale_string_to_integer
1359 scm_t_locale c_locale
;
1361 SCM_VALIDATE_STRING (1, str
);
1362 c_str
= scm_i_string_chars (str
);
1364 if (!scm_is_eq (base
, SCM_UNDEFINED
))
1365 SCM_VALIDATE_INT_COPY (2, base
, c_base
);
1369 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale
, c_locale
);
1371 if (c_locale
!= NULL
)
1373 #ifdef USE_GNU_LOCALE_API
1374 c_result
= strtol_l (c_str
, &c_endptr
, c_base
, c_locale
);
1376 RUN_IN_LOCALE_SECTION (c_locale
,
1377 c_result
= strtol (c_str
, &c_endptr
, c_base
));
1381 c_result
= strtol (c_str
, &c_endptr
, c_base
);
1383 scm_remember_upto_here (str
);
1385 if (c_endptr
== c_str
)
1386 result
= SCM_BOOL_F
;
1388 result
= scm_from_long (c_result
);
1390 return (scm_values (scm_list_2 (result
, scm_from_long (c_endptr
- c_str
))));
1394 SCM_DEFINE (scm_locale_string_to_inexact
, "locale-string->inexact",
1395 1, 1, 0, (SCM str
, SCM locale
),
1396 "Convert string @var{str} into an inexact number according to "
1397 "either @var{locale} (a locale object as returned by "
1398 "@code{make-locale}) or the current process locale. Return "
1399 "two values: an inexact number (on success) or @code{#f}, and "
1400 "the number of characters read from @var{str} (@code{0} on "
1402 #define FUNC_NAME s_scm_locale_string_to_inexact
1408 scm_t_locale c_locale
;
1410 SCM_VALIDATE_STRING (1, str
);
1411 c_str
= scm_i_string_chars (str
);
1413 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1415 if (c_locale
!= NULL
)
1417 #ifdef USE_GNU_LOCALE_API
1418 c_result
= strtod_l (c_str
, &c_endptr
, c_locale
);
1420 RUN_IN_LOCALE_SECTION (c_locale
,
1421 c_result
= strtod (c_str
, &c_endptr
));
1425 c_result
= strtod (c_str
, &c_endptr
);
1427 scm_remember_upto_here (str
);
1429 if (c_endptr
== c_str
)
1430 result
= SCM_BOOL_F
;
1432 result
= scm_from_double (c_result
);
1434 return (scm_values (scm_list_2 (result
, scm_from_long (c_endptr
- c_str
))));
1439 /* Language information, aka. `nl_langinfo ()'. */
1441 /* FIXME: Issues related to `nl-langinfo'.
1443 1. The `CODESET' value is not normalized. This is a secondary issue, but
1444 still a practical issue. See
1445 http://www.cl.cam.ac.uk/~mgk25/ucs/norm_charmap.c for codeset
1448 2. `nl_langinfo ()' is not available on Windows.
1450 3. `nl_langinfo ()' may return strings encoded in a locale different from
1454 (nl-langinfo DAY_1 (make-locale LC_ALL "eo_EO.UTF-8"))
1456 returns a result that is a UTF-8 string, regardless of the
1457 setting of the current locale. If nl_langinfo supports CODESET,
1458 we can convert the string properly using scm_from_stringn. If
1459 CODESET is not supported, we won't be able to make much sense of
1460 the returned string.
1462 Note: We don't use Gnulib's `nl_langinfo' module because it's currently not
1463 as complete as the compatibility hacks in `i18n.scm'. */
1466 SCM_DEFINE (scm_nl_langinfo
, "nl-langinfo", 1, 1, 0,
1467 (SCM item
, SCM locale
),
1468 "Return a string denoting locale information for @var{item} "
1469 "in the current locale or that specified by @var{locale}. "
1470 "The semantics and arguments are the same as those of the "
1471 "X/Open @code{nl_langinfo} function (@pxref{The Elegant and "
1472 "Fast Way, @code{nl_langinfo},, libc, The GNU C Library "
1473 "Reference Manual}).")
1474 #define FUNC_NAME s_scm_nl_langinfo
1479 scm_t_locale c_locale
;
1482 SCM_VALIDATE_INT_COPY (2, item
, c_item
);
1483 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1485 /* Sadly, `nl_langinfo ()' returns a pointer to a static string. According
1486 to SuS v2, that static string may be modified by subsequent calls to
1487 `nl_langinfo ()' as well as by calls to `setlocale ()'. Thus, we must
1488 acquire the locale mutex before doing invoking `nl_langinfo ()'. See
1489 http://opengroup.org/onlinepubs/007908799/xsh/nl_langinfo.html for
1492 lock_locale_mutex ();
1493 if (c_locale
!= NULL
)
1495 #ifdef USE_GNU_LOCALE_API
1496 c_result
= nl_langinfo_l (c_item
, c_locale
);
1497 codeset
= nl_langinfo_l (CODESET
, c_locale
);
1498 #else /* !USE_GNU_LOCALE_API */
1499 /* We can't use `RUN_IN_LOCALE_SECTION ()' here because the locale
1500 mutex is already taken. */
1502 scm_t_locale_settings lsec_prev_locale
;
1504 lsec_err
= get_current_locale_settings (&lsec_prev_locale
);
1506 unlock_locale_mutex ();
1509 lsec_err
= install_locale (c_locale
);
1512 leave_locale_section (&lsec_prev_locale
);
1513 free_locale_settings (&lsec_prev_locale
);
1518 scm_locale_error (FUNC_NAME
, lsec_err
);
1521 c_result
= nl_langinfo (c_item
);
1522 codeset
= nl_langinfo (CODESET
);
1524 restore_locale_settings (&lsec_prev_locale
);
1525 free_locale_settings (&lsec_prev_locale
);
1531 c_result
= nl_langinfo (c_item
);
1532 codeset
= nl_langinfo (CODESET
);
1535 c_result
= strdup (c_result
);
1536 unlock_locale_mutex ();
1538 if (c_result
== NULL
)
1539 result
= SCM_BOOL_F
;
1544 #if (defined GROUPING) && (defined MON_GROUPING)
1550 /* In this cases, the result is to be interpreted as a list
1551 of numbers. If the last item is `CHAR_MAX' or a negative
1552 number, it has the special meaning "no more grouping"
1553 (negative numbers aren't specified in POSIX but can be
1555 <http://lists.gnu.org/archive/html/bug-guile/2011-02/msg00159.html>). */
1557 for (p
= c_result
; (*p
> 0) && (*p
!= CHAR_MAX
); p
++)
1558 result
= scm_cons (SCM_I_MAKINUM ((int) *p
), result
);
1561 SCM last_pair
= result
;
1563 result
= scm_reverse_x (result
, SCM_EOL
);
1567 /* Cyclic grouping information. */
1568 if (!scm_is_null (last_pair
))
1569 SCM_SETCDR (last_pair
, result
);
1578 #if (defined FRAC_DIGITS) && (defined INT_FRAC_DIGITS)
1580 case INT_FRAC_DIGITS
:
1581 /* This is to be interpreted as a single integer. */
1582 if (*c_result
== CHAR_MAX
)
1584 result
= SCM_BOOL_F
;
1586 result
= SCM_I_MAKINUM (*c_result
);
1592 #if (defined P_CS_PRECEDES) && (defined INT_N_CS_PRECEDES)
1595 case INT_P_CS_PRECEDES
:
1596 case INT_N_CS_PRECEDES
:
1597 #if (defined P_SEP_BY_SPACE) && (defined N_SEP_BY_SPACE)
1598 case P_SEP_BY_SPACE
:
1599 case N_SEP_BY_SPACE
:
1601 /* This is to be interpreted as a boolean. */
1602 result
= scm_from_bool (*c_result
);
1608 #if (defined P_SIGN_POSN) && (defined INT_N_SIGN_POSN)
1611 case INT_P_SIGN_POSN
:
1612 case INT_N_SIGN_POSN
:
1613 /* See `(libc) Sign of Money Amount' for the interpretation of the
1614 return value here. */
1618 result
= scm_from_latin1_symbol ("parenthesize");
1622 result
= scm_from_latin1_symbol ("sign-before");
1626 result
= scm_from_latin1_symbol ("sign-after");
1630 result
= scm_from_latin1_symbol ("sign-before-currency-symbol");
1634 result
= scm_from_latin1_symbol ("sign-after-currency-symbol");
1638 result
= scm_from_latin1_symbol ("unspecified");
1645 result
= scm_from_stringn (c_result
, strlen (c_result
),
1647 SCM_FAILED_CONVERSION_QUESTION_MARK
);
1656 /* Define the `nl_item' constants. */
1658 define_langinfo_items (void)
1660 #define DEFINE_NLITEM_CONSTANT(_item) \
1661 scm_c_define (# _item, scm_from_int (_item))
1663 DEFINE_NLITEM_CONSTANT (CODESET
);
1665 /* Abbreviated days of the week. */
1666 DEFINE_NLITEM_CONSTANT (ABDAY_1
);
1667 DEFINE_NLITEM_CONSTANT (ABDAY_2
);
1668 DEFINE_NLITEM_CONSTANT (ABDAY_3
);
1669 DEFINE_NLITEM_CONSTANT (ABDAY_4
);
1670 DEFINE_NLITEM_CONSTANT (ABDAY_5
);
1671 DEFINE_NLITEM_CONSTANT (ABDAY_6
);
1672 DEFINE_NLITEM_CONSTANT (ABDAY_7
);
1674 /* Long-named days of the week. */
1675 DEFINE_NLITEM_CONSTANT (DAY_1
); /* Sunday */
1676 DEFINE_NLITEM_CONSTANT (DAY_2
); /* Monday */
1677 DEFINE_NLITEM_CONSTANT (DAY_3
); /* Tuesday */
1678 DEFINE_NLITEM_CONSTANT (DAY_4
); /* Wednesday */
1679 DEFINE_NLITEM_CONSTANT (DAY_5
); /* Thursday */
1680 DEFINE_NLITEM_CONSTANT (DAY_6
); /* Friday */
1681 DEFINE_NLITEM_CONSTANT (DAY_7
); /* Saturday */
1683 /* Abbreviated month names. */
1684 DEFINE_NLITEM_CONSTANT (ABMON_1
); /* Jan */
1685 DEFINE_NLITEM_CONSTANT (ABMON_2
);
1686 DEFINE_NLITEM_CONSTANT (ABMON_3
);
1687 DEFINE_NLITEM_CONSTANT (ABMON_4
);
1688 DEFINE_NLITEM_CONSTANT (ABMON_5
);
1689 DEFINE_NLITEM_CONSTANT (ABMON_6
);
1690 DEFINE_NLITEM_CONSTANT (ABMON_7
);
1691 DEFINE_NLITEM_CONSTANT (ABMON_8
);
1692 DEFINE_NLITEM_CONSTANT (ABMON_9
);
1693 DEFINE_NLITEM_CONSTANT (ABMON_10
);
1694 DEFINE_NLITEM_CONSTANT (ABMON_11
);
1695 DEFINE_NLITEM_CONSTANT (ABMON_12
);
1697 /* Long month names. */
1698 DEFINE_NLITEM_CONSTANT (MON_1
); /* January */
1699 DEFINE_NLITEM_CONSTANT (MON_2
);
1700 DEFINE_NLITEM_CONSTANT (MON_3
);
1701 DEFINE_NLITEM_CONSTANT (MON_4
);
1702 DEFINE_NLITEM_CONSTANT (MON_5
);
1703 DEFINE_NLITEM_CONSTANT (MON_6
);
1704 DEFINE_NLITEM_CONSTANT (MON_7
);
1705 DEFINE_NLITEM_CONSTANT (MON_8
);
1706 DEFINE_NLITEM_CONSTANT (MON_9
);
1707 DEFINE_NLITEM_CONSTANT (MON_10
);
1708 DEFINE_NLITEM_CONSTANT (MON_11
);
1709 DEFINE_NLITEM_CONSTANT (MON_12
);
1711 DEFINE_NLITEM_CONSTANT (AM_STR
); /* Ante meridiem string. */
1712 DEFINE_NLITEM_CONSTANT (PM_STR
); /* Post meridiem string. */
1714 DEFINE_NLITEM_CONSTANT (D_T_FMT
); /* Date and time format for strftime. */
1715 DEFINE_NLITEM_CONSTANT (D_FMT
); /* Date format for strftime. */
1716 DEFINE_NLITEM_CONSTANT (T_FMT
); /* Time format for strftime. */
1717 DEFINE_NLITEM_CONSTANT (T_FMT_AMPM
);/* 12-hour time format for strftime. */
1720 DEFINE_NLITEM_CONSTANT (ERA
); /* Alternate era. */
1723 DEFINE_NLITEM_CONSTANT (ERA_D_FMT
); /* Date in alternate era format. */
1726 DEFINE_NLITEM_CONSTANT (ERA_D_T_FMT
); /* Date and time in alternate era
1730 DEFINE_NLITEM_CONSTANT (ERA_T_FMT
); /* Time in alternate era format. */
1734 DEFINE_NLITEM_CONSTANT (ALT_DIGITS
); /* Alternate symbols for digits. */
1736 DEFINE_NLITEM_CONSTANT (RADIXCHAR
);
1737 DEFINE_NLITEM_CONSTANT (THOUSEP
);
1740 DEFINE_NLITEM_CONSTANT (YESEXPR
);
1743 DEFINE_NLITEM_CONSTANT (NOEXPR
);
1746 #ifdef CRNCYSTR /* currency symbol */
1747 DEFINE_NLITEM_CONSTANT (CRNCYSTR
);
1750 /* GNU extensions. */
1753 DEFINE_NLITEM_CONSTANT (ERA_YEAR
); /* Year in alternate era format. */
1756 /* LC_MONETARY category: formatting of monetary quantities.
1757 These items each correspond to a member of `struct lconv',
1758 defined in <locale.h>. */
1759 #ifdef INT_CURR_SYMBOL
1760 DEFINE_NLITEM_CONSTANT (INT_CURR_SYMBOL
);
1762 #ifdef MON_DECIMAL_POINT
1763 DEFINE_NLITEM_CONSTANT (MON_DECIMAL_POINT
);
1765 #ifdef MON_THOUSANDS_SEP
1766 DEFINE_NLITEM_CONSTANT (MON_THOUSANDS_SEP
);
1769 DEFINE_NLITEM_CONSTANT (MON_GROUPING
);
1771 #ifdef POSITIVE_SIGN
1772 DEFINE_NLITEM_CONSTANT (POSITIVE_SIGN
);
1774 #ifdef NEGATIVE_SIGN
1775 DEFINE_NLITEM_CONSTANT (NEGATIVE_SIGN
);
1778 DEFINE_NLITEM_CONSTANT (GROUPING
);
1780 #ifdef INT_FRAC_DIGITS
1781 DEFINE_NLITEM_CONSTANT (INT_FRAC_DIGITS
);
1784 DEFINE_NLITEM_CONSTANT (FRAC_DIGITS
);
1786 #ifdef P_CS_PRECEDES
1787 DEFINE_NLITEM_CONSTANT (P_CS_PRECEDES
);
1789 #ifdef P_SEP_BY_SPACE
1790 DEFINE_NLITEM_CONSTANT (P_SEP_BY_SPACE
);
1792 #ifdef N_CS_PRECEDES
1793 DEFINE_NLITEM_CONSTANT (N_CS_PRECEDES
);
1795 #ifdef N_SEP_BY_SPACE
1796 DEFINE_NLITEM_CONSTANT (N_SEP_BY_SPACE
);
1799 DEFINE_NLITEM_CONSTANT (P_SIGN_POSN
);
1802 DEFINE_NLITEM_CONSTANT (N_SIGN_POSN
);
1804 #ifdef INT_P_CS_PRECEDES
1805 DEFINE_NLITEM_CONSTANT (INT_P_CS_PRECEDES
);
1807 #ifdef INT_P_SEP_BY_SPACE
1808 DEFINE_NLITEM_CONSTANT (INT_P_SEP_BY_SPACE
);
1810 #ifdef INT_N_CS_PRECEDES
1811 DEFINE_NLITEM_CONSTANT (INT_N_CS_PRECEDES
);
1813 #ifdef INT_N_SEP_BY_SPACE
1814 DEFINE_NLITEM_CONSTANT (INT_N_SEP_BY_SPACE
);
1816 #ifdef INT_P_SIGN_POSN
1817 DEFINE_NLITEM_CONSTANT (INT_P_SIGN_POSN
);
1819 #ifdef INT_N_SIGN_POSN
1820 DEFINE_NLITEM_CONSTANT (INT_N_SIGN_POSN
);
1823 #undef DEFINE_NLITEM_CONSTANT
1830 SCM global_locale_smob
;
1832 scm_add_feature ("nl-langinfo");
1833 define_langinfo_items ();
1835 #include "libguile/i18n.x"
1837 /* Initialize the global locale object with a special `locale' SMOB. */
1838 /* XXX: We don't define it as `LC_GLOBAL_LOCALE' because of bugs as of
1839 glibc <= 2.11 not (yet) worked around by Gnulib. See
1840 http://sourceware.org/bugzilla/show_bug.cgi?id=11009 for details. */
1841 SCM_NEWSMOB (global_locale_smob
, scm_tc16_locale_smob_type
, NULL
);
1842 SCM_VARIABLE_SET (scm_global_locale
, global_locale_smob
);
1846 scm_bootstrap_i18n ()
1848 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION
,
1850 (scm_t_extension_init_func
) scm_init_i18n
,