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