--- orig/configure.in +++ mod/configure.in @@ -599,8 +599,9 @@ # stat64 - SuS largefile stuff, not on old systems # sysconf - not on old systems # _NSGetEnviron - Darwin specific +# strcoll_l, newlocale - GNU extensions (glibc) # -AC_CHECK_FUNCS([DINFINITY DQNAN ctermid fesetround ftime fchown getcwd geteuid gettimeofday gmtime_r ioctl lstat mkdir mknod nice readdir_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex unsetenv _NSGetEnviron]) +AC_CHECK_FUNCS([DINFINITY DQNAN ctermid fesetround ftime fchown getcwd geteuid gettimeofday gmtime_r ioctl lstat mkdir mknod nice readdir_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex unsetenv _NSGetEnviron strcoll strcoll_l newlocale]) # Reasons for testing: # netdb.h - not in mingw --- orig/libguile/i18n.c +++ mod/libguile/i18n.c @@ -15,6 +15,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE /* Ask for glibc's `newlocale' API */ #if HAVE_CONFIG_H # include @@ -24,10 +25,13 @@ #include "libguile/feature.h" #include "libguile/i18n.h" #include "libguile/strings.h" +#include "libguile/chars.h" #include "libguile/dynwind.h" +#include "libguile/validate.h" #include "gettext.h" #include +#include /* `strcoll ()' */ int @@ -312,10 +316,206 @@ } #undef FUNC_NAME -void + +/* Locale objects, string and character collation. */ + +SCM_SMOB (scm_tc16_locale_smob_type, "locale", 0); + +SCM_SMOB_FREE (scm_tc16_locale_smob_type, smob_locale_free, locale) +{ +#ifdef __GNU_LIBRARY__ + freelocale ((locale_t)SCM_SMOB_DATA (locale)); +#endif + + return 0; +} + +#ifndef __GNU_LIBRARY__ + +/* Provide the locale category masks as found in glibc (copied from + as found in glibc 2.3.6). */ + +# define LC_CTYPE_MASK (1 << LC_CTYPE) +# define LC_NUMERIC_MASK (1 << LC_NUMERIC) +# define LC_TIME_MASK (1 << LC_TIME) +# define LC_COLLATE_MASK (1 << LC_COLLATE) +# define LC_MONETARY_MASK (1 << LC_MONETARY) +# define LC_MESSAGES_MASK (1 << LC_MESSAGES) +# define LC_PAPER_MASK (1 << LC_PAPER) +# define LC_NAME_MASK (1 << LC_NAME) +# define LC_ADDRESS_MASK (1 << LC_ADDRESS) +# define LC_TELEPHONE_MASK (1 << LC_TELEPHONE) +# define LC_MEASUREMENT_MASK (1 << LC_MEASUREMENT) +# define LC_IDENTIFICATION_MASK (1 << LC_IDENTIFICATION) +# define LC_ALL_MASK (LC_CTYPE_MASK \ + | LC_NUMERIC_MASK \ + | LC_TIME_MASK \ + | LC_COLLATE_MASK \ + | LC_MONETARY_MASK \ + | LC_MESSAGES_MASK \ + | LC_PAPER_MASK \ + | LC_NAME_MASK \ + | LC_ADDRESS_MASK \ + | LC_TELEPHONE_MASK \ + | LC_MEASUREMENT_MASK \ + | LC_IDENTIFICATION_MASK \ + ) + +#endif + + +SCM_DEFINE (scm_make_locale, "make-locale", 2, 1, 0, + (SCM category_mask, SCM locale_name, SCM base_locale), + "Return a reference to a data structure representing a set of " + "locale datasets. Unlike for the @var{category} parameter for " + "@code{setlocale}, the @var{category_mask} parameter here uses " + "a single bit for each category, made by OR'ing together " + "@code{LC_*_MASK} bits.") +#define FUNC_NAME s_scm_make_locale +{ +#ifdef __GNU_LIBRARY__ + SCM locale; + int c_category_mask; + char *c_locale_name; + locale_t c_base_locale, c_locale; + + SCM_VALIDATE_INT_COPY (1, category_mask, c_category_mask); + SCM_VALIDATE_STRING (2, locale_name); + c_locale_name = scm_to_locale_string (locale_name); + + if (base_locale != SCM_UNDEFINED) + { + SCM_VALIDATE_SMOB (3, base_locale, locale_smob_type); + c_base_locale = (locale_t)SCM_SMOB_DATA (base_locale); + } + else + c_base_locale = NULL; + + c_locale = newlocale (c_category_mask, c_locale_name, c_base_locale); + free (c_base_locale); + + if (!c_locale) + locale = SCM_BOOL_F; + else + SCM_NEWSMOB (locale, scm_tc16_locale_smob_type, c_locale); + + return locale; +#else + /* FIXME: Handle this situation, for instance: + SCM_RETURN_NEWSMOB (scm_tc16_locale_smob_type, + scm_list_3 (category_mask, locale_name, + base_locale)); */ + return SCM_BOOL_F; +#endif +} +#undef FUNC_NAME + + +/* Compare null-terminated strings C_S1 and C_S2 according to LOCALE. Return + an integer whose sign is the same as the difference between C_S1 and + C_S2. */ +static inline int +compare_strings (const char *c_s1, const char *c_s2, SCM locale, + const char *func_name) +#define FUNC_NAME func_name +{ +#ifdef __GNU_LIBRARY__ + locale_t c_locale; +#endif + int result; + +#ifdef __GNU_LIBRARY__ + if (locale != SCM_UNDEFINED) + { + SCM_VALIDATE_SMOB (3, locale, locale_smob_type); + c_locale = (locale_t)SCM_SMOB_DATA (locale); + } + else + c_locale = NULL; + + if (c_locale) + result = strcoll_l (c_s1, c_s2, c_locale); + else +#endif + +#if HAVE_STRCOLL + result = strcoll (c_s1, c_s2); +#else + result = strcmp (c_s1, c_s2); +#endif + + return result; +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_string_locale_lt, "string-locale