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