fix scm_gc_strdup invocation
[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
073167ef 504 lock_locale_mutex ();
a2f00b9b
LC
505
506 c_locale->category_mask = LC_ALL_MASK;
507 c_locale->base_locale = SCM_UNDEFINED;
508
509 current_locale = setlocale (LC_ALL, NULL);
510 if (current_locale != NULL)
0b4f7719 511 c_locale->locale_name = scm_gc_strdup (current_locale, "locale");
a2f00b9b
LC
512 else
513 err = EINVAL;
514
073167ef 515 unlock_locale_mutex ();
a2f00b9b 516
42f95812 517 if (err == 0)
a2f00b9b 518 SCM_NEWSMOB (*result, scm_tc16_locale_smob_type, c_locale);
42f95812
AW
519 else
520 *result = SCM_BOOL_F;
a2f00b9b
LC
521
522 return err;
523}
524
5b878445 525#else /* USE_GNU_LOCALE_API */
a2f00b9b 526
5b878445 527/* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
12f0c3e5
LC
528#define RUN_IN_LOCALE_SECTION(_c_locale, _statement) \
529 do \
530 { \
531 scm_t_locale old_loc; \
532 \
533 old_loc = uselocale (_c_locale); \
534 _statement ; \
535 uselocale (old_loc); \
536 } \
5b878445
MG
537 while (0)
538
539
540#endif /* USE_GNU_LOCALE_API */
9361f762 541
a2f00b9b
LC
542
543\f
544/* `make-locale' can take either category lists or single categories (the
545 `LC_*' integer constants). */
546#define SCM_LIST_OR_INTEGER_P(arg) \
547 (scm_is_integer (arg) || scm_is_true (scm_list_p (arg)))
548
549
550/* Return the category mask corresponding to CATEGORY (an `LC_' integer
551 constant). */
552static inline int
553category_to_category_mask (SCM category,
554 const char *func_name, int pos)
555{
556 int c_category;
557 int c_category_mask;
558
559 c_category = scm_to_int (category);
560
561#define SCM_DEFINE_LOCALE_CATEGORY(_name) \
562 case LC_ ## _name: \
563 c_category_mask = SCM_LOCALE_CATEGORY_MASK (_name); \
564 break;
565
566 switch (c_category)
567 {
568#include "locale-categories.h"
569
570 case LC_ALL:
571 c_category_mask = LC_ALL_MASK;
572 break;
573
574 default:
575 scm_wrong_type_arg_msg (func_name, pos, category,
576 "locale category");
577 }
578
579#undef SCM_DEFINE_LOCALE_CATEGORY
580
581 return c_category_mask;
582}
583
584/* Convert CATEGORIES, a list of locale categories or a single category (an
585 integer), into a category mask. */
586static int
587category_list_to_category_mask (SCM categories,
588 const char *func_name, int pos)
589{
590 int c_category_mask = 0;
591
592 if (scm_is_integer (categories))
593 c_category_mask = category_to_category_mask (categories,
594 func_name, pos);
595 else
596 for (; !scm_is_null (categories); categories = SCM_CDR (categories))
597 {
598 SCM category = SCM_CAR (categories);
599
600 c_category_mask |=
601 category_to_category_mask (category, func_name, pos);
602 }
603
604 return c_category_mask;
605}
606
607
608SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0,
609 (SCM category_list, SCM locale_name, SCM base_locale),
610 "Return a reference to a data structure representing a set of "
611 "locale datasets. @var{category_list} should be either a list "
612 "of locale categories or a single category as used with "
613 "@code{setlocale} (@pxref{Locales, @code{setlocale}}) and "
614 "@var{locale_name} should be the name of the locale considered "
615 "(e.g., @code{\"sl_SI\"}). Optionally, if @code{base_locale} is "
616 "passed, it should be a locale object denoting settings for "
617 "categories not listed in @var{category_list}.")
618#define FUNC_NAME s_scm_make_locale
619{
620 SCM locale = SCM_BOOL_F;
621 int err = 0;
622 int c_category_mask;
623 char *c_locale_name;
624 scm_t_locale c_base_locale, c_locale;
625
626 SCM_MAKE_VALIDATE (1, category_list, LIST_OR_INTEGER_P);
627 SCM_VALIDATE_STRING (2, locale_name);
628 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, base_locale, c_base_locale);
629
630 c_category_mask = category_list_to_category_mask (category_list,
631 FUNC_NAME, 1);
632 c_locale_name = scm_to_locale_string (locale_name);
633
634#ifdef USE_GNU_LOCALE_API
635
636 if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale)))
c3b16a5d 637 c_base_locale = LC_GLOBAL_LOCALE;
a2f00b9b 638
c3b16a5d 639 if (c_base_locale != (locale_t) 0)
a2f00b9b
LC
640 {
641 /* C_BASE_LOCALE is to be consumed by `newlocale ()' so it needs to be
642 duplicated before. */
643 c_base_locale = duplocale (c_base_locale);
c3b16a5d 644
a2f00b9b
LC
645 if (c_base_locale == (locale_t) 0)
646 {
647 err = errno;
648 goto fail;
649 }
650 }
651
652 c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale);
653
654 free (c_locale_name);
655
656 if (c_locale == (locale_t) 0)
657 {
c3b16a5d 658 if (c_base_locale != (locale_t) 0)
a2f00b9b 659 freelocale (c_base_locale);
a2f00b9b
LC
660 scm_locale_error (FUNC_NAME, errno);
661 }
662 else
663 SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
664
665#else
666
667 c_locale = scm_gc_malloc (sizeof (* c_locale), "locale");
668
669 c_locale->category_mask = c_category_mask;
670 c_locale->locale_name = c_locale_name;
671
672 if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale)))
673 {
674 /* Get the current locale settings and turn them into a locale
675 object. */
676 err = get_current_locale (&base_locale);
677 if (err)
678 goto fail;
679 }
680
681 c_locale->base_locale = base_locale;
682
683 {
684 /* Try out the new locale and raise an exception if it doesn't work. */
685 int err;
686 scm_t_locale_settings prev_locale;
687
688 err = enter_locale_section (c_locale, &prev_locale);
a2f00b9b
LC
689
690 if (err)
691 goto fail;
692 else
1445e449
LC
693 {
694 leave_locale_section (&prev_locale);
695 SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
696 }
a2f00b9b
LC
697 }
698
699#endif
700
701 return locale;
702
703 fail:
704#ifndef USE_GNU_LOCALE_API
705 scm_gc_free (c_locale, sizeof (* c_locale), "locale");
706#endif
707 free (c_locale_name);
708 scm_locale_error (FUNC_NAME, err);
709
710 return SCM_BOOL_F;
711}
712#undef FUNC_NAME
713
714SCM_DEFINE (scm_locale_p, "locale?", 1, 0, 0,
715 (SCM obj),
716 "Return true if @var{obj} is a locale object.")
717#define FUNC_NAME s_scm_locale_p
718{
719 return scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_locale_smob_type, obj));
720}
721#undef FUNC_NAME
722
723
b89c4943 724\f
a2f00b9b
LC
725/* Locale-dependent string comparison.
726
727 A similar API can be found in MzScheme starting from version 200:
728 http://download.plt-scheme.org/chronology/mzmr200alpha14.html . */
729
df047aa2
LC
730#define SCM_STRING_TO_U32_BUF(s1, c_s1) \
731 do \
732 { \
733 if (scm_i_is_narrow_string (s1)) \
734 { \
735 size_t i, len; \
736 const char *buf = scm_i_string_chars (s1); \
737 \
738 len = scm_i_string_length (s1); \
c291b588 739 c_s1 = alloca (sizeof (scm_t_wchar) * (len + 1)); \
df047aa2
LC
740 \
741 for (i = 0; i < len; i ++) \
742 c_s1[i] = (unsigned char ) buf[i]; \
743 c_s1[len] = 0; \
744 } \
745 else \
746 c_s1 = (scm_t_wchar *) scm_i_string_wide_chars (s1); \
747 } while (0)
748
749
750/* Compare UTF-32 strings according to LOCALE. Returns a negative value if
751 S1 compares smaller than S2, a positive value if S1 compares larger than
752 S2, or 0 if they compare equal. */
b89c4943 753static inline int
5b878445 754compare_u32_strings (SCM s1, SCM s2, SCM locale, const char *func_name)
b89c4943
LC
755#define FUNC_NAME func_name
756{
757 int result;
758 scm_t_locale c_locale;
5b878445
MG
759 scm_t_wchar *c_s1, *c_s2;
760 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
761
762 SCM_STRING_TO_U32_BUF (s1, c_s1);
763 SCM_STRING_TO_U32_BUF (s2, c_s2);
764
765 if (c_locale)
766 RUN_IN_LOCALE_SECTION (c_locale,
767 result = u32_strcoll ((const scm_t_uint32 *) c_s1,
768 (const scm_t_uint32 *) c_s2));
769 else
cdf52ff0
LC
770 result = u32_strcoll ((const scm_t_uint32 *) c_s1,
771 (const scm_t_uint32 *) c_s2);
5b878445 772
5b878445
MG
773 scm_remember_upto_here_2 (s1, s2);
774 scm_remember_upto_here (locale);
775 return result;
776}
777#undef FUNC_NAME
778
aafb5062
MG
779/* Return the current language of the locale. */
780static const char *
781locale_language ()
782{
96c71c58
BH
783 /* Note: If the locale has been set with 'uselocale', uc_locale_language
784 from libunistring versions 0.9.1 and older will return the incorrect
785 (non-thread-specific) locale. This is fixed in versions 0.9.2 and
786 newer. */
aafb5062 787 return uc_locale_language ();
aafb5062
MG
788}
789
5b878445 790static inline int
aafb5062 791u32_locale_casecoll (const char *func_name, const scm_t_uint32 *c_s1,
c543e41e
LC
792 const scm_t_uint32 *c_s2,
793 int *result)
5b878445 794{
c543e41e
LC
795 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must note
796 make any non-local exit. */
5b878445 797
c543e41e 798 int ret;
aafb5062 799 const char *loc = locale_language ();
5b878445 800
aafb5062 801 ret = u32_casecoll (c_s1, u32_strlen (c_s1),
5b878445 802 c_s2, u32_strlen (c_s2),
c543e41e 803 loc, UNINORM_NFC, result);
5b878445 804
c543e41e 805 return ret == 0 ? ret : errno;
5b878445
MG
806}
807
808static inline int
809compare_u32_strings_ci (SCM s1, SCM s2, SCM locale, const char *func_name)
810#define FUNC_NAME func_name
811{
c543e41e 812 int result, ret = 0;
5b878445
MG
813 scm_t_locale c_locale;
814 scm_t_wchar *c_s1, *c_s2;
b89c4943 815 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
9361f762 816
5b878445
MG
817 SCM_STRING_TO_U32_BUF (s1, c_s1);
818 SCM_STRING_TO_U32_BUF (s2, c_s2);
819
b89c4943 820 if (c_locale)
cdf52ff0
LC
821 RUN_IN_LOCALE_SECTION
822 (c_locale,
c543e41e 823 ret = u32_locale_casecoll (func_name,
cdf52ff0 824 (const scm_t_uint32 *) c_s1,
c543e41e
LC
825 (const scm_t_uint32 *) c_s2,
826 &result));
827 else
828 ret = u32_locale_casecoll (func_name,
829 (const scm_t_uint32 *) c_s1,
830 (const scm_t_uint32 *) c_s2,
831 &result);
832
833 if (SCM_UNLIKELY (ret != 0))
834 {
835 errno = ret;
836 scm_syserror (FUNC_NAME);
837 }
b89c4943 838
5b878445
MG
839 scm_remember_upto_here_2 (s1, s2);
840 scm_remember_upto_here (locale);
b89c4943
LC
841
842 return result;
843}
844#undef FUNC_NAME
845
846/* Store into DST an upper-case version of SRC. */
847static inline void
848str_upcase (register char *dst, register const char *src)
849{
850 for (; *src != '\0'; src++, dst++)
4e641322 851 *dst = toupper ((int) *src);
b89c4943
LC
852 *dst = '\0';
853}
854
855static inline void
856str_downcase (register char *dst, register const char *src)
857{
858 for (; *src != '\0'; src++, dst++)
4e641322 859 *dst = tolower ((int) *src);
b89c4943
LC
860 *dst = '\0';
861}
862
863#ifdef USE_GNU_LOCALE_API
864static inline void
865str_upcase_l (register char *dst, register const char *src,
866 scm_t_locale locale)
867{
868 for (; *src != '\0'; src++, dst++)
869 *dst = toupper_l (*src, locale);
870 *dst = '\0';
871}
872
873static inline void
874str_downcase_l (register char *dst, register const char *src,
875 scm_t_locale locale)
876{
877 for (; *src != '\0'; src++, dst++)
878 *dst = tolower_l (*src, locale);
879 *dst = '\0';
880}
881#endif
882
883
b89c4943
LC
884SCM_DEFINE (scm_string_locale_lt, "string-locale<?", 2, 1, 0,
885 (SCM s1, SCM s2, SCM locale),
886 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
887 "If @var{locale} is provided, it should be locale object (as "
888 "returned by @code{make-locale}) and will be used to perform the "
889 "comparison; otherwise, the current system locale is used.")
890#define FUNC_NAME s_scm_string_locale_lt
9361f762 891{
b89c4943 892 int result;
9361f762 893
b89c4943
LC
894 SCM_VALIDATE_STRING (1, s1);
895 SCM_VALIDATE_STRING (2, s2);
9361f762 896
5b878445 897 result = compare_u32_strings (s1, s2, locale, FUNC_NAME);
b89c4943
LC
898
899 return scm_from_bool (result < 0);
900}
901#undef FUNC_NAME
902
903SCM_DEFINE (scm_string_locale_gt, "string-locale>?", 2, 1, 0,
904 (SCM s1, SCM s2, SCM locale),
905 "Compare strings @var{s1} and @var{s2} in a locale-dependent way."
906 "If @var{locale} is provided, it should be locale object (as "
907 "returned by @code{make-locale}) and will be used to perform the "
908 "comparison; otherwise, the current system locale is used.")
909#define FUNC_NAME s_scm_string_locale_gt
910{
911 int result;
b89c4943
LC
912
913 SCM_VALIDATE_STRING (1, s1);
914 SCM_VALIDATE_STRING (2, s2);
915
5b878445 916 result = compare_u32_strings (s1, s2, locale, FUNC_NAME);
b89c4943
LC
917
918 return scm_from_bool (result > 0);
919}
920#undef FUNC_NAME
921
922SCM_DEFINE (scm_string_locale_ci_lt, "string-locale-ci<?", 2, 1, 0,
923 (SCM s1, SCM s2, SCM locale),
924 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
925 "and locale-dependent way. If @var{locale} is provided, it "
926 "should be locale object (as returned by @code{make-locale}) "
927 "and will be used to perform the comparison; otherwise, the "
928 "current system locale is used.")
929#define FUNC_NAME s_scm_string_locale_ci_lt
930{
931 int result;
b89c4943
LC
932
933 SCM_VALIDATE_STRING (1, s1);
934 SCM_VALIDATE_STRING (2, s2);
935
5b878445 936 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
b89c4943
LC
937
938 return scm_from_bool (result < 0);
939}
940#undef FUNC_NAME
941
942SCM_DEFINE (scm_string_locale_ci_gt, "string-locale-ci>?", 2, 1, 0,
943 (SCM s1, SCM s2, SCM locale),
944 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
945 "and locale-dependent way. If @var{locale} is provided, it "
946 "should be locale object (as returned by @code{make-locale}) "
947 "and will be used to perform the comparison; otherwise, the "
948 "current system locale is used.")
949#define FUNC_NAME s_scm_string_locale_ci_gt
950{
951 int result;
b89c4943
LC
952
953 SCM_VALIDATE_STRING (1, s1);
954 SCM_VALIDATE_STRING (2, s2);
955
5b878445 956 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
b89c4943
LC
957
958 return scm_from_bool (result > 0);
959}
960#undef FUNC_NAME
961
962SCM_DEFINE (scm_string_locale_ci_eq, "string-locale-ci=?", 2, 1, 0,
963 (SCM s1, SCM s2, SCM locale),
964 "Compare strings @var{s1} and @var{s2} in a case-insensitive, "
965 "and locale-dependent way. If @var{locale} is provided, it "
966 "should be locale object (as returned by @code{make-locale}) "
967 "and will be used to perform the comparison; otherwise, the "
968 "current system locale is used.")
969#define FUNC_NAME s_scm_string_locale_ci_eq
970{
971 int result;
b89c4943
LC
972
973 SCM_VALIDATE_STRING (1, s1);
974 SCM_VALIDATE_STRING (2, s2);
975
5b878445 976 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
b89c4943
LC
977
978 return scm_from_bool (result == 0);
979}
980#undef FUNC_NAME
981
982
983SCM_DEFINE (scm_char_locale_lt, "char-locale<?", 2, 1, 0,
984 (SCM c1, SCM c2, SCM locale),
985 "Return true if character @var{c1} is lower than @var{c2} "
986 "according to @var{locale} or to the current locale.")
987#define FUNC_NAME s_scm_char_locale_lt
988{
5b878445 989 int result;
b89c4943
LC
990
991 SCM_VALIDATE_CHAR (1, c1);
992 SCM_VALIDATE_CHAR (2, c2);
993
5b878445
MG
994 result = compare_u32_strings (scm_string (scm_list_1 (c1)),
995 scm_string (scm_list_1 (c2)),
996 locale, FUNC_NAME);
b89c4943 997
5b878445 998 return scm_from_bool (result < 0);
b89c4943
LC
999}
1000#undef FUNC_NAME
1001
1002SCM_DEFINE (scm_char_locale_gt, "char-locale>?", 2, 1, 0,
1003 (SCM c1, SCM c2, SCM locale),
1004 "Return true if character @var{c1} is greater than @var{c2} "
1005 "according to @var{locale} or to the current locale.")
1006#define FUNC_NAME s_scm_char_locale_gt
1007{
5b878445 1008 int result;
b89c4943
LC
1009
1010 SCM_VALIDATE_CHAR (1, c1);
1011 SCM_VALIDATE_CHAR (2, c2);
1012
5b878445
MG
1013 result = compare_u32_strings (scm_string (scm_list_1 (c1)),
1014 scm_string (scm_list_1 (c2)),
1015 locale, FUNC_NAME);
b89c4943 1016
5b878445 1017 return scm_from_bool (result > 0);
b89c4943
LC
1018}
1019#undef FUNC_NAME
1020
1021SCM_DEFINE (scm_char_locale_ci_lt, "char-locale-ci<?", 2, 1, 0,
1022 (SCM c1, SCM c2, SCM locale),
1023 "Return true if character @var{c1} is lower than @var{c2}, "
1024 "in a case insensitive way according to @var{locale} or to "
1025 "the current locale.")
1026#define FUNC_NAME s_scm_char_locale_ci_lt
1027{
1028 int result;
b89c4943
LC
1029
1030 SCM_VALIDATE_CHAR (1, c1);
1031 SCM_VALIDATE_CHAR (2, c2);
1032
5b878445
MG
1033 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1034 scm_string (scm_list_1 (c2)),
1035 locale, FUNC_NAME);
b89c4943
LC
1036
1037 return scm_from_bool (result < 0);
1038}
1039#undef FUNC_NAME
1040
1041SCM_DEFINE (scm_char_locale_ci_gt, "char-locale-ci>?", 2, 1, 0,
1042 (SCM c1, SCM c2, SCM locale),
1043 "Return true if character @var{c1} is greater than @var{c2}, "
1044 "in a case insensitive way according to @var{locale} or to "
1045 "the current locale.")
1046#define FUNC_NAME s_scm_char_locale_ci_gt
1047{
1048 int result;
b89c4943
LC
1049
1050 SCM_VALIDATE_CHAR (1, c1);
1051 SCM_VALIDATE_CHAR (2, c2);
1052
5b878445
MG
1053 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1054 scm_string (scm_list_1 (c2)),
1055 locale, FUNC_NAME);
b89c4943
LC
1056
1057 return scm_from_bool (result > 0);
1058}
1059#undef FUNC_NAME
1060
1061SCM_DEFINE (scm_char_locale_ci_eq, "char-locale-ci=?", 2, 1, 0,
1062 (SCM c1, SCM c2, SCM locale),
1063 "Return true if character @var{c1} is equal to @var{c2}, "
1064 "in a case insensitive way according to @var{locale} or to "
1065 "the current locale.")
1066#define FUNC_NAME s_scm_char_locale_ci_eq
1067{
1068 int result;
b89c4943
LC
1069
1070 SCM_VALIDATE_CHAR (1, c1);
1071 SCM_VALIDATE_CHAR (2, c2);
1072
5b878445
MG
1073 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1074 scm_string (scm_list_1 (c2)),
1075 locale, FUNC_NAME);
b89c4943
LC
1076
1077 return scm_from_bool (result == 0);
1078}
1079#undef FUNC_NAME
1080
1081
1082\f
1083/* Locale-dependent alphabetic character mapping. */
1084
27f3413e
MG
1085static inline int
1086u32_locale_tocase (const scm_t_uint32 *c_s1, size_t len,
1087 scm_t_uint32 **p_c_s2, size_t * p_len2,
1088 scm_t_uint32 *(*func) (const scm_t_uint32 *, size_t,
1089 const char *, uninorm_t,
1090 scm_t_uint32 *, size_t *))
1091{
1092 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must not
1093 make any non-local exit. */
1094
1095 scm_t_uint32 *ret;
aafb5062 1096 const char *loc = locale_language ();
27f3413e
MG
1097
1098 /* The first NULL here indicates that no NFC or NFKC normalization
1099 is done. The second NULL means the return buffer is
1100 malloc'ed here. */
1101 ret = func (c_s1, len, loc, NULL, NULL, p_len2);
1102
1103 if (ret == NULL)
1104 {
2c48e4d5 1105 *p_c_s2 = (scm_t_uint32 *) NULL;
27f3413e
MG
1106 *p_len2 = 0;
1107 return errno;
1108 }
1109 *p_c_s2 = ret;
aafb5062 1110
27f3413e
MG
1111 return 0;
1112}
1113
1114
820f33aa
JG
1115static SCM
1116chr_to_case (SCM chr, scm_t_locale c_locale,
1117 scm_t_uint32 *(*func) (const scm_t_uint32 *, size_t, const char *,
1118 uninorm_t, scm_t_uint32 *, size_t *),
44d3d111 1119 const char *func_name,
820f33aa 1120 int *err)
44d3d111 1121#define FUNC_NAME func_name
b89c4943 1122{
27f3413e 1123 int ret;
03976fee 1124 scm_t_uint32 c;
820f33aa
JG
1125 scm_t_uint32 *convbuf;
1126 size_t convlen;
03976fee 1127 SCM convchar;
b89c4943 1128
03976fee 1129 c = SCM_CHAR (chr);
27f3413e 1130
b89c4943 1131 if (c_locale != NULL)
27f3413e 1132 RUN_IN_LOCALE_SECTION (c_locale, ret =
03976fee 1133 u32_locale_tocase (&c, 1, &convbuf, &convlen, func));
27f3413e
MG
1134 else
1135 ret =
03976fee 1136 u32_locale_tocase (&c, 1, &convbuf, &convlen, func);
27f3413e
MG
1137
1138 if (SCM_UNLIKELY (ret != 0))
9361f762 1139 {
820f33aa 1140 *err = ret;
4d40bea6 1141 return SCM_BOOL_F;
9361f762 1142 }
27f3413e 1143
820f33aa
JG
1144 if (convlen == 1)
1145 convchar = SCM_MAKE_CHAR ((scm_t_wchar) convbuf[0]);
b89c4943 1146 else
820f33aa
JG
1147 convchar = chr;
1148 free (convbuf);
1149
1150 return convchar;
1151}
44d3d111 1152#undef FUNC_NAME
820f33aa
JG
1153
1154SCM_DEFINE (scm_char_locale_downcase, "char-locale-downcase", 1, 1, 0,
1155 (SCM chr, SCM locale),
1156 "Return the lowercase character that corresponds to @var{chr} "
1157 "according to either @var{locale} or the current locale.")
1158#define FUNC_NAME s_scm_char_locale_downcase
1159{
1160 scm_t_locale c_locale;
1161 SCM ret;
1162 int err = 0;
1163
1164 SCM_VALIDATE_CHAR (1, chr);
1165 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1166
44d3d111 1167 ret = chr_to_case (chr, c_locale, u32_tolower, FUNC_NAME, &err);
820f33aa
JG
1168
1169 if (err != 0)
1170 {
1171 errno = err;
1172 scm_syserror (FUNC_NAME);
1173 }
1174 return ret;
9361f762
MV
1175}
1176#undef FUNC_NAME
1177
b89c4943
LC
1178SCM_DEFINE (scm_char_locale_upcase, "char-locale-upcase", 1, 1, 0,
1179 (SCM chr, SCM locale),
1180 "Return the uppercase character that corresponds to @var{chr} "
1181 "according to either @var{locale} or the current locale.")
1182#define FUNC_NAME s_scm_char_locale_upcase
9361f762 1183{
b89c4943 1184 scm_t_locale c_locale;
820f33aa
JG
1185 SCM ret;
1186 int err = 0;
b89c4943
LC
1187
1188 SCM_VALIDATE_CHAR (1, chr);
b89c4943 1189 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1190
44d3d111 1191 ret = chr_to_case (chr, c_locale, u32_toupper, FUNC_NAME, &err);
27f3413e 1192
820f33aa
JG
1193 if (err != 0)
1194 {
1195 errno = err;
1196 scm_syserror (FUNC_NAME);
1197 }
1198 return ret;
1199}
1200#undef FUNC_NAME
27f3413e 1201
820f33aa
JG
1202SCM_DEFINE (scm_char_locale_titlecase, "char-locale-titlecase", 1, 1, 0,
1203 (SCM chr, SCM locale),
1204 "Return the titlecase character that corresponds to @var{chr} "
1205 "according to either @var{locale} or the current locale.")
1206#define FUNC_NAME s_scm_char_locale_titlecase
1207{
1208 scm_t_locale c_locale;
1209 SCM ret;
1210 int err = 0;
1211
1212 SCM_VALIDATE_CHAR (1, chr);
1213 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1214
44d3d111 1215 ret = chr_to_case (chr, c_locale, u32_totitle, FUNC_NAME, &err);
820f33aa
JG
1216
1217 if (err != 0)
b89c4943 1218 {
820f33aa 1219 errno = err;
27f3413e 1220 scm_syserror (FUNC_NAME);
b89c4943 1221 }
820f33aa 1222 return ret;
b89c4943
LC
1223}
1224#undef FUNC_NAME
1225
820f33aa
JG
1226static SCM
1227str_to_case (SCM str, scm_t_locale c_locale,
1228 scm_t_uint32 *(*func) (const scm_t_uint32 *, size_t, const char *,
1229 uninorm_t, scm_t_uint32 *, size_t *),
44d3d111 1230 const char *func_name,
820f33aa 1231 int *err)
44d3d111 1232#define FUNC_NAME func_name
b89c4943 1233{
2c48e4d5 1234 scm_t_wchar *c_str, *c_buf;
820f33aa
JG
1235 scm_t_uint32 *c_convstr;
1236 size_t len, convlen;
27f3413e 1237 int ret;
820f33aa 1238 SCM convstr;
b89c4943 1239
27f3413e
MG
1240 len = scm_i_string_length (str);
1241 if (len == 0)
1242 return scm_nullstr;
1243 SCM_STRING_TO_U32_BUF (str, c_str);
b89c4943
LC
1244
1245 if (c_locale)
27f3413e
MG
1246 RUN_IN_LOCALE_SECTION (c_locale, ret =
1247 u32_locale_tocase ((scm_t_uint32 *) c_str, len,
820f33aa
JG
1248 &c_convstr,
1249 &convlen, func));
b89c4943 1250 else
27f3413e
MG
1251 ret =
1252 u32_locale_tocase ((scm_t_uint32 *) c_str, len,
820f33aa 1253 &c_convstr, &convlen, func);
b89c4943
LC
1254
1255 scm_remember_upto_here (str);
1256
27f3413e
MG
1257 if (SCM_UNLIKELY (ret != 0))
1258 {
820f33aa 1259 *err = ret;
4d40bea6 1260 return SCM_BOOL_F;
27f3413e
MG
1261 }
1262
190d4b0d 1263 convstr = scm_i_make_wide_string (convlen, &c_buf, 0);
820f33aa
JG
1264 memcpy (c_buf, c_convstr, convlen * sizeof (scm_t_wchar));
1265 free (c_convstr);
27f3413e 1266
820f33aa 1267 scm_i_try_narrow_string (convstr);
27f3413e 1268
820f33aa
JG
1269 return convstr;
1270}
44d3d111 1271#undef FUNC_NAME
820f33aa
JG
1272
1273SCM_DEFINE (scm_string_locale_upcase, "string-locale-upcase", 1, 1, 0,
1274 (SCM str, SCM locale),
1275 "Return a new string that is the uppercase version of "
1276 "@var{str} according to either @var{locale} or the current "
1277 "locale.")
1278#define FUNC_NAME s_scm_string_locale_upcase
1279{
1280 scm_t_locale c_locale;
1281 SCM ret;
1282 int err = 0;
1283
1284 SCM_VALIDATE_STRING (1, str);
1285 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1286
44d3d111 1287 ret = str_to_case (str, c_locale, u32_toupper, FUNC_NAME, &err);
820f33aa
JG
1288
1289 if (err != 0)
1290 {
1291 errno = err;
1292 scm_syserror (FUNC_NAME);
1293 }
1294 return ret;
b89c4943
LC
1295}
1296#undef FUNC_NAME
9361f762 1297
b89c4943
LC
1298SCM_DEFINE (scm_string_locale_downcase, "string-locale-downcase", 1, 1, 0,
1299 (SCM str, SCM locale),
1300 "Return a new string that is the down-case version of "
1301 "@var{str} according to either @var{locale} or the current "
1302 "locale.")
1303#define FUNC_NAME s_scm_string_locale_downcase
1304{
b89c4943 1305 scm_t_locale c_locale;
820f33aa
JG
1306 SCM ret;
1307 int err = 0;
b89c4943
LC
1308
1309 SCM_VALIDATE_STRING (1, str);
1310 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1311
44d3d111 1312 ret = str_to_case (str, c_locale, u32_tolower, FUNC_NAME, &err);
9361f762 1313
820f33aa 1314 if (err != 0)
27f3413e 1315 {
820f33aa 1316 errno = err;
27f3413e
MG
1317 scm_syserror (FUNC_NAME);
1318 }
820f33aa
JG
1319 return ret;
1320}
1321#undef FUNC_NAME
1322
1323SCM_DEFINE (scm_string_locale_titlecase, "string-locale-titlecase", 1, 1, 0,
1324 (SCM str, SCM locale),
1325 "Return a new string that is the title-case version of "
1326 "@var{str} according to either @var{locale} or the current "
1327 "locale.")
1328#define FUNC_NAME s_scm_string_locale_titlecase
1329{
1330 scm_t_locale c_locale;
1331 SCM ret;
1332 int err = 0;
27f3413e 1333
820f33aa
JG
1334 SCM_VALIDATE_STRING (1, str);
1335 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
27f3413e 1336
44d3d111 1337 ret = str_to_case (str, c_locale, u32_totitle, FUNC_NAME, &err);
27f3413e 1338
820f33aa
JG
1339 if (err != 0)
1340 {
1341 errno = err;
1342 scm_syserror (FUNC_NAME);
1343 }
1344 return ret;
9361f762
MV
1345}
1346#undef FUNC_NAME
1347
b89c4943
LC
1348/* Note: We don't provide mutative versions of `string-locale-(up|down)case'
1349 because, in some languages, a single downcase character maps to a couple
1350 of uppercase characters. Read the SRFI-13 document for a detailed
1351 discussion about this. */
1352
1353
1354\f
1355/* Locale-dependent number parsing. */
1356
1357SCM_DEFINE (scm_locale_string_to_integer, "locale-string->integer",
1358 1, 2, 0, (SCM str, SCM base, SCM locale),
1359 "Convert string @var{str} into an integer according to either "
1360 "@var{locale} (a locale object as returned by @code{make-locale}) "
1361 "or the current process locale. Return two values: an integer "
1362 "(on success) or @code{#f}, and the number of characters read "
1363 "from @var{str} (@code{0} on failure).")
1364#define FUNC_NAME s_scm_locale_string_to_integer
9361f762 1365{
9361f762 1366 SCM result;
b89c4943
LC
1367 long c_result;
1368 int c_base;
1369 const char *c_str;
1370 char *c_endptr;
1371 scm_t_locale c_locale;
9361f762 1372
b89c4943
LC
1373 SCM_VALIDATE_STRING (1, str);
1374 c_str = scm_i_string_chars (str);
9361f762 1375
d223c3fc 1376 if (!scm_is_eq (base, SCM_UNDEFINED))
b89c4943 1377 SCM_VALIDATE_INT_COPY (2, base, c_base);
9361f762 1378 else
b89c4943
LC
1379 c_base = 10;
1380
1381 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
1382
1383 if (c_locale != NULL)
9361f762 1384 {
b89c4943
LC
1385#ifdef USE_GNU_LOCALE_API
1386 c_result = strtol_l (c_str, &c_endptr, c_base, c_locale);
1387#else
1388 RUN_IN_LOCALE_SECTION (c_locale,
1389 c_result = strtol (c_str, &c_endptr, c_base));
1390#endif
9361f762 1391 }
b89c4943
LC
1392 else
1393 c_result = strtol (c_str, &c_endptr, c_base);
1394
1395 scm_remember_upto_here (str);
1396
1397 if (c_endptr == c_str)
1398 result = SCM_BOOL_F;
1399 else
1400 result = scm_from_long (c_result);
1401
1402 return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
1403}
1404#undef FUNC_NAME
1405
1406SCM_DEFINE (scm_locale_string_to_inexact, "locale-string->inexact",
1407 1, 1, 0, (SCM str, SCM locale),
1408 "Convert string @var{str} into an inexact number according to "
1409 "either @var{locale} (a locale object as returned by "
1410 "@code{make-locale}) or the current process locale. Return "
1411 "two values: an inexact number (on success) or @code{#f}, and "
1412 "the number of characters read from @var{str} (@code{0} on "
1413 "failure).")
1414#define FUNC_NAME s_scm_locale_string_to_inexact
1415{
1416 SCM result;
1417 double c_result;
1418 const char *c_str;
1419 char *c_endptr;
1420 scm_t_locale c_locale;
9361f762 1421
b89c4943
LC
1422 SCM_VALIDATE_STRING (1, str);
1423 c_str = scm_i_string_chars (str);
9361f762 1424
b89c4943 1425 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
9361f762 1426
b89c4943
LC
1427 if (c_locale != NULL)
1428 {
1429#ifdef USE_GNU_LOCALE_API
1430 c_result = strtod_l (c_str, &c_endptr, c_locale);
1431#else
1432 RUN_IN_LOCALE_SECTION (c_locale,
1433 c_result = strtod (c_str, &c_endptr));
1434#endif
1435 }
9361f762 1436 else
b89c4943
LC
1437 c_result = strtod (c_str, &c_endptr);
1438
1439 scm_remember_upto_here (str);
1440
1441 if (c_endptr == c_str)
9361f762 1442 result = SCM_BOOL_F;
b89c4943
LC
1443 else
1444 result = scm_from_double (c_result);
9361f762 1445
b89c4943 1446 return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
9361f762
MV
1447}
1448#undef FUNC_NAME
1449
b89c4943 1450\f
a2f00b9b
LC
1451/* Language information, aka. `nl_langinfo ()'. */
1452
1453/* FIXME: Issues related to `nl-langinfo'.
1454
1455 1. The `CODESET' value is not normalized. This is a secondary issue, but
1456 still a practical issue. See
1457 http://www.cl.cam.ac.uk/~mgk25/ucs/norm_charmap.c for codeset
1458 normalization.
1459
1460 2. `nl_langinfo ()' is not available on Windows.
1461
1462 3. `nl_langinfo ()' may return strings encoded in a locale different from
52642040
MG
1463 the current one.
1464 For example:
a2f00b9b
LC
1465
1466 (nl-langinfo DAY_1 (make-locale LC_ALL "eo_EO.UTF-8"))
1467
52642040
MG
1468 returns a result that is a UTF-8 string, regardless of the
1469 setting of the current locale. If nl_langinfo supports CODESET,
1470 we can convert the string properly using scm_from_stringn. If
1471 CODESET is not supported, we won't be able to make much sense of
56d288b8
LC
1472 the returned string.
1473
1474 Note: We don't use Gnulib's `nl_langinfo' module because it's currently not
1475 as complete as the compatibility hacks in `i18n.scm'. */
a2f00b9b
LC
1476
1477
1478SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0,
1479 (SCM item, SCM locale),
1480 "Return a string denoting locale information for @var{item} "
1481 "in the current locale or that specified by @var{locale}. "
1482 "The semantics and arguments are the same as those of the "
1483 "X/Open @code{nl_langinfo} function (@pxref{The Elegant and "
1484 "Fast Way, @code{nl_langinfo},, libc, The GNU C Library "
1485 "Reference Manual}).")
1486#define FUNC_NAME s_scm_nl_langinfo
1487{
1488#ifdef HAVE_NL_LANGINFO
1489 SCM result;
1490 nl_item c_item;
1491 char *c_result;
1492 scm_t_locale c_locale;
52642040
MG
1493#ifdef HAVE_LANGINFO_CODESET
1494 char *codeset;
1495#endif
a2f00b9b
LC
1496
1497 SCM_VALIDATE_INT_COPY (2, item, c_item);
1498 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1499
1500 /* Sadly, `nl_langinfo ()' returns a pointer to a static string. According
1501 to SuS v2, that static string may be modified by subsequent calls to
1502 `nl_langinfo ()' as well as by calls to `setlocale ()'. Thus, we must
1503 acquire the locale mutex before doing invoking `nl_langinfo ()'. See
1504 http://opengroup.org/onlinepubs/007908799/xsh/nl_langinfo.html for
1505 details. */
1506
073167ef 1507 lock_locale_mutex ();
a2f00b9b
LC
1508 if (c_locale != NULL)
1509 {
1510#ifdef USE_GNU_LOCALE_API
1511 c_result = nl_langinfo_l (c_item, c_locale);
52642040
MG
1512#ifdef HAVE_LANGINFO_CODESET
1513 codeset = nl_langinfo_l (CODESET, c_locale);
1514#endif /* HAVE_LANGINFO_CODESET */
1515#else /* !USE_GNU_LOCALE_API */
a2f00b9b
LC
1516 /* We can't use `RUN_IN_LOCALE_SECTION ()' here because the locale
1517 mutex is already taken. */
1518 int lsec_err;
1519 scm_t_locale_settings lsec_prev_locale;
1520
1521 lsec_err = get_current_locale_settings (&lsec_prev_locale);
1522 if (lsec_err)
073167ef 1523 unlock_locale_mutex ();
a2f00b9b
LC
1524 else
1525 {
1526 lsec_err = install_locale (c_locale);
1527 if (lsec_err)
1528 {
1529 leave_locale_section (&lsec_prev_locale);
1530 free_locale_settings (&lsec_prev_locale);
1531 }
1532 }
1533
1534 if (lsec_err)
1535 scm_locale_error (FUNC_NAME, lsec_err);
1536 else
1537 {
1538 c_result = nl_langinfo (c_item);
52642040
MG
1539#ifdef HAVE_LANGINFO_CODESET
1540 codeset = nl_langinfo (CODESET);
1541#endif /* HAVE_LANGINFO_CODESET */
a2f00b9b 1542
1445e449 1543 restore_locale_settings (&lsec_prev_locale);
a2f00b9b
LC
1544 free_locale_settings (&lsec_prev_locale);
1545 }
1546#endif
1547 }
1548 else
52642040
MG
1549 {
1550 c_result = nl_langinfo (c_item);
1551#ifdef HAVE_LANGINFO_CODESET
1552 codeset = nl_langinfo (CODESET);
1553#endif /* HAVE_LANGINFO_CODESET */
1554 }
a2f00b9b
LC
1555
1556 c_result = strdup (c_result);
073167ef 1557 unlock_locale_mutex ();
a2f00b9b
LC
1558
1559 if (c_result == NULL)
1560 result = SCM_BOOL_F;
1561 else
1562 {
a2f00b9b
LC
1563 switch (c_item)
1564 {
afb49959 1565#if (defined GROUPING) && (defined MON_GROUPING)
a2f00b9b
LC
1566 case GROUPING:
1567 case MON_GROUPING:
a2f00b9b 1568 {
afb49959 1569 char *p;
a2f00b9b 1570
914c4300
LC
1571 /* In this cases, the result is to be interpreted as a list
1572 of numbers. If the last item is `CHAR_MAX' or a negative
1573 number, it has the special meaning "no more grouping"
1574 (negative numbers aren't specified in POSIX but can be
1575 used by glibc; see
1576 <http://lists.gnu.org/archive/html/bug-guile/2011-02/msg00159.html>). */
afb49959 1577 result = SCM_EOL;
914c4300 1578 for (p = c_result; (*p > 0) && (*p != CHAR_MAX); p++)
afb49959 1579 result = scm_cons (SCM_I_MAKINUM ((int) *p), result);
a2f00b9b 1580
afb49959
LC
1581 {
1582 SCM last_pair = result;
a2f00b9b 1583
afb49959
LC
1584 result = scm_reverse_x (result, SCM_EOL);
1585
914c4300 1586 if (*p == 0)
afb49959
LC
1587 {
1588 /* Cyclic grouping information. */
393baa8a 1589 if (!scm_is_null (last_pair))
afb49959
LC
1590 SCM_SETCDR (last_pair, result);
1591 }
1592 }
a2f00b9b 1593
afb49959
LC
1594 free (c_result);
1595 break;
1596 }
1597#endif
1598
1599#if (defined FRAC_DIGITS) && (defined INT_FRAC_DIGITS)
a2f00b9b
LC
1600 case FRAC_DIGITS:
1601 case INT_FRAC_DIGITS:
1602 /* This is to be interpreted as a single integer. */
1603 if (*c_result == CHAR_MAX)
1604 /* Unspecified. */
1605 result = SCM_BOOL_F;
1606 else
1607 result = SCM_I_MAKINUM (*c_result);
1608
1609 free (c_result);
1610 break;
afb49959 1611#endif
a2f00b9b 1612
afb49959 1613#if (defined P_CS_PRECEDES) && (defined INT_N_CS_PRECEDES)
a2f00b9b
LC
1614 case P_CS_PRECEDES:
1615 case N_CS_PRECEDES:
1616 case INT_P_CS_PRECEDES:
1617 case INT_N_CS_PRECEDES:
afb49959 1618#if (defined P_SEP_BY_SPACE) && (defined N_SEP_BY_SPACE)
a2f00b9b
LC
1619 case P_SEP_BY_SPACE:
1620 case N_SEP_BY_SPACE:
afb49959 1621#endif
a2f00b9b
LC
1622 /* This is to be interpreted as a boolean. */
1623 result = scm_from_bool (*c_result);
1624
1625 free (c_result);
1626 break;
afb49959 1627#endif
a2f00b9b 1628
afb49959 1629#if (defined P_SIGN_POSN) && (defined INT_N_SIGN_POSN)
a2f00b9b
LC
1630 case P_SIGN_POSN:
1631 case N_SIGN_POSN:
1632 case INT_P_SIGN_POSN:
1633 case INT_N_SIGN_POSN:
1634 /* See `(libc) Sign of Money Amount' for the interpretation of the
1635 return value here. */
1636 switch (*c_result)
1637 {
1638 case 0:
4a655e50 1639 result = scm_from_latin1_symbol ("parenthesize");
a2f00b9b
LC
1640 break;
1641
1642 case 1:
4a655e50 1643 result = scm_from_latin1_symbol ("sign-before");
a2f00b9b
LC
1644 break;
1645
1646 case 2:
4a655e50 1647 result = scm_from_latin1_symbol ("sign-after");
a2f00b9b
LC
1648 break;
1649
1650 case 3:
4a655e50 1651 result = scm_from_latin1_symbol ("sign-before-currency-symbol");
a2f00b9b
LC
1652 break;
1653
1654 case 4:
4a655e50 1655 result = scm_from_latin1_symbol ("sign-after-currency-symbol");
a2f00b9b
LC
1656 break;
1657
1658 default:
4a655e50 1659 result = scm_from_latin1_symbol ("unspecified");
a2f00b9b
LC
1660 }
1661 break;
afb49959 1662#endif
a2f00b9b
LC
1663
1664 default:
52642040
MG
1665#ifdef HAVE_LANGINFO_CODESET
1666 result = scm_from_stringn (c_result, strlen (c_result),
1667 codeset,
1668 SCM_FAILED_CONVERSION_QUESTION_MARK);
1669#else /* !HAVE_LANGINFO_CODESET */
1670 /* This may be incorrectly encoded if the locale differs
1671 from the c_locale. */
1672 result = scm_from_locale_string (c_result);
1673#endif /* !HAVE_LANGINFO_CODESET */
b8fc11d2 1674 free (c_result);
a2f00b9b
LC
1675 }
1676 }
1677
1678 return result;
1679#else
1680 scm_syserror_msg (FUNC_NAME, "`nl-langinfo' not supported on your system",
1681 SCM_EOL, ENOSYS);
1682
1683 return SCM_BOOL_F;
1684#endif
1685}
1686#undef FUNC_NAME
1687
1688/* Define the `nl_item' constants. */
1689static inline void
1690define_langinfo_items (void)
9361f762 1691{
24deb6d0 1692#ifdef HAVE_LANGINFO_H
a2f00b9b
LC
1693
1694#define DEFINE_NLITEM_CONSTANT(_item) \
1695 scm_c_define (# _item, scm_from_int (_item))
1696
1697 DEFINE_NLITEM_CONSTANT (CODESET);
1698
1699 /* Abbreviated days of the week. */
1700 DEFINE_NLITEM_CONSTANT (ABDAY_1);
1701 DEFINE_NLITEM_CONSTANT (ABDAY_2);
1702 DEFINE_NLITEM_CONSTANT (ABDAY_3);
1703 DEFINE_NLITEM_CONSTANT (ABDAY_4);
1704 DEFINE_NLITEM_CONSTANT (ABDAY_5);
1705 DEFINE_NLITEM_CONSTANT (ABDAY_6);
1706 DEFINE_NLITEM_CONSTANT (ABDAY_7);
1707
1708 /* Long-named days of the week. */
1709 DEFINE_NLITEM_CONSTANT (DAY_1); /* Sunday */
1710 DEFINE_NLITEM_CONSTANT (DAY_2); /* Monday */
1711 DEFINE_NLITEM_CONSTANT (DAY_3); /* Tuesday */
1712 DEFINE_NLITEM_CONSTANT (DAY_4); /* Wednesday */
1713 DEFINE_NLITEM_CONSTANT (DAY_5); /* Thursday */
1714 DEFINE_NLITEM_CONSTANT (DAY_6); /* Friday */
1715 DEFINE_NLITEM_CONSTANT (DAY_7); /* Saturday */
1716
1717 /* Abbreviated month names. */
1718 DEFINE_NLITEM_CONSTANT (ABMON_1); /* Jan */
1719 DEFINE_NLITEM_CONSTANT (ABMON_2);
1720 DEFINE_NLITEM_CONSTANT (ABMON_3);
1721 DEFINE_NLITEM_CONSTANT (ABMON_4);
1722 DEFINE_NLITEM_CONSTANT (ABMON_5);
1723 DEFINE_NLITEM_CONSTANT (ABMON_6);
1724 DEFINE_NLITEM_CONSTANT (ABMON_7);
1725 DEFINE_NLITEM_CONSTANT (ABMON_8);
1726 DEFINE_NLITEM_CONSTANT (ABMON_9);
1727 DEFINE_NLITEM_CONSTANT (ABMON_10);
1728 DEFINE_NLITEM_CONSTANT (ABMON_11);
1729 DEFINE_NLITEM_CONSTANT (ABMON_12);
1730
1731 /* Long month names. */
1732 DEFINE_NLITEM_CONSTANT (MON_1); /* January */
1733 DEFINE_NLITEM_CONSTANT (MON_2);
1734 DEFINE_NLITEM_CONSTANT (MON_3);
1735 DEFINE_NLITEM_CONSTANT (MON_4);
1736 DEFINE_NLITEM_CONSTANT (MON_5);
1737 DEFINE_NLITEM_CONSTANT (MON_6);
1738 DEFINE_NLITEM_CONSTANT (MON_7);
1739 DEFINE_NLITEM_CONSTANT (MON_8);
1740 DEFINE_NLITEM_CONSTANT (MON_9);
1741 DEFINE_NLITEM_CONSTANT (MON_10);
1742 DEFINE_NLITEM_CONSTANT (MON_11);
1743 DEFINE_NLITEM_CONSTANT (MON_12);
1744
1745 DEFINE_NLITEM_CONSTANT (AM_STR); /* Ante meridiem string. */
1746 DEFINE_NLITEM_CONSTANT (PM_STR); /* Post meridiem string. */
1747
1748 DEFINE_NLITEM_CONSTANT (D_T_FMT); /* Date and time format for strftime. */
1749 DEFINE_NLITEM_CONSTANT (D_FMT); /* Date format for strftime. */
1750 DEFINE_NLITEM_CONSTANT (T_FMT); /* Time format for strftime. */
1751 DEFINE_NLITEM_CONSTANT (T_FMT_AMPM);/* 12-hour time format for strftime. */
1752
1753 DEFINE_NLITEM_CONSTANT (ERA); /* Alternate era. */
1754 DEFINE_NLITEM_CONSTANT (ERA_D_FMT); /* Date in alternate era format. */
1755 DEFINE_NLITEM_CONSTANT (ERA_D_T_FMT); /* Date and time in alternate era
1756 format. */
1757 DEFINE_NLITEM_CONSTANT (ERA_T_FMT); /* Time in alternate era format. */
1758
1759 DEFINE_NLITEM_CONSTANT (ALT_DIGITS); /* Alternate symbols for digits. */
1760 DEFINE_NLITEM_CONSTANT (RADIXCHAR);
1761 DEFINE_NLITEM_CONSTANT (THOUSEP);
1762
1763#ifdef YESEXPR
1764 DEFINE_NLITEM_CONSTANT (YESEXPR);
1765#endif
1766#ifdef NOEXPR
1767 DEFINE_NLITEM_CONSTANT (NOEXPR);
1768#endif
b89c4943 1769
a2f00b9b
LC
1770#ifdef CRNCYSTR /* currency symbol */
1771 DEFINE_NLITEM_CONSTANT (CRNCYSTR);
1772#endif
b89c4943 1773
a2f00b9b 1774 /* GNU extensions. */
b89c4943 1775
a2f00b9b
LC
1776#ifdef ERA_YEAR
1777 DEFINE_NLITEM_CONSTANT (ERA_YEAR); /* Year in alternate era format. */
1778#endif
b89c4943 1779
a2f00b9b
LC
1780 /* LC_MONETARY category: formatting of monetary quantities.
1781 These items each correspond to a member of `struct lconv',
1782 defined in <locale.h>. */
1783#ifdef INT_CURR_SYMBOL
1784 DEFINE_NLITEM_CONSTANT (INT_CURR_SYMBOL);
1785#endif
1786#ifdef MON_DECIMAL_POINT
1787 DEFINE_NLITEM_CONSTANT (MON_DECIMAL_POINT);
1788#endif
1789#ifdef MON_THOUSANDS_SEP
1790 DEFINE_NLITEM_CONSTANT (MON_THOUSANDS_SEP);
1791#endif
1792#ifdef MON_GROUPING
1793 DEFINE_NLITEM_CONSTANT (MON_GROUPING);
1794#endif
1795#ifdef POSITIVE_SIGN
1796 DEFINE_NLITEM_CONSTANT (POSITIVE_SIGN);
1797#endif
1798#ifdef NEGATIVE_SIGN
1799 DEFINE_NLITEM_CONSTANT (NEGATIVE_SIGN);
1800#endif
1801#ifdef GROUPING
1802 DEFINE_NLITEM_CONSTANT (GROUPING);
1803#endif
1804#ifdef INT_FRAC_DIGITS
1805 DEFINE_NLITEM_CONSTANT (INT_FRAC_DIGITS);
1806#endif
1807#ifdef FRAC_DIGITS
1808 DEFINE_NLITEM_CONSTANT (FRAC_DIGITS);
1809#endif
1810#ifdef P_CS_PRECEDES
1811 DEFINE_NLITEM_CONSTANT (P_CS_PRECEDES);
1812#endif
1813#ifdef P_SEP_BY_SPACE
1814 DEFINE_NLITEM_CONSTANT (P_SEP_BY_SPACE);
1815#endif
1816#ifdef N_CS_PRECEDES
1817 DEFINE_NLITEM_CONSTANT (N_CS_PRECEDES);
1818#endif
1819#ifdef N_SEP_BY_SPACE
1820 DEFINE_NLITEM_CONSTANT (N_SEP_BY_SPACE);
1821#endif
1822#ifdef P_SIGN_POSN
1823 DEFINE_NLITEM_CONSTANT (P_SIGN_POSN);
1824#endif
1825#ifdef N_SIGN_POSN
1826 DEFINE_NLITEM_CONSTANT (N_SIGN_POSN);
1827#endif
1828#ifdef INT_P_CS_PRECEDES
1829 DEFINE_NLITEM_CONSTANT (INT_P_CS_PRECEDES);
1830#endif
1831#ifdef INT_P_SEP_BY_SPACE
1832 DEFINE_NLITEM_CONSTANT (INT_P_SEP_BY_SPACE);
1833#endif
1834#ifdef INT_N_CS_PRECEDES
1835 DEFINE_NLITEM_CONSTANT (INT_N_CS_PRECEDES);
1836#endif
1837#ifdef INT_N_SEP_BY_SPACE
1838 DEFINE_NLITEM_CONSTANT (INT_N_SEP_BY_SPACE);
1839#endif
1840#ifdef INT_P_SIGN_POSN
1841 DEFINE_NLITEM_CONSTANT (INT_P_SIGN_POSN);
1842#endif
1843#ifdef INT_N_SIGN_POSN
1844 DEFINE_NLITEM_CONSTANT (INT_N_SIGN_POSN);
1845#endif
1846
1847#undef DEFINE_NLITEM_CONSTANT
1848
1849#endif /* HAVE_NL_TYPES_H */
1850}
1851
1852\f
1853void
1854scm_init_i18n ()
1855{
1856 SCM global_locale_smob;
1857
1858#ifdef HAVE_NL_LANGINFO
1859 scm_add_feature ("nl-langinfo");
1860 define_langinfo_items ();
1861#endif
b89c4943 1862
9361f762 1863#include "libguile/i18n.x"
b89c4943 1864
a2f00b9b 1865 /* Initialize the global locale object with a special `locale' SMOB. */
c3b16a5d
LC
1866 /* XXX: We don't define it as `LC_GLOBAL_LOCALE' because of bugs as of
1867 glibc <= 2.11 not (yet) worked around by Gnulib. See
1868 http://sourceware.org/bugzilla/show_bug.cgi?id=11009 for details. */
a2f00b9b
LC
1869 SCM_NEWSMOB (global_locale_smob, scm_tc16_locale_smob_type, NULL);
1870 SCM_VARIABLE_SET (scm_global_locale, global_locale_smob);
9361f762
MV
1871}
1872
756e8a3a
LC
1873void
1874scm_bootstrap_i18n ()
1875{
44602b08
AW
1876 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1877 "scm_init_i18n",
756e8a3a
LC
1878 (scm_t_extension_init_func) scm_init_i18n,
1879 NULL);
1880
1881}
1882
9361f762
MV
1883
1884/*
1885 Local Variables:
1886 c-file-style: "gnu"
1887 End:
1888*/