i18n: Don't use `!=' to compare SCMs.
[bpt/guile.git] / libguile / i18n.c
CommitLineData
4a655e50 1/* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
9361f762
MV
2 *
3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
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.
9361f762 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
9361f762
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
9361f762
MV
17 */
18
dbb605f5 19#ifdef HAVE_CONFIG_H
9361f762
MV
20# include <config.h>
21#endif
22
f7439099 23#include <alloca.h>
b89c4943 24
9361f762 25#include "libguile/_scm.h"
756e8a3a 26#include "libguile/extensions.h"
9361f762
MV
27#include "libguile/feature.h"
28#include "libguile/i18n.h"
29#include "libguile/strings.h"
b89c4943 30#include "libguile/chars.h"
9361f762 31#include "libguile/dynwind.h"
b89c4943
LC
32#include "libguile/validate.h"
33#include "libguile/values.h"
a2f00b9b 34#include "libguile/threads.h"
9361f762 35
9361f762 36#include <locale.h>
b89c4943
LC
37#include <string.h> /* `strcoll ()' */
38#include <ctype.h> /* `toupper ()' et al. */
39#include <errno.h>
5b878445
MG
40#include <unicase.h>
41#include <unistr.h>
9361f762 42
b89c4943 43#if (defined HAVE_NEWLOCALE) && (defined HAVE_STRCOLL_L)
a2f00b9b
LC
44/* The GNU thread-aware locale API is documented in ``Thread-Aware Locale
45 Model, a Proposal'', by Ulrich Drepper:
46
47 http://people.redhat.com/drepper/tllocale.ps.gz
48
49 It is now also implemented by Darwin:
50
51 http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/newlocale.3.html
52
83fda470
LC
53 The whole API was eventually standardized in the ``Open Group Base
54 Specifications Issue 7'' (aka. "POSIX 2008"):
55
56 http://www.opengroup.org/onlinepubs/9699919799/basedefs/locale.h.html */
b89c4943 57# define USE_GNU_LOCALE_API
9361f762 58#endif
b89c4943 59
a2f00b9b
LC
60#include "libguile/posix.h" /* for `scm_i_locale_mutex' */
61
56d288b8 62#ifdef HAVE_LANGINFO_H
a2f00b9b 63# include <langinfo.h>
56d288b8
LC
64#endif
65#ifdef HAVE_NL_TYPES_H
a2f00b9b 66# include <nl_types.h>
9361f762 67#endif
56d288b8
LC
68#ifndef HAVE_NL_ITEM
69/* Cygwin has <langinfo.h> but lacks <nl_types.h> and `nl_item'. */
70typedef int nl_item;
71#endif
b89c4943
LC
72
73#ifndef HAVE_SETLOCALE
74static inline char *
75setlocale (int category, const char *name)
76{
77 errno = ENOSYS;
78 return NULL;
79}
9361f762 80#endif
b89c4943 81
a2f00b9b
LC
82/* Helper stringification macro. */
83#define SCM_I18N_STRINGIFY(_name) # _name
84
073167ef
LC
85/* Acquiring and releasing the locale lock. */
86
87static inline void
88lock_locale_mutex (void)
89{
90#ifdef HAVE_POSIX
91 scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
92#else
93#endif
94}
95
96static inline void
97unlock_locale_mutex (void)
98{
99#ifdef HAVE_POSIX
100 scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
101#else
102#endif
103}
b89c4943
LC
104
105\f
106/* Locale objects, string and character collation, and other locale-dependent
107 string operations.
108
109 A large part of the code here deals with emulating glibc's reentrant
110 locale API on non-GNU systems. The emulation is a bit "brute-force":
111 Whenever a `-locale<?' procedure is passed a locale object, then:
112
a2f00b9b 113 1. The `scm_i_locale_mutex' is locked.
b89c4943 114 2. A series of `setlocale ()' call is performed to store the current
a2f00b9b 115 locale for each category in an `scm_t_locale' object.
b89c4943
LC
116 3. A series of `setlocale ()' call is made to install each of the locale
117 categories of each of the base locales of each locale object,
118 recursively, starting from the last locale object of the chain.
119 4. The settings captured in step (2) are restored.
a2f00b9b 120 5. The `scm_i_locale_mutex' is released.
b89c4943 121
a2f00b9b 122 Hopefully, the X/Open standard will eventually make this hack useless.
b89c4943
LC
123
124 Note: We don't wrap glibc's `uselocale ()' call because it sets the locale
125 of the current _thread_ (unlike `setlocale ()') and doing so would require
126 maintaining per-thread locale information on non-GNU systems and always
127 re-installing this locale upon locale-dependent calls. */
128
129
a2f00b9b
LC
130/* Return the category mask corresponding to CAT. */
131#define SCM_LOCALE_CATEGORY_MASK(_cat) LC_ ## _cat ## _MASK
132
133
b89c4943
LC
134#ifndef USE_GNU_LOCALE_API
135
a2f00b9b
LC
136/* Provide the locale category masks as found in glibc. This must be kept in
137 sync with `locale-categories.h'. */
b89c4943 138
a2f00b9b
LC
139# define LC_CTYPE_MASK 1
140# define LC_COLLATE_MASK 2
141# define LC_MESSAGES_MASK 4
142# define LC_MONETARY_MASK 8
143# define LC_NUMERIC_MASK 16
144# define LC_TIME_MASK 32
b89c4943
LC
145
146# ifdef LC_PAPER
a2f00b9b 147# define LC_PAPER_MASK 64
b89c4943
LC
148# else
149# define LC_PAPER_MASK 0
150# endif
151# ifdef LC_NAME
a2f00b9b 152# define LC_NAME_MASK 128
b89c4943
LC
153# else
154# define LC_NAME_MASK 0
155# endif
156# ifdef LC_ADDRESS
a2f00b9b 157# define LC_ADDRESS_MASK 256
b89c4943
LC
158# else
159# define LC_ADDRESS_MASK 0
160# endif
161# ifdef LC_TELEPHONE
a2f00b9b 162# define LC_TELEPHONE_MASK 512
b89c4943
LC
163# else
164# define LC_TELEPHONE_MASK 0
165# endif
166# ifdef LC_MEASUREMENT
a2f00b9b 167# define LC_MEASUREMENT_MASK 1024
b89c4943
LC
168# else
169# define LC_MEASUREMENT_MASK 0
170# endif
171# ifdef LC_IDENTIFICATION
a2f00b9b 172# define LC_IDENTIFICATION_MASK 2048
b89c4943
LC
173# else
174# define LC_IDENTIFICATION_MASK 0
175# endif
176
a2f00b9b
LC
177# define LC_ALL_MASK (LC_CTYPE_MASK \
178 | LC_NUMERIC_MASK \
179 | LC_TIME_MASK \
180 | LC_COLLATE_MASK \
181 | LC_MONETARY_MASK \
182 | LC_MESSAGES_MASK \
183 | LC_PAPER_MASK \
184 | LC_NAME_MASK \
185 | LC_ADDRESS_MASK \
186 | LC_TELEPHONE_MASK \
187 | LC_MEASUREMENT_MASK \
188 | LC_IDENTIFICATION_MASK \
b89c4943
LC
189 )
190
191/* Locale objects as returned by `make-locale' on non-GNU systems. */
192typedef struct scm_locale
193{
194 SCM base_locale; /* a `locale' object */
195 char *locale_name;
196 int category_mask;
197} *scm_t_locale;
198
a2f00b9b
LC
199
200/* Free the resources used by LOCALE. */
201static inline void
202scm_i_locale_free (scm_t_locale locale)
203{
204 free (locale->locale_name);
205 locale->locale_name = NULL;
206}
207
208#else /* USE_GNU_LOCALE_API */
b89c4943
LC
209
210/* Alias for glibc's locale type. */
211typedef locale_t scm_t_locale;
212
a2f00b9b
LC
213#define scm_i_locale_free freelocale
214
215#endif /* USE_GNU_LOCALE_API */
216
217
218/* A locale object denoting the global locale. */
219SCM_GLOBAL_VARIABLE (scm_global_locale, "%global-locale");
220
b89c4943
LC
221
222/* Validate parameter ARG as a locale object and set C_LOCALE to the
223 corresponding C locale object. */
224#define SCM_VALIDATE_LOCALE_COPY(_pos, _arg, _c_locale) \
225 do \
226 { \
227 SCM_VALIDATE_SMOB ((_pos), (_arg), locale_smob_type); \
228 (_c_locale) = (scm_t_locale)SCM_SMOB_DATA (_arg); \
229 } \
230 while (0)
231
232/* Validate optional parameter ARG as either undefined or bound to a locale
233 object. Set C_LOCALE to the corresponding C locale object or NULL. */
234#define SCM_VALIDATE_OPTIONAL_LOCALE_COPY(_pos, _arg, _c_locale) \
235 do \
236 { \
d223c3fc 237 if (!scm_is_eq ((_arg), SCM_UNDEFINED)) \
b89c4943
LC
238 SCM_VALIDATE_LOCALE_COPY (_pos, _arg, _c_locale); \
239 else \
240 (_c_locale) = NULL; \
241 } \
242 while (0)
243
244
245SCM_SMOB (scm_tc16_locale_smob_type, "locale", 0);
246
247SCM_SMOB_FREE (scm_tc16_locale_smob_type, smob_locale_free, locale)
248{
249 scm_t_locale c_locale;
250
a2f00b9b
LC
251 c_locale = (scm_t_locale) SCM_SMOB_DATA (locale);
252 scm_i_locale_free (c_locale);
b89c4943
LC
253
254 return 0;
255}
256
9361f762 257
a2f00b9b 258static void inline scm_locale_error (const char *, int) SCM_NORETURN;
b89c4943 259
a2f00b9b
LC
260/* Throw an exception corresponding to error ERR. */
261static void inline
262scm_locale_error (const char *func_name, int err)
263{
264 scm_syserror_msg (func_name,
265 "Failed to install locale",
266 SCM_EOL, err);
b89c4943 267}
b89c4943
LC
268
269
270\f
a2f00b9b
LC
271/* Emulating GNU's reentrant locale API. */
272#ifndef USE_GNU_LOCALE_API
b89c4943
LC
273
274
275/* Maximum number of chained locales (via `base_locale'). */
276#define LOCALE_STACK_SIZE_MAX 256
277
278typedef struct
279{
280#define SCM_DEFINE_LOCALE_CATEGORY(_name) char * _name;
281#include "locale-categories.h"
282#undef SCM_DEFINE_LOCALE_CATEGORY
283} scm_t_locale_settings;
284
285/* Fill out SETTINGS according to the current locale settings. On success
286 zero is returned and SETTINGS is properly initialized. */
287static int
288get_current_locale_settings (scm_t_locale_settings *settings)
289{
290 const char *locale_name;
291
292#define SCM_DEFINE_LOCALE_CATEGORY(_name) \
293 { \
294 SCM_SYSCALL (locale_name = setlocale (LC_ ## _name, NULL)); \
a2f00b9b 295 if (locale_name == NULL) \
b89c4943
LC
296 goto handle_error; \
297 \
298 settings-> _name = strdup (locale_name); \
299 if (settings-> _name == NULL) \
300 goto handle_oom; \
301 }
302
303#include "locale-categories.h"
304#undef SCM_DEFINE_LOCALE_CATEGORY
305
306 return 0;
307
308 handle_error:
a2f00b9b 309 return EINVAL;
9361f762 310
b89c4943
LC
311 handle_oom:
312 return ENOMEM;
313}
314
315/* Restore locale settings SETTINGS. On success, return zero. */
316static int
317restore_locale_settings (const scm_t_locale_settings *settings)
318{
319 const char *result;
320
321#define SCM_DEFINE_LOCALE_CATEGORY(_name) \
322 SCM_SYSCALL (result = setlocale (LC_ ## _name, settings-> _name)); \
323 if (result == NULL) \
324 goto handle_error;
325
326#include "locale-categories.h"
327#undef SCM_DEFINE_LOCALE_CATEGORY
328
329 return 0;
330
331 handle_error:
a2f00b9b 332 return EINVAL;
b89c4943
LC
333}
334
335/* Free memory associated with SETTINGS. */
336static void
337free_locale_settings (scm_t_locale_settings *settings)
338{
339#define SCM_DEFINE_LOCALE_CATEGORY(_name) \
340 free (settings-> _name); \
341 settings->_name = NULL;
342#include "locale-categories.h"
343#undef SCM_DEFINE_LOCALE_CATEGORY
344}
9361f762 345
b89c4943
LC
346/* Install the locale named LOCALE_NAME for all the categories listed in
347 CATEGORY_MASK. */
348static int
349install_locale_categories (const char *locale_name, int category_mask)
350{
351 const char *result;
9361f762 352
b89c4943 353 if (category_mask == LC_ALL_MASK)
9361f762 354 {
b89c4943
LC
355 SCM_SYSCALL (result = setlocale (LC_ALL, locale_name));
356 if (result == NULL)
357 goto handle_error;
9361f762
MV
358 }
359 else
360 {
b89c4943 361#define SCM_DEFINE_LOCALE_CATEGORY(_name) \
a2f00b9b 362 if (category_mask & SCM_LOCALE_CATEGORY_MASK (_name)) \
b89c4943
LC
363 { \
364 SCM_SYSCALL (result = setlocale (LC_ ## _name, locale_name)); \
365 if (result == NULL) \
366 goto handle_error; \
367 }
368#include "locale-categories.h"
369#undef SCM_DEFINE_LOCALE_CATEGORY
370 }
9361f762 371
b89c4943 372 return 0;
9361f762 373
b89c4943 374 handle_error:
a2f00b9b 375 return EINVAL;
b89c4943
LC
376}
377
378/* Install LOCALE, recursively installing its base locales first. On
379 success, zero is returned. */
380static int
381install_locale (scm_t_locale locale)
382{
383 scm_t_locale stack[LOCALE_STACK_SIZE_MAX];
a2f00b9b 384 int category_mask = 0;
b89c4943
LC
385 size_t stack_size = 0;
386 int stack_offset = 0;
387 const char *result = NULL;
388
389 /* Build up a locale stack by traversing the `base_locale' link. */
390 do
391 {
392 if (stack_size >= LOCALE_STACK_SIZE_MAX)
393 /* We cannot use `scm_error ()' here because otherwise the locale
394 mutex may remain locked. */
395 return EINVAL;
396
397 stack[stack_size++] = locale;
398
a2f00b9b
LC
399 /* Keep track of which categories have already been taken into
400 account. */
401 category_mask |= locale->category_mask;
402
e780c14f 403 if (!SCM_UNBNDP (locale->base_locale))
a2f00b9b 404 locale = (scm_t_locale) SCM_SMOB_DATA (locale->base_locale);
9361f762 405 else
b89c4943
LC
406 locale = NULL;
407 }
a2f00b9b 408 while ((locale != NULL) && (category_mask != LC_ALL_MASK));
9361f762 409
b89c4943
LC
410 /* Install the C locale to start from a pristine state. */
411 SCM_SYSCALL (result = setlocale (LC_ALL, "C"));
412 if (result == NULL)
413 goto handle_error;
414
415 /* Install the locales in reverse order. */
416 for (stack_offset = stack_size - 1;
417 stack_offset >= 0;
418 stack_offset--)
419 {
420 int err;
421 scm_t_locale locale;
422
423 locale = stack[stack_offset];
424 err = install_locale_categories (locale->locale_name,
425 locale->category_mask);
426 if (err)
427 goto handle_error;
9361f762
MV
428 }
429
b89c4943 430 return 0;
9361f762 431
b89c4943 432 handle_error:
a2f00b9b 433 return EINVAL;
9361f762 434}
9361f762 435
b89c4943
LC
436/* Leave the locked locale section. */
437static inline void
438leave_locale_section (const scm_t_locale_settings *settings)
439{
440 /* Restore the previous locale settings. */
441 (void)restore_locale_settings (settings);
442
073167ef 443 unlock_locale_mutex ();
b89c4943 444}
9361f762 445
b89c4943
LC
446/* Enter a locked locale section. */
447static inline int
448enter_locale_section (scm_t_locale locale,
449 scm_t_locale_settings *prev_locale)
9361f762 450{
b89c4943
LC
451 int err;
452
073167ef 453 lock_locale_mutex ();
b89c4943
LC
454
455 err = get_current_locale_settings (prev_locale);
456 if (err)
457 {
073167ef 458 unlock_locale_mutex ();
b89c4943
LC
459 return err;
460 }
9361f762 461
b89c4943
LC
462 err = install_locale (locale);
463 if (err)
464 {
465 leave_locale_section (prev_locale);
466 free_locale_settings (prev_locale);
467 }
468
469 return err;
470}
471
b89c4943
LC
472/* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
473#define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
474 do \
475 { \
476 int lsec_err; \
477 scm_t_locale_settings lsec_prev_locale; \
478 \
479 lsec_err = enter_locale_section ((_c_locale), &lsec_prev_locale); \
480 if (lsec_err) \
481 scm_locale_error (FUNC_NAME, lsec_err); \
482 else \
483 { \
484 _statement ; \
485 \
486 leave_locale_section (&lsec_prev_locale); \
487 free_locale_settings (&lsec_prev_locale); \
488 } \
489 } \
490 while (0)
491
a2f00b9b
LC
492/* Convert the current locale settings into a locale SMOB. On success, zero
493 is returned and RESULT points to the new SMOB. Otherwise, an error is
494 returned. */
495static int
496get_current_locale (SCM *result)
497{
498 int err = 0;
499 scm_t_locale c_locale;
500 const char *current_locale;
501
502 c_locale = scm_gc_malloc (sizeof (* c_locale), "locale");
503
504
073167ef 505 lock_locale_mutex ();
a2f00b9b
LC
506
507 c_locale->category_mask = LC_ALL_MASK;
508 c_locale->base_locale = SCM_UNDEFINED;
509
510 current_locale = setlocale (LC_ALL, NULL);
511 if (current_locale != NULL)
512 {
513 c_locale->locale_name = strdup (current_locale);
514 if (c_locale->locale_name == NULL)
515 err = ENOMEM;
516 }
517 else
518 err = EINVAL;
519
073167ef 520 unlock_locale_mutex ();
a2f00b9b
LC
521
522 if (err)
523 scm_gc_free (c_locale, sizeof (* c_locale), "locale");
524 else
525 SCM_NEWSMOB (*result, scm_tc16_locale_smob_type, c_locale);
526
527 return err;
528}
529
5b878445 530#else /* USE_GNU_LOCALE_API */
a2f00b9b 531
5b878445 532/* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
12f0c3e5
LC
533#define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
534 do \
535 { \
536 scm_t_locale old_loc; \
537 \
538 old_loc = uselocale (_c_locale); \
539 _statement ; \
540 uselocale (old_loc); \
541 } \
5b878445
MG
542 while (0)
543
544
545#endif /* USE_GNU_LOCALE_API */
9361f762 546
a2f00b9b
LC
547
548\f
549/* `make-locale' can take either category lists or single categories (the
550 `LC_*' integer constants). */
551#define SCM_LIST_OR_INTEGER_P(arg) \
552 (scm_is_integer (arg) || scm_is_true (scm_list_p (arg)))
553
554
555/* Return the category mask corresponding to CATEGORY (an `LC_' integer
556 constant). */
557static inline int
558category_to_category_mask (SCM category,
559 const char *func_name, int pos)
560{
561 int c_category;
562 int c_category_mask;
563
564 c_category = scm_to_int (category);
565
566#define SCM_DEFINE_LOCALE_CATEGORY(_name) \
567 case LC_ ## _name: \
568 c_category_mask = SCM_LOCALE_CATEGORY_MASK (_name); \
569 break;
570
571 switch (c_category)
572 {
573#include "locale-categories.h"
574
575 case LC_ALL:
576 c_category_mask = LC_ALL_MASK;
577 break;
578
579 default:
580 scm_wrong_type_arg_msg (func_name, pos, category,
581 "locale category");
582 }
583
584#undef SCM_DEFINE_LOCALE_CATEGORY
585
586 return c_category_mask;
587}
588
589/* Convert CATEGORIES, a list of locale categories or a single category (an
590 integer), into a category mask. */
591static int
592category_list_to_category_mask (SCM categories,
593 const char *func_name, int pos)
594{
595 int c_category_mask = 0;
596
597 if (scm_is_integer (categories))
598 c_category_mask = category_to_category_mask (categories,
599 func_name, pos);
600 else
601 for (; !scm_is_null (categories); categories = SCM_CDR (categories))
602 {
603 SCM category = SCM_CAR (categories);
604
605 c_category_mask |=
606 category_to_category_mask (category, func_name, pos);
607 }
608
609 return c_category_mask;
610}
611
612
613SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0,
614 (SCM category_list, SCM locale_name, SCM base_locale),
615 "Return a reference to a data structure representing a set of "
616 "locale datasets. @var{category_list} should be either a list "
617 "of locale categories or a single category as used with "
618 "@code{setlocale} (@pxref{Locales, @code{setlocale}}) and "
619 "@var{locale_name} should be the name of the locale considered "
620 "(e.g., @code{\"sl_SI\"}). Optionally, if @code{base_locale} is "
621 "passed, it should be a locale object denoting settings for "
622 "categories not listed in @var{category_list}.")
623#define FUNC_NAME s_scm_make_locale
624{
625 SCM locale = SCM_BOOL_F;
626 int err = 0;
627 int c_category_mask;
628 char *c_locale_name;
629 scm_t_locale c_base_locale, c_locale;
630
631 SCM_MAKE_VALIDATE (1, category_list, LIST_OR_INTEGER_P);
632 SCM_VALIDATE_STRING (2, locale_name);
633 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, base_locale, c_base_locale);
634
635 c_category_mask = category_list_to_category_mask (category_list,
636 FUNC_NAME, 1);
637 c_locale_name = scm_to_locale_string (locale_name);
638
639#ifdef USE_GNU_LOCALE_API
640
641 if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale)))
c3b16a5d 642 c_base_locale = LC_GLOBAL_LOCALE;
a2f00b9b 643
c3b16a5d 644 if (c_base_locale != (locale_t) 0)
a2f00b9b
LC
645 {
646 /* C_BASE_LOCALE is to be consumed by `newlocale ()' so it needs to be
647 duplicated before. */
648 c_base_locale = duplocale (c_base_locale);
c3b16a5d 649
a2f00b9b
LC
650 if (c_base_locale == (locale_t) 0)
651 {
652 err = errno;
653 goto fail;
654 }
655 }
656
657 c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale);
658
659 free (c_locale_name);
660
661 if (c_locale == (locale_t) 0)
662 {
c3b16a5d 663 if (c_base_locale != (locale_t) 0)
a2f00b9b 664 freelocale (c_base_locale);
a2f00b9b
LC
665 scm_locale_error (FUNC_NAME, errno);
666 }
667 else
668 SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
669
670#else
671
672 c_locale = scm_gc_malloc (sizeof (* c_locale), "locale");
673
674 c_locale->category_mask = c_category_mask;
675 c_locale->locale_name = c_locale_name;
676
677 if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale)))
678 {
679 /* Get the current locale settings and turn them into a locale
680 object. */
681 err = get_current_locale (&base_locale);
682 if (err)
683 goto fail;
684 }
685
686 c_locale->base_locale = base_locale;
687
688 {
689 /* Try out the new locale and raise an exception if it doesn't work. */
690 int err;
691 scm_t_locale_settings prev_locale;
692
693 err = enter_locale_section (c_locale, &prev_locale);
a2f00b9b
LC
694
695 if (err)
696 goto fail;
697 else
1445e449
LC
698 {
699 leave_locale_section (&prev_locale);
700 SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
701 }
a2f00b9b
LC
702 }
703
704#endif
705
706 return locale;
707
708 fail:
709#ifndef USE_GNU_LOCALE_API
710 scm_gc_free (c_locale, sizeof (* c_locale), "locale");
711#endif
712 free (c_locale_name);
713 scm_locale_error (FUNC_NAME, err);
714
715 return SCM_BOOL_F;
716}
717#undef FUNC_NAME
718
719SCM_DEFINE (scm_locale_p, "locale?", 1, 0, 0,
720 (SCM obj),
721 "Return true if @var{obj} is a locale object.")
722#define FUNC_NAME s_scm_locale_p
723{
724 return scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_locale_smob_type, obj));
725}
726#undef FUNC_NAME
727
728
b89c4943 729\f
a2f00b9b
LC
730/* Locale-dependent string comparison.
731
732 A similar API can be found in MzScheme starting from version 200:
733 http://download.plt-scheme.org/chronology/mzmr200alpha14.html . */
734
df047aa2
LC
735#define SCM_STRING_TO_U32_BUF(s1, c_s1) \
736 do \
737 { \
738 if (scm_i_is_narrow_string (s1)) \
739 { \
740 size_t i, len; \
741 const char *buf = scm_i_string_chars (s1); \
742 \
743 len = scm_i_string_length (s1); \
c291b588 744 c_s1 = alloca (sizeof (scm_t_wchar) * (len + 1)); \
df047aa2
LC
745 \
746 for (i = 0; i < len; i ++) \
747 c_s1[i] = (unsigned char ) buf[i]; \
748 c_s1[len] = 0; \
749 } \
750 else \
751 c_s1 = (scm_t_wchar *) scm_i_string_wide_chars (s1); \
752 } while (0)
753
754
755/* Compare UTF-32 strings according to LOCALE. Returns a negative value if
756 S1 compares smaller than S2, a positive value if S1 compares larger than
757 S2, or 0 if they compare equal. */
b89c4943 758static inline int
5b878445 759compare_u32_strings (SCM s1, SCM s2, SCM locale, const char *func_name)
b89c4943
LC
760#define FUNC_NAME func_name
761{
762 int result;
763 scm_t_locale c_locale;
5b878445
MG
764 scm_t_wchar *c_s1, *c_s2;
765 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
766
767 SCM_STRING_TO_U32_BUF (s1, c_s1);
768 SCM_STRING_TO_U32_BUF (s2, c_s2);
769
770 if (c_locale)
771 RUN_IN_LOCALE_SECTION (c_locale,
772 result = u32_strcoll ((const scm_t_uint32 *) c_s1,
773 (const scm_t_uint32 *) c_s2));
774 else
cdf52ff0
LC
775 result = u32_strcoll ((const scm_t_uint32 *) c_s1,
776 (const scm_t_uint32 *) c_s2);
5b878445 777
5b878445
MG
778 scm_remember_upto_here_2 (s1, s2);
779 scm_remember_upto_here (locale);
780 return result;
781}
782#undef FUNC_NAME
783
aafb5062
MG
784/* Return the current language of the locale. */
785static const char *
786locale_language ()
787{
96c71c58
BH
788 /* Note: If the locale has been set with 'uselocale', uc_locale_language
789 from libunistring versions 0.9.1 and older will return the incorrect
790 (non-thread-specific) locale. This is fixed in versions 0.9.2 and
791 newer. */
aafb5062 792 return uc_locale_language ();
aafb5062
MG
793}
794
5b878445 795static inline int
aafb5062 796u32_locale_casecoll (const char *func_name, const scm_t_uint32 *c_s1,
c543e41e
LC
797 const scm_t_uint32 *c_s2,
798 int *result)
5b878445 799{
c543e41e
LC
800 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must note
801 make any non-local exit. */
5b878445 802
c543e41e 803 int ret;
aafb5062 804 const char *loc = locale_language ();
5b878445 805
aafb5062 806 ret = u32_casecoll (c_s1, u32_strlen (c_s1),
5b878445 807 c_s2, u32_strlen (c_s2),
c543e41e 808 loc, UNINORM_NFC, result);
5b878445 809
c543e41e 810 return ret == 0 ? ret : errno;
5b878445
MG
811}
812
813static inline int
814compare_u32_strings_ci (SCM s1, SCM s2, SCM locale, const char *func_name)
815#define FUNC_NAME func_name
816{
c543e41e 817 int result, ret = 0;
5b878445
MG
818 scm_t_locale c_locale;
819 scm_t_wchar *c_s1, *c_s2;
b89c4943 820 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
9361f762 821
5b878445
MG
822 SCM_STRING_TO_U32_BUF (s1, c_s1);
823 SCM_STRING_TO_U32_BUF (s2, c_s2);
824
b89c4943 825 if (c_locale)
cdf52ff0
LC
826 RUN_IN_LOCALE_SECTION
827 (c_locale,
c543e41e 828 ret = u32_locale_casecoll (func_name,
cdf52ff0 829 (const scm_t_uint32 *) c_s1,
c543e41e
LC
830 (const scm_t_uint32 *) c_s2,
831 &result));
832 else
833 ret = u32_locale_casecoll (func_name,
834 (const scm_t_uint32 *) c_s1,
835 (const scm_t_uint32 *) c_s2,
836 &result);
837
838 if (SCM_UNLIKELY (ret != 0))
839 {
840 errno = ret;
841 scm_syserror (FUNC_NAME);
842 }
b89c4943 843
5b878445
MG
844 scm_remember_upto_here_2 (s1, s2);
845 scm_remember_upto_here (locale);
b89c4943
LC
846
847 return result;
848}
849#undef FUNC_NAME
850
851/* Store into DST an upper-case version of SRC. */
852static inline void
853str_upcase (register char *dst, register const char *src)
854{
855 for (; *src != '\0'; src++, dst++)
4e641322 856 *dst = toupper ((int) *src);
b89c4943
LC
857 *dst = '\0';
858}
859
860static inline void
861str_downcase (register char *dst, register const char *src)
862{
863 for (; *src != '\0'; src++, dst++)
4e641322 864 *dst = tolower ((int) *src);
b89c4943
LC
865 *dst = '\0';
866}
867
868#ifdef USE_GNU_LOCALE_API
869static inline void
870str_upcase_l (register char *dst, register const char *src,
871 scm_t_locale locale)
872{
873 for (; *src != '\0'; src++, dst++)
874 *dst = toupper_l (*src, locale);
875 *dst = '\0';
876}
877
878static inline void
879str_downcase_l (register char *dst, register const char *src,
880 scm_t_locale locale)
881{
882 for (; *src != '\0'; src++, dst++)
883 *dst = tolower_l (*src, locale);
884 *dst = '\0';
885}
886#endif
887
888
b89c4943
LC
889SCM_DEFINE (scm_string_locale_lt, "string-locale<?", 2, 1, 0,
890 (SCM s1, SCM s2, SCM locale),
891 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
892 "If @var{locale} is provided, it should be locale object (as "
893 "returned by @code{make-locale}) and will be used to perform the "
894 "comparison; otherwise, the current system locale is used.")
895#define FUNC_NAME s_scm_string_locale_lt
9361f762 896{
b89c4943 897 int result;
9361f762 898
b89c4943
LC
899 SCM_VALIDATE_STRING (1, s1);
900 SCM_VALIDATE_STRING (2, s2);
9361f762 901
5b878445 902 result = compare_u32_strings (s1, s2, locale, FUNC_NAME);
b89c4943
LC
903
904 return scm_from_bool (result < 0);
905}
906#undef FUNC_NAME
907
908SCM_DEFINE (scm_string_locale_gt, "string-locale>?", 2, 1, 0,
909 (SCM s1, SCM s2, SCM locale),
910 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
911 "If @var{locale} is provided, it should be locale object (as "
912 "returned by @code{make-locale}) and will be used to perform the "
913 "comparison; otherwise, the current system locale is used.")
914#define FUNC_NAME s_scm_string_locale_gt
915{
916 int result;
b89c4943
LC
917
918 SCM_VALIDATE_STRING (1, s1);
919 SCM_VALIDATE_STRING (2, s2);
920
5b878445 921 result = compare_u32_strings (s1, s2, locale, FUNC_NAME);
b89c4943
LC
922
923 return scm_from_bool (result > 0);
924}
925#undef FUNC_NAME
926
927SCM_DEFINE (scm_string_locale_ci_lt, "string-locale-ci<?", 2, 1, 0,
928 (SCM s1, SCM s2, SCM locale),
929 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
930 "and locale-dependent way. If @var{locale} is provided, it "
931 "should be locale object (as returned by @code{make-locale}) "
932 "and will be used to perform the comparison; otherwise, the "
933 "current system locale is used.")
934#define FUNC_NAME s_scm_string_locale_ci_lt
935{
936 int result;
b89c4943
LC
937
938 SCM_VALIDATE_STRING (1, s1);
939 SCM_VALIDATE_STRING (2, s2);
940
5b878445 941 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
b89c4943
LC
942
943 return scm_from_bool (result < 0);
944}
945#undef FUNC_NAME
946
947SCM_DEFINE (scm_string_locale_ci_gt, "string-locale-ci>?", 2, 1, 0,
948 (SCM s1, SCM s2, SCM locale),
949 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
950 "and locale-dependent way. If @var{locale} is provided, it "
951 "should be locale object (as returned by @code{make-locale}) "
952 "and will be used to perform the comparison; otherwise, the "
953 "current system locale is used.")
954#define FUNC_NAME s_scm_string_locale_ci_gt
955{
956 int result;
b89c4943
LC
957
958 SCM_VALIDATE_STRING (1, s1);
959 SCM_VALIDATE_STRING (2, s2);
960
5b878445 961 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
b89c4943
LC
962
963 return scm_from_bool (result > 0);
964}
965#undef FUNC_NAME
966
967SCM_DEFINE (scm_string_locale_ci_eq, "string-locale-ci=?", 2, 1, 0,
968 (SCM s1, SCM s2, SCM locale),
969 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
970 "and locale-dependent way. If @var{locale} is provided, it "
971 "should be locale object (as returned by @code{make-locale}) "
972 "and will be used to perform the comparison; otherwise, the "
973 "current system locale is used.")
974#define FUNC_NAME s_scm_string_locale_ci_eq
975{
976 int result;
b89c4943
LC
977
978 SCM_VALIDATE_STRING (1, s1);
979 SCM_VALIDATE_STRING (2, s2);
980
5b878445 981 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
b89c4943
LC
982
983 return scm_from_bool (result == 0);
984}
985#undef FUNC_NAME
986
987
988SCM_DEFINE (scm_char_locale_lt, "char-locale<?", 2, 1, 0,
989 (SCM c1, SCM c2, SCM locale),
990 "Return true if character @var{c1} is lower than @var{c2} "
991 "according to @var{locale} or to the current locale.")
992#define FUNC_NAME s_scm_char_locale_lt
993{
5b878445 994 int result;
b89c4943
LC
995
996 SCM_VALIDATE_CHAR (1, c1);
997 SCM_VALIDATE_CHAR (2, c2);
998
5b878445
MG
999 result = compare_u32_strings (scm_string (scm_list_1 (c1)),
1000 scm_string (scm_list_1 (c2)),
1001 locale, FUNC_NAME);
b89c4943 1002
5b878445 1003 return scm_from_bool (result < 0);
b89c4943
LC
1004}
1005#undef FUNC_NAME
1006
1007SCM_DEFINE (scm_char_locale_gt, "char-locale>?", 2, 1, 0,
1008 (SCM c1, SCM c2, SCM locale),
1009 "Return true if character @var{c1} is greater than @var{c2} "
1010 "according to @var{locale} or to the current locale.")
1011#define FUNC_NAME s_scm_char_locale_gt
1012{
5b878445 1013 int result;
b89c4943
LC
1014
1015 SCM_VALIDATE_CHAR (1, c1);
1016 SCM_VALIDATE_CHAR (2, c2);
1017
5b878445
MG
1018 result = compare_u32_strings (scm_string (scm_list_1 (c1)),
1019 scm_string (scm_list_1 (c2)),
1020 locale, FUNC_NAME);
b89c4943 1021
5b878445 1022 return scm_from_bool (result > 0);
b89c4943
LC
1023}
1024#undef FUNC_NAME
1025
1026SCM_DEFINE (scm_char_locale_ci_lt, "char-locale-ci<?", 2, 1, 0,
1027 (SCM c1, SCM c2, SCM locale),
1028 "Return true if character @var{c1} is lower than @var{c2}, "
1029 "in a case insensitive way according to @var{locale} or to "
1030 "the current locale.")
1031#define FUNC_NAME s_scm_char_locale_ci_lt
1032{
1033 int result;
b89c4943
LC
1034
1035 SCM_VALIDATE_CHAR (1, c1);
1036 SCM_VALIDATE_CHAR (2, c2);
1037
5b878445
MG
1038 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1039 scm_string (scm_list_1 (c2)),
1040 locale, FUNC_NAME);
b89c4943
LC
1041
1042 return scm_from_bool (result < 0);
1043}
1044#undef FUNC_NAME
1045
1046SCM_DEFINE (scm_char_locale_ci_gt, "char-locale-ci>?", 2, 1, 0,
1047 (SCM c1, SCM c2, SCM locale),
1048 "Return true if character @var{c1} is greater than @var{c2}, "
1049 "in a case insensitive way according to @var{locale} or to "
1050 "the current locale.")
1051#define FUNC_NAME s_scm_char_locale_ci_gt
1052{
1053 int result;
b89c4943
LC
1054
1055 SCM_VALIDATE_CHAR (1, c1);
1056 SCM_VALIDATE_CHAR (2, c2);
1057
5b878445
MG
1058 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1059 scm_string (scm_list_1 (c2)),
1060 locale, FUNC_NAME);
b89c4943
LC
1061
1062 return scm_from_bool (result > 0);
1063}
1064#undef FUNC_NAME
1065
1066SCM_DEFINE (scm_char_locale_ci_eq, "char-locale-ci=?", 2, 1, 0,
1067 (SCM c1, SCM c2, SCM locale),
1068 "Return true if character @var{c1} is equal to @var{c2}, "
1069 "in a case insensitive way according to @var{locale} or to "
1070 "the current locale.")
1071#define FUNC_NAME s_scm_char_locale_ci_eq
1072{
1073 int result;
b89c4943
LC
1074
1075 SCM_VALIDATE_CHAR (1, c1);
1076 SCM_VALIDATE_CHAR (2, c2);
1077
5b878445
MG
1078 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1079 scm_string (scm_list_1 (c2)),
1080 locale, FUNC_NAME);
b89c4943
LC
1081
1082 return scm_from_bool (result == 0);
1083}
1084#undef FUNC_NAME
1085
1086
1087\f
1088/* Locale-dependent alphabetic character mapping. */
1089
27f3413e
MG
1090static inline int
1091u32_locale_tocase (const scm_t_uint32 *c_s1, size_t len,
1092 scm_t_uint32 **p_c_s2, size_t * p_len2,
1093 scm_t_uint32 *(*func) (const scm_t_uint32 *, size_t,
1094 const char *, uninorm_t,
1095 scm_t_uint32 *, size_t *))
1096{
1097 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must not
1098 make any non-local exit. */
1099
1100 scm_t_uint32 *ret;
aafb5062 1101 const char *loc = locale_language ();
27f3413e
MG
1102
1103 /* The first NULL here indicates that no NFC or NFKC normalization
1104 is done. The second NULL means the return buffer is
1105 malloc'ed here. */
1106 ret = func (c_s1, len, loc, NULL, NULL, p_len2);
1107
1108 if (ret == NULL)
1109 {
2c48e4d5 1110 *p_c_s2 = (scm_t_uint32 *) NULL;
27f3413e
MG
1111 *p_len2 = 0;
1112 return errno;
1113 }
1114 *p_c_s2 = ret;
aafb5062 1115
27f3413e
MG
1116 return 0;
1117}
1118
1119
820f33aa
JG
1120static SCM
1121chr_to_case (SCM chr, scm_t_locale c_locale,
1122 scm_t_uint32 *(*func) (const scm_t_uint32 *, size_t, const char *,
1123 uninorm_t, scm_t_uint32 *, size_t *),
44d3d111 1124 const char *func_name,
820f33aa 1125 int *err)
44d3d111 1126#define FUNC_NAME func_name
b89c4943 1127{
27f3413e 1128 int ret;
03976fee 1129 scm_t_uint32 c;
820f33aa
JG
1130 scm_t_uint32 *convbuf;
1131 size_t convlen;
03976fee 1132 SCM convchar;
b89c4943 1133
03976fee 1134 c = SCM_CHAR (chr);
27f3413e 1135
b89c4943 1136 if (c_locale != NULL)
27f3413e 1137 RUN_IN_LOCALE_SECTION (c_locale, ret =
03976fee 1138 u32_locale_tocase (&c, 1, &convbuf, &convlen, func));
27f3413e
MG
1139 else
1140 ret =
03976fee 1141 u32_locale_tocase (&c, 1, &convbuf, &convlen, func);
27f3413e
MG
1142
1143 if (SCM_UNLIKELY (ret != 0))
9361f762 1144 {
820f33aa 1145 *err = ret;
4d40bea6 1146 return SCM_BOOL_F;
9361f762 1147 }
27f3413e 1148
820f33aa
JG
1149 if (convlen == 1)
1150 convchar = SCM_MAKE_CHAR ((scm_t_wchar) convbuf[0]);
b89c4943 1151 else
820f33aa
JG
1152 convchar = chr;
1153 free (convbuf);
1154
1155 return convchar;
1156}
44d3d111 1157#undef FUNC_NAME
820f33aa
JG
1158
1159SCM_DEFINE (scm_char_locale_downcase, "char-locale-downcase", 1, 1, 0,
1160 (SCM chr, SCM locale),
1161 "Return the lowercase character that corresponds to @var{chr} "
1162 "according to either @var{locale} or the current locale.")
1163#define FUNC_NAME s_scm_char_locale_downcase
1164{
1165 scm_t_locale c_locale;
1166 SCM ret;
1167 int err = 0;
1168
1169 SCM_VALIDATE_CHAR (1, chr);
1170 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1171
44d3d111 1172 ret = chr_to_case (chr, c_locale, u32_tolower, FUNC_NAME, &err);
820f33aa
JG
1173
1174 if (err != 0)
1175 {
1176 errno = err;
1177 scm_syserror (FUNC_NAME);
1178 }
1179 return ret;
9361f762
MV
1180}
1181#undef FUNC_NAME
1182
b89c4943
LC
1183SCM_DEFINE (scm_char_locale_upcase, "char-locale-upcase", 1, 1, 0,
1184 (SCM chr, SCM locale),
1185 "Return the uppercase character that corresponds to @var{chr} "
1186 "according to either @var{locale} or the current locale.")
1187#define FUNC_NAME s_scm_char_locale_upcase
9361f762 1188{
b89c4943 1189 scm_t_locale c_locale;
820f33aa
JG
1190 SCM ret;
1191 int err = 0;
b89c4943
LC
1192
1193 SCM_VALIDATE_CHAR (1, chr);
b89c4943 1194 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1195
44d3d111 1196 ret = chr_to_case (chr, c_locale, u32_toupper, FUNC_NAME, &err);
27f3413e 1197
820f33aa
JG
1198 if (err != 0)
1199 {
1200 errno = err;
1201 scm_syserror (FUNC_NAME);
1202 }
1203 return ret;
1204}
1205#undef FUNC_NAME
27f3413e 1206
820f33aa
JG
1207SCM_DEFINE (scm_char_locale_titlecase, "char-locale-titlecase", 1, 1, 0,
1208 (SCM chr, SCM locale),
1209 "Return the titlecase character that corresponds to @var{chr} "
1210 "according to either @var{locale} or the current locale.")
1211#define FUNC_NAME s_scm_char_locale_titlecase
1212{
1213 scm_t_locale c_locale;
1214 SCM ret;
1215 int err = 0;
1216
1217 SCM_VALIDATE_CHAR (1, chr);
1218 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1219
44d3d111 1220 ret = chr_to_case (chr, c_locale, u32_totitle, FUNC_NAME, &err);
820f33aa
JG
1221
1222 if (err != 0)
b89c4943 1223 {
820f33aa 1224 errno = err;
27f3413e 1225 scm_syserror (FUNC_NAME);
b89c4943 1226 }
820f33aa 1227 return ret;
b89c4943
LC
1228}
1229#undef FUNC_NAME
1230
820f33aa
JG
1231static SCM
1232str_to_case (SCM str, scm_t_locale c_locale,
1233 scm_t_uint32 *(*func) (const scm_t_uint32 *, size_t, const char *,
1234 uninorm_t, scm_t_uint32 *, size_t *),
44d3d111 1235 const char *func_name,
820f33aa 1236 int *err)
44d3d111 1237#define FUNC_NAME func_name
b89c4943 1238{
2c48e4d5 1239 scm_t_wchar *c_str, *c_buf;
820f33aa
JG
1240 scm_t_uint32 *c_convstr;
1241 size_t len, convlen;
27f3413e 1242 int ret;
820f33aa 1243 SCM convstr;
b89c4943 1244
27f3413e
MG
1245 len = scm_i_string_length (str);
1246 if (len == 0)
1247 return scm_nullstr;
1248 SCM_STRING_TO_U32_BUF (str, c_str);
b89c4943
LC
1249
1250 if (c_locale)
27f3413e
MG
1251 RUN_IN_LOCALE_SECTION (c_locale, ret =
1252 u32_locale_tocase ((scm_t_uint32 *) c_str, len,
820f33aa
JG
1253 &c_convstr,
1254 &convlen, func));
b89c4943 1255 else
27f3413e
MG
1256 ret =
1257 u32_locale_tocase ((scm_t_uint32 *) c_str, len,
820f33aa 1258 &c_convstr, &convlen, func);
b89c4943
LC
1259
1260 scm_remember_upto_here (str);
1261
27f3413e
MG
1262 if (SCM_UNLIKELY (ret != 0))
1263 {
820f33aa 1264 *err = ret;
4d40bea6 1265 return SCM_BOOL_F;
27f3413e
MG
1266 }
1267
190d4b0d 1268 convstr = scm_i_make_wide_string (convlen, &c_buf, 0);
820f33aa
JG
1269 memcpy (c_buf, c_convstr, convlen * sizeof (scm_t_wchar));
1270 free (c_convstr);
27f3413e 1271
820f33aa 1272 scm_i_try_narrow_string (convstr);
27f3413e 1273
820f33aa
JG
1274 return convstr;
1275}
44d3d111 1276#undef FUNC_NAME
820f33aa
JG
1277
1278SCM_DEFINE (scm_string_locale_upcase, "string-locale-upcase", 1, 1, 0,
1279 (SCM str, SCM locale),
1280 "Return a new string that is the uppercase version of "
1281 "@var{str} according to either @var{locale} or the current "
1282 "locale.")
1283#define FUNC_NAME s_scm_string_locale_upcase
1284{
1285 scm_t_locale c_locale;
1286 SCM ret;
1287 int err = 0;
1288
1289 SCM_VALIDATE_STRING (1, str);
1290 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1291
44d3d111 1292 ret = str_to_case (str, c_locale, u32_toupper, FUNC_NAME, &err);
820f33aa
JG
1293
1294 if (err != 0)
1295 {
1296 errno = err;
1297 scm_syserror (FUNC_NAME);
1298 }
1299 return ret;
b89c4943
LC
1300}
1301#undef FUNC_NAME
9361f762 1302
b89c4943
LC
1303SCM_DEFINE (scm_string_locale_downcase, "string-locale-downcase", 1, 1, 0,
1304 (SCM str, SCM locale),
1305 "Return a new string that is the down-case version of "
1306 "@var{str} according to either @var{locale} or the current "
1307 "locale.")
1308#define FUNC_NAME s_scm_string_locale_downcase
1309{
b89c4943 1310 scm_t_locale c_locale;
820f33aa
JG
1311 SCM ret;
1312 int err = 0;
b89c4943
LC
1313
1314 SCM_VALIDATE_STRING (1, str);
1315 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1316
44d3d111 1317 ret = str_to_case (str, c_locale, u32_tolower, FUNC_NAME, &err);
9361f762 1318
820f33aa 1319 if (err != 0)
27f3413e 1320 {
820f33aa 1321 errno = err;
27f3413e
MG
1322 scm_syserror (FUNC_NAME);
1323 }
820f33aa
JG
1324 return ret;
1325}
1326#undef FUNC_NAME
1327
1328SCM_DEFINE (scm_string_locale_titlecase, "string-locale-titlecase", 1, 1, 0,
1329 (SCM str, SCM locale),
1330 "Return a new string that is the title-case version of "
1331 "@var{str} according to either @var{locale} or the current "
1332 "locale.")
1333#define FUNC_NAME s_scm_string_locale_titlecase
1334{
1335 scm_t_locale c_locale;
1336 SCM ret;
1337 int err = 0;
27f3413e 1338
820f33aa
JG
1339 SCM_VALIDATE_STRING (1, str);
1340 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
27f3413e 1341
44d3d111 1342 ret = str_to_case (str, c_locale, u32_totitle, FUNC_NAME, &err);
27f3413e 1343
820f33aa
JG
1344 if (err != 0)
1345 {
1346 errno = err;
1347 scm_syserror (FUNC_NAME);
1348 }
1349 return ret;
9361f762
MV
1350}
1351#undef FUNC_NAME
1352
b89c4943
LC
1353/* Note: We don't provide mutative versions of `string-locale-(up|down)case'
1354 because, in some languages, a single downcase character maps to a couple
1355 of uppercase characters. Read the SRFI-13 document for a detailed
1356 discussion about this. */
1357
1358
1359\f
1360/* Locale-dependent number parsing. */
1361
1362SCM_DEFINE (scm_locale_string_to_integer, "locale-string->integer",
1363 1, 2, 0, (SCM str, SCM base, SCM locale),
1364 "Convert string @var{str} into an integer according to either "
1365 "@var{locale} (a locale object as returned by @code{make-locale}) "
1366 "or the current process locale. Return two values: an integer "
1367 "(on success) or @code{#f}, and the number of characters read "
1368 "from @var{str} (@code{0} on failure).")
1369#define FUNC_NAME s_scm_locale_string_to_integer
9361f762 1370{
9361f762 1371 SCM result;
b89c4943
LC
1372 long c_result;
1373 int c_base;
1374 const char *c_str;
1375 char *c_endptr;
1376 scm_t_locale c_locale;
9361f762 1377
b89c4943
LC
1378 SCM_VALIDATE_STRING (1, str);
1379 c_str = scm_i_string_chars (str);
9361f762 1380
d223c3fc 1381 if (!scm_is_eq (base, SCM_UNDEFINED))
b89c4943 1382 SCM_VALIDATE_INT_COPY (2, base, c_base);
9361f762 1383 else
b89c4943
LC
1384 c_base = 10;
1385
1386 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
1387
1388 if (c_locale != NULL)
9361f762 1389 {
b89c4943
LC
1390#ifdef USE_GNU_LOCALE_API
1391 c_result = strtol_l (c_str, &c_endptr, c_base, c_locale);
1392#else
1393 RUN_IN_LOCALE_SECTION (c_locale,
1394 c_result = strtol (c_str, &c_endptr, c_base));
1395#endif
9361f762 1396 }
b89c4943
LC
1397 else
1398 c_result = strtol (c_str, &c_endptr, c_base);
1399
1400 scm_remember_upto_here (str);
1401
1402 if (c_endptr == c_str)
1403 result = SCM_BOOL_F;
1404 else
1405 result = scm_from_long (c_result);
1406
1407 return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
1408}
1409#undef FUNC_NAME
1410
1411SCM_DEFINE (scm_locale_string_to_inexact, "locale-string->inexact",
1412 1, 1, 0, (SCM str, SCM locale),
1413 "Convert string @var{str} into an inexact number according to "
1414 "either @var{locale} (a locale object as returned by "
1415 "@code{make-locale}) or the current process locale. Return "
1416 "two values: an inexact number (on success) or @code{#f}, and "
1417 "the number of characters read from @var{str} (@code{0} on "
1418 "failure).")
1419#define FUNC_NAME s_scm_locale_string_to_inexact
1420{
1421 SCM result;
1422 double c_result;
1423 const char *c_str;
1424 char *c_endptr;
1425 scm_t_locale c_locale;
9361f762 1426
b89c4943
LC
1427 SCM_VALIDATE_STRING (1, str);
1428 c_str = scm_i_string_chars (str);
9361f762 1429
b89c4943 1430 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1431
b89c4943
LC
1432 if (c_locale != NULL)
1433 {
1434#ifdef USE_GNU_LOCALE_API
1435 c_result = strtod_l (c_str, &c_endptr, c_locale);
1436#else
1437 RUN_IN_LOCALE_SECTION (c_locale,
1438 c_result = strtod (c_str, &c_endptr));
1439#endif
1440 }
9361f762 1441 else
b89c4943
LC
1442 c_result = strtod (c_str, &c_endptr);
1443
1444 scm_remember_upto_here (str);
1445
1446 if (c_endptr == c_str)
9361f762 1447 result = SCM_BOOL_F;
b89c4943
LC
1448 else
1449 result = scm_from_double (c_result);
9361f762 1450
b89c4943 1451 return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
9361f762
MV
1452}
1453#undef FUNC_NAME
1454
b89c4943 1455\f
a2f00b9b
LC
1456/* Language information, aka. `nl_langinfo ()'. */
1457
1458/* FIXME: Issues related to `nl-langinfo'.
1459
1460 1. The `CODESET' value is not normalized. This is a secondary issue, but
1461 still a practical issue. See
1462 http://www.cl.cam.ac.uk/~mgk25/ucs/norm_charmap.c for codeset
1463 normalization.
1464
1465 2. `nl_langinfo ()' is not available on Windows.
1466
1467 3. `nl_langinfo ()' may return strings encoded in a locale different from
52642040
MG
1468 the current one.
1469 For example:
a2f00b9b
LC
1470
1471 (nl-langinfo DAY_1 (make-locale LC_ALL "eo_EO.UTF-8"))
1472
52642040
MG
1473 returns a result that is a UTF-8 string, regardless of the
1474 setting of the current locale. If nl_langinfo supports CODESET,
1475 we can convert the string properly using scm_from_stringn. If
1476 CODESET is not supported, we won't be able to make much sense of
56d288b8
LC
1477 the returned string.
1478
1479 Note: We don't use Gnulib's `nl_langinfo' module because it's currently not
1480 as complete as the compatibility hacks in `i18n.scm'. */
a2f00b9b
LC
1481
1482
1483SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0,
1484 (SCM item, SCM locale),
1485 "Return a string denoting locale information for @var{item} "
1486 "in the current locale or that specified by @var{locale}. "
1487 "The semantics and arguments are the same as those of the "
1488 "X/Open @code{nl_langinfo} function (@pxref{The Elegant and "
1489 "Fast Way, @code{nl_langinfo},, libc, The GNU C Library "
1490 "Reference Manual}).")
1491#define FUNC_NAME s_scm_nl_langinfo
1492{
1493#ifdef HAVE_NL_LANGINFO
1494 SCM result;
1495 nl_item c_item;
1496 char *c_result;
1497 scm_t_locale c_locale;
52642040
MG
1498#ifdef HAVE_LANGINFO_CODESET
1499 char *codeset;
1500#endif
a2f00b9b
LC
1501
1502 SCM_VALIDATE_INT_COPY (2, item, c_item);
1503 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1504
1505 /* Sadly, `nl_langinfo ()' returns a pointer to a static string. According
1506 to SuS v2, that static string may be modified by subsequent calls to
1507 `nl_langinfo ()' as well as by calls to `setlocale ()'. Thus, we must
1508 acquire the locale mutex before doing invoking `nl_langinfo ()'. See
1509 http://opengroup.org/onlinepubs/007908799/xsh/nl_langinfo.html for
1510 details. */
1511
073167ef 1512 lock_locale_mutex ();
a2f00b9b
LC
1513 if (c_locale != NULL)
1514 {
1515#ifdef USE_GNU_LOCALE_API
1516 c_result = nl_langinfo_l (c_item, c_locale);
52642040
MG
1517#ifdef HAVE_LANGINFO_CODESET
1518 codeset = nl_langinfo_l (CODESET, c_locale);
1519#endif /* HAVE_LANGINFO_CODESET */
1520#else /* !USE_GNU_LOCALE_API */
a2f00b9b
LC
1521 /* We can't use `RUN_IN_LOCALE_SECTION ()' here because the locale
1522 mutex is already taken. */
1523 int lsec_err;
1524 scm_t_locale_settings lsec_prev_locale;
1525
1526 lsec_err = get_current_locale_settings (&lsec_prev_locale);
1527 if (lsec_err)
073167ef 1528 unlock_locale_mutex ();
a2f00b9b
LC
1529 else
1530 {
1531 lsec_err = install_locale (c_locale);
1532 if (lsec_err)
1533 {
1534 leave_locale_section (&lsec_prev_locale);
1535 free_locale_settings (&lsec_prev_locale);
1536 }
1537 }
1538
1539 if (lsec_err)
1540 scm_locale_error (FUNC_NAME, lsec_err);
1541 else
1542 {
1543 c_result = nl_langinfo (c_item);
52642040
MG
1544#ifdef HAVE_LANGINFO_CODESET
1545 codeset = nl_langinfo (CODESET);
1546#endif /* HAVE_LANGINFO_CODESET */
a2f00b9b 1547
1445e449 1548 restore_locale_settings (&lsec_prev_locale);
a2f00b9b
LC
1549 free_locale_settings (&lsec_prev_locale);
1550 }
1551#endif
1552 }
1553 else
52642040
MG
1554 {
1555 c_result = nl_langinfo (c_item);
1556#ifdef HAVE_LANGINFO_CODESET
1557 codeset = nl_langinfo (CODESET);
1558#endif /* HAVE_LANGINFO_CODESET */
1559 }
a2f00b9b
LC
1560
1561 c_result = strdup (c_result);
073167ef 1562 unlock_locale_mutex ();
a2f00b9b
LC
1563
1564 if (c_result == NULL)
1565 result = SCM_BOOL_F;
1566 else
1567 {
a2f00b9b
LC
1568 switch (c_item)
1569 {
afb49959 1570#if (defined GROUPING) && (defined MON_GROUPING)
a2f00b9b
LC
1571 case GROUPING:
1572 case MON_GROUPING:
a2f00b9b 1573 {
afb49959 1574 char *p;
a2f00b9b 1575
914c4300
LC
1576 /* In this cases, the result is to be interpreted as a list
1577 of numbers. If the last item is `CHAR_MAX' or a negative
1578 number, it has the special meaning "no more grouping"
1579 (negative numbers aren't specified in POSIX but can be
1580 used by glibc; see
1581 <http://lists.gnu.org/archive/html/bug-guile/2011-02/msg00159.html>). */
afb49959 1582 result = SCM_EOL;
914c4300 1583 for (p = c_result; (*p > 0) && (*p != CHAR_MAX); p++)
afb49959 1584 result = scm_cons (SCM_I_MAKINUM ((int) *p), result);
a2f00b9b 1585
afb49959
LC
1586 {
1587 SCM last_pair = result;
a2f00b9b 1588
afb49959
LC
1589 result = scm_reverse_x (result, SCM_EOL);
1590
914c4300 1591 if (*p == 0)
afb49959
LC
1592 {
1593 /* Cyclic grouping information. */
393baa8a 1594 if (!scm_is_null (last_pair))
afb49959
LC
1595 SCM_SETCDR (last_pair, result);
1596 }
1597 }
a2f00b9b 1598
afb49959
LC
1599 free (c_result);
1600 break;
1601 }
1602#endif
1603
1604#if (defined FRAC_DIGITS) && (defined INT_FRAC_DIGITS)
a2f00b9b
LC
1605 case FRAC_DIGITS:
1606 case INT_FRAC_DIGITS:
1607 /* This is to be interpreted as a single integer. */
1608 if (*c_result == CHAR_MAX)
1609 /* Unspecified. */
1610 result = SCM_BOOL_F;
1611 else
1612 result = SCM_I_MAKINUM (*c_result);
1613
1614 free (c_result);
1615 break;
afb49959 1616#endif
a2f00b9b 1617
afb49959 1618#if (defined P_CS_PRECEDES) && (defined INT_N_CS_PRECEDES)
a2f00b9b
LC
1619 case P_CS_PRECEDES:
1620 case N_CS_PRECEDES:
1621 case INT_P_CS_PRECEDES:
1622 case INT_N_CS_PRECEDES:
afb49959 1623#if (defined P_SEP_BY_SPACE) && (defined N_SEP_BY_SPACE)
a2f00b9b
LC
1624 case P_SEP_BY_SPACE:
1625 case N_SEP_BY_SPACE:
afb49959 1626#endif
a2f00b9b
LC
1627 /* This is to be interpreted as a boolean. */
1628 result = scm_from_bool (*c_result);
1629
1630 free (c_result);
1631 break;
afb49959 1632#endif
a2f00b9b 1633
afb49959 1634#if (defined P_SIGN_POSN) && (defined INT_N_SIGN_POSN)
a2f00b9b
LC
1635 case P_SIGN_POSN:
1636 case N_SIGN_POSN:
1637 case INT_P_SIGN_POSN:
1638 case INT_N_SIGN_POSN:
1639 /* See `(libc) Sign of Money Amount' for the interpretation of the
1640 return value here. */
1641 switch (*c_result)
1642 {
1643 case 0:
4a655e50 1644 result = scm_from_latin1_symbol ("parenthesize");
a2f00b9b
LC
1645 break;
1646
1647 case 1:
4a655e50 1648 result = scm_from_latin1_symbol ("sign-before");
a2f00b9b
LC
1649 break;
1650
1651 case 2:
4a655e50 1652 result = scm_from_latin1_symbol ("sign-after");
a2f00b9b
LC
1653 break;
1654
1655 case 3:
4a655e50 1656 result = scm_from_latin1_symbol ("sign-before-currency-symbol");
a2f00b9b
LC
1657 break;
1658
1659 case 4:
4a655e50 1660 result = scm_from_latin1_symbol ("sign-after-currency-symbol");
a2f00b9b
LC
1661 break;
1662
1663 default:
4a655e50 1664 result = scm_from_latin1_symbol ("unspecified");
a2f00b9b
LC
1665 }
1666 break;
afb49959 1667#endif
a2f00b9b
LC
1668
1669 default:
52642040
MG
1670#ifdef HAVE_LANGINFO_CODESET
1671 result = scm_from_stringn (c_result, strlen (c_result),
1672 codeset,
1673 SCM_FAILED_CONVERSION_QUESTION_MARK);
1674#else /* !HAVE_LANGINFO_CODESET */
1675 /* This may be incorrectly encoded if the locale differs
1676 from the c_locale. */
1677 result = scm_from_locale_string (c_result);
1678#endif /* !HAVE_LANGINFO_CODESET */
b8fc11d2 1679 free (c_result);
a2f00b9b
LC
1680 }
1681 }
1682
1683 return result;
1684#else
1685 scm_syserror_msg (FUNC_NAME, "`nl-langinfo' not supported on your system",
1686 SCM_EOL, ENOSYS);
1687
1688 return SCM_BOOL_F;
1689#endif
1690}
1691#undef FUNC_NAME
1692
1693/* Define the `nl_item' constants. */
1694static inline void
1695define_langinfo_items (void)
9361f762 1696{
24deb6d0 1697#ifdef HAVE_LANGINFO_H
a2f00b9b
LC
1698
1699#define DEFINE_NLITEM_CONSTANT(_item) \
1700 scm_c_define (# _item, scm_from_int (_item))
1701
1702 DEFINE_NLITEM_CONSTANT (CODESET);
1703
1704 /* Abbreviated days of the week. */
1705 DEFINE_NLITEM_CONSTANT (ABDAY_1);
1706 DEFINE_NLITEM_CONSTANT (ABDAY_2);
1707 DEFINE_NLITEM_CONSTANT (ABDAY_3);
1708 DEFINE_NLITEM_CONSTANT (ABDAY_4);
1709 DEFINE_NLITEM_CONSTANT (ABDAY_5);
1710 DEFINE_NLITEM_CONSTANT (ABDAY_6);
1711 DEFINE_NLITEM_CONSTANT (ABDAY_7);
1712
1713 /* Long-named days of the week. */
1714 DEFINE_NLITEM_CONSTANT (DAY_1); /* Sunday */
1715 DEFINE_NLITEM_CONSTANT (DAY_2); /* Monday */
1716 DEFINE_NLITEM_CONSTANT (DAY_3); /* Tuesday */
1717 DEFINE_NLITEM_CONSTANT (DAY_4); /* Wednesday */
1718 DEFINE_NLITEM_CONSTANT (DAY_5); /* Thursday */
1719 DEFINE_NLITEM_CONSTANT (DAY_6); /* Friday */
1720 DEFINE_NLITEM_CONSTANT (DAY_7); /* Saturday */
1721
1722 /* Abbreviated month names. */
1723 DEFINE_NLITEM_CONSTANT (ABMON_1); /* Jan */
1724 DEFINE_NLITEM_CONSTANT (ABMON_2);
1725 DEFINE_NLITEM_CONSTANT (ABMON_3);
1726 DEFINE_NLITEM_CONSTANT (ABMON_4);
1727 DEFINE_NLITEM_CONSTANT (ABMON_5);
1728 DEFINE_NLITEM_CONSTANT (ABMON_6);
1729 DEFINE_NLITEM_CONSTANT (ABMON_7);
1730 DEFINE_NLITEM_CONSTANT (ABMON_8);
1731 DEFINE_NLITEM_CONSTANT (ABMON_9);
1732 DEFINE_NLITEM_CONSTANT (ABMON_10);
1733 DEFINE_NLITEM_CONSTANT (ABMON_11);
1734 DEFINE_NLITEM_CONSTANT (ABMON_12);
1735
1736 /* Long month names. */
1737 DEFINE_NLITEM_CONSTANT (MON_1); /* January */
1738 DEFINE_NLITEM_CONSTANT (MON_2);
1739 DEFINE_NLITEM_CONSTANT (MON_3);
1740 DEFINE_NLITEM_CONSTANT (MON_4);
1741 DEFINE_NLITEM_CONSTANT (MON_5);
1742 DEFINE_NLITEM_CONSTANT (MON_6);
1743 DEFINE_NLITEM_CONSTANT (MON_7);
1744 DEFINE_NLITEM_CONSTANT (MON_8);
1745 DEFINE_NLITEM_CONSTANT (MON_9);
1746 DEFINE_NLITEM_CONSTANT (MON_10);
1747 DEFINE_NLITEM_CONSTANT (MON_11);
1748 DEFINE_NLITEM_CONSTANT (MON_12);
1749
1750 DEFINE_NLITEM_CONSTANT (AM_STR); /* Ante meridiem string. */
1751 DEFINE_NLITEM_CONSTANT (PM_STR); /* Post meridiem string. */
1752
1753 DEFINE_NLITEM_CONSTANT (D_T_FMT); /* Date and time format for strftime. */
1754 DEFINE_NLITEM_CONSTANT (D_FMT); /* Date format for strftime. */
1755 DEFINE_NLITEM_CONSTANT (T_FMT); /* Time format for strftime. */
1756 DEFINE_NLITEM_CONSTANT (T_FMT_AMPM);/* 12-hour time format for strftime. */
1757
1758 DEFINE_NLITEM_CONSTANT (ERA); /* Alternate era. */
1759 DEFINE_NLITEM_CONSTANT (ERA_D_FMT); /* Date in alternate era format. */
1760 DEFINE_NLITEM_CONSTANT (ERA_D_T_FMT); /* Date and time in alternate era
1761 format. */
1762 DEFINE_NLITEM_CONSTANT (ERA_T_FMT); /* Time in alternate era format. */
1763
1764 DEFINE_NLITEM_CONSTANT (ALT_DIGITS); /* Alternate symbols for digits. */
1765 DEFINE_NLITEM_CONSTANT (RADIXCHAR);
1766 DEFINE_NLITEM_CONSTANT (THOUSEP);
1767
1768#ifdef YESEXPR
1769 DEFINE_NLITEM_CONSTANT (YESEXPR);
1770#endif
1771#ifdef NOEXPR
1772 DEFINE_NLITEM_CONSTANT (NOEXPR);
1773#endif
b89c4943 1774
a2f00b9b
LC
1775#ifdef CRNCYSTR /* currency symbol */
1776 DEFINE_NLITEM_CONSTANT (CRNCYSTR);
1777#endif
b89c4943 1778
a2f00b9b 1779 /* GNU extensions. */
b89c4943 1780
a2f00b9b
LC
1781#ifdef ERA_YEAR
1782 DEFINE_NLITEM_CONSTANT (ERA_YEAR); /* Year in alternate era format. */
1783#endif
b89c4943 1784
a2f00b9b
LC
1785 /* LC_MONETARY category: formatting of monetary quantities.
1786 These items each correspond to a member of `struct lconv',
1787 defined in <locale.h>. */
1788#ifdef INT_CURR_SYMBOL
1789 DEFINE_NLITEM_CONSTANT (INT_CURR_SYMBOL);
1790#endif
1791#ifdef MON_DECIMAL_POINT
1792 DEFINE_NLITEM_CONSTANT (MON_DECIMAL_POINT);
1793#endif
1794#ifdef MON_THOUSANDS_SEP
1795 DEFINE_NLITEM_CONSTANT (MON_THOUSANDS_SEP);
1796#endif
1797#ifdef MON_GROUPING
1798 DEFINE_NLITEM_CONSTANT (MON_GROUPING);
1799#endif
1800#ifdef POSITIVE_SIGN
1801 DEFINE_NLITEM_CONSTANT (POSITIVE_SIGN);
1802#endif
1803#ifdef NEGATIVE_SIGN
1804 DEFINE_NLITEM_CONSTANT (NEGATIVE_SIGN);
1805#endif
1806#ifdef GROUPING
1807 DEFINE_NLITEM_CONSTANT (GROUPING);
1808#endif
1809#ifdef INT_FRAC_DIGITS
1810 DEFINE_NLITEM_CONSTANT (INT_FRAC_DIGITS);
1811#endif
1812#ifdef FRAC_DIGITS
1813 DEFINE_NLITEM_CONSTANT (FRAC_DIGITS);
1814#endif
1815#ifdef P_CS_PRECEDES
1816 DEFINE_NLITEM_CONSTANT (P_CS_PRECEDES);
1817#endif
1818#ifdef P_SEP_BY_SPACE
1819 DEFINE_NLITEM_CONSTANT (P_SEP_BY_SPACE);
1820#endif
1821#ifdef N_CS_PRECEDES
1822 DEFINE_NLITEM_CONSTANT (N_CS_PRECEDES);
1823#endif
1824#ifdef N_SEP_BY_SPACE
1825 DEFINE_NLITEM_CONSTANT (N_SEP_BY_SPACE);
1826#endif
1827#ifdef P_SIGN_POSN
1828 DEFINE_NLITEM_CONSTANT (P_SIGN_POSN);
1829#endif
1830#ifdef N_SIGN_POSN
1831 DEFINE_NLITEM_CONSTANT (N_SIGN_POSN);
1832#endif
1833#ifdef INT_P_CS_PRECEDES
1834 DEFINE_NLITEM_CONSTANT (INT_P_CS_PRECEDES);
1835#endif
1836#ifdef INT_P_SEP_BY_SPACE
1837 DEFINE_NLITEM_CONSTANT (INT_P_SEP_BY_SPACE);
1838#endif
1839#ifdef INT_N_CS_PRECEDES
1840 DEFINE_NLITEM_CONSTANT (INT_N_CS_PRECEDES);
1841#endif
1842#ifdef INT_N_SEP_BY_SPACE
1843 DEFINE_NLITEM_CONSTANT (INT_N_SEP_BY_SPACE);
1844#endif
1845#ifdef INT_P_SIGN_POSN
1846 DEFINE_NLITEM_CONSTANT (INT_P_SIGN_POSN);
1847#endif
1848#ifdef INT_N_SIGN_POSN
1849 DEFINE_NLITEM_CONSTANT (INT_N_SIGN_POSN);
1850#endif
1851
1852#undef DEFINE_NLITEM_CONSTANT
1853
1854#endif /* HAVE_NL_TYPES_H */
1855}
1856
1857\f
1858void
1859scm_init_i18n ()
1860{
1861 SCM global_locale_smob;
1862
1863#ifdef HAVE_NL_LANGINFO
1864 scm_add_feature ("nl-langinfo");
1865 define_langinfo_items ();
1866#endif
b89c4943 1867
9361f762 1868#include "libguile/i18n.x"
b89c4943 1869
a2f00b9b 1870 /* Initialize the global locale object with a special `locale' SMOB. */
c3b16a5d
LC
1871 /* XXX: We don't define it as `LC_GLOBAL_LOCALE' because of bugs as of
1872 glibc <= 2.11 not (yet) worked around by Gnulib. See
1873 http://sourceware.org/bugzilla/show_bug.cgi?id=11009 for details. */
a2f00b9b
LC
1874 SCM_NEWSMOB (global_locale_smob, scm_tc16_locale_smob_type, NULL);
1875 SCM_VARIABLE_SET (scm_global_locale, global_locale_smob);
9361f762
MV
1876}
1877
756e8a3a
LC
1878void
1879scm_bootstrap_i18n ()
1880{
44602b08
AW
1881 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1882 "scm_init_i18n",
756e8a3a
LC
1883 (scm_t_extension_init_func) scm_init_i18n,
1884 NULL);
1885
1886}
1887
9361f762
MV
1888
1889/*
1890 Local Variables:
1891 c-file-style: "gnu"
1892 End:
1893*/