X-Git-Url: https://git.hcoop.net/bpt/guile.git/blobdiff_plain/26b9f9090073c896762af3125af54958e153f8f2..8051cf23044e5dbbece0d328102197a04ce5718d:/libguile/i18n.c diff --git a/libguile/i18n.c b/libguile/i18n.c index 9c78bfc2d..0f607f331 100644 --- a/libguile/i18n.c +++ b/libguile/i18n.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +/* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -59,16 +59,8 @@ #include "libguile/posix.h" /* for `scm_i_locale_mutex' */ -#ifdef HAVE_LANGINFO_H -# include -#endif -#ifdef HAVE_NL_TYPES_H -# include -#endif -#ifndef HAVE_NL_ITEM -/* Cygwin has but lacks and `nl_item'. */ -typedef int nl_item; -#endif +/* Use Gnulib's header, which also provides `nl_item' & co. */ +#include #ifndef HAVE_SETLOCALE static inline char * @@ -82,6 +74,25 @@ setlocale (int category, const char *name) /* Helper stringification macro. */ #define SCM_I18N_STRINGIFY(_name) # _name +/* Acquiring and releasing the locale lock. */ + +static inline void +lock_locale_mutex (void) +{ +#ifdef HAVE_POSIX + scm_i_pthread_mutex_lock (&scm_i_locale_mutex); +#else +#endif +} + +static inline void +unlock_locale_mutex (void) +{ +#ifdef HAVE_POSIX + scm_i_pthread_mutex_unlock (&scm_i_locale_mutex); +#else +#endif +} /* Locale objects, string and character collation, and other locale-dependent @@ -177,22 +188,11 @@ typedef struct scm_locale int category_mask; } *scm_t_locale; - -/* Free the resources used by LOCALE. */ -static inline void -scm_i_locale_free (scm_t_locale locale) -{ - free (locale->locale_name); - locale->locale_name = NULL; -} - #else /* USE_GNU_LOCALE_API */ /* Alias for glibc's locale type. */ typedef locale_t scm_t_locale; -#define scm_i_locale_free freelocale - #endif /* USE_GNU_LOCALE_API */ @@ -215,7 +215,7 @@ SCM_GLOBAL_VARIABLE (scm_global_locale, "%global-locale"); #define SCM_VALIDATE_OPTIONAL_LOCALE_COPY(_pos, _arg, _c_locale) \ do \ { \ - if ((_arg) != SCM_UNDEFINED) \ + if (!SCM_UNBNDP (_arg)) \ SCM_VALIDATE_LOCALE_COPY (_pos, _arg, _c_locale); \ else \ (_c_locale) = NULL; \ @@ -225,16 +225,21 @@ SCM_GLOBAL_VARIABLE (scm_global_locale, "%global-locale"); SCM_SMOB (scm_tc16_locale_smob_type, "locale", 0); +#ifdef USE_GNU_LOCALE_API + SCM_SMOB_FREE (scm_tc16_locale_smob_type, smob_locale_free, locale) { scm_t_locale c_locale; c_locale = (scm_t_locale) SCM_SMOB_DATA (locale); - scm_i_locale_free (c_locale); + if (c_locale) + freelocale (c_locale); return 0; } +#endif /* USE_GNU_LOCALE_API */ + static void inline scm_locale_error (const char *, int) SCM_NORETURN; @@ -381,7 +386,7 @@ install_locale (scm_t_locale locale) account. */ category_mask |= locale->category_mask; - if (locale->base_locale != SCM_UNDEFINED) + if (!SCM_UNBNDP (locale->base_locale)) locale = (scm_t_locale) SCM_SMOB_DATA (locale->base_locale); else locale = NULL; @@ -421,7 +426,7 @@ leave_locale_section (const scm_t_locale_settings *settings) /* Restore the previous locale settings. */ (void)restore_locale_settings (settings); - scm_i_pthread_mutex_unlock (&scm_i_locale_mutex); + unlock_locale_mutex (); } /* Enter a locked locale section. */ @@ -431,12 +436,12 @@ enter_locale_section (scm_t_locale locale, { int err; - scm_i_pthread_mutex_lock (&scm_i_locale_mutex); + lock_locale_mutex (); err = get_current_locale_settings (prev_locale); if (err) { - scm_i_pthread_mutex_unlock (&scm_i_locale_mutex); + unlock_locale_mutex (); return err; } @@ -482,28 +487,23 @@ get_current_locale (SCM *result) c_locale = scm_gc_malloc (sizeof (* c_locale), "locale"); - - scm_i_pthread_mutex_lock (&scm_i_locale_mutex); + lock_locale_mutex (); c_locale->category_mask = LC_ALL_MASK; c_locale->base_locale = SCM_UNDEFINED; current_locale = setlocale (LC_ALL, NULL); if (current_locale != NULL) - { - c_locale->locale_name = strdup (current_locale); - if (c_locale->locale_name == NULL) - err = ENOMEM; - } + c_locale->locale_name = scm_gc_strdup (current_locale, "locale"); else err = EINVAL; - scm_i_pthread_mutex_unlock (&scm_i_locale_mutex); + unlock_locale_mutex (); - if (err) - scm_gc_free (c_locale, sizeof (* c_locale), "locale"); - else + if (err == 0) SCM_NEWSMOB (*result, scm_tc16_locale_smob_type, c_locale); + else + *result = SCM_BOOL_F; return err; } @@ -638,6 +638,7 @@ SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0, c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale); free (c_locale_name); + c_locale_name = NULL; if (c_locale == (locale_t) 0) { @@ -653,7 +654,9 @@ SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0, c_locale = scm_gc_malloc (sizeof (* c_locale), "locale"); c_locale->category_mask = c_category_mask; - c_locale->locale_name = c_locale_name; + c_locale->locale_name = scm_gc_strdup (c_locale_name, "locale"); + free (c_locale_name); + c_locale_name = NULL; if (scm_is_eq (base_locale, SCM_VARIABLE_REF (scm_global_locale))) { @@ -682,6 +685,8 @@ SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0, } } + /* silence gcc's unused variable warning */ + (void) c_base_locale; #endif return locale; @@ -766,16 +771,10 @@ compare_u32_strings (SCM s1, SCM s2, SCM locale, const char *func_name) static const char * locale_language () { - /* FIXME: If the locale has been set with 'uselocale', - libunistring's uc_locale_language will return the incorrect - language: it will return the language appropriate for the global - (non-thread-specific) locale. - - There appears to be no portable way to extract the language from - the thread-specific locale_t. There is no LANGUAGE capability in - nl_langinfo or nl_langinfo_l. - - Thus, uc_locale_language needs to be fixed upstream. */ + /* Note: If the locale has been set with 'uselocale', uc_locale_language + from libunistring versions 0.9.1 and older will return the incorrect + (non-thread-specific) locale. This is fixed in versions 0.9.2 and + newer. */ return uc_locale_language (); } @@ -1113,28 +1112,24 @@ chr_to_case (SCM chr, scm_t_locale c_locale, #define FUNC_NAME func_name { int ret; - scm_t_wchar *buf; + scm_t_uint32 c; scm_t_uint32 *convbuf; size_t convlen; - SCM str, convchar; + SCM convchar; - str = scm_i_make_wide_string (1, &buf); - buf[0] = SCM_CHAR (chr); + c = SCM_CHAR (chr); if (c_locale != NULL) RUN_IN_LOCALE_SECTION (c_locale, ret = - u32_locale_tocase ((scm_t_uint32 *) buf, 1, - &convbuf, - &convlen, func)); + u32_locale_tocase (&c, 1, &convbuf, &convlen, func)); else ret = - u32_locale_tocase ((scm_t_uint32 *) buf, 1, &convbuf, - &convlen, func); + u32_locale_tocase (&c, 1, &convbuf, &convlen, func); if (SCM_UNLIKELY (ret != 0)) { *err = ret; - return NULL; + return SCM_BOOL_F; } if (convlen == 1) @@ -1253,10 +1248,10 @@ str_to_case (SCM str, scm_t_locale c_locale, if (SCM_UNLIKELY (ret != 0)) { *err = ret; - return NULL; + return SCM_BOOL_F; } - convstr = scm_i_make_wide_string (convlen, &c_buf); + convstr = scm_i_make_wide_string (convlen, &c_buf, 0); memcpy (c_buf, c_convstr, convlen * sizeof (scm_t_wchar)); free (c_convstr); @@ -1369,7 +1364,7 @@ SCM_DEFINE (scm_locale_string_to_integer, "locale-string->integer", SCM_VALIDATE_STRING (1, str); c_str = scm_i_string_chars (str); - if (base != SCM_UNDEFINED) + if (!scm_is_eq (base, SCM_UNDEFINED)) SCM_VALIDATE_INT_COPY (2, base, c_base); else c_base = 10; @@ -1481,14 +1476,11 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, "Reference Manual}).") #define FUNC_NAME s_scm_nl_langinfo { -#ifdef HAVE_NL_LANGINFO SCM result; nl_item c_item; char *c_result; scm_t_locale c_locale; -#ifdef HAVE_LANGINFO_CODESET char *codeset; -#endif SCM_VALIDATE_INT_COPY (2, item, c_item); SCM_VALIDATE_OPTIONAL_LOCALE_COPY (2, locale, c_locale); @@ -1500,14 +1492,12 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, http://opengroup.org/onlinepubs/007908799/xsh/nl_langinfo.html for details. */ - scm_i_pthread_mutex_lock (&scm_i_locale_mutex); + lock_locale_mutex (); if (c_locale != NULL) { #ifdef USE_GNU_LOCALE_API c_result = nl_langinfo_l (c_item, c_locale); -#ifdef HAVE_LANGINFO_CODESET codeset = nl_langinfo_l (CODESET, c_locale); -#endif /* HAVE_LANGINFO_CODESET */ #else /* !USE_GNU_LOCALE_API */ /* We can't use `RUN_IN_LOCALE_SECTION ()' here because the locale mutex is already taken. */ @@ -1516,7 +1506,7 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, lsec_err = get_current_locale_settings (&lsec_prev_locale); if (lsec_err) - scm_i_pthread_mutex_unlock (&scm_i_locale_mutex); + unlock_locale_mutex (); else { lsec_err = install_locale (c_locale); @@ -1532,9 +1522,7 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, else { c_result = nl_langinfo (c_item); -#ifdef HAVE_LANGINFO_CODESET codeset = nl_langinfo (CODESET); -#endif /* HAVE_LANGINFO_CODESET */ restore_locale_settings (&lsec_prev_locale); free_locale_settings (&lsec_prev_locale); @@ -1544,13 +1532,13 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, else { c_result = nl_langinfo (c_item); -#ifdef HAVE_LANGINFO_CODESET codeset = nl_langinfo (CODESET); -#endif /* HAVE_LANGINFO_CODESET */ } - c_result = strdup (c_result); - scm_i_pthread_mutex_unlock (&scm_i_locale_mutex); + if (c_result != NULL) + c_result = strdup (c_result); + + unlock_locale_mutex (); if (c_result == NULL) result = SCM_BOOL_F; @@ -1564,11 +1552,14 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, { char *p; - /* In this cases, the result is to be interpreted as a list of - numbers. If the last item is `CHARS_MAX', it has the special - meaning "no more grouping". */ + /* In this cases, the result is to be interpreted as a list + of numbers. If the last item is `CHAR_MAX' or a negative + number, it has the special meaning "no more grouping" + (negative numbers aren't specified in POSIX but can be + used by glibc; see + ). */ result = SCM_EOL; - for (p = c_result; (*p != '\0') && (*p != CHAR_MAX); p++) + for (p = c_result; (*p > 0) && (*p != CHAR_MAX); p++) result = scm_cons (SCM_I_MAKINUM ((int) *p), result); { @@ -1576,10 +1567,10 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, result = scm_reverse_x (result, SCM_EOL); - if (*p != CHAR_MAX) + if (*p == 0) { /* Cyclic grouping information. */ - if (last_pair != SCM_EOL) + if (!scm_is_null (last_pair)) SCM_SETCDR (last_pair, result); } } @@ -1629,52 +1620,41 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, switch (*c_result) { case 0: - result = scm_from_locale_symbol ("parenthesize"); + result = scm_from_latin1_symbol ("parenthesize"); break; case 1: - result = scm_from_locale_symbol ("sign-before"); + result = scm_from_latin1_symbol ("sign-before"); break; case 2: - result = scm_from_locale_symbol ("sign-after"); + result = scm_from_latin1_symbol ("sign-after"); break; case 3: - result = scm_from_locale_symbol ("sign-before-currency-symbol"); + result = scm_from_latin1_symbol ("sign-before-currency-symbol"); break; case 4: - result = scm_from_locale_symbol ("sign-after-currency-symbol"); + result = scm_from_latin1_symbol ("sign-after-currency-symbol"); break; default: - result = scm_from_locale_symbol ("unspecified"); + result = scm_from_latin1_symbol ("unspecified"); } + free (c_result); break; #endif default: -#ifdef HAVE_LANGINFO_CODESET result = scm_from_stringn (c_result, strlen (c_result), codeset, SCM_FAILED_CONVERSION_QUESTION_MARK); -#else /* !HAVE_LANGINFO_CODESET */ - /* This may be incorrectly encoded if the locale differs - from the c_locale. */ - result = scm_from_locale_string (c_result); -#endif /* !HAVE_LANGINFO_CODESET */ free (c_result); } } return result; -#else - scm_syserror_msg (FUNC_NAME, "`nl-langinfo' not supported on your system", - SCM_EOL, ENOSYS); - - return SCM_BOOL_F; -#endif } #undef FUNC_NAME @@ -1682,8 +1662,6 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0, static inline void define_langinfo_items (void) { -#if (defined HAVE_NL_TYPES_H) && (defined HAVE_LANGINFO_H) - #define DEFINE_NLITEM_CONSTANT(_item) \ scm_c_define (# _item, scm_from_int (_item)) @@ -1743,13 +1721,23 @@ define_langinfo_items (void) DEFINE_NLITEM_CONSTANT (T_FMT); /* Time format for strftime. */ DEFINE_NLITEM_CONSTANT (T_FMT_AMPM);/* 12-hour time format for strftime. */ +#ifdef ERA DEFINE_NLITEM_CONSTANT (ERA); /* Alternate era. */ +#endif +#ifdef ERA_D_FMT DEFINE_NLITEM_CONSTANT (ERA_D_FMT); /* Date in alternate era format. */ +#endif +#ifdef ERA_D_T_FMT DEFINE_NLITEM_CONSTANT (ERA_D_T_FMT); /* Date and time in alternate era format. */ +#endif +#ifdef ERA_T_FMT DEFINE_NLITEM_CONSTANT (ERA_T_FMT); /* Time in alternate era format. */ +#endif +#ifdef ALT_DIGITS DEFINE_NLITEM_CONSTANT (ALT_DIGITS); /* Alternate symbols for digits. */ +#endif DEFINE_NLITEM_CONSTANT (RADIXCHAR); DEFINE_NLITEM_CONSTANT (THOUSEP); @@ -1838,8 +1826,6 @@ define_langinfo_items (void) #endif #undef DEFINE_NLITEM_CONSTANT - -#endif /* HAVE_NL_TYPES_H */ } @@ -1848,10 +1834,8 @@ scm_init_i18n () { SCM global_locale_smob; -#ifdef HAVE_NL_LANGINFO scm_add_feature ("nl-langinfo"); define_langinfo_items (); -#endif #include "libguile/i18n.x"