fix leak in get_current_locale()
[bpt/guile.git] / libguile / i18n.c
1 /* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
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
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <alloca.h>
24
25 #include "libguile/_scm.h"
26 #include "libguile/extensions.h"
27 #include "libguile/feature.h"
28 #include "libguile/i18n.h"
29 #include "libguile/strings.h"
30 #include "libguile/chars.h"
31 #include "libguile/dynwind.h"
32 #include "libguile/validate.h"
33 #include "libguile/values.h"
34 #include "libguile/threads.h"
35
36 #include <locale.h>
37 #include <string.h> /* `strcoll ()' */
38 #include <ctype.h> /* `toupper ()' et al. */
39 #include <errno.h>
40 #include <unicase.h>
41 #include <unistr.h>
42
43 #if (defined HAVE_NEWLOCALE) && (defined HAVE_STRCOLL_L)
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
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 */
57 # define USE_GNU_LOCALE_API
58 #endif
59
60 #include "libguile/posix.h" /* for `scm_i_locale_mutex' */
61
62 #ifdef HAVE_LANGINFO_H
63 # include <langinfo.h>
64 #endif
65 #ifdef HAVE_NL_TYPES_H
66 # include <nl_types.h>
67 #endif
68 #ifndef HAVE_NL_ITEM
69 /* Cygwin has <langinfo.h> but lacks <nl_types.h> and `nl_item'. */
70 typedef int nl_item;
71 #endif
72
73 #ifndef HAVE_SETLOCALE
74 static inline char *
75 setlocale (int category, const char *name)
76 {
77 errno = ENOSYS;
78 return NULL;
79 }
80 #endif
81
82 /* Helper stringification macro. */
83 #define SCM_I18N_STRINGIFY(_name) # _name
84
85 /* Acquiring and releasing the locale lock. */
86
87 static inline void
88 lock_locale_mutex (void)
89 {
90 #ifdef HAVE_POSIX
91 scm_i_pthread_mutex_lock (&scm_i_locale_mutex);
92 #else
93 #endif
94 }
95
96 static inline void
97 unlock_locale_mutex (void)
98 {
99 #ifdef HAVE_POSIX
100 scm_i_pthread_mutex_unlock (&scm_i_locale_mutex);
101 #else
102 #endif
103 }
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
113 1. The `scm_i_locale_mutex' is locked.
114 2. A series of `setlocale ()' call is performed to store the current
115 locale for each category in an `scm_t_locale' object.
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.
120 5. The `scm_i_locale_mutex' is released.
121
122 Hopefully, the X/Open standard will eventually make this hack useless.
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
130 /* Return the category mask corresponding to CAT. */
131 #define SCM_LOCALE_CATEGORY_MASK(_cat) LC_ ## _cat ## _MASK
132
133
134 #ifndef USE_GNU_LOCALE_API
135
136 /* Provide the locale category masks as found in glibc. This must be kept in
137 sync with `locale-categories.h'. */
138
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
145
146 # ifdef LC_PAPER
147 # define LC_PAPER_MASK 64
148 # else
149 # define LC_PAPER_MASK 0
150 # endif
151 # ifdef LC_NAME
152 # define LC_NAME_MASK 128
153 # else
154 # define LC_NAME_MASK 0
155 # endif
156 # ifdef LC_ADDRESS
157 # define LC_ADDRESS_MASK 256
158 # else
159 # define LC_ADDRESS_MASK 0
160 # endif
161 # ifdef LC_TELEPHONE
162 # define LC_TELEPHONE_MASK 512
163 # else
164 # define LC_TELEPHONE_MASK 0
165 # endif
166 # ifdef LC_MEASUREMENT
167 # define LC_MEASUREMENT_MASK 1024
168 # else
169 # define LC_MEASUREMENT_MASK 0
170 # endif
171 # ifdef LC_IDENTIFICATION
172 # define LC_IDENTIFICATION_MASK 2048
173 # else
174 # define LC_IDENTIFICATION_MASK 0
175 # endif
176
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 \
189 )
190
191 /* Locale objects as returned by `make-locale' on non-GNU systems. */
192 typedef struct scm_locale
193 {
194 SCM base_locale; /* a `locale' object */
195 char *locale_name;
196 int category_mask;
197 } *scm_t_locale;
198
199
200 /* Free the resources used by LOCALE. */
201 static inline void
202 scm_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 */
209
210 /* Alias for glibc's locale type. */
211 typedef locale_t scm_t_locale;
212
213 #define scm_i_locale_free freelocale
214
215 #endif /* USE_GNU_LOCALE_API */
216
217
218 /* A locale object denoting the global locale. */
219 SCM_GLOBAL_VARIABLE (scm_global_locale, "%global-locale");
220
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 { \
237 if (!scm_is_eq ((_arg), SCM_UNDEFINED)) \
238 SCM_VALIDATE_LOCALE_COPY (_pos, _arg, _c_locale); \
239 else \
240 (_c_locale) = NULL; \
241 } \
242 while (0)
243
244
245 SCM_SMOB (scm_tc16_locale_smob_type, "locale", 0);
246
247 SCM_SMOB_FREE (scm_tc16_locale_smob_type, smob_locale_free, locale)
248 {
249 scm_t_locale c_locale;
250
251 c_locale = (scm_t_locale) SCM_SMOB_DATA (locale);
252 scm_i_locale_free (c_locale);
253
254 return 0;
255 }
256
257
258 static void inline scm_locale_error (const char *, int) SCM_NORETURN;
259
260 /* Throw an exception corresponding to error ERR. */
261 static void inline
262 scm_locale_error (const char *func_name, int err)
263 {
264 scm_syserror_msg (func_name,
265 "Failed to install locale",
266 SCM_EOL, err);
267 }
268
269
270 \f
271 /* Emulating GNU's reentrant locale API. */
272 #ifndef USE_GNU_LOCALE_API
273
274
275 /* Maximum number of chained locales (via `base_locale'). */
276 #define LOCALE_STACK_SIZE_MAX 256
277
278 typedef 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. */
287 static int
288 get_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)); \
295 if (locale_name == NULL) \
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:
309 return EINVAL;
310
311 handle_oom:
312 return ENOMEM;
313 }
314
315 /* Restore locale settings SETTINGS. On success, return zero. */
316 static int
317 restore_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:
332 return EINVAL;
333 }
334
335 /* Free memory associated with SETTINGS. */
336 static void
337 free_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 }
345
346 /* Install the locale named LOCALE_NAME for all the categories listed in
347 CATEGORY_MASK. */
348 static int
349 install_locale_categories (const char *locale_name, int category_mask)
350 {
351 const char *result;
352
353 if (category_mask == LC_ALL_MASK)
354 {
355 SCM_SYSCALL (result = setlocale (LC_ALL, locale_name));
356 if (result == NULL)
357 goto handle_error;
358 }
359 else
360 {
361 #define SCM_DEFINE_LOCALE_CATEGORY(_name) \
362 if (category_mask & SCM_LOCALE_CATEGORY_MASK (_name)) \
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 }
371
372 return 0;
373
374 handle_error:
375 return EINVAL;
376 }
377
378 /* Install LOCALE, recursively installing its base locales first. On
379 success, zero is returned. */
380 static int
381 install_locale (scm_t_locale locale)
382 {
383 scm_t_locale stack[LOCALE_STACK_SIZE_MAX];
384 int category_mask = 0;
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
399 /* Keep track of which categories have already been taken into
400 account. */
401 category_mask |= locale->category_mask;
402
403 if (!SCM_UNBNDP (locale->base_locale))
404 locale = (scm_t_locale) SCM_SMOB_DATA (locale->base_locale);
405 else
406 locale = NULL;
407 }
408 while ((locale != NULL) && (category_mask != LC_ALL_MASK));
409
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;
428 }
429
430 return 0;
431
432 handle_error:
433 return EINVAL;
434 }
435
436 /* Leave the locked locale section. */
437 static inline void
438 leave_locale_section (const scm_t_locale_settings *settings)
439 {
440 /* Restore the previous locale settings. */
441 (void)restore_locale_settings (settings);
442
443 unlock_locale_mutex ();
444 }
445
446 /* Enter a locked locale section. */
447 static inline int
448 enter_locale_section (scm_t_locale locale,
449 scm_t_locale_settings *prev_locale)
450 {
451 int err;
452
453 lock_locale_mutex ();
454
455 err = get_current_locale_settings (prev_locale);
456 if (err)
457 {
458 unlock_locale_mutex ();
459 return err;
460 }
461
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
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
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. */
495 static int
496 get_current_locale (SCM *result)
497 {
498 int err = 0;
499 scm_t_locale c_locale;
500 const char *current_locale;
501
502 c_locale = scm_gc_malloc (sizeof (* c_locale), "locale");
503
504 lock_locale_mutex ();
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)
511 c_locale->locale_name = scm_gc_strdup (current_locale);
512 else
513 err = EINVAL;
514
515 unlock_locale_mutex ();
516
517 if (err == 0)
518 SCM_NEWSMOB (*result, scm_tc16_locale_smob_type, c_locale);
519 else
520 *result = SCM_BOOL_F;
521
522 return err;
523 }
524
525 #else /* USE_GNU_LOCALE_API */
526
527 /* Convenient macro to run STATEMENT in the locale context of C_LOCALE. */
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 } \
537 while (0)
538
539
540 #endif /* USE_GNU_LOCALE_API */
541
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). */
552 static inline int
553 category_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. */
586 static int
587 category_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
608 SCM_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)))
637 c_base_locale = LC_GLOBAL_LOCALE;
638
639 if (c_base_locale != (locale_t) 0)
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);
644
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 {
658 if (c_base_locale != (locale_t) 0)
659 freelocale (c_base_locale);
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);
689
690 if (err)
691 goto fail;
692 else
693 {
694 leave_locale_section (&prev_locale);
695 SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale);
696 }
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
714 SCM_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
724 \f
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
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); \
739 c_s1 = alloca (sizeof (scm_t_wchar) * (len + 1)); \
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. */
753 static inline int
754 compare_u32_strings (SCM s1, SCM s2, SCM locale, const char *func_name)
755 #define FUNC_NAME func_name
756 {
757 int result;
758 scm_t_locale c_locale;
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
770 result = u32_strcoll ((const scm_t_uint32 *) c_s1,
771 (const scm_t_uint32 *) c_s2);
772
773 scm_remember_upto_here_2 (s1, s2);
774 scm_remember_upto_here (locale);
775 return result;
776 }
777 #undef FUNC_NAME
778
779 /* Return the current language of the locale. */
780 static const char *
781 locale_language ()
782 {
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. */
787 return uc_locale_language ();
788 }
789
790 static inline int
791 u32_locale_casecoll (const char *func_name, const scm_t_uint32 *c_s1,
792 const scm_t_uint32 *c_s2,
793 int *result)
794 {
795 /* Note: Since this is called from `RUN_IN_LOCALE_SECTION', it must note
796 make any non-local exit. */
797
798 int ret;
799 const char *loc = locale_language ();
800
801 ret = u32_casecoll (c_s1, u32_strlen (c_s1),
802 c_s2, u32_strlen (c_s2),
803 loc, UNINORM_NFC, result);
804
805 return ret == 0 ? ret : errno;
806 }
807
808 static inline int
809 compare_u32_strings_ci (SCM s1, SCM s2, SCM locale, const char *func_name)
810 #define FUNC_NAME func_name
811 {
812 int result, ret = 0;
813 scm_t_locale c_locale;
814 scm_t_wchar *c_s1, *c_s2;
815 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
816
817 SCM_STRING_TO_U32_BUF (s1, c_s1);
818 SCM_STRING_TO_U32_BUF (s2, c_s2);
819
820 if (c_locale)
821 RUN_IN_LOCALE_SECTION
822 (c_locale,
823 ret = u32_locale_casecoll (func_name,
824 (const scm_t_uint32 *) c_s1,
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 }
838
839 scm_remember_upto_here_2 (s1, s2);
840 scm_remember_upto_here (locale);
841
842 return result;
843 }
844 #undef FUNC_NAME
845
846 /* Store into DST an upper-case version of SRC. */
847 static inline void
848 str_upcase (register char *dst, register const char *src)
849 {
850 for (; *src != '\0'; src++, dst++)
851 *dst = toupper ((int) *src);
852 *dst = '\0';
853 }
854
855 static inline void
856 str_downcase (register char *dst, register const char *src)
857 {
858 for (; *src != '\0'; src++, dst++)
859 *dst = tolower ((int) *src);
860 *dst = '\0';
861 }
862
863 #ifdef USE_GNU_LOCALE_API
864 static inline void
865 str_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
873 static inline void
874 str_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
884 SCM_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
891 {
892 int result;
893
894 SCM_VALIDATE_STRING (1, s1);
895 SCM_VALIDATE_STRING (2, s2);
896
897 result = compare_u32_strings (s1, s2, locale, FUNC_NAME);
898
899 return scm_from_bool (result < 0);
900 }
901 #undef FUNC_NAME
902
903 SCM_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;
912
913 SCM_VALIDATE_STRING (1, s1);
914 SCM_VALIDATE_STRING (2, s2);
915
916 result = compare_u32_strings (s1, s2, locale, FUNC_NAME);
917
918 return scm_from_bool (result > 0);
919 }
920 #undef FUNC_NAME
921
922 SCM_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;
932
933 SCM_VALIDATE_STRING (1, s1);
934 SCM_VALIDATE_STRING (2, s2);
935
936 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
937
938 return scm_from_bool (result < 0);
939 }
940 #undef FUNC_NAME
941
942 SCM_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;
952
953 SCM_VALIDATE_STRING (1, s1);
954 SCM_VALIDATE_STRING (2, s2);
955
956 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
957
958 return scm_from_bool (result > 0);
959 }
960 #undef FUNC_NAME
961
962 SCM_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;
972
973 SCM_VALIDATE_STRING (1, s1);
974 SCM_VALIDATE_STRING (2, s2);
975
976 result = compare_u32_strings_ci (s1, s2, locale, FUNC_NAME);
977
978 return scm_from_bool (result == 0);
979 }
980 #undef FUNC_NAME
981
982
983 SCM_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 {
989 int result;
990
991 SCM_VALIDATE_CHAR (1, c1);
992 SCM_VALIDATE_CHAR (2, c2);
993
994 result = compare_u32_strings (scm_string (scm_list_1 (c1)),
995 scm_string (scm_list_1 (c2)),
996 locale, FUNC_NAME);
997
998 return scm_from_bool (result < 0);
999 }
1000 #undef FUNC_NAME
1001
1002 SCM_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 {
1008 int result;
1009
1010 SCM_VALIDATE_CHAR (1, c1);
1011 SCM_VALIDATE_CHAR (2, c2);
1012
1013 result = compare_u32_strings (scm_string (scm_list_1 (c1)),
1014 scm_string (scm_list_1 (c2)),
1015 locale, FUNC_NAME);
1016
1017 return scm_from_bool (result > 0);
1018 }
1019 #undef FUNC_NAME
1020
1021 SCM_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;
1029
1030 SCM_VALIDATE_CHAR (1, c1);
1031 SCM_VALIDATE_CHAR (2, c2);
1032
1033 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1034 scm_string (scm_list_1 (c2)),
1035 locale, FUNC_NAME);
1036
1037 return scm_from_bool (result < 0);
1038 }
1039 #undef FUNC_NAME
1040
1041 SCM_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;
1049
1050 SCM_VALIDATE_CHAR (1, c1);
1051 SCM_VALIDATE_CHAR (2, c2);
1052
1053 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1054 scm_string (scm_list_1 (c2)),
1055 locale, FUNC_NAME);
1056
1057 return scm_from_bool (result > 0);
1058 }
1059 #undef FUNC_NAME
1060
1061 SCM_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;
1069
1070 SCM_VALIDATE_CHAR (1, c1);
1071 SCM_VALIDATE_CHAR (2, c2);
1072
1073 result = compare_u32_strings_ci (scm_string (scm_list_1 (c1)),
1074 scm_string (scm_list_1 (c2)),
1075 locale, FUNC_NAME);
1076
1077 return scm_from_bool (result == 0);
1078 }
1079 #undef FUNC_NAME
1080
1081
1082 \f
1083 /* Locale-dependent alphabetic character mapping. */
1084
1085 static inline int
1086 u32_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;
1096 const char *loc = locale_language ();
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 {
1105 *p_c_s2 = (scm_t_uint32 *) NULL;
1106 *p_len2 = 0;
1107 return errno;
1108 }
1109 *p_c_s2 = ret;
1110
1111 return 0;
1112 }
1113
1114
1115 static SCM
1116 chr_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 *),
1119 const char *func_name,
1120 int *err)
1121 #define FUNC_NAME func_name
1122 {
1123 int ret;
1124 scm_t_uint32 c;
1125 scm_t_uint32 *convbuf;
1126 size_t convlen;
1127 SCM convchar;
1128
1129 c = SCM_CHAR (chr);
1130
1131 if (c_locale != NULL)
1132 RUN_IN_LOCALE_SECTION (c_locale, ret =
1133 u32_locale_tocase (&c, 1, &convbuf, &convlen, func));
1134 else
1135 ret =
1136 u32_locale_tocase (&c, 1, &convbuf, &convlen, func);
1137
1138 if (SCM_UNLIKELY (ret != 0))
1139 {
1140 *err = ret;
1141 return SCM_BOOL_F;
1142 }
1143
1144 if (convlen == 1)
1145 convchar = SCM_MAKE_CHAR ((scm_t_wchar) convbuf[0]);
1146 else
1147 convchar = chr;
1148 free (convbuf);
1149
1150 return convchar;
1151 }
1152 #undef FUNC_NAME
1153
1154 SCM_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);
1166
1167 ret = chr_to_case (chr, c_locale, u32_tolower, FUNC_NAME, &err);
1168
1169 if (err != 0)
1170 {
1171 errno = err;
1172 scm_syserror (FUNC_NAME);
1173 }
1174 return ret;
1175 }
1176 #undef FUNC_NAME
1177
1178 SCM_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
1183 {
1184 scm_t_locale c_locale;
1185 SCM ret;
1186 int err = 0;
1187
1188 SCM_VALIDATE_CHAR (1, chr);
1189 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1190
1191 ret = chr_to_case (chr, c_locale, u32_toupper, FUNC_NAME, &err);
1192
1193 if (err != 0)
1194 {
1195 errno = err;
1196 scm_syserror (FUNC_NAME);
1197 }
1198 return ret;
1199 }
1200 #undef FUNC_NAME
1201
1202 SCM_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
1215 ret = chr_to_case (chr, c_locale, u32_totitle, FUNC_NAME, &err);
1216
1217 if (err != 0)
1218 {
1219 errno = err;
1220 scm_syserror (FUNC_NAME);
1221 }
1222 return ret;
1223 }
1224 #undef FUNC_NAME
1225
1226 static SCM
1227 str_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 *),
1230 const char *func_name,
1231 int *err)
1232 #define FUNC_NAME func_name
1233 {
1234 scm_t_wchar *c_str, *c_buf;
1235 scm_t_uint32 *c_convstr;
1236 size_t len, convlen;
1237 int ret;
1238 SCM convstr;
1239
1240 len = scm_i_string_length (str);
1241 if (len == 0)
1242 return scm_nullstr;
1243 SCM_STRING_TO_U32_BUF (str, c_str);
1244
1245 if (c_locale)
1246 RUN_IN_LOCALE_SECTION (c_locale, ret =
1247 u32_locale_tocase ((scm_t_uint32 *) c_str, len,
1248 &c_convstr,
1249 &convlen, func));
1250 else
1251 ret =
1252 u32_locale_tocase ((scm_t_uint32 *) c_str, len,
1253 &c_convstr, &convlen, func);
1254
1255 scm_remember_upto_here (str);
1256
1257 if (SCM_UNLIKELY (ret != 0))
1258 {
1259 *err = ret;
1260 return SCM_BOOL_F;
1261 }
1262
1263 convstr = scm_i_make_wide_string (convlen, &c_buf, 0);
1264 memcpy (c_buf, c_convstr, convlen * sizeof (scm_t_wchar));
1265 free (c_convstr);
1266
1267 scm_i_try_narrow_string (convstr);
1268
1269 return convstr;
1270 }
1271 #undef FUNC_NAME
1272
1273 SCM_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
1287 ret = str_to_case (str, c_locale, u32_toupper, FUNC_NAME, &err);
1288
1289 if (err != 0)
1290 {
1291 errno = err;
1292 scm_syserror (FUNC_NAME);
1293 }
1294 return ret;
1295 }
1296 #undef FUNC_NAME
1297
1298 SCM_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 {
1305 scm_t_locale c_locale;
1306 SCM ret;
1307 int err = 0;
1308
1309 SCM_VALIDATE_STRING (1, str);
1310 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1311
1312 ret = str_to_case (str, c_locale, u32_tolower, FUNC_NAME, &err);
1313
1314 if (err != 0)
1315 {
1316 errno = err;
1317 scm_syserror (FUNC_NAME);
1318 }
1319 return ret;
1320 }
1321 #undef FUNC_NAME
1322
1323 SCM_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;
1333
1334 SCM_VALIDATE_STRING (1, str);
1335 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1336
1337 ret = str_to_case (str, c_locale, u32_totitle, FUNC_NAME, &err);
1338
1339 if (err != 0)
1340 {
1341 errno = err;
1342 scm_syserror (FUNC_NAME);
1343 }
1344 return ret;
1345 }
1346 #undef FUNC_NAME
1347
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
1357 SCM_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
1365 {
1366 SCM result;
1367 long c_result;
1368 int c_base;
1369 const char *c_str;
1370 char *c_endptr;
1371 scm_t_locale c_locale;
1372
1373 SCM_VALIDATE_STRING (1, str);
1374 c_str = scm_i_string_chars (str);
1375
1376 if (!scm_is_eq (base, SCM_UNDEFINED))
1377 SCM_VALIDATE_INT_COPY (2, base, c_base);
1378 else
1379 c_base = 10;
1380
1381 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (3, locale, c_locale);
1382
1383 if (c_locale != NULL)
1384 {
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
1391 }
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
1406 SCM_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;
1421
1422 SCM_VALIDATE_STRING (1, str);
1423 c_str = scm_i_string_chars (str);
1424
1425 SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale);
1426
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 }
1436 else
1437 c_result = strtod (c_str, &c_endptr);
1438
1439 scm_remember_upto_here (str);
1440
1441 if (c_endptr == c_str)
1442 result = SCM_BOOL_F;
1443 else
1444 result = scm_from_double (c_result);
1445
1446 return (scm_values (scm_list_2 (result, scm_from_long (c_endptr - c_str))));
1447 }
1448 #undef FUNC_NAME
1449
1450 \f
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
1463 the current one.
1464 For example:
1465
1466 (nl-langinfo DAY_1 (make-locale LC_ALL "eo_EO.UTF-8"))
1467
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
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'. */
1476
1477
1478 SCM_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;
1493 #ifdef HAVE_LANGINFO_CODESET
1494 char *codeset;
1495 #endif
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
1507 lock_locale_mutex ();
1508 if (c_locale != NULL)
1509 {
1510 #ifdef USE_GNU_LOCALE_API
1511 c_result = nl_langinfo_l (c_item, c_locale);
1512 #ifdef HAVE_LANGINFO_CODESET
1513 codeset = nl_langinfo_l (CODESET, c_locale);
1514 #endif /* HAVE_LANGINFO_CODESET */
1515 #else /* !USE_GNU_LOCALE_API */
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)
1523 unlock_locale_mutex ();
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);
1539 #ifdef HAVE_LANGINFO_CODESET
1540 codeset = nl_langinfo (CODESET);
1541 #endif /* HAVE_LANGINFO_CODESET */
1542
1543 restore_locale_settings (&lsec_prev_locale);
1544 free_locale_settings (&lsec_prev_locale);
1545 }
1546 #endif
1547 }
1548 else
1549 {
1550 c_result = nl_langinfo (c_item);
1551 #ifdef HAVE_LANGINFO_CODESET
1552 codeset = nl_langinfo (CODESET);
1553 #endif /* HAVE_LANGINFO_CODESET */
1554 }
1555
1556 c_result = strdup (c_result);
1557 unlock_locale_mutex ();
1558
1559 if (c_result == NULL)
1560 result = SCM_BOOL_F;
1561 else
1562 {
1563 switch (c_item)
1564 {
1565 #if (defined GROUPING) && (defined MON_GROUPING)
1566 case GROUPING:
1567 case MON_GROUPING:
1568 {
1569 char *p;
1570
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>). */
1577 result = SCM_EOL;
1578 for (p = c_result; (*p > 0) && (*p != CHAR_MAX); p++)
1579 result = scm_cons (SCM_I_MAKINUM ((int) *p), result);
1580
1581 {
1582 SCM last_pair = result;
1583
1584 result = scm_reverse_x (result, SCM_EOL);
1585
1586 if (*p == 0)
1587 {
1588 /* Cyclic grouping information. */
1589 if (!scm_is_null (last_pair))
1590 SCM_SETCDR (last_pair, result);
1591 }
1592 }
1593
1594 free (c_result);
1595 break;
1596 }
1597 #endif
1598
1599 #if (defined FRAC_DIGITS) && (defined INT_FRAC_DIGITS)
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;
1611 #endif
1612
1613 #if (defined P_CS_PRECEDES) && (defined INT_N_CS_PRECEDES)
1614 case P_CS_PRECEDES:
1615 case N_CS_PRECEDES:
1616 case INT_P_CS_PRECEDES:
1617 case INT_N_CS_PRECEDES:
1618 #if (defined P_SEP_BY_SPACE) && (defined N_SEP_BY_SPACE)
1619 case P_SEP_BY_SPACE:
1620 case N_SEP_BY_SPACE:
1621 #endif
1622 /* This is to be interpreted as a boolean. */
1623 result = scm_from_bool (*c_result);
1624
1625 free (c_result);
1626 break;
1627 #endif
1628
1629 #if (defined P_SIGN_POSN) && (defined INT_N_SIGN_POSN)
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:
1639 result = scm_from_latin1_symbol ("parenthesize");
1640 break;
1641
1642 case 1:
1643 result = scm_from_latin1_symbol ("sign-before");
1644 break;
1645
1646 case 2:
1647 result = scm_from_latin1_symbol ("sign-after");
1648 break;
1649
1650 case 3:
1651 result = scm_from_latin1_symbol ("sign-before-currency-symbol");
1652 break;
1653
1654 case 4:
1655 result = scm_from_latin1_symbol ("sign-after-currency-symbol");
1656 break;
1657
1658 default:
1659 result = scm_from_latin1_symbol ("unspecified");
1660 }
1661 break;
1662 #endif
1663
1664 default:
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 */
1674 free (c_result);
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. */
1689 static inline void
1690 define_langinfo_items (void)
1691 {
1692 #ifdef HAVE_LANGINFO_H
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
1769
1770 #ifdef CRNCYSTR /* currency symbol */
1771 DEFINE_NLITEM_CONSTANT (CRNCYSTR);
1772 #endif
1773
1774 /* GNU extensions. */
1775
1776 #ifdef ERA_YEAR
1777 DEFINE_NLITEM_CONSTANT (ERA_YEAR); /* Year in alternate era format. */
1778 #endif
1779
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
1853 void
1854 scm_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
1862
1863 #include "libguile/i18n.x"
1864
1865 /* Initialize the global locale object with a special `locale' SMOB. */
1866 /* XXX: We don't define it as `LC_GLOBAL_LOCALE' because of bugs as of
1867 glibc <= 2.11 not (yet) worked around by Gnulib. See
1868 http://sourceware.org/bugzilla/show_bug.cgi?id=11009 for details. */
1869 SCM_NEWSMOB (global_locale_smob, scm_tc16_locale_smob_type, NULL);
1870 SCM_VARIABLE_SET (scm_global_locale, global_locale_smob);
1871 }
1872
1873 void
1874 scm_bootstrap_i18n ()
1875 {
1876 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1877 "scm_init_i18n",
1878 (scm_t_extension_init_func) scm_init_i18n,
1879 NULL);
1880
1881 }
1882
1883
1884 /*
1885 Local Variables:
1886 c-file-style: "gnu"
1887 End:
1888 */