diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2014-08-27 11:56:47 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2014-08-27 11:56:47 -0700 |
commit | 110d87a1cc6a47e31ad9d70cc6366dd81d213860 (patch) | |
tree | d6b77b26ec0ce70df4684c0a859989ff426e3ef5 /src/sysdep.c | |
parent | 17d94f1ba4333a0d53558af02583dbf80e9157ff (diff) | |
download | emacs-110d87a1cc6a47e31ad9d70cc6366dd81d213860.tar.gz |
Improve robustness of new string-collation code.
* configure.ac (newlocale): Check for this, not for uselocale.
* src/sysdep.c (LC_COLLATE, LC_COLLATE_MASK, freelocale, locale_t)
(newlocale, wcscoll_l): Define substitutes for platforms that
lack them, so as to simplify the mainline code.
(str_collate): Simplify the code by assuming the above definitions.
Use wcscoll_l, not uselocale, as uselocale is too fragile. For
example, the old version left the Emacs in the wrong locale if
wcscoll reported an error. Use 'int', not ptrdiff_t, for the int
result. Report an error if newlocale fails.
Fixes: debbugs:18051
Diffstat (limited to 'src/sysdep.c')
-rw-r--r-- | src/sysdep.c | 129 |
1 files changed, 89 insertions, 40 deletions
diff --git a/src/sysdep.c b/src/sysdep.c index 4b0f54ebe6e..d50e2398a53 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -3599,24 +3599,89 @@ system_process_attributes (Lisp_Object pid) #ifdef __STDC_ISO_10646__ # include <wchar.h> -# if defined HAVE_USELOCALE || defined HAVE_SETLOCALE +# if defined HAVE_NEWLOCALE || defined HAVE_SETLOCALE # include <locale.h> +# else +# define LC_COLLATE 0 +# define LC_COLLATE_MASK 0 # endif -# ifndef HAVE_SETLOCALE -# define setlocale(category, locale) ((char *) 0) +# ifndef HAVE_NEWLOCALE +# undef freelocale +# undef locale_t +# undef newlocale +# undef wcscoll_l +# define freelocale emacs_freelocale +# define locale_t emacs_locale_t +# define newlocale emacs_newlocale +# define wcscoll_l emacs_wcscoll_l + +typedef char const *locale_t; + +static locale_t +newlocale (int category_mask, char const *locale, locale_t loc) +{ + return locale; +} + +static void +freelocale (locale_t loc) +{ +} + +static char * +emacs_setlocale (int category, char const *locale) +{ +# ifdef HAVE_SETLOCALE + errno = 0; + char *loc = setlocale (category, locale); + if (loc || errno) + return loc; + errno = EINVAL; +# else + errno = ENOTSUP; +# endif + return 0; +} + +static int +wcscoll_l (wchar_t const *a, wchar_t const *b, locale_t loc) +{ + int result = 0; + char *oldloc = emacs_setlocale (LC_COLLATE, NULL); + int err; + + if (! oldloc) + err = errno; + else + { + USE_SAFE_ALLOCA; + char *oldcopy = SAFE_ALLOCA (strlen (oldloc) + 1); + strcpy (oldcopy, oldloc); + if (! emacs_setlocale (LC_COLLATE, loc)) + err = errno; + else + { + errno = 0; + result = wcscoll (a, b); + err = errno; + if (! emacs_setlocale (LC_COLLATE, oldcopy)) + err = errno; + } + SAFE_FREE (); + } + + errno = err; + return result; +} # endif int str_collate (Lisp_Object s1, Lisp_Object s2) { - ptrdiff_t res, len, i, i_byte; + int res, err; + ptrdiff_t len, i, i_byte; wchar_t *p1, *p2; Lisp_Object lc_collate; -# ifdef HAVE_USELOCALE - locale_t loc = 0, oldloc = 0; -# else - char *oldloc = NULL; -# endif USE_SAFE_ALLOCA; @@ -3633,44 +3698,28 @@ str_collate (Lisp_Object s1, Lisp_Object s2) FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte); *(p2+len) = 0; - /* Create a new locale object, and set it. */ lc_collate = Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment); if (STRINGP (lc_collate)) { -#ifdef HAVE_USELOCALE - loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0); - if (loc) - oldloc = uselocale (loc); -#else - oldloc = setlocale (LC_COLLATE, NULL); - if (oldloc) - { - oldloc = xstrdup (oldloc); - setlocale (LC_COLLATE, SSDATA (lc_collate)); - } -#endif + locale_t loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0); + if (!loc) + error ("Wrong locale: %s", strerror (errno)); + errno = 0; + res = wcscoll_l (p1, p2, loc); + err = errno; + freelocale (loc); } + else + { + errno = 0; + res = wcscoll (p1, p2); + err = errno; + } + if (err) + error ("Wrong argument: %s", strerror (err)); - errno = 0; - res = wcscoll (p1, p2); - if (errno) - error ("Wrong argument: %s", strerror (errno)); - -#ifdef HAVE_USELOCALE - /* Free the locale object, and reset. */ - if (loc) - freelocale (loc); - if (oldloc) - uselocale (oldloc); -#else - /* Restore the original locale. */ - setlocale (LC_COLLATE, oldloc); - xfree (oldloc); -#endif - - /* Return result. */ SAFE_FREE (); return res; } |