------------------------------------------------------------ revno: 117742 committer: Dmitry Antipov branch nick: trunk timestamp: Tue 2014-08-26 12:01:48 +0400 message: * sysdep.c (init_sigsegv) [HAVE_STACK_OVERFLOW_HANDLING]: Add comment. diff: === modified file 'src/sysdep.c' --- src/sysdep.c 2014-08-26 06:25:59 +0000 +++ src/sysdep.c 2014-08-26 08:01:48 +0000 @@ -1754,6 +1754,9 @@ } } +/* Return true if we have successfully set up SIGSEGV handler on alternate + stack. Otherwise we just treat SIGSEGV among the rest of fatal signals. */ + static bool init_sigsegv (void) { ------------------------------------------------------------ revno: 117741 committer: Dmitry Antipov branch nick: trunk timestamp: Tue 2014-08-26 10:25:59 +0400 message: Handle C stack overflow caused by too nested Lisp evaluation. * configure.ac: Check for sigaltstack and related sigaction support. Unconditionally check for sigsetjmp and siglongjmp. (HAVE_STACK_OVERFLOW_HANDLING): Define if we can support it. * src/lisp.h (toplevel) [HAVE_STACK_OVERFLOW_HANDLING]: Declare siglongjmp point to transfer control from SIGSEGV handler. * src/keyboard.c (return_to_command_loop, recover_top_level_message) [HAVE_STACK_OVERFLOW_HANDLING]: New variables. (regular_top_level_message): New variable. (command_loop) [HAVE_STACK_OVERFLOW_HANDLING]: Handle non-local exit from SIGSEGV handler and adjust message displayed by Vtop_level if appropriate. (syms_of_keyboard): DEFVAR Vtop_level_message and initialize new variables described above. * src/sysdep.c [HAVE_SYS_RESOURCE_H]: Include sys/resource.h as such. (stack_grows_down, sigsegv_stack, handle_sigsegv) [HAVE_STACK_OVERFLOW_HANDLING]: New variables and function. (init_sigsegv): New function. (init_signals): Use it. * lisp/startup.el (normal-top-level): Use top-level-message. diff: === modified file 'ChangeLog' --- ChangeLog 2014-08-25 20:49:52 +0000 +++ ChangeLog 2014-08-26 06:25:59 +0000 @@ -1,3 +1,10 @@ +2014-08-26 Dmitry Antipov + + Detect features needed to handle C stack overflows. + * configure.ac: Check for sigaltstack and related sigaction + support. Unconditionally check for sigsetjmp and siglongjmp. + (HAVE_STACK_OVERFLOW_HANDLING): Define if we can support it. + 2014-08-25 Ken Brown * configure.ac (G_SLICE_ALWAYS_MALLOC): Remove obsolete macro. === modified file 'configure.ac' --- configure.ac 2014-08-25 20:55:37 +0000 +++ configure.ac 2014-08-26 06:25:59 +0000 @@ -3728,6 +3728,22 @@ [Define to 1 if timerfd functions are supported as in GNU/Linux.]) fi +# Alternate stack for signal handlers. +AC_CACHE_CHECK([whether signals can be handled on alternate stack], + [emacs_cv_alternate_stack], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include + ]], + [[stack_t ss; + struct sigaction sa; + ss.ss_sp = malloc (SIGSTKSZ); + ss.ss_size = SIGSTKSZ; + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigaltstack (&ss, 0); + sigaction (SIGSEGV, &sa, 0);]])], + [emacs_cv_alternate_stack=yes], + [emacs_cv_alternate_stack=no])]) + # Do we have res_init, for detecting changes in /etc/resolv.conf? # On Darwin, res_init appears not to be useful: see bug#562 and # http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01467.html @@ -4447,22 +4463,31 @@ [emacs_cv_func__setjmp=no])]) if test $emacs_cv_func__setjmp = yes; then AC_DEFINE([HAVE__SETJMP], 1, [Define to 1 if _setjmp and _longjmp work.]) -else - AC_CACHE_CHECK([for sigsetjmp], [emacs_cv_func_sigsetjmp], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[#include - ]], - [[sigjmp_buf j; - if (! sigsetjmp (j, 1)) - siglongjmp (j, 1);]])], - [emacs_cv_func_sigsetjmp=yes], - [emacs_cv_func_sigsetjmp=no])]) - if test $emacs_cv_func_sigsetjmp = yes; then - AC_DEFINE([HAVE_SIGSETJMP], 1, - [Define to 1 if sigsetjmp and siglongjmp work. - The value of this symbol is irrelevant if HAVE__SETJMP is defined.]) - fi +fi + +# We need to preserve signal mask to handle C stack overflows. +AC_CACHE_CHECK([for sigsetjmp], [emacs_cv_func_sigsetjmp], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include + ]], + [[sigjmp_buf j; + if (! sigsetjmp (j, 1)) + siglongjmp (j, 1);]])], + [emacs_cv_func_sigsetjmp=yes], + [emacs_cv_func_sigsetjmp=no])]) +if test $emacs_cv_func_sigsetjmp = yes; then + AC_DEFINE([HAVE_SIGSETJMP], 1, + [Define to 1 if sigsetjmp and siglongjmp work.]) +fi + +# We need all of these features to handle C stack overflows. +if test "$ac_cv_header_sys_resource_h" = "yes" -a \ + "$ac_cv_func_getrlimit" = "yes" -a \ + "$emacs_cv_func_sigsetjmp" = "yes" -a \ + "$emacs_cv_alternate_stack" = yes; then + AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], 1, + [Define to 1 if C stack overflow can be handled in some cases.]) fi case $opsys in === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2014-08-25 15:59:38 +0000 +++ lisp/ChangeLog 2014-08-26 06:25:59 +0000 @@ -1,3 +1,7 @@ +2014-08-26 Dmitry Antipov + + * startup.el (normal-top-level): Use top-level-message. + 2014-08-25 Lars Magne Ingebrigtsen * net/shr.el (shr-copy-url): Encode copied URL to avoid getting === modified file 'lisp/startup.el' --- lisp/startup.el 2014-07-27 13:21:30 +0000 +++ lisp/startup.el 2014-08-26 06:25:59 +0000 @@ -497,7 +497,7 @@ reads the initialization files, etc. It is the default value of the variable `top-level'." (if command-line-processed - (message "Back to top level.") + (message top-level-message) (setq command-line-processed t) ;; Look in each dir in load-path for a subdirs.el file. If we === modified file 'src/ChangeLog' --- src/ChangeLog 2014-08-25 20:49:52 +0000 +++ src/ChangeLog 2014-08-26 06:25:59 +0000 @@ -1,3 +1,22 @@ +2014-08-26 Dmitry Antipov + + Handle C stack overflow caused by too nested Lisp evaluation. + * lisp.h (toplevel) [HAVE_STACK_OVERFLOW_HANDLING]: Declare + siglongjmp point to transfer control from SIGSEGV handler. + * keyboard.c (return_to_command_loop, recover_top_level_message) + [HAVE_STACK_OVERFLOW_HANDLING]: New variables. + (regular_top_level_message): New variable. + (command_loop) [HAVE_STACK_OVERFLOW_HANDLING]: Handle non-local + exit from SIGSEGV handler and adjust message displayed by Vtop_level + if appropriate. + (syms_of_keyboard): DEFVAR Vtop_level_message and initialize + new variables described above. + * sysdep.c [HAVE_SYS_RESOURCE_H]: Include sys/resource.h as such. + (stack_grows_down, sigsegv_stack, handle_sigsegv) + [HAVE_STACK_OVERFLOW_HANDLING]: New variables and function. + (init_sigsegv): New function. + (init_signals): Use it. + 2014-08-25 Ken Brown * emacs.c (main): Remove use of obsolete macro === modified file 'src/keyboard.c' --- src/keyboard.c 2014-08-10 08:26:28 +0000 +++ src/keyboard.c 2014-08-26 06:25:59 +0000 @@ -133,6 +133,19 @@ static ptrdiff_t before_command_key_count; static ptrdiff_t before_command_echo_length; +#ifdef HAVE_STACK_OVERFLOW_HANDLING + +/* For longjmp to recover from C stack overflow. */ +sigjmp_buf return_to_command_loop; + +/* Message displayed by Vtop_level when recovering from C stack overflow. */ +static Lisp_Object recover_top_level_message; + +#endif /* HAVE_STACK_OVERFLOW_HANDLING */ + +/* Message normally displayed by Vtop_level. */ +static Lisp_Object regular_top_level_message; + /* For longjmp to where kbd input is being done. */ static sys_jmp_buf getcjmp; @@ -1134,6 +1147,17 @@ Lisp_Object command_loop (void) { +#ifdef HAVE_STACK_OVERFLOW_HANDLING + /* At least on GNU/Linux, saving signal mask is important here. */ + if (sigsetjmp (return_to_command_loop, 1) != 0) + { + /* Comes here from handle_sigsegv, see sysdep.c. */ + init_eval (); + Vtop_level_message = recover_top_level_message; + } + else + Vtop_level_message = regular_top_level_message; +#endif /* HAVE_STACK_OVERFLOW_HANDLING */ if (command_loop_level > 0 || minibuf_level > 0) { Lisp_Object val; @@ -11000,6 +11024,15 @@ Vlispy_mouse_stem = build_pure_c_string ("mouse"); staticpro (&Vlispy_mouse_stem); + regular_top_level_message = build_pure_c_string ("Back to top level"); +#ifdef HAVE_STACK_OVERFLOW_HANDLING + recover_top_level_message + = build_pure_c_string ("Re-entering top level after C stack overflow"); +#endif + DEFVAR_LISP ("top-level-message", Vtop_level_message, + doc: /* Message displayed by `normal-top-level'. */); + Vtop_level_message = regular_top_level_message; + /* Tool-bars. */ DEFSYM (QCimage, ":image"); DEFSYM (Qhelp_echo, "help-echo"); === modified file 'src/lisp.h' --- src/lisp.h 2014-08-25 05:44:57 +0000 +++ src/lisp.h 2014-08-26 06:25:59 +0000 @@ -4093,6 +4093,9 @@ extern Lisp_Object Qup, Qdown; extern Lisp_Object last_undo_boundary; extern bool input_pending; +#ifdef HAVE_STACK_OVERFLOW_HANDLING +extern sigjmp_buf return_to_command_loop; +#endif extern Lisp_Object menu_bar_items (Lisp_Object); extern Lisp_Object tool_bar_items (Lisp_Object, int *); extern void discard_mouse_events (void); === modified file 'src/sysdep.c' --- src/sysdep.c 2014-08-25 15:55:46 +0000 +++ src/sysdep.c 2014-08-26 06:25:59 +0000 @@ -46,7 +46,6 @@ # include # undef frame -# include # include #endif @@ -72,6 +71,9 @@ #include "msdos.h" #endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif #include #include #include @@ -1716,6 +1718,72 @@ xsignal0 (Qarith_error); } +#ifdef HAVE_STACK_OVERFLOW_HANDLING + +/* True if stack grows down as expected on most OS/ABI variants. */ + +static bool stack_grows_down; + +/* Alternate stack used by SIGSEGV handler below. */ + +static unsigned char sigsegv_stack[SIGSTKSZ]; + +/* Attempt to recover from SIGSEGV caused by C stack overflow. */ + +static void +handle_sigsegv (int sig, siginfo_t *siginfo, void *arg) +{ + /* Hard GC error may lead to stack overflow caused by + too nested calls to mark_object. No way to survive. */ + if (!gc_in_progress) + { + struct rlimit rlim; + + if (!getrlimit (RLIMIT_STACK, &rlim)) + { + enum { STACK_EXTRA = 16 * 1024 }; + char *fault_addr = (char *) siginfo->si_addr; + unsigned long used = (stack_grows_down + ? stack_bottom - fault_addr + : fault_addr - stack_bottom); + + if (used + STACK_EXTRA > rlim.rlim_cur) + /* Most likely this is it. */ + siglongjmp (return_to_command_loop, 1); + } + } +} + +static bool +init_sigsegv (void) +{ + struct sigaction sa; + stack_t ss; + + stack_grows_down = ((char *) &ss < stack_bottom); + + ss.ss_sp = sigsegv_stack; + ss.ss_size = sizeof (sigsegv_stack); + ss.ss_flags = 0; + if (sigaltstack (&ss, NULL) < 0) + return 0; + + sigfillset (&sa.sa_mask); + sa.sa_sigaction = handle_sigsegv; + sa.sa_flags = SA_SIGINFO | SA_ONSTACK | emacs_sigaction_flags (); + return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1; +} + +#else /* not HAVE_STACK_OVERFLOW_HANDLING */ + +static bool +init_sigsegv (void) +{ + return 0; +} + +#endif /* HAVE_STACK_OVERFLOW_HANDLING */ + static void deliver_arith_signal (int sig) { @@ -1982,7 +2050,8 @@ #ifdef SIGBUS sigaction (SIGBUS, &thread_fatal_action, 0); #endif - sigaction (SIGSEGV, &thread_fatal_action, 0); + if (!init_sigsegv ()) + sigaction (SIGSEGV, &thread_fatal_action, 0); #ifdef SIGSYS sigaction (SIGSYS, &thread_fatal_action, 0); #endif ------------------------------------------------------------ revno: 117740 committer: Ken Brown branch nick: trunk timestamp: Mon 2014-08-25 16:55:37 -0400 message: Fix accidental deletion of a line in last change. diff: === modified file 'configure.ac' --- configure.ac 2014-08-25 20:49:52 +0000 +++ configure.ac 2014-08-25 20:55:37 +0000 @@ -4593,6 +4593,7 @@ fi fi +case $opsys in hpux11) dnl It works to open the pty's tty in the parent (Emacs), then dnl close and reopen it in the child. ------------------------------------------------------------ revno: 117739 committer: Ken Brown branch nick: trunk timestamp: Mon 2014-08-25 16:49:52 -0400 message: * configure.ac (G_SLICE_ALWAYS_MALLOC): Remove obsolete macro. * src/emacs.c (main): Remove use of obsolete macro G_SLICE_ALWAYS_MALLOC. diff: === modified file 'ChangeLog' --- ChangeLog 2014-08-25 02:29:58 +0000 +++ ChangeLog 2014-08-25 20:49:52 +0000 @@ -1,3 +1,7 @@ +2014-08-25 Ken Brown + + * configure.ac (G_SLICE_ALWAYS_MALLOC): Remove obsolete macro. + 2014-08-25 Christoph Scholtes * INSTALL.REPO: Remove reference to obsolete configure scripts === modified file 'configure.ac' --- configure.ac 2014-08-24 15:40:07 +0000 +++ configure.ac 2014-08-25 20:49:52 +0000 @@ -4593,20 +4593,6 @@ fi fi - -case $opsys in - dnl Emacs supplies its own malloc, but glib calls posix_memalign, - dnl and on Cygwin prior to version 1.7.24 that becomes the - dnl Cygwin-supplied posix_memalign. As malloc is not the Cygwin - dnl malloc, the Cygwin posix_memalign always returns ENOSYS. A - dnl workaround is to set G_SLICE=always-malloc. This is no longer - dnl needed starting with cygwin-1.7.24, and it is no longer - dnl effective starting with glib-2.36. */ - cygwin) - AC_DEFINE(G_SLICE_ALWAYS_MALLOC, 1, [Define to set the - G_SLICE environment variable to "always-malloc" at startup.]) - ;; - hpux11) dnl It works to open the pty's tty in the parent (Emacs), then dnl close and reopen it in the child. === modified file 'src/ChangeLog' --- src/ChangeLog 2014-08-25 15:55:46 +0000 +++ src/ChangeLog 2014-08-25 20:49:52 +0000 @@ -1,3 +1,8 @@ +2014-08-25 Ken Brown + + * emacs.c (main): Remove use of obsolete macro + G_SLICE_ALWAYS_MALLOC. + 2014-08-25 Eli Zaretskii Implement locale-sensitive string collation for MS-Windows. === modified file 'src/emacs.c' --- src/emacs.c 2014-07-14 19:23:18 +0000 +++ src/emacs.c 2014-08-25 20:49:52 +0000 @@ -734,12 +734,6 @@ stack_base = &dummy; #endif -#ifdef G_SLICE_ALWAYS_MALLOC - /* This is used by the Cygwin build. It's not needed starting with - cygwin-1.7.24, but it doesn't do any harm. */ - xputenv ("G_SLICE=always-malloc"); -#endif - #ifndef CANNOT_DUMP might_dump = !initialized; #endif ------------------------------------------------------------ revno: 117738 committer: Glenn Morris branch nick: trunk timestamp: Mon 2014-08-25 12:48:08 -0400 message: * vc-git.el: Comments. diff: === modified file 'lisp/vc/vc-git.el' --- lisp/vc/vc-git.el 2014-08-13 08:42:33 +0000 +++ lisp/vc/vc-git.el 2014-08-25 16:48:08 +0000 @@ -798,6 +798,10 @@ (defun vc-git-find-file-hook () "Activate `smerge-mode' if there is a conflict." (when (and buffer-file-name + ;; FIXME + ;; 1) the net result is to call git twice per file. + ;; 2) v-g-c-f is documented to take a directory. + ;; http://lists.gnu.org/archive/html/emacs-devel/2014-01/msg01126.html (vc-git-conflicted-files buffer-file-name) (save-excursion (goto-char (point-min)) ------------------------------------------------------------ revno: 117737 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Mon 2014-08-25 18:04:39 +0200 message: Fix typo in last shr.el check-in diff: === modified file 'lisp/net/shr.el' --- lisp/net/shr.el 2014-08-25 15:59:38 +0000 +++ lisp/net/shr.el 2014-08-25 16:04:39 +0000 @@ -248,7 +248,7 @@ (with-temp-buffer (insert (url-encode-url url)) (copy-region-as-kill (point-min) (point-max)) - (message "Copied %s" (buffer-substring))))))) + (message "Copied %s" (buffer-string))))))) (defun shr-next-link () "Skip to the next link." ------------------------------------------------------------ revno: 117736 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Mon 2014-08-25 17:59:38 +0200 message: shr.el: Encode copied URLs * net/shr.el (shr-copy-url): Encode copied URL to avoid getting URLs containing spaces and the like. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2014-08-25 03:16:36 +0000 +++ lisp/ChangeLog 2014-08-25 15:59:38 +0000 @@ -1,3 +1,8 @@ +2014-08-25 Lars Magne Ingebrigtsen + + * net/shr.el (shr-copy-url): Encode copied URL to avoid getting + URLs containing spaces and the like. + 2014-08-25 Christoph Scholtes * subr.el (remq): Fix docstring (Bug#18253). === modified file 'lisp/net/shr.el' --- lisp/net/shr.el 2014-08-05 18:15:03 +0000 +++ lisp/net/shr.el 2014-08-25 15:59:38 +0000 @@ -246,9 +246,9 @@ ;; Copy the URL to the kill ring. (t (with-temp-buffer - (insert url) + (insert (url-encode-url url)) (copy-region-as-kill (point-min) (point-max)) - (message "Copied %s" url)))))) + (message "Copied %s" (buffer-substring))))))) (defun shr-next-link () "Skip to the next link." ------------------------------------------------------------ revno: 117735 fixes bug: http://debbugs.gnu.org/18051 committer: Eli Zaretskii branch nick: trunk timestamp: Mon 2014-08-25 18:55:46 +0300 message: Implement locale-sensitive string collation for MS-Windows. (Bug#18051) src/w32proc.c (get_lcid_callback, get_lcid, w32_compare_strings): New functions. src/w32.h (w32_compare_strings): Add prototype. src/w32.c : New global flag. (globals_of_w32): Initialize it. src/sysdep.c (str_collate) [WINDOWSNT]: Implementation for MS-Windows. src/fns.c (Fstring_collate_lessp, Fstring_collate_equalp) [WINDOWSNT]: Call str_collate on MS-Windows. etc/NEWS: Mention that string-collate-* functions are supported on MS-Windows as well. diff: === modified file 'etc/ChangeLog' --- etc/ChangeLog 2014-08-13 19:17:21 +0000 +++ etc/ChangeLog 2014-08-25 15:55:46 +0000 @@ -1,3 +1,8 @@ +2014-08-25 Eli Zaretskii + + * NEWS: Mention that string-collate-* functions are supported on + MS-Windows as well. + 2014-08-08 Jan Nieuwenhuizen * compilation.txt (file): Add Guile backtrace example. === modified file 'etc/NEWS' --- etc/NEWS 2014-08-24 15:47:06 +0000 +++ etc/NEWS 2014-08-25 15:55:46 +0000 @@ -68,9 +68,9 @@ ** The new functions `string-collate-lessp' and `string-collate-equalp' preserve the collation order as defined by the system's locale(1) -environment. For the time being this is implemented for POSIX systems -only, for other systems they fall back to their counterparts -`string-lessp' and `string-equal'. +environment. For the time being this is implemented for modern POSIX +systems and for MS-Windows, for other systems they fall back to their +counterparts `string-lessp' and `string-equal'. * Editing Changes in Emacs 24.5 === modified file 'src/ChangeLog' --- src/ChangeLog 2014-08-25 07:00:42 +0000 +++ src/ChangeLog 2014-08-25 15:55:46 +0000 @@ -1,3 +1,19 @@ +2014-08-25 Eli Zaretskii + + Implement locale-sensitive string collation for MS-Windows. + * w32proc.c (get_lcid_callback, get_lcid, w32_compare_strings): + New functions. (Bug#18051) + + * w32.h (w32_compare_strings): Add prototype. + + * w32.c : New global flag. + (globals_of_w32): Initialize it. + + * sysdep.c (str_collate) [WINDOWSNT]: Implementation for MS-Windows. + + * fns.c (Fstring_collate_lessp, Fstring_collate_equalp) + [WINDOWSNT]: Call str_collate on MS-Windows. + 2014-08-25 Dmitry Antipov One more minor cleanup of font subsystem. === modified file 'src/fns.c' --- src/fns.c 2014-08-25 05:44:57 +0000 +++ src/fns.c 2014-08-25 15:55:46 +0000 @@ -364,7 +364,7 @@ it overrides the setting of your current locale. */) (Lisp_Object s1, Lisp_Object s2) { -#ifdef __STDC_ISO_10646__ +#if defined __STDC_ISO_10646__ || defined WINDOWSNT /* Check parameters. */ if (SYMBOLP (s1)) s1 = SYMBOL_NAME (s1); @@ -375,9 +375,9 @@ return (str_collate (s1, s2) < 0) ? Qt : Qnil; -#else +#else /* !__STDC_ISO_10646__, !WINDOWSNT */ return Fstring_lessp (s1, s2); -#endif /* __STDC_ISO_10646__ */ +#endif /* !__STDC_ISO_10646__, !WINDOWSNT */ } DEFUN ("string-collate-equalp", Fstring_collate_equalp, Sstring_collate_equalp, 2, 2, 0, @@ -401,7 +401,7 @@ it overrides the setting of your current locale. */) (Lisp_Object s1, Lisp_Object s2) { -#ifdef __STDC_ISO_10646__ +#if defined __STDC_ISO_10646__ || defined WINDOWSNT /* Check parameters. */ if (SYMBOLP (s1)) s1 = SYMBOL_NAME (s1); @@ -412,9 +412,9 @@ return (str_collate (s1, s2) == 0) ? Qt : Qnil; -#else +#else /* !__STDC_ISO_10646__, !WINDOWSNT */ return Fstring_equal (s1, s2); -#endif /* __STDC_ISO_10646__ */ +#endif /* !__STDC_ISO_10646__, !WINDOWSNT */ } static Lisp_Object concat (ptrdiff_t nargs, Lisp_Object *args, === modified file 'src/sysdep.c' --- src/sysdep.c 2014-08-25 05:44:57 +0000 +++ src/sysdep.c 2014-08-25 15:55:46 +0000 @@ -3592,3 +3592,15 @@ return res; } #endif /* __STDC_ISO_10646__ */ + +#ifdef WINDOWSNT +ptrdiff_t +str_collate (Lisp_Object s1, Lisp_Object s2) +{ + Lisp_Object lc_collate = + Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment); + char *loc = STRINGP (lc_collate) ? SSDATA (lc_collate) : NULL; + + return w32_compare_strings (SDATA (s1), SDATA (s2), loc); +} +#endif /* WINDOWSNT */ === modified file 'src/w32.c' --- src/w32.c 2014-07-14 19:23:18 +0000 +++ src/w32.c 2014-08-25 15:55:46 +0000 @@ -309,6 +309,8 @@ static BOOL g_b_init_set_named_security_info_a; static BOOL g_b_init_get_adapters_info; +BOOL g_b_init_compare_string_w; + /* BEGIN: Wrapper functions around OpenProcessToken and other functions in advapi32.dll that are only @@ -9068,6 +9070,7 @@ g_b_init_set_named_security_info_w = 0; g_b_init_set_named_security_info_a = 0; g_b_init_get_adapters_info = 0; + g_b_init_compare_string_w = 0; num_of_processors = 0; /* The following sets a handler for shutdown notifications for console apps. This actually applies to Emacs in both console and === modified file 'src/w32.h' --- src/w32.h 2014-07-10 19:09:26 +0000 +++ src/w32.h 2014-08-25 15:55:46 +0000 @@ -210,6 +210,9 @@ extern int w32_memory_info (unsigned long long *, unsigned long long *, unsigned long long *, unsigned long long *); +/* Compare 2 UTF-8 strings in locale-dependent fashion. */ +extern int w32_compare_strings (const char *, const char *, char *); + #ifdef HAVE_GNUTLS #include === modified file 'src/w32proc.c' --- src/w32proc.c 2014-03-26 10:21:55 +0000 +++ src/w32proc.c 2014-08-25 15:55:46 +0000 @@ -32,6 +32,7 @@ #include #include #include +#include /* must include CRT headers *before* config.h */ #include @@ -3144,6 +3145,159 @@ return Fw32_get_keyboard_layout (); } +/* Two variables to interface between get_lcid and the EnumLocales + callback function below. */ +#ifndef LOCALE_NAME_MAX_LENGTH +# define LOCALE_NAME_MAX_LENGTH 85 +#endif +static LCID found_lcid; +static char lname[3 * LOCALE_NAME_MAX_LENGTH + 1 + 1]; + +/* Callback function for EnumLocales. */ +static BOOL CALLBACK +get_lcid_callback (LPTSTR locale_num_str) +{ + char *endp; + char locval[2 * LOCALE_NAME_MAX_LENGTH + 1 + 1]; + LCID try_lcid = strtoul (locale_num_str, &endp, 16); + + if (GetLocaleInfo (try_lcid, LOCALE_SABBREVLANGNAME, + locval, LOCALE_NAME_MAX_LENGTH)) + { + strcat (locval, "_"); + if (GetLocaleInfo (try_lcid, LOCALE_SABBREVCTRYNAME, + locval + strlen (locval), LOCALE_NAME_MAX_LENGTH)) + { + size_t locval_len = strlen (locval); + + if (strnicmp (locval, lname, locval_len) == 0 + && (lname[locval_len] == '.' + || lname[locval_len] == '\0')) + { + found_lcid = try_lcid; + return FALSE; + } + } + } + return TRUE; +} + +/* Return the Locale ID (LCID) number given the locale's name, a + string, in LOCALE_NAME. This works by enumerating all the locales + supported by the system, until we find one whose name matches + LOCALE_NAME. */ +static LCID +get_lcid (const char *locale_name) +{ + /* A simple cache. */ + static LCID last_lcid; + static char last_locale[1000]; + + /* The code below is not thread-safe, as it uses static variables. + But this function is called only from the Lisp thread. */ + if (last_lcid > 0 && strcmp (locale_name, last_locale) == 0) + return last_lcid; + + strncpy (lname, locale_name, sizeof (lname) - 1); + lname[sizeof (lname) - 1] = '\0'; + found_lcid = 0; + EnumSystemLocales (get_lcid_callback, LCID_SUPPORTED); + if (found_lcid > 0) + { + last_lcid = found_lcid; + strcpy (last_locale, locale_name); + } + return found_lcid; +} + +#ifndef _NSLCMPERROR +# define _NSLCMPERROR INT_MAX +#endif + +int +w32_compare_strings (const char *s1, const char *s2, char *locname) +{ + LCID lcid = GetThreadLocale (); + wchar_t *string1_w, *string2_w; + int val, needed; + extern BOOL g_b_init_compare_string_w; + static int (WINAPI *pCompareStringW)(LCID, DWORD, LPCWSTR, int, LPCWSTR, int); + + USE_SAFE_ALLOCA; + + if (!g_b_init_compare_string_w) + { + if (os_subtype == OS_9X) + { + pCompareStringW = GetProcAddress (LoadLibrary ("Unicows.dll"), + "CompareStringW"); + if (!pCompareStringW) + { + errno = EINVAL; + /* This return value is compatible with wcscoll and + other MS CRT functions. */ + return _NSLCMPERROR; + } + } + else + pCompareStringW = CompareStringW; + + g_b_init_compare_string_w = 1; + } + + needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, NULL, 0); + if (needed > 0) + { + SAFE_NALLOCA (string1_w, 1, needed + 1); + pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, + string1_w, needed); + } + else + { + errno = EINVAL; + return _NSLCMPERROR; + } + + needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0); + if (needed > 0) + { + SAFE_NALLOCA (string2_w, 1, needed + 1); + pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, + string2_w, needed); + } + else + { + SAFE_FREE (); + errno = EINVAL; + return _NSLCMPERROR; + } + + if (locname) + { + /* Convert locale name string to LCID. We don't want to use + LocaleNameToLCID because (a) it is only available since + Vista, and (b) it doesn't accept locale names returned by + 'setlocale' and 'GetLocaleInfo'. */ + LCID new_lcid = get_lcid (locname); + + if (new_lcid > 0) + lcid = new_lcid; + } + + /* FIXME: Need a way to control the FLAGS argument, perhaps via the + CODESET part of LOCNAME. In particular, ls-lisp will want + NORM_IGNORESYMBOLS and sometimes LINGUISTIC_IGNORECASE or + NORM_IGNORECASE. */ + val = pCompareStringW (lcid, 0, string1_w, -1, string2_w, -1); + SAFE_FREE (); + if (!val) + { + errno = EINVAL; + return _NSLCMPERROR; + } + return val - 2; +} + void syms_of_ntproc (void) ------------------------------------------------------------ revno: 117734 committer: Dmitry Antipov branch nick: trunk timestamp: Mon 2014-08-25 11:00:42 +0400 message: One more minor cleanup of font subsystem. * font.h (struct font_driver): Convert text_extents to return void because returned value is never actually used. * macfont.c (macfont_text_extents): * w32font.c (w32font_text_extents): * xftfont.c (xftfont_text_extents): Adjust to return void and assume that 'metrics' argument is always non-NULL. * ftfont.c (ftfont_text_extents): * xfont.c (xfont_text_extents): Likewise. Avoid redundant memset. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2014-08-25 05:44:57 +0000 +++ src/ChangeLog 2014-08-25 07:00:42 +0000 @@ -1,3 +1,15 @@ +2014-08-25 Dmitry Antipov + + One more minor cleanup of font subsystem. + * font.h (struct font_driver): Convert text_extents to + return void because returned value is never actually used. + * macfont.c (macfont_text_extents): + * w32font.c (w32font_text_extents): + * xftfont.c (xftfont_text_extents): Adjust to return void + and assume that 'metrics' argument is always non-NULL. + * ftfont.c (ftfont_text_extents): + * xfont.c (xfont_text_extents): Likewise. Avoid redundant memset. + 2014-08-25 Paul Eggert Minor cleanups of str_collate fix (Bug#18051). === modified file 'src/font.h' --- src/font.h 2014-07-09 23:35:31 +0000 +++ src/font.h 2014-08-25 07:00:42 +0000 @@ -570,9 +570,9 @@ /* Compute the total metrics of the NGLYPHS glyphs specified by the font FONT and the sequence of glyph codes CODE, and store the result in METRICS. */ - int (*text_extents) (struct font *font, - unsigned *code, int nglyphs, - struct font_metrics *metrics); + void (*text_extents) (struct font *font, + unsigned *code, int nglyphs, + struct font_metrics *metrics); #ifdef HAVE_WINDOW_SYSTEM === modified file 'src/ftfont.c' --- src/ftfont.c 2014-07-09 06:25:35 +0000 +++ src/ftfont.c 2014-08-25 07:00:42 +0000 @@ -499,8 +499,8 @@ static void ftfont_close (struct font *); static int ftfont_has_char (Lisp_Object, int); static unsigned ftfont_encode_char (struct font *, int); -static int ftfont_text_extents (struct font *, unsigned *, int, - struct font_metrics *); +static void ftfont_text_extents (struct font *, unsigned *, int, + struct font_metrics *); static int ftfont_get_bitmap (struct font *, unsigned, struct font_bitmap *, int); static int ftfont_anchor_point (struct font *, unsigned, int, @@ -1371,19 +1371,18 @@ return (code > 0 ? code : FONT_INVALID_CODE); } -static int -ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics) +static void +ftfont_text_extents (struct font *font, unsigned int *code, + int nglyphs, struct font_metrics *metrics) { struct ftfont_info *ftfont_info = (struct ftfont_info *) font; FT_Face ft_face = ftfont_info->ft_size->face; - int width = 0; - int i; + int i, width = 0; bool first; if (ftfont_info->ft_size != ft_face->size) FT_Activate_Size (ftfont_info->ft_size); - if (metrics) - memset (metrics, 0, sizeof (struct font_metrics)); + for (i = 0, first = 1; i < nglyphs; i++) { if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0) @@ -1392,39 +1391,28 @@ if (first) { - if (metrics) - { - metrics->lbearing = m->horiBearingX >> 6; - metrics->rbearing = (m->horiBearingX + m->width) >> 6; - metrics->ascent = m->horiBearingY >> 6; - metrics->descent = (m->height - m->horiBearingY) >> 6; - } + metrics->lbearing = m->horiBearingX >> 6; + metrics->rbearing = (m->horiBearingX + m->width) >> 6; + metrics->ascent = m->horiBearingY >> 6; + metrics->descent = (m->height - m->horiBearingY) >> 6; first = 0; } - if (metrics) - { - if (metrics->lbearing > width + (m->horiBearingX >> 6)) - metrics->lbearing = width + (m->horiBearingX >> 6); - if (metrics->rbearing - < width + ((m->horiBearingX + m->width) >> 6)) - metrics->rbearing - = width + ((m->horiBearingX + m->width) >> 6); - if (metrics->ascent < (m->horiBearingY >> 6)) - metrics->ascent = m->horiBearingY >> 6; - if (metrics->descent > ((m->height - m->horiBearingY) >> 6)) - metrics->descent = (m->height - m->horiBearingY) >> 6; - } + if (metrics->lbearing > width + (m->horiBearingX >> 6)) + metrics->lbearing = width + (m->horiBearingX >> 6); + if (metrics->rbearing + < width + ((m->horiBearingX + m->width) >> 6)) + metrics->rbearing + = width + ((m->horiBearingX + m->width) >> 6); + if (metrics->ascent < (m->horiBearingY >> 6)) + metrics->ascent = m->horiBearingY >> 6; + if (metrics->descent > ((m->height - m->horiBearingY) >> 6)) + metrics->descent = (m->height - m->horiBearingY) >> 6; width += m->horiAdvance >> 6; } else - { - width += font->space_width; - } + width += font->space_width; } - if (metrics) - metrics->width = width; - - return width; + metrics->width = width; } static int === modified file 'src/macfont.m' --- src/macfont.m 2014-07-21 06:03:08 +0000 +++ src/macfont.m 2014-08-25 07:00:42 +0000 @@ -1553,8 +1553,8 @@ static void macfont_close (struct font *); static int macfont_has_char (Lisp_Object, int); static unsigned macfont_encode_char (struct font *, int); -static int macfont_text_extents (struct font *, unsigned int *, int, - struct font_metrics *); +static void macfont_text_extents (struct font *, unsigned int *, int, + struct font_metrics *); static int macfont_draw (struct glyph_string *, int, int, int, int, bool); static Lisp_Object macfont_shape (Lisp_Object); static int macfont_variation_glyphs (struct font *, int c, @@ -2653,9 +2653,9 @@ return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE; } -static int -macfont_text_extents (struct font *font, unsigned int *code, int nglyphs, - struct font_metrics *metrics) +static void +macfont_text_extents (struct font *font, unsigned int *code, + int nglyphs, struct font_metrics *metrics) { int width, i; @@ -2664,28 +2664,21 @@ for (i = 1; i < nglyphs; i++) { struct font_metrics m; - int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL, - NULL, 0); + int w = macfont_glyph_extents (font, code[i], &m, NULL, 0); - if (metrics) - { - if (width + m.lbearing < metrics->lbearing) - metrics->lbearing = width + m.lbearing; - if (width + m.rbearing > metrics->rbearing) - metrics->rbearing = width + m.rbearing; - if (m.ascent > metrics->ascent) - metrics->ascent = m.ascent; - if (m.descent > metrics->descent) - metrics->descent = m.descent; - } + if (width + m.lbearing < metrics->lbearing) + metrics->lbearing = width + m.lbearing; + if (width + m.rbearing > metrics->rbearing) + metrics->rbearing = width + m.rbearing; + if (m.ascent > metrics->ascent) + metrics->ascent = m.ascent; + if (m.descent > metrics->descent) + metrics->descent = m.descent; width += w; } unblock_input (); - if (metrics) - metrics->width = width; - - return width; + metrics->width = width; } static int === modified file 'src/nsfont.m' --- src/nsfont.m 2014-07-09 06:25:35 +0000 +++ src/nsfont.m 2014-08-25 07:00:42 +0000 @@ -627,8 +627,8 @@ static void nsfont_close (struct font *font); static int nsfont_has_char (Lisp_Object entity, int c); static unsigned int nsfont_encode_char (struct font *font, int c); -static int nsfont_text_extents (struct font *font, unsigned int *code, - int nglyphs, struct font_metrics *metrics); +static void nsfont_text_extents (struct font *font, unsigned int *code, + int nglyphs, struct font_metrics *metrics); static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background); @@ -988,9 +988,9 @@ /* Perform the size computation of glyphs of FONT and fill in members of METRICS. The glyphs are specified by their glyph codes in CODE (length NGLYPHS). */ -static int -nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs, - struct font_metrics *metrics) +static void +nsfont_text_extents (struct font *font, unsigned int *code, + int nglyphs, struct font_metrics *metrics) { struct nsfont_info *font_info = (struct nsfont_info *)font; struct font_metrics *pcm; @@ -1000,7 +1000,7 @@ memset (metrics, 0, sizeof (struct font_metrics)); - for (i =0; iwidth = totalWidth; - - return totalWidth; /* not specified in doc, but xfont.c does it */ } === modified file 'src/w32font.c' --- src/w32font.c 2014-07-09 06:25:35 +0000 +++ src/w32font.c 2014-08-25 07:00:42 +0000 @@ -473,7 +473,7 @@ of METRICS. The glyphs are specified by their glyph codes in CODE (length NGLYPHS). Apparently metrics can be NULL, in this case just return the overall width. */ -int +void w32font_text_extents (struct font *font, unsigned *code, int nglyphs, struct font_metrics *metrics) { @@ -487,84 +487,80 @@ struct w32font_info *w32_font = (struct w32font_info *) font; - if (metrics) + memset (metrics, 0, sizeof (struct font_metrics)); + metrics->ascent = font->ascent; + metrics->descent = font->descent; + + for (i = 0; i < nglyphs; i++) { - memset (metrics, 0, sizeof (struct font_metrics)); - metrics->ascent = font->ascent; - metrics->descent = font->descent; - - for (i = 0; i < nglyphs; i++) - { - struct w32_metric_cache *char_metric; - int block = *(code + i) / CACHE_BLOCKSIZE; - int pos_in_block = *(code + i) % CACHE_BLOCKSIZE; - - if (block >= w32_font->n_cache_blocks) - { - if (!w32_font->cached_metrics) - w32_font->cached_metrics - = xmalloc ((block + 1) - * sizeof (struct w32_metric_cache *)); - else - w32_font->cached_metrics - = xrealloc (w32_font->cached_metrics, - (block + 1) - * sizeof (struct w32_metric_cache *)); - memset (w32_font->cached_metrics + w32_font->n_cache_blocks, 0, - ((block + 1 - w32_font->n_cache_blocks) - * sizeof (struct w32_metric_cache *))); - w32_font->n_cache_blocks = block + 1; - } - - if (!w32_font->cached_metrics[block]) - { - w32_font->cached_metrics[block] - = xzalloc (CACHE_BLOCKSIZE * sizeof (struct w32_metric_cache)); - } - - char_metric = w32_font->cached_metrics[block] + pos_in_block; - - if (char_metric->status == W32METRIC_NO_ATTEMPT) - { - if (dc == NULL) - { - /* TODO: Frames can come and go, and their fonts - outlive them. So we can't cache the frame in the - font structure. Use selected_frame until the API - is updated to pass in a frame. */ - f = XFRAME (selected_frame); - - dc = get_frame_dc (f); - old_font = SelectObject (dc, w32_font->hfont); - } - compute_metrics (dc, w32_font, *(code + i), char_metric); - } - - if (char_metric->status == W32METRIC_SUCCESS) - { - metrics->lbearing = min (metrics->lbearing, - metrics->width + char_metric->lbearing); - metrics->rbearing = max (metrics->rbearing, - metrics->width + char_metric->rbearing); - metrics->width += char_metric->width; - } + struct w32_metric_cache *char_metric; + int block = *(code + i) / CACHE_BLOCKSIZE; + int pos_in_block = *(code + i) % CACHE_BLOCKSIZE; + + if (block >= w32_font->n_cache_blocks) + { + if (!w32_font->cached_metrics) + w32_font->cached_metrics + = xmalloc ((block + 1) + * sizeof (struct w32_metric_cache *)); else - /* If we couldn't get metrics for a char, - use alternative method. */ - break; - } - /* If we got through everything, return. */ - if (i == nglyphs) - { - if (dc != NULL) - { - /* Restore state and release DC. */ - SelectObject (dc, old_font); - release_frame_dc (f, dc); - } - - return metrics->width; - } + w32_font->cached_metrics + = xrealloc (w32_font->cached_metrics, + (block + 1) + * sizeof (struct w32_metric_cache *)); + memset (w32_font->cached_metrics + w32_font->n_cache_blocks, 0, + ((block + 1 - w32_font->n_cache_blocks) + * sizeof (struct w32_metric_cache *))); + w32_font->n_cache_blocks = block + 1; + } + + if (!w32_font->cached_metrics[block]) + { + w32_font->cached_metrics[block] + = xzalloc (CACHE_BLOCKSIZE * sizeof (struct w32_metric_cache)); + } + + char_metric = w32_font->cached_metrics[block] + pos_in_block; + + if (char_metric->status == W32METRIC_NO_ATTEMPT) + { + if (dc == NULL) + { + /* TODO: Frames can come and go, and their fonts + outlive them. So we can't cache the frame in the + font structure. Use selected_frame until the API + is updated to pass in a frame. */ + f = XFRAME (selected_frame); + + dc = get_frame_dc (f); + old_font = SelectObject (dc, w32_font->hfont); + } + compute_metrics (dc, w32_font, *(code + i), char_metric); + } + + if (char_metric->status == W32METRIC_SUCCESS) + { + metrics->lbearing = min (metrics->lbearing, + metrics->width + char_metric->lbearing); + metrics->rbearing = max (metrics->rbearing, + metrics->width + char_metric->rbearing); + metrics->width += char_metric->width; + } + else + /* If we couldn't get metrics for a char, + use alternative method. */ + break; + } + /* If we got through everything, return. */ + if (i == nglyphs) + { + if (dc != NULL) + { + /* Restore state and release DC. */ + SelectObject (dc, old_font); + release_frame_dc (f, dc); + } + return; } /* For non-truetype fonts, GetGlyphOutlineW is not supported, so @@ -620,18 +616,13 @@ } /* Give our best estimate of the metrics, based on what we know. */ - if (metrics) - { - metrics->width = total_width - w32_font->metrics.tmOverhang; - metrics->lbearing = 0; - metrics->rbearing = total_width; - } + metrics->width = total_width - w32_font->metrics.tmOverhang; + metrics->lbearing = 0; + metrics->rbearing = total_width; /* Restore state and release DC. */ SelectObject (dc, old_font); release_frame_dc (f, dc); - - return total_width; } /* w32 implementation of draw for font backend. === modified file 'src/w32font.h' --- src/w32font.h 2014-01-01 07:43:34 +0000 +++ src/w32font.h 2014-08-25 07:00:42 +0000 @@ -74,8 +74,8 @@ int pixel_size, Lisp_Object font_object); void w32font_close (struct font *font); int w32font_has_char (Lisp_Object entity, int c); -int w32font_text_extents (struct font *font, unsigned *code, int nglyphs, - struct font_metrics *metrics); +void w32font_text_extents (struct font *font, unsigned *code, int nglyphs, + struct font_metrics *metrics); int w32font_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background); === modified file 'src/w32uniscribe.c' --- src/w32uniscribe.c 2014-07-09 06:25:35 +0000 +++ src/w32uniscribe.c 2014-08-25 07:00:42 +0000 @@ -591,8 +591,8 @@ Lisp_Object uniscribe_get_cache (Lisp_Object frame); void uniscribe_free_entity (Lisp_Object font_entity); int uniscribe_has_char (Lisp_Object entity, int c); - int uniscribe_text_extents (struct font *font, unsigned *code, - int nglyphs, struct font_metrics *metrics); + void uniscribe_text_extents (struct font *font, unsigned *code, + int nglyphs, struct font_metrics *metrics); int uniscribe_draw (struct glyph_string *s, int from, int to, int x, int y, int with_background); === modified file 'src/xfont.c' --- src/xfont.c 2014-07-09 06:25:35 +0000 +++ src/xfont.c 2014-08-25 07:00:42 +0000 @@ -124,8 +124,8 @@ static void xfont_prepare_face (struct frame *, struct face *); static int xfont_has_char (Lisp_Object, int); static unsigned xfont_encode_char (struct font *, int); -static int xfont_text_extents (struct font *, unsigned *, int, - struct font_metrics *); +static void xfont_text_extents (struct font *, unsigned *, int, + struct font_metrics *); static int xfont_draw (struct glyph_string *, int, int, int, int, bool); static int xfont_check (struct frame *, struct font *); @@ -975,15 +975,14 @@ return (xfont_get_pcm (xfont, &char2b) ? code : FONT_INVALID_CODE); } -static int -xfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics) +static void +xfont_text_extents (struct font *font, unsigned int *code, + int nglyphs, struct font_metrics *metrics) { XFontStruct *xfont = ((struct xfont_info *) font)->xfont; - int width = 0; - int i, first; + int i, width = 0; + bool first; - if (metrics) - memset (metrics, 0, sizeof (struct font_metrics)); for (i = 0, first = 1; i < nglyphs; i++) { XChar2b char2b; @@ -997,34 +996,27 @@ continue; if (first) { - if (metrics) - { - metrics->lbearing = pcm->lbearing; - metrics->rbearing = pcm->rbearing; - metrics->ascent = pcm->ascent; - metrics->descent = pcm->descent; - } + metrics->lbearing = pcm->lbearing; + metrics->rbearing = pcm->rbearing; + metrics->ascent = pcm->ascent; + metrics->descent = pcm->descent; first = 0; } else { - if (metrics) - { - if (metrics->lbearing > width + pcm->lbearing) - metrics->lbearing = width + pcm->lbearing; - if (metrics->rbearing < width + pcm->rbearing) - metrics->rbearing = width + pcm->rbearing; - if (metrics->ascent < pcm->ascent) - metrics->ascent = pcm->ascent; - if (metrics->descent < pcm->descent) - metrics->descent = pcm->descent; - } + if (metrics->lbearing > width + pcm->lbearing) + metrics->lbearing = width + pcm->lbearing; + if (metrics->rbearing < width + pcm->rbearing) + metrics->rbearing = width + pcm->rbearing; + if (metrics->ascent < pcm->ascent) + metrics->ascent = pcm->ascent; + if (metrics->descent < pcm->descent) + metrics->descent = pcm->descent; } width += pcm->width; } - if (metrics) - metrics->width = width; - return width; + + metrics->width = width; } static int === modified file 'src/xftfont.c' --- src/xftfont.c 2014-07-09 06:25:35 +0000 +++ src/xftfont.c 2014-08-25 07:00:42 +0000 @@ -557,8 +557,9 @@ return (code ? code : FONT_INVALID_CODE); } -static int -xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics) +static void +xftfont_text_extents (struct font *font, unsigned int *code, + int nglyphs, struct font_metrics *metrics) { struct xftfont_info *xftfont_info = (struct xftfont_info *) font; XGlyphInfo extents; @@ -567,15 +568,12 @@ XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs, &extents); unblock_input (); - if (metrics) - { - metrics->lbearing = - extents.x; - metrics->rbearing = - extents.x + extents.width; - metrics->width = extents.xOff; - metrics->ascent = extents.y; - metrics->descent = extents.height - extents.y; - } - return extents.xOff; + + metrics->lbearing = - extents.x; + metrics->rbearing = - extents.x + extents.width; + metrics->width = extents.xOff; + metrics->ascent = extents.y; + metrics->descent = extents.height - extents.y; } static XftDraw *