aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2014-08-27 11:56:47 -0700
committerPaul Eggert2014-08-27 11:56:47 -0700
commit110d87a1cc6a47e31ad9d70cc6366dd81d213860 (patch)
treed6b77b26ec0ce70df4684c0a859989ff426e3ef5 /src
parent17d94f1ba4333a0d53558af02583dbf80e9157ff (diff)
downloademacs-110d87a1cc6a47e31ad9d70cc6366dd81d213860.tar.gz
emacs-110d87a1cc6a47e31ad9d70cc6366dd81d213860.zip
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')
-rw-r--r--src/ChangeLog12
-rw-r--r--src/sysdep.c129
2 files changed, 101 insertions, 40 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index d7066b823b9..8a32bc27b0b 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,15 @@
12014-08-27 Paul Eggert <eggert@cs.ucla.edu>
2
3 Improve robustness of new string-collation code (Bug#18051).
4 * sysdep.c (LC_COLLATE, LC_COLLATE_MASK, freelocale, locale_t)
5 (newlocale, wcscoll_l): Define substitutes for platforms that
6 lack them, so as to simplify the mainline code.
7 (str_collate): Simplify the code by assuming the above definitions.
8 Use wcscoll_l, not uselocale, as uselocale is too fragile. For
9 example, the old version left the Emacs in the wrong locale if
10 wcscoll reported an error. Use 'int', not ptrdiff_t, for the int
11 result. Report an error if newlocale fails.
12
12014-08-27 Michael Albinus <michael.albinus@gmx.de> 132014-08-27 Michael Albinus <michael.albinus@gmx.de>
2 14
3 * lisp.h (str_collate): 15 * lisp.h (str_collate):
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)
3599#ifdef __STDC_ISO_10646__ 3599#ifdef __STDC_ISO_10646__
3600# include <wchar.h> 3600# include <wchar.h>
3601 3601
3602# if defined HAVE_USELOCALE || defined HAVE_SETLOCALE 3602# if defined HAVE_NEWLOCALE || defined HAVE_SETLOCALE
3603# include <locale.h> 3603# include <locale.h>
3604# else
3605# define LC_COLLATE 0
3606# define LC_COLLATE_MASK 0
3604# endif 3607# endif
3605# ifndef HAVE_SETLOCALE 3608# ifndef HAVE_NEWLOCALE
3606# define setlocale(category, locale) ((char *) 0) 3609# undef freelocale
3610# undef locale_t
3611# undef newlocale
3612# undef wcscoll_l
3613# define freelocale emacs_freelocale
3614# define locale_t emacs_locale_t
3615# define newlocale emacs_newlocale
3616# define wcscoll_l emacs_wcscoll_l
3617
3618typedef char const *locale_t;
3619
3620static locale_t
3621newlocale (int category_mask, char const *locale, locale_t loc)
3622{
3623 return locale;
3624}
3625
3626static void
3627freelocale (locale_t loc)
3628{
3629}
3630
3631static char *
3632emacs_setlocale (int category, char const *locale)
3633{
3634# ifdef HAVE_SETLOCALE
3635 errno = 0;
3636 char *loc = setlocale (category, locale);
3637 if (loc || errno)
3638 return loc;
3639 errno = EINVAL;
3640# else
3641 errno = ENOTSUP;
3642# endif
3643 return 0;
3644}
3645
3646static int
3647wcscoll_l (wchar_t const *a, wchar_t const *b, locale_t loc)
3648{
3649 int result = 0;
3650 char *oldloc = emacs_setlocale (LC_COLLATE, NULL);
3651 int err;
3652
3653 if (! oldloc)
3654 err = errno;
3655 else
3656 {
3657 USE_SAFE_ALLOCA;
3658 char *oldcopy = SAFE_ALLOCA (strlen (oldloc) + 1);
3659 strcpy (oldcopy, oldloc);
3660 if (! emacs_setlocale (LC_COLLATE, loc))
3661 err = errno;
3662 else
3663 {
3664 errno = 0;
3665 result = wcscoll (a, b);
3666 err = errno;
3667 if (! emacs_setlocale (LC_COLLATE, oldcopy))
3668 err = errno;
3669 }
3670 SAFE_FREE ();
3671 }
3672
3673 errno = err;
3674 return result;
3675}
3607# endif 3676# endif
3608 3677
3609int 3678int
3610str_collate (Lisp_Object s1, Lisp_Object s2) 3679str_collate (Lisp_Object s1, Lisp_Object s2)
3611{ 3680{
3612 ptrdiff_t res, len, i, i_byte; 3681 int res, err;
3682 ptrdiff_t len, i, i_byte;
3613 wchar_t *p1, *p2; 3683 wchar_t *p1, *p2;
3614 Lisp_Object lc_collate; 3684 Lisp_Object lc_collate;
3615# ifdef HAVE_USELOCALE
3616 locale_t loc = 0, oldloc = 0;
3617# else
3618 char *oldloc = NULL;
3619# endif
3620 3685
3621 USE_SAFE_ALLOCA; 3686 USE_SAFE_ALLOCA;
3622 3687
@@ -3633,44 +3698,28 @@ str_collate (Lisp_Object s1, Lisp_Object s2)
3633 FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte); 3698 FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte);
3634 *(p2+len) = 0; 3699 *(p2+len) = 0;
3635 3700
3636 /* Create a new locale object, and set it. */
3637 lc_collate = 3701 lc_collate =
3638 Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment); 3702 Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment);
3639 3703
3640 if (STRINGP (lc_collate)) 3704 if (STRINGP (lc_collate))
3641 { 3705 {
3642#ifdef HAVE_USELOCALE 3706 locale_t loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0);
3643 loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0); 3707 if (!loc)
3644 if (loc) 3708 error ("Wrong locale: %s", strerror (errno));
3645 oldloc = uselocale (loc); 3709 errno = 0;
3646#else 3710 res = wcscoll_l (p1, p2, loc);
3647 oldloc = setlocale (LC_COLLATE, NULL); 3711 err = errno;
3648 if (oldloc) 3712 freelocale (loc);
3649 {
3650 oldloc = xstrdup (oldloc);
3651 setlocale (LC_COLLATE, SSDATA (lc_collate));
3652 }
3653#endif
3654 } 3713 }
3714 else
3715 {
3716 errno = 0;
3717 res = wcscoll (p1, p2);
3718 err = errno;
3719 }
3720 if (err)
3721 error ("Wrong argument: %s", strerror (err));
3655 3722
3656 errno = 0;
3657 res = wcscoll (p1, p2);
3658 if (errno)
3659 error ("Wrong argument: %s", strerror (errno));
3660
3661#ifdef HAVE_USELOCALE
3662 /* Free the locale object, and reset. */
3663 if (loc)
3664 freelocale (loc);
3665 if (oldloc)
3666 uselocale (oldloc);
3667#else
3668 /* Restore the original locale. */
3669 setlocale (LC_COLLATE, oldloc);
3670 xfree (oldloc);
3671#endif
3672
3673 /* Return result. */
3674 SAFE_FREE (); 3723 SAFE_FREE ();
3675 return res; 3724 return res;
3676} 3725}