1 /* Copyright (C) 2006-2014 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 && defined HAVE_USELOCALE
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
);
236 freelocale (c_locale
);
241 #endif /* USE_GNU_LOCALE_API */
244 static void inline scm_locale_error (const char *, int) SCM_NORETURN
;
246 /* Throw an exception corresponding to error ERR. */
248 scm_locale_error (const char *func_name
, int err
)
250 scm_syserror_msg (func_name
,
251 "Failed to install locale",
257 /* Emulating GNU's reentrant locale API. */
258 #ifndef USE_GNU_LOCALE_API
261 /* Maximum number of chained locales (via `base_locale'). */
262 #define LOCALE_STACK_SIZE_MAX 256
266 #define SCM_DEFINE_LOCALE_CATEGORY(_name) char * _name;
267 #include "locale-categories.h"
268 #undef SCM_DEFINE_LOCALE_CATEGORY
269 } scm_t_locale_settings
;
271 /* Fill out SETTINGS according to the current locale settings. On success
272 zero is returned and SETTINGS is properly initialized. */
274 get_current_locale_settings (scm_t_locale_settings
*settings
)
276 const char *locale_name
;
278 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
280 SCM_SYSCALL (locale_name = setlocale (LC_ ## _name, NULL)); \
281 if (locale_name == NULL) \
284 settings-> _name = strdup (locale_name); \
285 if (settings-> _name == NULL) \
289 #include "locale-categories.h"
290 #undef SCM_DEFINE_LOCALE_CATEGORY
301 /* Restore locale settings SETTINGS. On success, return zero. */
303 restore_locale_settings (const scm_t_locale_settings
*settings
)
307 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
308 SCM_SYSCALL (result = setlocale (LC_ ## _name, settings-> _name)); \
309 if (result == NULL) \
312 #include "locale-categories.h"
313 #undef SCM_DEFINE_LOCALE_CATEGORY
321 /* Free memory associated with SETTINGS. */
323 free_locale_settings (scm_t_locale_settings
*settings
)
325 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
326 free (settings-> _name); \
327 settings->_name = NULL;
328 #include "locale-categories.h"
329 #undef SCM_DEFINE_LOCALE_CATEGORY
332 /* Install the locale named LOCALE_NAME for all the categories listed in
335 install_locale_categories (const char *locale_name
, int category_mask
)
339 if (category_mask
== LC_ALL_MASK
)
341 SCM_SYSCALL (result
= setlocale (LC_ALL
, locale_name
));
347 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
348 if (category_mask & SCM_LOCALE_CATEGORY_MASK (_name)) \
350 SCM_SYSCALL (result = setlocale (LC_ ## _name, locale_name)); \
351 if (result == NULL) \
354 #include "locale-categories.h"
355 #undef SCM_DEFINE_LOCALE_CATEGORY
364 /* Install LOCALE, recursively installing its base locales first. On
365 success, zero is returned. */
367 install_locale (scm_t_locale locale
)
369 scm_t_locale stack
[LOCALE_STACK_SIZE_MAX
];
370 int category_mask
= 0;
371 size_t stack_size
= 0;
372 int stack_offset
= 0;
373 const char *result
= NULL
;
375 /* Build up a locale stack by traversing the `base_locale' link. */
378 if (stack_size
>= LOCALE_STACK_SIZE_MAX
)
379 /* We cannot use `scm_error ()' here because otherwise the locale
380 mutex may remain locked. */
383 stack
[stack_size
++] = locale
;
385 /* Keep track of which categories have already been taken into
387 category_mask
|= locale
->category_mask
;
389 if (!SCM_UNBNDP (locale
->base_locale
))
390 locale
= (scm_t_locale
) SCM_SMOB_DATA (locale
->base_locale
);
394 while ((locale
!= NULL
) && (category_mask
!= LC_ALL_MASK
));
396 /* Install the C locale to start from a pristine state. */
397 SCM_SYSCALL (result
= setlocale (LC_ALL
, "C"));
401 /* Install the locales in reverse order. */
402 for (stack_offset
= stack_size
- 1;
409 locale
= stack
[stack_offset
];
410 err
= install_locale_categories (locale
->locale_name
,
411 locale
->category_mask
);
422 /* Leave the locked locale section. */
424 leave_locale_section (const scm_t_locale_settings
*settings
)
426 /* Restore the previous locale settings. */
427 (void)restore_locale_settings (settings
);
429 unlock_locale_mutex ();
432 /* Enter a locked locale section. */
434 enter_locale_section (scm_t_locale locale
,
435 scm_t_locale_settings
*prev_locale
)
439 lock_locale_mutex ();
441 err
= get_current_locale_settings (prev_locale
);
444 unlock_locale_mutex ();
448 err
= install_locale (locale
);
451 leave_locale_section (prev_locale
);
452 free_locale_settings (prev_locale
);
458 /* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
459 #define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
463 scm_t_locale_settings lsec_prev_locale; \
465 lsec_err = enter_locale_section ((_c_locale), &lsec_prev_locale); \
467 scm_locale_error (FUNC_NAME, lsec_err); \
472 leave_locale_section (&lsec_prev_locale); \
473 free_locale_settings (&lsec_prev_locale); \
478 /* Convert the current locale settings into a locale SMOB. On success, zero
479 is returned and RESULT points to the new SMOB. Otherwise, an error is
482 get_current_locale (SCM
*result
)
485 scm_t_locale c_locale
;
486 const char *current_locale
;
488 c_locale
= scm_gc_malloc (sizeof (* c_locale
), "locale");
490 lock_locale_mutex ();
492 c_locale
->category_mask
= LC_ALL_MASK
;
493 c_locale
->base_locale
= SCM_UNDEFINED
;
495 current_locale
= setlocale (LC_ALL
, NULL
);
496 if (current_locale
!= NULL
)
497 c_locale
->locale_name
= scm_gc_strdup (current_locale
, "locale");
501 unlock_locale_mutex ();
504 SCM_NEWSMOB (*result
, scm_tc16_locale_smob_type
, c_locale
);
506 *result
= SCM_BOOL_F
;
511 #else /* USE_GNU_LOCALE_API */
513 /* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
514 #define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
517 scm_t_locale old_loc; \
519 old_loc = uselocale (_c_locale); \
521 uselocale (old_loc); \
526 #endif /* USE_GNU_LOCALE_API */
530 /* `make-locale' can take either category lists or single categories (the
531 `LC_*' integer constants). */
532 #define SCM_LIST_OR_INTEGER_P(arg) \
533 (scm_is_integer (arg) || scm_is_true (scm_list_p (arg)))
536 /* Return the category mask corresponding to CATEGORY (an `LC_' integer
539 category_to_category_mask (SCM category
,
540 const char *func_name
, int pos
)
545 c_category
= scm_to_int (category
);
547 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
549 c_category_mask = SCM_LOCALE_CATEGORY_MASK (_name); \
554 #include "locale-categories.h"
557 c_category_mask
= LC_ALL_MASK
;
561 scm_wrong_type_arg_msg (func_name
, pos
, category
,
565 #undef SCM_DEFINE_LOCALE_CATEGORY
567 return c_category_mask
;
570 /* Convert CATEGORIES, a list of locale categories or a single category (an
571 integer), into a category mask. */
573 category_list_to_category_mask (SCM categories
,
574 const char *func_name
, int pos
)
576 int c_category_mask
= 0;
578 if (scm_is_integer (categories
))
579 c_category_mask
= category_to_category_mask (categories
,
582 for (; !scm_is_null (categories
); categories
= SCM_CDR (categories
))
584 SCM category
= SCM_CAR (categories
);
587 category_to_category_mask (category
, func_name
, pos
);
590 return c_category_mask
;
594 SCM_DEFINE (scm_make_locale
, "make-locale", 2, 1, 0,
595 (SCM category_list
, SCM locale_name
, SCM base_locale
),
596 "Return a reference to a data structure representing a set of "
597 "locale datasets. @var{category_list} should be either a list "
598 "of locale categories or a single category as used with "
599 "@code{setlocale} (@pxref{Locales, @code{setlocale}}) and "
600 "@var{locale_name} should be the name of the locale considered "
601 "(e.g., @code{\"sl_SI\"}). Optionally, if @code{base_locale} is "
602 "passed, it should be a locale object denoting settings for "
603 "categories not listed in @var{category_list}.")
604 #define FUNC_NAME s_scm_make_locale
606 SCM locale
= SCM_BOOL_F
;
610 scm_t_locale c_base_locale
, c_locale
;
612 SCM_MAKE_VALIDATE (1, category_list
, LIST_OR_INTEGER_P
);
613 SCM_VALIDATE_STRING (2, locale_name
);
614 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, base_locale
, c_base_locale
);
616 c_category_mask
= category_list_to_category_mask (category_list
,
618 c_locale_name
= scm_to_locale_string (locale_name
);
620 #ifdef USE_GNU_LOCALE_API
622 if (scm_is_eq (base_locale
, SCM_VARIABLE_REF (scm_global_locale
)))
623 c_base_locale
= LC_GLOBAL_LOCALE
;
625 if (c_base_locale
!= (locale_t
) 0)
627 /* C_BASE_LOCALE is to be consumed by `newlocale ()' so it needs to be
628 duplicated before. */
629 c_base_locale
= duplocale (c_base_locale
);
631 if (c_base_locale
== (locale_t
) 0)
638 c_locale
= newlocale (c_category_mask
, c_locale_name
, c_base_locale
);
640 free (c_locale_name
);
641 c_locale_name
= NULL
;
643 if (c_locale
== (locale_t
) 0)
645 if (c_base_locale
!= (locale_t
) 0)
646 freelocale (c_base_locale
);
647 scm_locale_error (FUNC_NAME
, errno
);
650 SCM_NEWSMOB (locale
, scm_tc16_locale_smob_type
, c_locale
);
654 c_locale
= scm_gc_malloc (sizeof (* c_locale
), "locale");
656 c_locale
->category_mask
= c_category_mask
;
657 c_locale
->locale_name
= scm_gc_strdup (c_locale_name
, "locale");
658 free (c_locale_name
);
659 c_locale_name
= NULL
;
661 if (scm_is_eq (base_locale
, SCM_VARIABLE_REF (scm_global_locale
)))
663 /* Get the current locale settings and turn them into a locale
665 err
= get_current_locale (&base_locale
);
670 c_locale
->base_locale
= base_locale
;
673 /* Try out the new locale and raise an exception if it doesn't work. */
675 scm_t_locale_settings prev_locale
;
677 err
= enter_locale_section (c_locale
, &prev_locale
);
683 leave_locale_section (&prev_locale
);
684 SCM_NEWSMOB (locale
, scm_tc16_locale_smob_type
, c_locale
);
688 /* silence gcc's unused variable warning */
689 (void) c_base_locale
;
695 #ifndef USE_GNU_LOCALE_API
696 scm_gc_free (c_locale
, sizeof (* c_locale
), "locale");
698 free (c_locale_name
);
699 scm_locale_error (FUNC_NAME
, err
);
705 SCM_DEFINE (scm_locale_p
, "locale?", 1, 0, 0,
707 "Return true if @var{obj} is a locale object.")
708 #define FUNC_NAME s_scm_locale_p
710 return scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_locale_smob_type
, obj
));
716 /* Locale-dependent string comparison.
718 A similar API can be found in MzScheme starting from version 200:
719 http://download.plt-scheme.org/chronology/mzmr200alpha14.html . */
721 #define SCM_STRING_TO_U32_BUF(s1, c_s1) \
724 if (scm_i_is_narrow_string (s1)) \
727 const char *buf = scm_i_string_chars (s1); \
729 len = scm_i_string_length (s1); \
730 c_s1 = alloca (sizeof (scm_t_wchar) * (len + 1)); \
732 for (i = 0; i < len; i ++) \
733 c_s1[i] = (unsigned char ) buf[i]; \
737 c_s1 = (scm_t_wchar *) scm_i_string_wide_chars (s1); \
741 /* Compare UTF-32 strings according to LOCALE. Returns a negative value if
742 S1 compares smaller than S2, a positive value if S1 compares larger than
743 S2, or 0 if they compare equal. */
745 compare_u32_strings (SCM s1
, SCM s2
, SCM locale
, const char *func_name
)
746 #define FUNC_NAME func_name
749 scm_t_locale c_locale
;
750 scm_t_wchar
*c_s1
, *c_s2
;
751 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale
, c_locale
);
753 SCM_STRING_TO_U32_BUF (s1
, c_s1
);
754 SCM_STRING_TO_U32_BUF (s2
, c_s2
);
757 RUN_IN_LOCALE_SECTION (c_locale
,
758 result
= u32_strcoll ((const scm_t_uint32
*) c_s1
,
759 (const scm_t_uint32
*) c_s2
));
761 result
= u32_strcoll ((const scm_t_uint32
*) c_s1
,
762 (const scm_t_uint32
*) c_s2
);
764 scm_remember_upto_here_2 (s1
, s2
);
765 scm_remember_upto_here (locale
);
770 /* Return the current language of the locale. */
774 /* Note: If the locale has been set with 'uselocale', uc_locale_language
775 from libunistring versions 0.9.1 and older will return the incorrect
776 (non-thread-specific) locale. This is fixed in versions 0.9.2 and
778 return uc_locale_language ();
782 u32_locale_casecoll (const char *func_name
, const scm_t_uint32
*c_s1
,
783 const scm_t_uint32
*c_s2
,
786 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must note
787 make any non-local exit. */
790 const char *loc
= locale_language ();
792 ret
= u32_casecoll (c_s1
, u32_strlen (c_s1
),
793 c_s2
, u32_strlen (c_s2
),
794 loc
, UNINORM_NFC
, result
);
796 return ret
== 0 ? ret
: errno
;
800 compare_u32_strings_ci (SCM s1
, SCM s2
, SCM locale
, const char *func_name
)
801 #define FUNC_NAME func_name
804 scm_t_locale c_locale
;
805 scm_t_wchar
*c_s1
, *c_s2
;
806 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale
, c_locale
);
808 SCM_STRING_TO_U32_BUF (s1
, c_s1
);
809 SCM_STRING_TO_U32_BUF (s2
, c_s2
);
812 RUN_IN_LOCALE_SECTION
814 ret
= u32_locale_casecoll (func_name
,
815 (const scm_t_uint32
*) c_s1
,
816 (const scm_t_uint32
*) c_s2
,
819 ret
= u32_locale_casecoll (func_name
,
820 (const scm_t_uint32
*) c_s1
,
821 (const scm_t_uint32
*) c_s2
,
824 if (SCM_UNLIKELY (ret
!= 0))
827 scm_syserror (FUNC_NAME
);
830 scm_remember_upto_here_2 (s1
, s2
);
831 scm_remember_upto_here (locale
);
837 /* Store into DST an upper-case version of SRC. */
839 str_upcase (register char *dst
, register const char *src
)
841 for (; *src
!= '\0'; src
++, dst
++)
842 *dst
= toupper ((int) *src
);
847 str_downcase (register char *dst
, register const char *src
)
849 for (; *src
!= '\0'; src
++, dst
++)
850 *dst
= tolower ((int) *src
);
854 #ifdef USE_GNU_LOCALE_API
856 str_upcase_l (register char *dst
, register const char *src
,
859 for (; *src
!= '\0'; src
++, dst
++)
860 *dst
= toupper_l (*src
, locale
);
865 str_downcase_l (register char *dst
, register const char *src
,
868 for (; *src
!= '\0'; src
++, dst
++)
869 *dst
= tolower_l (*src
, locale
);
875 SCM_DEFINE (scm_string_locale_lt
, "string-locale<?", 2, 1, 0,
876 (SCM s1
, SCM s2
, SCM locale
),
877 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
878 "If @var{locale} is provided, it should be locale object (as "
879 "returned by @code{make-locale}) and will be used to perform the "
880 "comparison; otherwise, the current system locale is used.")
881 #define FUNC_NAME s_scm_string_locale_lt
885 SCM_VALIDATE_STRING (1, s1
);
886 SCM_VALIDATE_STRING (2, s2
);
888 result
= compare_u32_strings (s1
, s2
, locale
, FUNC_NAME
);
890 return scm_from_bool (result
< 0);
894 SCM_DEFINE (scm_string_locale_gt
, "string-locale>?", 2, 1, 0,
895 (SCM s1
, SCM s2
, SCM locale
),
896 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
897 "If @var{locale} is provided, it should be locale object (as "
898 "returned by @code{make-locale}) and will be used to perform the "
899 "comparison; otherwise, the current system locale is used.")
900 #define FUNC_NAME s_scm_string_locale_gt
904 SCM_VALIDATE_STRING (1, s1
);
905 SCM_VALIDATE_STRING (2, s2
);
907 result
= compare_u32_strings (s1
, s2
, locale
, FUNC_NAME
);
909 return scm_from_bool (result
> 0);
913 SCM_DEFINE (scm_string_locale_ci_lt
, "string-locale-ci<?", 2, 1, 0,
914 (SCM s1
, SCM s2
, SCM locale
),
915 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
916 "and locale-dependent way. If @var{locale} is provided, it "
917 "should be locale object (as returned by @code{make-locale}) "
918 "and will be used to perform the comparison; otherwise, the "
919 "current system locale is used.")
920 #define FUNC_NAME s_scm_string_locale_ci_lt
924 SCM_VALIDATE_STRING (1, s1
);
925 SCM_VALIDATE_STRING (2, s2
);
927 result
= compare_u32_strings_ci (s1
, s2
, locale
, FUNC_NAME
);
929 return scm_from_bool (result
< 0);
933 SCM_DEFINE (scm_string_locale_ci_gt
, "string-locale-ci>?", 2, 1, 0,
934 (SCM s1
, SCM s2
, SCM locale
),
935 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
936 "and locale-dependent way. If @var{locale} is provided, it "
937 "should be locale object (as returned by @code{make-locale}) "
938 "and will be used to perform the comparison; otherwise, the "
939 "current system locale is used.")
940 #define FUNC_NAME s_scm_string_locale_ci_gt
944 SCM_VALIDATE_STRING (1, s1
);
945 SCM_VALIDATE_STRING (2, s2
);
947 result
= compare_u32_strings_ci (s1
, s2
, locale
, FUNC_NAME
);
949 return scm_from_bool (result
> 0);
953 SCM_DEFINE (scm_string_locale_ci_eq
, "string-locale-ci=?", 2, 1, 0,
954 (SCM s1
, SCM s2
, SCM locale
),
955 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
956 "and locale-dependent way. If @var{locale} is provided, it "
957 "should be locale object (as returned by @code{make-locale}) "
958 "and will be used to perform the comparison; otherwise, the "
959 "current system locale is used.")
960 #define FUNC_NAME s_scm_string_locale_ci_eq
964 SCM_VALIDATE_STRING (1, s1
);
965 SCM_VALIDATE_STRING (2, s2
);
967 result
= compare_u32_strings_ci (s1
, s2
, locale
, FUNC_NAME
);
969 return scm_from_bool (result
== 0);
974 SCM_DEFINE (scm_char_locale_lt
, "char-locale<?", 2, 1, 0,
975 (SCM c1
, SCM c2
, SCM locale
),
976 "Return true if character @var{c1} is lower than @var{c2} "
977 "according to @var{locale} or to the current locale.")
978 #define FUNC_NAME s_scm_char_locale_lt
982 SCM_VALIDATE_CHAR (1, c1
);
983 SCM_VALIDATE_CHAR (2, c2
);
985 result
= compare_u32_strings (scm_string (scm_list_1 (c1
)),
986 scm_string (scm_list_1 (c2
)),
989 return scm_from_bool (result
< 0);
993 SCM_DEFINE (scm_char_locale_gt
, "char-locale>?", 2, 1, 0,
994 (SCM c1
, SCM c2
, SCM locale
),
995 "Return true if character @var{c1} is greater than @var{c2} "
996 "according to @var{locale} or to the current locale.")
997 #define FUNC_NAME s_scm_char_locale_gt
1001 SCM_VALIDATE_CHAR (1, c1
);
1002 SCM_VALIDATE_CHAR (2, c2
);
1004 result
= compare_u32_strings (scm_string (scm_list_1 (c1
)),
1005 scm_string (scm_list_1 (c2
)),
1008 return scm_from_bool (result
> 0);
1012 SCM_DEFINE (scm_char_locale_ci_lt
, "char-locale-ci<?", 2, 1, 0,
1013 (SCM c1
, SCM c2
, SCM locale
),
1014 "Return true if character @var{c1} is lower than @var{c2}, "
1015 "in a case insensitive way according to @var{locale} or to "
1016 "the current locale.")
1017 #define FUNC_NAME s_scm_char_locale_ci_lt
1021 SCM_VALIDATE_CHAR (1, c1
);
1022 SCM_VALIDATE_CHAR (2, c2
);
1024 result
= compare_u32_strings_ci (scm_string (scm_list_1 (c1
)),
1025 scm_string (scm_list_1 (c2
)),
1028 return scm_from_bool (result
< 0);
1032 SCM_DEFINE (scm_char_locale_ci_gt
, "char-locale-ci>?", 2, 1, 0,
1033 (SCM c1
, SCM c2
, SCM locale
),
1034 "Return true if character @var{c1} is greater than @var{c2}, "
1035 "in a case insensitive way according to @var{locale} or to "
1036 "the current locale.")
1037 #define FUNC_NAME s_scm_char_locale_ci_gt
1041 SCM_VALIDATE_CHAR (1, c1
);
1042 SCM_VALIDATE_CHAR (2, c2
);
1044 result
= compare_u32_strings_ci (scm_string (scm_list_1 (c1
)),
1045 scm_string (scm_list_1 (c2
)),
1048 return scm_from_bool (result
> 0);
1052 SCM_DEFINE (scm_char_locale_ci_eq
, "char-locale-ci=?", 2, 1, 0,
1053 (SCM c1
, SCM c2
, SCM locale
),
1054 "Return true if character @var{c1} is equal to @var{c2}, "
1055 "in a case insensitive way according to @var{locale} or to "
1056 "the current locale.")
1057 #define FUNC_NAME s_scm_char_locale_ci_eq
1061 SCM_VALIDATE_CHAR (1, c1
);
1062 SCM_VALIDATE_CHAR (2, c2
);
1064 result
= compare_u32_strings_ci (scm_string (scm_list_1 (c1
)),
1065 scm_string (scm_list_1 (c2
)),
1068 return scm_from_bool (result
== 0);
1074 /* Locale-dependent alphabetic character mapping. */
1077 u32_locale_tocase (const scm_t_uint32
*c_s1
, size_t len
,
1078 scm_t_uint32
**p_c_s2
, size_t * p_len2
,
1079 scm_t_uint32
*(*func
) (const scm_t_uint32
*, size_t,
1080 const char *, uninorm_t
,
1081 scm_t_uint32
*, size_t *))
1083 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must not
1084 make any non-local exit. */
1087 const char *loc
= locale_language ();
1089 /* The first NULL here indicates that no NFC or NFKC normalization
1090 is done. The second NULL means the return buffer is
1092 ret
= func (c_s1
, len
, loc
, NULL
, NULL
, p_len2
);
1096 *p_c_s2
= (scm_t_uint32
*) NULL
;
1107 chr_to_case (SCM chr
, scm_t_locale c_locale
,
1108 scm_t_uint32
*(*func
) (const scm_t_uint32
*, size_t, const char *,
1109 uninorm_t
, scm_t_uint32
*, size_t *),
1110 const char *func_name
,
1112 #define FUNC_NAME func_name
1116 scm_t_uint32
*convbuf
;
1122 if (c_locale
!= NULL
)
1123 RUN_IN_LOCALE_SECTION (c_locale
, ret
=
1124 u32_locale_tocase (&c
, 1, &convbuf
, &convlen
, func
));
1127 u32_locale_tocase (&c
, 1, &convbuf
, &convlen
, func
);
1129 if (SCM_UNLIKELY (ret
!= 0))
1136 convchar
= SCM_MAKE_CHAR ((scm_t_wchar
) convbuf
[0]);
1145 SCM_DEFINE (scm_char_locale_downcase
, "char-locale-downcase", 1, 1, 0,
1146 (SCM chr
, SCM locale
),
1147 "Return the lowercase character that corresponds to @var{chr} "
1148 "according to either @var{locale} or the current locale.")
1149 #define FUNC_NAME s_scm_char_locale_downcase
1151 scm_t_locale c_locale
;
1155 SCM_VALIDATE_CHAR (1, chr
);
1156 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1158 ret
= chr_to_case (chr
, c_locale
, u32_tolower
, FUNC_NAME
, &err
);
1163 scm_syserror (FUNC_NAME
);
1169 SCM_DEFINE (scm_char_locale_upcase
, "char-locale-upcase", 1, 1, 0,
1170 (SCM chr
, SCM locale
),
1171 "Return the uppercase character that corresponds to @var{chr} "
1172 "according to either @var{locale} or the current locale.")
1173 #define FUNC_NAME s_scm_char_locale_upcase
1175 scm_t_locale c_locale
;
1179 SCM_VALIDATE_CHAR (1, chr
);
1180 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1182 ret
= chr_to_case (chr
, c_locale
, u32_toupper
, FUNC_NAME
, &err
);
1187 scm_syserror (FUNC_NAME
);
1193 SCM_DEFINE (scm_char_locale_titlecase
, "char-locale-titlecase", 1, 1, 0,
1194 (SCM chr
, SCM locale
),
1195 "Return the titlecase character that corresponds to @var{chr} "
1196 "according to either @var{locale} or the current locale.")
1197 #define FUNC_NAME s_scm_char_locale_titlecase
1199 scm_t_locale c_locale
;
1203 SCM_VALIDATE_CHAR (1, chr
);
1204 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1206 ret
= chr_to_case (chr
, c_locale
, u32_totitle
, FUNC_NAME
, &err
);
1211 scm_syserror (FUNC_NAME
);
1218 str_to_case (SCM str
, scm_t_locale c_locale
,
1219 scm_t_uint32
*(*func
) (const scm_t_uint32
*, size_t, const char *,
1220 uninorm_t
, scm_t_uint32
*, size_t *),
1221 const char *func_name
,
1223 #define FUNC_NAME func_name
1225 scm_t_wchar
*c_str
, *c_buf
;
1226 scm_t_uint32
*c_convstr
;
1227 size_t len
, convlen
;
1231 len
= scm_i_string_length (str
);
1234 SCM_STRING_TO_U32_BUF (str
, c_str
);
1237 RUN_IN_LOCALE_SECTION (c_locale
, ret
=
1238 u32_locale_tocase ((scm_t_uint32
*) c_str
, len
,
1243 u32_locale_tocase ((scm_t_uint32
*) c_str
, len
,
1244 &c_convstr
, &convlen
, func
);
1246 scm_remember_upto_here (str
);
1248 if (SCM_UNLIKELY (ret
!= 0))
1254 convstr
= scm_i_make_wide_string (convlen
, &c_buf
, 0);
1255 memcpy (c_buf
, c_convstr
, convlen
* sizeof (scm_t_wchar
));
1258 scm_i_try_narrow_string (convstr
);
1264 SCM_DEFINE (scm_string_locale_upcase
, "string-locale-upcase", 1, 1, 0,
1265 (SCM str
, SCM locale
),
1266 "Return a new string that is the uppercase version of "
1267 "@var{str} according to either @var{locale} or the current "
1269 #define FUNC_NAME s_scm_string_locale_upcase
1271 scm_t_locale c_locale
;
1275 SCM_VALIDATE_STRING (1, str
);
1276 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1278 ret
= str_to_case (str
, c_locale
, u32_toupper
, FUNC_NAME
, &err
);
1283 scm_syserror (FUNC_NAME
);
1289 SCM_DEFINE (scm_string_locale_downcase
, "string-locale-downcase", 1, 1, 0,
1290 (SCM str
, SCM locale
),
1291 "Return a new string that is the down-case version of "
1292 "@var{str} according to either @var{locale} or the current "
1294 #define FUNC_NAME s_scm_string_locale_downcase
1296 scm_t_locale c_locale
;
1300 SCM_VALIDATE_STRING (1, str
);
1301 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1303 ret
= str_to_case (str
, c_locale
, u32_tolower
, FUNC_NAME
, &err
);
1308 scm_syserror (FUNC_NAME
);
1314 SCM_DEFINE (scm_string_locale_titlecase
, "string-locale-titlecase", 1, 1, 0,
1315 (SCM str
, SCM locale
),
1316 "Return a new string that is the title-case version of "
1317 "@var{str} according to either @var{locale} or the current "
1319 #define FUNC_NAME s_scm_string_locale_titlecase
1321 scm_t_locale c_locale
;
1325 SCM_VALIDATE_STRING (1, str
);
1326 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1328 ret
= str_to_case (str
, c_locale
, u32_totitle
, FUNC_NAME
, &err
);
1333 scm_syserror (FUNC_NAME
);
1339 /* Note: We don't provide mutative versions of `string-locale-(up|down)case'
1340 because, in some languages, a single downcase character maps to a couple
1341 of uppercase characters. Read the SRFI-13 document for a detailed
1342 discussion about this. */
1346 /* Locale-dependent number parsing. */
1348 SCM_DEFINE (scm_locale_string_to_integer
, "locale-string->integer",
1349 1, 2, 0, (SCM str
, SCM base
, SCM locale
),
1350 "Convert string @var{str} into an integer according to either "
1351 "@var{locale} (a locale object as returned by @code{make-locale}) "
1352 "or the current process locale. Return two values: an integer "
1353 "(on success) or @code{#f}, and the number of characters read "
1354 "from @var{str} (@code{0} on failure).")
1355 #define FUNC_NAME s_scm_locale_string_to_integer
1362 scm_t_locale c_locale
;
1364 SCM_VALIDATE_STRING (1, str
);
1365 c_str
= scm_i_string_chars (str
);
1367 if (!scm_is_eq (base
, SCM_UNDEFINED
))
1368 SCM_VALIDATE_INT_COPY (2, base
, c_base
);
1372 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale
, c_locale
);
1374 if (c_locale
!= NULL
)
1376 #ifdef USE_GNU_LOCALE_API
1377 c_result
= strtol_l (c_str
, &c_endptr
, c_base
, c_locale
);
1379 RUN_IN_LOCALE_SECTION (c_locale
,
1380 c_result
= strtol (c_str
, &c_endptr
, c_base
));
1384 c_result
= strtol (c_str
, &c_endptr
, c_base
);
1386 scm_remember_upto_here (str
);
1388 if (c_endptr
== c_str
)
1389 result
= SCM_BOOL_F
;
1391 result
= scm_from_long (c_result
);
1393 return (scm_values (scm_list_2 (result
, scm_from_long (c_endptr
- c_str
))));
1397 SCM_DEFINE (scm_locale_string_to_inexact
, "locale-string->inexact",
1398 1, 1, 0, (SCM str
, SCM locale
),
1399 "Convert string @var{str} into an inexact number according to "
1400 "either @var{locale} (a locale object as returned by "
1401 "@code{make-locale}) or the current process locale. Return "
1402 "two values: an inexact number (on success) or @code{#f}, and "
1403 "the number of characters read from @var{str} (@code{0} on "
1405 #define FUNC_NAME s_scm_locale_string_to_inexact
1411 scm_t_locale c_locale
;
1413 SCM_VALIDATE_STRING (1, str
);
1414 c_str
= scm_i_string_chars (str
);
1416 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1418 if (c_locale
!= NULL
)
1420 #ifdef USE_GNU_LOCALE_API
1421 c_result
= strtod_l (c_str
, &c_endptr
, c_locale
);
1423 RUN_IN_LOCALE_SECTION (c_locale
,
1424 c_result
= strtod (c_str
, &c_endptr
));
1428 c_result
= strtod (c_str
, &c_endptr
);
1430 scm_remember_upto_here (str
);
1432 if (c_endptr
== c_str
)
1433 result
= SCM_BOOL_F
;
1435 result
= scm_from_double (c_result
);
1437 return (scm_values (scm_list_2 (result
, scm_from_long (c_endptr
- c_str
))));
1442 /* Language information, aka. `nl_langinfo ()'. */
1444 /* FIXME: Issues related to `nl-langinfo'.
1446 1. The `CODESET' value is not normalized. This is a secondary issue, but
1447 still a practical issue. See
1448 http://www.cl.cam.ac.uk/~mgk25/ucs/norm_charmap.c for codeset
1451 2. `nl_langinfo ()' is not available on Windows.
1453 3. `nl_langinfo ()' may return strings encoded in a locale different from
1457 (nl-langinfo DAY_1 (make-locale LC_ALL "eo_EO.UTF-8"))
1459 returns a result that is a UTF-8 string, regardless of the
1460 setting of the current locale. If nl_langinfo supports CODESET,
1461 we can convert the string properly using scm_from_stringn. If
1462 CODESET is not supported, we won't be able to make much sense of
1463 the returned string.
1465 Note: We don't use Gnulib's `nl_langinfo' module because it's currently not
1466 as complete as the compatibility hacks in `i18n.scm'. */
1469 copy_string_or_null (const char *s
)
1477 SCM_DEFINE (scm_nl_langinfo
, "nl-langinfo", 1, 1, 0,
1478 (SCM item
, SCM locale
),
1479 "Return a string denoting locale information for @var{item} "
1480 "in the current locale or that specified by @var{locale}. "
1481 "The semantics and arguments are the same as those of the "
1482 "X/Open @code{nl_langinfo} function (@pxref{The Elegant and "
1483 "Fast Way, @code{nl_langinfo},, libc, The GNU C Library "
1484 "Reference Manual}).")
1485 #define FUNC_NAME s_scm_nl_langinfo
1490 scm_t_locale c_locale
;
1493 SCM_VALIDATE_INT_COPY (2, item
, c_item
);
1494 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale
, c_locale
);
1496 /* Sadly, `nl_langinfo ()' returns a pointer to a static string. According
1497 to SuS v2, that static string may be modified by subsequent calls to
1498 `nl_langinfo ()' as well as by calls to `setlocale ()'. Thus, we must
1499 acquire the locale mutex before doing invoking `nl_langinfo ()'. See
1500 http://opengroup.org/onlinepubs/007908799/xsh/nl_langinfo.html for
1503 lock_locale_mutex ();
1504 if (c_locale
!= NULL
)
1506 #ifdef USE_GNU_LOCALE_API
1507 c_result
= copy_string_or_null (nl_langinfo_l (c_item
, c_locale
));
1508 codeset
= copy_string_or_null (nl_langinfo_l (CODESET
, c_locale
));
1509 #else /* !USE_GNU_LOCALE_API */
1510 /* We can't use `RUN_IN_LOCALE_SECTION ()' here because the locale
1511 mutex is already taken. */
1513 scm_t_locale_settings lsec_prev_locale
;
1515 lsec_err
= get_current_locale_settings (&lsec_prev_locale
);
1517 unlock_locale_mutex ();
1520 lsec_err
= install_locale (c_locale
);
1523 leave_locale_section (&lsec_prev_locale
);
1524 free_locale_settings (&lsec_prev_locale
);
1529 scm_locale_error (FUNC_NAME
, lsec_err
);
1532 c_result
= copy_string_or_null (nl_langinfo (c_item
));
1533 codeset
= copy_string_or_null (nl_langinfo (CODESET
));
1535 restore_locale_settings (&lsec_prev_locale
);
1536 free_locale_settings (&lsec_prev_locale
);
1542 c_result
= copy_string_or_null (nl_langinfo (c_item
));
1543 codeset
= copy_string_or_null (nl_langinfo (CODESET
));
1546 unlock_locale_mutex ();
1548 if (c_result
== NULL
)
1549 result
= SCM_BOOL_F
;
1554 #if (defined GROUPING) && (defined MON_GROUPING)
1560 /* In this cases, the result is to be interpreted as a list
1561 of numbers. If the last item is `CHAR_MAX' or a negative
1562 number, it has the special meaning "no more grouping"
1563 (negative numbers aren't specified in POSIX but can be
1565 <http://lists.gnu.org/archive/html/bug-guile/2011-02/msg00159.html>). */
1567 for (p
= c_result
; (*p
> 0) && (*p
!= CHAR_MAX
); p
++)
1568 result
= scm_cons (SCM_I_MAKINUM ((int) *p
), result
);
1571 SCM last_pair
= result
;
1573 result
= scm_reverse_x (result
, SCM_EOL
);
1577 /* Cyclic grouping information. */
1578 if (!scm_is_null (last_pair
))
1579 SCM_SETCDR (last_pair
, result
);
1588 #if defined FRAC_DIGITS || defined INT_FRAC_DIGITS
1592 #ifdef INT_FRAC_DIGITS
1593 case INT_FRAC_DIGITS
:
1595 /* This is to be interpreted as a single integer. */
1596 if (*c_result
== CHAR_MAX
)
1598 result
= SCM_BOOL_F
;
1600 result
= SCM_I_MAKINUM (*c_result
);
1606 #if defined P_CS_PRECEDES || defined N_CS_PRECEDES || \
1607 defined INT_P_CS_PRECEDES || defined INT_N_CS_PRECEDES || \
1608 defined P_SEP_BY_SPACE || defined N_SEP_BY_SPACE
1609 #ifdef P_CS_PRECEDES
1613 #ifdef INT_N_CS_PRECEDES
1614 case INT_P_CS_PRECEDES
:
1615 case INT_N_CS_PRECEDES
:
1617 #ifdef P_SEP_BY_SPACE
1618 case P_SEP_BY_SPACE
:
1619 case N_SEP_BY_SPACE
:
1621 /* This is to be interpreted as a boolean. */
1622 result
= scm_from_bool (*c_result
);
1628 #if defined P_SIGN_POSN || defined N_SIGN_POSN || \
1629 defined INT_P_SIGN_POSN || defined INT_N_SIGN_POSN
1634 #ifdef INT_P_SIGN_POSN
1635 case INT_P_SIGN_POSN
:
1636 case INT_N_SIGN_POSN
:
1638 /* See `(libc) Sign of Money Amount' for the interpretation of the
1639 return value here. */
1643 result
= scm_from_latin1_symbol ("parenthesize");
1647 result
= scm_from_latin1_symbol ("sign-before");
1651 result
= scm_from_latin1_symbol ("sign-after");
1655 result
= scm_from_latin1_symbol ("sign-before-currency-symbol");
1659 result
= scm_from_latin1_symbol ("sign-after-currency-symbol");
1663 result
= scm_from_latin1_symbol ("unspecified");
1670 result
= scm_from_stringn (c_result
, strlen (c_result
),
1672 SCM_FAILED_CONVERSION_QUESTION_MARK
);
1677 if (codeset
!= NULL
)
1684 /* Define the `nl_item' constants. */
1686 define_langinfo_items (void)
1688 #define DEFINE_NLITEM_CONSTANT(_item) \
1689 scm_c_define (# _item, scm_from_int (_item))
1691 DEFINE_NLITEM_CONSTANT (CODESET
);
1693 /* Abbreviated days of the week. */
1694 DEFINE_NLITEM_CONSTANT (ABDAY_1
);
1695 DEFINE_NLITEM_CONSTANT (ABDAY_2
);
1696 DEFINE_NLITEM_CONSTANT (ABDAY_3
);
1697 DEFINE_NLITEM_CONSTANT (ABDAY_4
);
1698 DEFINE_NLITEM_CONSTANT (ABDAY_5
);
1699 DEFINE_NLITEM_CONSTANT (ABDAY_6
);
1700 DEFINE_NLITEM_CONSTANT (ABDAY_7
);
1702 /* Long-named days of the week. */
1703 DEFINE_NLITEM_CONSTANT (DAY_1
); /* Sunday */
1704 DEFINE_NLITEM_CONSTANT (DAY_2
); /* Monday */
1705 DEFINE_NLITEM_CONSTANT (DAY_3
); /* Tuesday */
1706 DEFINE_NLITEM_CONSTANT (DAY_4
); /* Wednesday */
1707 DEFINE_NLITEM_CONSTANT (DAY_5
); /* Thursday */
1708 DEFINE_NLITEM_CONSTANT (DAY_6
); /* Friday */
1709 DEFINE_NLITEM_CONSTANT (DAY_7
); /* Saturday */
1711 /* Abbreviated month names. */
1712 DEFINE_NLITEM_CONSTANT (ABMON_1
); /* Jan */
1713 DEFINE_NLITEM_CONSTANT (ABMON_2
);
1714 DEFINE_NLITEM_CONSTANT (ABMON_3
);
1715 DEFINE_NLITEM_CONSTANT (ABMON_4
);
1716 DEFINE_NLITEM_CONSTANT (ABMON_5
);
1717 DEFINE_NLITEM_CONSTANT (ABMON_6
);
1718 DEFINE_NLITEM_CONSTANT (ABMON_7
);
1719 DEFINE_NLITEM_CONSTANT (ABMON_8
);
1720 DEFINE_NLITEM_CONSTANT (ABMON_9
);
1721 DEFINE_NLITEM_CONSTANT (ABMON_10
);
1722 DEFINE_NLITEM_CONSTANT (ABMON_11
);
1723 DEFINE_NLITEM_CONSTANT (ABMON_12
);
1725 /* Long month names. */
1726 DEFINE_NLITEM_CONSTANT (MON_1
); /* January */
1727 DEFINE_NLITEM_CONSTANT (MON_2
);
1728 DEFINE_NLITEM_CONSTANT (MON_3
);
1729 DEFINE_NLITEM_CONSTANT (MON_4
);
1730 DEFINE_NLITEM_CONSTANT (MON_5
);
1731 DEFINE_NLITEM_CONSTANT (MON_6
);
1732 DEFINE_NLITEM_CONSTANT (MON_7
);
1733 DEFINE_NLITEM_CONSTANT (MON_8
);
1734 DEFINE_NLITEM_CONSTANT (MON_9
);
1735 DEFINE_NLITEM_CONSTANT (MON_10
);
1736 DEFINE_NLITEM_CONSTANT (MON_11
);
1737 DEFINE_NLITEM_CONSTANT (MON_12
);
1739 DEFINE_NLITEM_CONSTANT (AM_STR
); /* Ante meridiem string. */
1740 DEFINE_NLITEM_CONSTANT (PM_STR
); /* Post meridiem string. */
1742 DEFINE_NLITEM_CONSTANT (D_T_FMT
); /* Date and time format for strftime. */
1743 DEFINE_NLITEM_CONSTANT (D_FMT
); /* Date format for strftime. */
1744 DEFINE_NLITEM_CONSTANT (T_FMT
); /* Time format for strftime. */
1745 DEFINE_NLITEM_CONSTANT (T_FMT_AMPM
);/* 12-hour time format for strftime. */
1748 DEFINE_NLITEM_CONSTANT (ERA
); /* Alternate era. */
1751 DEFINE_NLITEM_CONSTANT (ERA_D_FMT
); /* Date in alternate era format. */
1754 DEFINE_NLITEM_CONSTANT (ERA_D_T_FMT
); /* Date and time in alternate era
1758 DEFINE_NLITEM_CONSTANT (ERA_T_FMT
); /* Time in alternate era format. */
1762 DEFINE_NLITEM_CONSTANT (ALT_DIGITS
); /* Alternate symbols for digits. */
1764 DEFINE_NLITEM_CONSTANT (RADIXCHAR
);
1765 DEFINE_NLITEM_CONSTANT (THOUSEP
);
1768 DEFINE_NLITEM_CONSTANT (YESEXPR
);
1771 DEFINE_NLITEM_CONSTANT (NOEXPR
);
1774 #ifdef CRNCYSTR /* currency symbol */
1775 DEFINE_NLITEM_CONSTANT (CRNCYSTR
);
1778 /* GNU extensions. */
1781 DEFINE_NLITEM_CONSTANT (ERA_YEAR
); /* Year in alternate era format. */
1784 /* LC_MONETARY category: formatting of monetary quantities.
1785 These items each correspond to a member of `struct lconv',
1786 defined in <locale.h>. */
1787 #ifdef INT_CURR_SYMBOL
1788 DEFINE_NLITEM_CONSTANT (INT_CURR_SYMBOL
);
1790 #ifdef MON_DECIMAL_POINT
1791 DEFINE_NLITEM_CONSTANT (MON_DECIMAL_POINT
);
1793 #ifdef MON_THOUSANDS_SEP
1794 DEFINE_NLITEM_CONSTANT (MON_THOUSANDS_SEP
);
1797 DEFINE_NLITEM_CONSTANT (MON_GROUPING
);
1799 #ifdef POSITIVE_SIGN
1800 DEFINE_NLITEM_CONSTANT (POSITIVE_SIGN
);
1802 #ifdef NEGATIVE_SIGN
1803 DEFINE_NLITEM_CONSTANT (NEGATIVE_SIGN
);
1806 DEFINE_NLITEM_CONSTANT (GROUPING
);
1808 #ifdef INT_FRAC_DIGITS
1809 DEFINE_NLITEM_CONSTANT (INT_FRAC_DIGITS
);
1812 DEFINE_NLITEM_CONSTANT (FRAC_DIGITS
);
1814 #ifdef P_CS_PRECEDES
1815 DEFINE_NLITEM_CONSTANT (P_CS_PRECEDES
);
1817 #ifdef P_SEP_BY_SPACE
1818 DEFINE_NLITEM_CONSTANT (P_SEP_BY_SPACE
);
1820 #ifdef N_CS_PRECEDES
1821 DEFINE_NLITEM_CONSTANT (N_CS_PRECEDES
);
1823 #ifdef N_SEP_BY_SPACE
1824 DEFINE_NLITEM_CONSTANT (N_SEP_BY_SPACE
);
1827 DEFINE_NLITEM_CONSTANT (P_SIGN_POSN
);
1830 DEFINE_NLITEM_CONSTANT (N_SIGN_POSN
);
1832 #ifdef INT_P_CS_PRECEDES
1833 DEFINE_NLITEM_CONSTANT (INT_P_CS_PRECEDES
);
1835 #ifdef INT_P_SEP_BY_SPACE
1836 DEFINE_NLITEM_CONSTANT (INT_P_SEP_BY_SPACE
);
1838 #ifdef INT_N_CS_PRECEDES
1839 DEFINE_NLITEM_CONSTANT (INT_N_CS_PRECEDES
);
1841 #ifdef INT_N_SEP_BY_SPACE
1842 DEFINE_NLITEM_CONSTANT (INT_N_SEP_BY_SPACE
);
1844 #ifdef INT_P_SIGN_POSN
1845 DEFINE_NLITEM_CONSTANT (INT_P_SIGN_POSN
);
1847 #ifdef INT_N_SIGN_POSN
1848 DEFINE_NLITEM_CONSTANT (INT_N_SIGN_POSN
);
1851 #undef DEFINE_NLITEM_CONSTANT
1858 SCM global_locale_smob
;
1860 scm_add_feature ("nl-langinfo");
1861 define_langinfo_items ();
1863 #include "libguile/i18n.x"
1865 /* Initialize the global locale object with a special `locale' SMOB. */
1866 /* XXX: We don't define it as `LC_GLOBAL_LOCALE' because of bugs as of
1867 glibc <= 2.11 not (yet) worked around by Gnulib. See
1868 http://sourceware.org/bugzilla/show_bug.cgi?id=11009 for details. */
1869 SCM_NEWSMOB (global_locale_smob
, scm_tc16_locale_smob_type
, NULL
);
1870 SCM_VARIABLE_SET (scm_global_locale
, global_locale_smob
);
1874 scm_bootstrap_i18n ()
1876 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION
,
1878 (scm_t_extension_init_func
) scm_init_i18n
,