commit e9e807e9317ca7aa99a5dd220ee8586f8f4331bf (HEAD, refs/remotes/origin/master) Author: Mattias Engdegård Date: Wed Apr 10 15:25:53 2019 +0200 Don't remove notify descriptor that is already gone * lisp/autorevert.el (auto-revert-use-notify, auto-revert-mode, global-auto-revert-mode, auto-revert-notify-rm-watch, auto-revert-notify-add-watch, auto-revert-notify-handler, auto-revert-notify-rm-watch-callback): Don't remove a notify descriptor after receiving a `stopped' notification event, because the descriptor is then already gone and any attempt to remove it causes a recursive call to `auto-revert-notify-handler'. diff --git a/lisp/autorevert.el b/lisp/autorevert.el index 4fb865e8ad..1dc2f0eafd 100644 --- a/lisp/autorevert.el +++ b/lisp/autorevert.el @@ -287,7 +287,7 @@ You should set this variable through Custom." (dolist (buf (buffer-list)) (with-current-buffer buf (when (symbol-value 'auto-revert-notify-watch-descriptor) - (auto-revert-notify-rm-watch)))))) + (auto-revert-notify-rm-watch t)))))) :initialize 'custom-initialize-default :version "24.4") @@ -371,7 +371,7 @@ without being changed in the part that is already in the buffer." 'kill-buffer-hook #'auto-revert-remove-current-buffer nil t)) - (when auto-revert-notify-watch-descriptor (auto-revert-notify-rm-watch)) + (when auto-revert-notify-watch-descriptor (auto-revert-notify-rm-watch t)) (auto-revert-remove-current-buffer)) (auto-revert-set-timer) (when auto-revert-mode @@ -480,7 +480,7 @@ specifies in the mode line." (dolist (buf (buffer-list)) (with-current-buffer buf (when auto-revert-notify-watch-descriptor - (auto-revert-notify-rm-watch)))))) + (auto-revert-notify-rm-watch t)))))) (defun auto-revert-set-timer () "Restart or cancel the timer used by Auto-Revert Mode. @@ -497,8 +497,10 @@ will use an up-to-date value of `auto-revert-interval'" auto-revert-interval 'auto-revert-buffers)))) -(defun auto-revert-notify-rm-watch () - "Disable file notification for current buffer's associated file." +(defun auto-revert-notify-rm-watch (remove-descriptor) + "Disable file notification for current buffer's associated file. +If REMOVE-DESCRIPTOR is non-nil, remove the corresponding notification +descriptor; otherwise assume that it has already been removed." (when auto-revert-notify-watch-descriptor (maphash (lambda (key value) @@ -507,13 +509,19 @@ will use an up-to-date value of `auto-revert-interval'" (if value (puthash key value auto-revert-notify-watch-descriptor-hash-list) (remhash key auto-revert-notify-watch-descriptor-hash-list) - (ignore-errors - (file-notify-rm-watch auto-revert-notify-watch-descriptor))))) + (when remove-descriptor + (ignore-errors + (file-notify-rm-watch auto-revert-notify-watch-descriptor)))))) auto-revert-notify-watch-descriptor-hash-list) - (remove-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch t)) + (remove-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch-callback t)) (setq auto-revert-notify-watch-descriptor nil auto-revert-notify-modified-p nil)) +(defun auto-revert-notify-rm-watch-callback () + "Disable file notification for current buffer's associated file, +and remove the notification descriptor." + (auto-revert-notify-rm-watch t)) + (defun auto-revert-notify-add-watch () "Enable file notification for current buffer's associated file." ;; We can assume that `auto-revert-notify-watch-descriptor' is nil. @@ -553,7 +561,8 @@ will use an up-to-date value of `auto-revert-interval'" (gethash auto-revert-notify-watch-descriptor auto-revert-notify-watch-descriptor-hash-list)) auto-revert-notify-watch-descriptor-hash-list) - (add-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch nil t))))) + (add-hook 'kill-buffer-hook #'auto-revert-notify-rm-watch-callback + nil t))))) ;; If we have file notifications, we want to update the auto-revert buffers ;; immediately when a notification occurs. Since file updates can happen very @@ -609,7 +618,9 @@ no more reverts are possible until the next call of (file-name-nondirectory buffer-file-name))) ;; A buffer w/o a file, like dired. (null buffer-file-name))) - (auto-revert-notify-rm-watch)))) + ;; Since we got a `stopped' event, the notification descriptor + ;; is already gone; don't try to remove it. + (auto-revert-notify-rm-watch nil)))) ;; Loop over all buffers, in order to find the intended one. (cl-dolist (buffer buffers) commit ba6ed9a48dda6e8c9c4e886817dbac64f32437fd Author: Michael Albinus Date: Mon Apr 15 09:35:31 2019 +0200 * doc/misc/tramp.texi: Fix direntry. diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index b272c385d1..ca86458e90 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -27,10 +27,10 @@ copy and modify this GNU manual.'' @end quotation @end copying -@c Entries for @command{install-info} to use +@c Entries for @command{install-info} to use. We cannot use @value{tramp}. @dircategory Emacs network features @direntry -* @value{tramp}: (tramp). Transparent Remote Access, Multiple Protocol +* Tramp: (tramp). Transparent Remote Access, Multiple Protocol Emacs remote file access via ssh and scp. @end direntry @@ -113,8 +113,8 @@ For the developer: Installing @value{tramp} with your Emacs -* System Requirements:: Prerequisites for :@value{tramp} installation. -* Basic Installation:: Installation steps.: +* System Requirements:: Prerequisites for @value{tramp} installation. +* Basic Installation:: Installation steps. * Installation parameters:: Parameters in order to control installation. * Testing:: A test suite for @value{tramp}. * Load paths:: How to plug-in @value{tramp} into your environment. commit 8065e05a9ce32d95b3c50d694375eca78a7b8aeb Author: Paul Eggert Date: Sun Apr 14 23:10:45 2019 -0700 Remove static var system_eol_type * src/coding.c (system_eol_type): Remove. (coding_inherit_eol_type, syms_of_coding): Simplify to avoid the need for system_eol_type. diff --git a/src/coding.c b/src/coding.c index e351cc72fa..2c6b2c4d05 100644 --- a/src/coding.c +++ b/src/coding.c @@ -302,12 +302,6 @@ encode_coding_XXX (struct coding_system *coding) Lisp_Object Vcoding_system_hash_table; -/* Format of end-of-line decided by system. This is Qunix on - Unix and Mac, Qdos on DOS/Windows. - This has an effect only for external encoding (i.e. for output to - file and process), not for in-buffer or Lisp string encoding. */ -static Lisp_Object system_eol_type; - /* Coding-systems are handed between Emacs Lisp programs and C internal routines by the following three variables. */ /* Coding system to be used to encode text for terminal display when @@ -5972,8 +5966,7 @@ raw_text_coding_system_p (struct coding_system *coding) /* If CODING_SYSTEM doesn't specify end-of-line format, return one of the subsidiary that has the same eol-spec as PARENT (if it is not - nil and specifies end-of-line format) or the system's setting - (system_eol_type). */ + nil and specifies end-of-line format) or the system's setting. */ Lisp_Object coding_inherit_eol_type (Lisp_Object coding_system, Lisp_Object parent) @@ -5988,20 +5981,24 @@ coding_inherit_eol_type (Lisp_Object coding_system, Lisp_Object parent) eol_type = AREF (spec, 2); if (VECTORP (eol_type)) { - Lisp_Object parent_eol_type; + /* Format of end-of-line decided by system. + This is Qunix on Unix and Mac, Qdos on DOS/Windows. + This has an effect only for external encoding (i.e., for output to + file and process), not for in-buffer or Lisp string encoding. */ + Lisp_Object system_eol_type = Qunix; + #ifdef DOS_NT + system_eol_type = Qdos; + #endif + Lisp_Object parent_eol_type = system_eol_type; if (! NILP (parent)) { - Lisp_Object parent_spec; - CHECK_CODING_SYSTEM (parent); - parent_spec = CODING_SYSTEM_SPEC (parent); - parent_eol_type = AREF (parent_spec, 2); - if (VECTORP (parent_eol_type)) - parent_eol_type = system_eol_type; + Lisp_Object parent_spec = CODING_SYSTEM_SPEC (parent); + Lisp_Object pspec_type = AREF (parent_spec, 2); + if (!VECTORP (pspec_type)) + parent_eol_type = pspec_type; } - else - parent_eol_type = system_eol_type; if (EQ (parent_eol_type, Qunix)) coding_system = AREF (eol_type, 0); else if (EQ (parent_eol_type, Qdos)) @@ -11306,13 +11303,6 @@ internal character representation. */); for (int i = 0; i < coding_category_max; i++) Fset (AREF (Vcoding_category_table, i), Qno_conversion); -#if defined (DOS_NT) - system_eol_type = Qdos; -#else - system_eol_type = Qunix; -#endif - staticpro (&system_eol_type); - pdumper_do_now_and_after_load (reset_coding_after_pdumper_load); } commit da3e3fc7971eab2391a745d9429c6c70bc70e27c Author: YAMAMOTO Mitsuharu Date: Mon Apr 15 12:39:05 2019 +0900 Avoid compiler warnings on cairo build * src/image.c (jpeg_load_body) [USE_CAIRO]: #ifdef out USE_SAFE_ALLOCA and SAFE_FREE. * src/xterm.c (x_composite_image) [USE_CAIRO]: #ifdef out unused function. (x_draw_image_glyph_string) [USE_CAIRO]: #ifdef out unused variable pixmap. diff --git a/src/image.c b/src/image.c index 6e415ef1f7..c1a23edefc 100644 --- a/src/image.c +++ b/src/image.c @@ -7043,7 +7043,9 @@ jpeg_load_body (struct frame *f, struct image *img, colors generated, and mgr->cinfo.colormap is a two-dimensional array of color indices in the range 0..mgr->cinfo.actual_number_of_colors. No more than 255 colors will be generated. */ +#ifndef USE_CAIRO USE_SAFE_ALLOCA; +#endif { if (mgr->cinfo.out_color_components > 2) ir = 0, ig = 1, ib = 2; @@ -7127,8 +7129,8 @@ jpeg_load_body (struct frame *f, struct image *img, /* Put ximg into the image. */ image_put_x_image (f, img, ximg, 0); -#endif SAFE_FREE (); +#endif return 1; } diff --git a/src/xterm.c b/src/xterm.c index b9f4a1fc30..0facb52454 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2989,6 +2989,7 @@ x_draw_glyph_string_box (struct glyph_string *s) } +#ifndef USE_CAIRO static void x_composite_image (struct glyph_string *s, Pixmap dest, int srcX, int srcY, int dstX, int dstY, @@ -3028,6 +3029,7 @@ x_composite_image (struct glyph_string *s, Pixmap dest, srcX, srcY, width, height, dstX, dstY); } +#endif /* !USE_CAIRO */ /* Draw foreground of image glyph string S. */ @@ -3335,7 +3337,9 @@ x_draw_image_glyph_string (struct glyph_string *s) int box_line_hwidth = eabs (s->face->box_line_width); int box_line_vwidth = max (s->face->box_line_width, 0); int height; +#ifndef USE_CAIRO Pixmap pixmap = None; +#endif height = s->height; if (s->slice.y == 0) commit 9800df69cb7003bda1f2b98d6f11e89ba95afb9b Author: Noam Postavsky Date: Mon Apr 8 17:57:22 2019 -0400 Let debugger handle process spawn errors on w32 (Bug#33016) Since child_setup() is called between block_input()...unblock_input(), when an error is signaled the Lisp debugger is prevented from starting. Therefore, let the callers signal the error instead (which they already do for non-w32 platforms, just the error message needs an update). * src/callproc.c (child_setup) [WINDOWSNT]: Don't call report_file_error here. (call_process) [WINDOWNT]: * src/process.c (create_process) [WINDOWSNT]: Call report_file_errno here instead, after the unblock_input() call, same as for !WINDOWSNT. * src/lisp.h (CHILD_SETUP_ERROR_DESC): New preprocessor define. Flip the containing ifndef DOS_NT branches so that it's ifdef DOS_NT. * src/eval.c (when_entered_debugger): Remove. (syms_of_eval) : Define it as a Lisp integer variable instead. (maybe_call_debugger): Update comment. * test/src/process-tests.el (make-process-w32-debug-spawn-error): * test/src/callproc-tests.el (call-process-w32-debug-spawn-error): New tests. diff --git a/src/callproc.c b/src/callproc.c index a3d09609d7..2cdf84d9a8 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -681,7 +681,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, unblock_input (); if (pid < 0) - report_file_errno ("Doing vfork", Qnil, child_errno); + report_file_errno (CHILD_SETUP_ERROR_DESC, Qnil, child_errno); /* Close our file descriptors, except for callproc_fd[CALLPROC_PIPEREAD] since we will use that to read input from. */ @@ -1174,7 +1174,7 @@ exec_failed (char const *name, int err) executable directory by the parent. On GNUish hosts, either exec or return an error number. - On MS-Windows, either return a pid or signal an error. + On MS-Windows, either return a pid or return -1 and set errno. On MS-DOS, either return an exit status or signal an error. */ CHILD_SETUP_TYPE @@ -1319,9 +1319,6 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, /* Spawn the child. (See w32proc.c:sys_spawnve). */ cpid = spawnve (_P_NOWAIT, new_argv[0], new_argv, env); reset_standard_handles (in, out, err, handles); - if (cpid == -1) - /* An error occurred while trying to spawn the process. */ - report_file_error ("Spawning child process", Qnil); return cpid; #else /* not WINDOWSNT */ diff --git a/src/eval.c b/src/eval.c index e9f118c5cb..fa7b2d0603 100644 --- a/src/eval.c +++ b/src/eval.c @@ -52,15 +52,6 @@ Lisp_Object Vautoload_queue; is shutting down. */ Lisp_Object Vrun_hooks; -/* The value of num_nonmacro_input_events as of the last time we - started to enter the debugger. If we decide to enter the debugger - again when this is still equal to num_nonmacro_input_events, then we - know that the debugger itself has an error, and we should just - signal the error instead of entering an infinite loop of debugger - invocations. */ - -static intmax_t when_entered_debugger; - /* The function from which the last `signal' was called. Set in Fsignal. */ /* FIXME: We should probably get rid of this! */ @@ -1835,7 +1826,8 @@ maybe_call_debugger (Lisp_Object conditions, Lisp_Object sig, Lisp_Object data) ? debug_on_quit : wants_debugger (Vdebug_on_error, conditions)) && ! skip_debugger (conditions, combined_data) - /* RMS: What's this for? */ + /* See commentary on definition of + `internal-when-entered-debugger'. */ && when_entered_debugger < num_nonmacro_input_events) { call_debugger (list2 (Qerror, combined_data)); @@ -4170,6 +4162,18 @@ Note that `debug-on-error', `debug-on-quit' and friends still determine whether to handle the particular condition. */); Vdebug_on_signal = Qnil; + /* The value of num_nonmacro_input_events as of the last time we + started to enter the debugger. If we decide to enter the debugger + again when this is still equal to num_nonmacro_input_events, then we + know that the debugger itself has an error, and we should just + signal the error instead of entering an infinite loop of debugger + invocations. */ + DEFSYM (Qinternal_when_entered_debugger, "internal-when-entered-debugger"); + DEFVAR_INT ("internal-when-entered-debugger", when_entered_debugger, + doc: /* The number of keyboard events as of last time `debugger' was called. +Used to avoid infinite loops if the debugger itself has an error. +Don't set this unless you're sure that can't happen. */); + /* When lexical binding is being used, Vinternal_interpreter_environment is non-nil, and contains an alist of lexically-bound variable, or (t), indicating an empty diff --git a/src/lisp.h b/src/lisp.h index 681efc3b52..2915944ffe 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4480,11 +4480,14 @@ extern void syms_of_process (void); extern void setup_process_coding_systems (Lisp_Object); /* Defined in callproc.c. */ -#ifndef DOS_NT -# define CHILD_SETUP_TYPE _Noreturn void -#else +#ifdef DOS_NT # define CHILD_SETUP_TYPE int +# define CHILD_SETUP_ERROR_DESC "Spawning child process" +#else +# define CHILD_SETUP_TYPE _Noreturn void +# define CHILD_SETUP_ERROR_DESC "Doing vfork" #endif + extern CHILD_SETUP_TYPE child_setup (int, int, int, char **, bool, Lisp_Object); extern void init_callproc_1 (void); extern void init_callproc (void); diff --git a/src/process.c b/src/process.c index 6770a5ed88..0c44037162 100644 --- a/src/process.c +++ b/src/process.c @@ -2233,7 +2233,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) unblock_input (); if (pid < 0) - report_file_errno ("Doing vfork", Qnil, vfork_errno); + report_file_errno (CHILD_SETUP_ERROR_DESC, Qnil, vfork_errno); else { /* vfork succeeded. */ diff --git a/test/src/callproc-tests.el b/test/src/callproc-tests.el index 7b30a251cc..f351b6e214 100644 --- a/test/src/callproc-tests.el +++ b/test/src/callproc-tests.el @@ -37,3 +37,25 @@ (split-string-and-unquote (buffer-string))) (should (equal initial-shell "nil")) (should-not (equal initial-shell shell)))) + +(ert-deftest call-process-w32-debug-spawn-error () + "Check that debugger runs on `call-process' failure (Bug#33016)." + (skip-unless (eq system-type 'windows-nt)) + (let* ((debug-on-error t) + (have-called-debugger nil) + (debugger (lambda (&rest _) + (setq have-called-debugger t) + ;; Allow entering the debugger later in the same + ;; test run, before going back to the command + ;; loop. + (setq internal-when-entered-debugger -1)))) + (should (eq :got-error ;; NOTE: `should-error' would inhibit debugger. + (condition-case-unless-debug () + ;; On Windows, "nul.FOO" act like an always-empty + ;; file for any FOO, in any directory. So this + ;; passes Emacs' test for the file's existence, + ;; and ensures we hit an error in the w32 process + ;; spawn code. + (call-process "c:/nul.exe") + (error :got-error)))) + (should have-called-debugger))) diff --git a/test/src/process-tests.el b/test/src/process-tests.el index 5dbf441e8c..0bb7ebe50a 100644 --- a/test/src/process-tests.el +++ b/test/src/process-tests.el @@ -215,6 +215,26 @@ (string-to-list "stdout\n") (string-to-list "stderr\n")))))) +(ert-deftest make-process-w32-debug-spawn-error () + "Check that debugger runs on `make-process' failure (Bug#33016)." + (skip-unless (eq system-type 'windows-nt)) + (let* ((debug-on-error t) + (have-called-debugger nil) + (debugger (lambda (&rest _) + (setq have-called-debugger t) + ;; Allow entering the debugger later in the same + ;; test run, before going back to the command + ;; loop. + (setq internal-when-entered-debugger -1)))) + (should (eq :got-error ;; NOTE: `should-error' would inhibit debugger. + (condition-case-unless-debug () + ;; Emacs doesn't search for absolute filenames, so + ;; the error will be hit in the w32 process spawn + ;; code. + (make-process :name "test" :command '("c:/No-Such-Command")) + (error :got-error)))) + (should have-called-debugger))) + (ert-deftest make-process/file-handler/found () "Check that the ‘:file-handler’ argument of ‘make-process’ works as expected if a file name handler is found." commit fc0f469fb5b5eb28ca4d9948190be6cb1bd8156e Author: Alexander Gramiak Date: Sun Apr 7 19:02:03 2019 -0600 Bump minimum GTK versions to 2.24 and 3.10 * configure.ac: Bump required GTK 2 and GTK 3 versions and the associated GLib versions. Remove obsolete AC_CHECK_FUNCS calls. These check for functions available in later GTK 2 versions. These checks and can safely be removed with the exception of gtk_window_set_has_resize_grip, which according to a comment in gtkutil.c causes an issue in Ubuntu's GTK 2. * src/gtkutil.c: * src/xfns.c: * src/xterm.c: * src/xterm.h: Remove now unused conditional blocks. Use HAVE_GTK3 instead of GTK_CHECK_VERSION where now applicable. Remove checks of now always true USE_GTK_TOOLTIP. diff --git a/configure.ac b/configure.ac index cff9a27422..3cebf3d78c 100644 --- a/configure.ac +++ b/configure.ac @@ -2688,8 +2688,8 @@ check_gtk2=no gtk3_pkg_errors= if test "${opsys}" != "mingw32"; then if test "${with_gtk3}" = "yes" || test "${with_gtk}" = "yes" || test "$USE_X_TOOLKIT" = "maybe"; then - GLIB_REQUIRED=2.28 - GTK_REQUIRED=3.0 + GLIB_REQUIRED=2.37.5 + GTK_REQUIRED=3.10 GTK_MODULES="gtk+-3.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED" dnl Checks for libraries. @@ -2716,8 +2716,8 @@ if test "${opsys}" != "mingw32"; then fi if test "${with_gtk2}" = "yes" || test "$check_gtk2" = "yes"; then - GLIB_REQUIRED=2.10 - GTK_REQUIRED=2.10 + GLIB_REQUIRED=2.28 + GTK_REQUIRED=2.24 GTK_MODULES="gtk+-2.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED" dnl Checks for libraries. @@ -2804,30 +2804,8 @@ if test "${HAVE_GTK}" = "yes"; then AC_CHECK_FUNCS(gtk_file_selection_new) fi - dnl Same as above for gtk_handle_box. - HAVE_GTK_HANDLE_BOX=no - AC_CHECK_DECL(GTK_TYPE_HANDLE_BOX, HAVE_GTK_HANDLE_BOX=yes, - HAVE_GTK_HANDLE_BOX=no, [AC_INCLUDES_DEFAULT -#include ]) - if test "$HAVE_GTK_HANDLE_BOX" = yes; then - AC_CHECK_FUNCS(gtk_handle_box_new) - fi - - dnl Same as above for gtk_tearoff_menu_item. - HAVE_GTK_TEAROFF_MENU_ITEM=no - AC_CHECK_DECL(GTK_TYPE_TEAROFF_MENU_ITEM, HAVE_GTK_TEAROFF_MENU_ITEM=yes, - HAVE_GTK_TEAROFF_MENU_ITEM=no, [AC_INCLUDES_DEFAULT -#include ]) - if test "$HAVE_GTK_TEAROFF_MENU_ITEM" = yes; then - AC_CHECK_FUNCS(gtk_tearoff_menu_item_new) - fi - - dnl Check for functions introduced in 2.14 and later. - AC_CHECK_FUNCS(gtk_widget_get_window gtk_widget_set_has_window \ - gtk_dialog_get_action_area gtk_widget_get_sensitive \ - gtk_widget_get_mapped gtk_adjustment_get_page_size \ - gtk_orientable_set_orientation \ - gtk_window_set_has_resize_grip) + dnl This procedure causes a bug on certain Ubuntu GTK+2 builds + AC_CHECK_FUNCS(gtk_window_set_has_resize_grip) term_header=gtkutil.h fi diff --git a/etc/NEWS b/etc/NEWS index 82d27d7e74..272da3d800 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -89,6 +89,10 @@ Options" in the Emacs manual for more information. check that the portable dumper code has been updated to match the last change to one of the data structures that it relies on. +--- +** Emacs now requires GTK 2.24 and GTK 3.10 for the GTK 2 and GTK 3 +builds respectively. + * Startup Changes in Emacs 27.1 diff --git a/src/gtkutil.c b/src/gtkutil.c index b130692c87..2612683bcb 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -52,48 +52,19 @@ along with GNU Emacs. If not, see . */ #include #endif -#ifndef HAVE_GTK_WIDGET_SET_HAS_WINDOW -#define gtk_widget_set_has_window(w, b) \ - (gtk_fixed_set_has_window (GTK_FIXED (w), b)) -#endif -#ifndef HAVE_GTK_DIALOG_GET_ACTION_AREA -#define gtk_dialog_get_action_area(w) ((w)->action_area) -#define gtk_dialog_get_content_area(w) ((w)->vbox) -#endif -#ifndef HAVE_GTK_WIDGET_GET_SENSITIVE -#define gtk_widget_get_sensitive(w) (GTK_WIDGET_SENSITIVE (w)) -#endif -#ifndef HAVE_GTK_ADJUSTMENT_GET_PAGE_SIZE -#define gtk_adjustment_set_page_size(w, s) ((w)->page_size = (s)) -#define gtk_adjustment_set_page_increment(w, s) ((w)->page_increment = (s)) -#define gtk_adjustment_get_step_increment(w) ((w)->step_increment) -#define gtk_adjustment_set_step_increment(w, s) ((w)->step_increment = (s)) -#endif -#if GTK_CHECK_VERSION (2, 12, 0) -#define remove_submenu(w) gtk_menu_item_set_submenu ((w), NULL) +#ifdef HAVE_GTK3 +#define XG_TEXT_CANCEL "Cancel" +#define XG_TEXT_OK "OK" +#define XG_TEXT_OPEN "Open" #else -#define remove_submenu(w) gtk_menu_item_remove_submenu ((w)) +#define XG_TEXT_CANCEL GTK_STOCK_CANCEL +#define XG_TEXT_OK GTK_STOCK_OK +#define XG_TEXT_OPEN GTK_STOCK_OPEN #endif -#if ! GTK_CHECK_VERSION (2, 14, 0) -#define gtk_adjustment_configure(adj, xvalue, xlower, \ - xupper, xstep_increment, \ - xpage_increment, xpagesize) \ - do { \ - adj->lower = xlower; \ - adj->upper = xupper; \ - adj->page_size = xpagesize; \ - gtk_adjustment_set_value (adj, xvalue); \ - adj->page_increment = xpage_increment; \ - adj->step_increment = xstep_increment; \ - } while (0) -#endif /* < Gtk+ 2.14 */ +#ifndef HAVE_GTK3 #ifdef HAVE_FREETYPE -#if GTK_CHECK_VERSION (3, 2, 0) -#define USE_NEW_GTK_FONT_CHOOSER 1 -#else -#define USE_NEW_GTK_FONT_CHOOSER 0 #define gtk_font_chooser_dialog_new(x, y) \ gtk_font_selection_dialog_new (x) #undef GTK_FONT_CHOOSER @@ -101,35 +72,15 @@ along with GNU Emacs. If not, see . */ #define gtk_font_chooser_set_font(x, y) \ gtk_font_selection_dialog_set_font_name (x, y) #endif -#endif /* HAVE_FREETYPE */ - -#if GTK_CHECK_VERSION (3, 10, 0) -#define XG_TEXT_CANCEL "Cancel" -#define XG_TEXT_OK "OK" -#define XG_TEXT_OPEN "Open" -#else -#define XG_TEXT_CANCEL GTK_STOCK_CANCEL -#define XG_TEXT_OK GTK_STOCK_OK -#define XG_TEXT_OPEN GTK_STOCK_OPEN -#endif -#ifndef HAVE_GTK3 -#ifdef USE_GTK_TOOLTIP -#define gdk_window_get_screen(w) gdk_drawable_get_screen (w) -#endif #define gdk_window_get_geometry(w, a, b, c, d) \ gdk_window_get_geometry (w, a, b, c, d, 0) -#define gdk_x11_window_lookup_for_display(d, w) \ - gdk_xid_table_lookup_for_display (d, w) #define gtk_box_new(ori, spacing) \ ((ori) == GTK_ORIENTATION_HORIZONTAL \ ? gtk_hbox_new (FALSE, (spacing)) : gtk_vbox_new (FALSE, (spacing))) #define gtk_scrollbar_new(ori, spacing) \ ((ori) == GTK_ORIENTATION_HORIZONTAL \ ? gtk_hscrollbar_new ((spacing)) : gtk_vscrollbar_new ((spacing))) -#ifndef GDK_KEY_g -#define GDK_KEY_g GDK_g -#endif #endif /* HAVE_GTK3 */ #define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x)) @@ -227,7 +178,7 @@ xg_get_gdk_scale (void) int xg_get_scale (struct frame *f) { -#if GTK_CHECK_VERSION (3, 10, 0) +#ifdef HAVE_GTK3 if (FRAME_GTK_WIDGET (f)) return gtk_widget_get_scale_factor (FRAME_GTK_WIDGET (f)); #endif @@ -261,15 +212,7 @@ xg_display_close (Display *dpy) gdpy_def = gdpy_new; } -#if GTK_CHECK_VERSION (2, 0, 0) && ! GTK_CHECK_VERSION (2, 10, 0) - /* GTK 2.2-2.8 has a bug that makes gdk_display_close crash - . This way we - can continue running, but there will be memory leaks. */ - g_object_run_dispose (G_OBJECT (gdpy)); -#else - /* This seems to be fixed in GTK 2.10. */ gdk_display_close (gdpy); -#endif } @@ -368,7 +311,7 @@ xg_get_image_for_pixmap (struct frame *f, GtkWidget *widget, GtkImage *old_widget) { -#if defined USE_CAIRO && GTK_CHECK_VERSION (3, 10, 0) +#if defined USE_CAIRO && defined HAVE_GTK3 cairo_surface_t *surface; #else GdkPixbuf *icon_buf; @@ -400,7 +343,7 @@ xg_get_image_for_pixmap (struct frame *f, on a monochrome display, and sometimes bad on all displays with certain themes. */ -#if defined USE_CAIRO && GTK_CHECK_VERSION (3, 10, 0) +#if defined USE_CAIRO && defined HAVE_GTK3 surface = img->cr_data; if (surface) @@ -643,8 +586,6 @@ xg_check_special_colors (struct frame *f, We use that to pop down the tooltip. This happens if Gtk+ for some reason wants to change or hide the tooltip. */ -#ifdef USE_GTK_TOOLTIP - static void hierarchy_ch_cb (GtkWidget *widget, GtkWidget *previous_toplevel, @@ -711,8 +652,6 @@ qttip_cb (GtkWidget *widget, return FALSE; } -#endif /* USE_GTK_TOOLTIP */ - /* Prepare a tooltip to be shown, i.e. calculate WIDTH and HEIGHT. Return true if a system tooltip is available. */ @@ -722,9 +661,6 @@ xg_prepare_tooltip (struct frame *f, int *width, int *height) { -#ifndef USE_GTK_TOOLTIP - return 0; -#else struct x_output *x = f->output_data.x; GtkWidget *widget; GdkWindow *gwin; @@ -768,7 +704,6 @@ xg_prepare_tooltip (struct frame *f, unblock_input (); return TRUE; -#endif /* USE_GTK_TOOLTIP */ } /* Show the tooltip at ROOT_X and ROOT_Y. @@ -777,7 +712,6 @@ xg_prepare_tooltip (struct frame *f, void xg_show_tooltip (struct frame *f, int root_x, int root_y) { -#ifdef USE_GTK_TOOLTIP struct x_output *x = f->output_data.x; if (x->ttip_window) { @@ -787,7 +721,6 @@ xg_show_tooltip (struct frame *f, int root_x, int root_y) gtk_widget_show (GTK_WIDGET (x->ttip_window)); unblock_input (); } -#endif } @@ -797,7 +730,6 @@ xg_show_tooltip (struct frame *f, int root_x, int root_y) bool xg_hide_tooltip (struct frame *f) { -#ifdef USE_GTK_TOOLTIP if (f->output_data.x->ttip_window) { GtkWindow *win = f->output_data.x->ttip_window; @@ -816,7 +748,6 @@ xg_hide_tooltip (struct frame *f) return TRUE; } -#endif return FALSE; } @@ -1193,7 +1124,7 @@ xg_create_frame_widgets (struct frame *f) has backported it to Gtk+ 2.0 and they add the resize grip for Gtk+ 2.0 applications also. But it has a bug that makes Emacs loop forever, so disable the grip. */ -#if (! GTK_CHECK_VERSION (3, 0, 0) \ +#if (! defined HAVE_GTK3 \ && defined HAVE_GTK_WINDOW_SET_HAS_RESIZE_GRIP) gtk_window_set_has_resize_grip (GTK_WINDOW (wtop), FALSE); #endif @@ -1328,14 +1259,12 @@ xg_create_frame_widgets (struct frame *f) gdk_window_set_override_redirect (gwin, TRUE); } -#ifdef USE_GTK_TOOLTIP /* Steal a tool tip window we can move ourselves. */ f->output_data.x->ttip_widget = 0; f->output_data.x->ttip_lbl = 0; f->output_data.x->ttip_window = 0; gtk_widget_set_tooltip_text (wtop, "Dummy text"); g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f); -#endif { GdkScreen *screen = gtk_widget_get_screen (wtop); @@ -1363,9 +1292,7 @@ xg_free_frame_widgets (struct frame *f) { if (FRAME_GTK_OUTER_WIDGET (f)) { -#ifdef USE_GTK_TOOLTIP struct x_output *x = f->output_data.x; -#endif struct xg_frame_tb_info *tbinfo = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), TB_INFO_KEY); @@ -1378,12 +1305,10 @@ xg_free_frame_widgets (struct frame *f) FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */ FRAME_X_RAW_DRAWABLE (f) = 0; FRAME_GTK_OUTER_WIDGET (f) = 0; -#ifdef USE_GTK_TOOLTIP if (x->ttip_lbl) gtk_widget_destroy (x->ttip_lbl); if (x->ttip_widget) g_object_unref (G_OBJECT (x->ttip_widget)); -#endif } } @@ -1561,7 +1486,6 @@ xg_set_undecorated (struct frame *f, Lisp_Object undecorated) void xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) { -#if GTK_CHECK_VERSION (2, 18, 0) block_input (); if (FRAME_GTK_OUTER_WIDGET (f1) && FRAME_GTK_OUTER_WIDGET (f2)) { @@ -1576,7 +1500,6 @@ xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) x_sync (f1); } unblock_input (); -#endif } @@ -2216,7 +2139,7 @@ xg_get_file_name (struct frame *f, #ifdef HAVE_FREETYPE -#if USE_NEW_GTK_FONT_CHOOSER +#ifdef HAVE_GTK3 #define XG_WEIGHT_TO_SYMBOL(w) \ (w <= PANGO_WEIGHT_THIN ? Qextra_light \ @@ -2233,7 +2156,7 @@ xg_get_file_name (struct frame *f, : s == PANGO_STYLE_ITALIC ? Qitalic \ : Qnormal) -#endif /* USE_NEW_GTK_FONT_CHOOSER */ +#endif /* HAVE_GTK3 */ static char *x_last_font_name; @@ -2280,7 +2203,7 @@ xg_get_font (struct frame *f, const char *default_name) done = xg_dialog_run (f, w); if (done == GTK_RESPONSE_OK) { -#if USE_NEW_GTK_FONT_CHOOSER +#ifdef HAVE_GTK3 /* Use the GTK3 font chooser. */ PangoFontDescription *desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (w)); @@ -2320,7 +2243,7 @@ xg_get_font (struct frame *f, const char *default_name) g_free (x_last_font_name); x_last_font_name = font_name; } -#endif /* USE_NEW_GTK_FONT_CHOOSER */ +#endif /* HAVE_GTK3 */ } gtk_widget_destroy (w); @@ -3041,9 +2964,7 @@ xg_update_menubar (GtkWidget *menubar, bridge that might be loaded) that the item's label has changed. */ gtk_label_set_text (wlabel, utf8_label); -#if GTK_CHECK_VERSION (2, 16, 0) g_object_notify (G_OBJECT (witem), "label"); -#endif if (utf8_label) g_free (utf8_label); iter = g_list_next (iter); val = val->next; @@ -3222,10 +3143,8 @@ xg_update_menu_item (widget_value *val, } } -#if GTK_CHECK_VERSION (2, 16, 0) if (label_changed) /* See comment in xg_update_menubar. */ g_object_notify (G_OBJECT (w), "label"); -#endif } /* Update the toggle menu item W so it corresponds to VAL. */ @@ -3324,7 +3243,7 @@ xg_update_submenu (GtkWidget *submenu, { /* Not a submenu anymore. */ g_object_ref (G_OBJECT (sub)); - remove_submenu (witem); + gtk_menu_item_set_submenu (witem, NULL); gtk_widget_destroy (sub); } else if (cur->contents) @@ -4492,14 +4411,6 @@ xg_tool_bar_item_expose_callback (GtkWidget *w, } #endif -#ifdef HAVE_GTK_ORIENTABLE_SET_ORIENTATION -#define toolbar_set_orientation(w, o) \ - gtk_orientable_set_orientation (GTK_ORIENTABLE (w), o) -#else -#define toolbar_set_orientation(w, o) \ - gtk_toolbar_set_orientation (GTK_TOOLBAR (w), o) -#endif - /* Attach a tool bar to frame F. */ static void @@ -4509,10 +4420,10 @@ xg_pack_tool_bar (struct frame *f, Lisp_Object pos) bool into_hbox = EQ (pos, Qleft) || EQ (pos, Qright); GtkWidget *top_widget = x->toolbar_widget; - toolbar_set_orientation (x->toolbar_widget, - into_hbox - ? GTK_ORIENTATION_VERTICAL - : GTK_ORIENTATION_HORIZONTAL); + gtk_orientable_set_orientation (GTK_ORIENTABLE (x->toolbar_widget), + into_hbox + ? GTK_ORIENTATION_VERTICAL + : GTK_ORIENTATION_HORIZONTAL); if (into_hbox) { @@ -4565,7 +4476,7 @@ static void xg_create_tool_bar (struct frame *f) { struct x_output *x = f->output_data.x; -#if GTK_CHECK_VERSION (3, 3, 6) +#ifdef HAVE_GTK3 GtkStyleContext *gsty; #endif struct xg_frame_tb_info *tbinfo @@ -4589,10 +4500,11 @@ xg_create_tool_bar (struct frame *f) gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar"); gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS); - toolbar_set_orientation (x->toolbar_widget, GTK_ORIENTATION_HORIZONTAL); + gtk_orientable_set_orientation (GTK_ORIENTABLE (x->toolbar_widget), + GTK_ORIENTATION_HORIZONTAL); g_signal_connect (x->toolbar_widget, "size-allocate", G_CALLBACK (tb_size_cb), f); -#if GTK_CHECK_VERSION (3, 3, 6) +#ifdef HAVE_GTK3 gsty = gtk_widget_get_style_context (x->toolbar_widget); gtk_style_context_add_class (gsty, "primary-toolbar"); #endif @@ -4645,7 +4557,7 @@ xg_make_tool_item (struct frame *f, GtkWidget *wb = gtk_button_new (); /* The eventbox is here so we can have tooltips on disabled items. */ GtkWidget *weventbox = gtk_event_box_new (); -#if GTK_CHECK_VERSION (3, 3, 6) +#ifdef HAVE_GTK3 GtkCssProvider *css_prov = gtk_css_provider_new (); GtkStyleContext *gsty; @@ -4777,7 +4689,7 @@ xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name, { gpointer gold_img = g_object_get_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA); -#if defined USE_CAIRO && GTK_CHECK_VERSION (3, 10, 0) +#if defined USE_CAIRO && defined HAVE_GTK3 void *old_img = (void *) gold_img; if (old_img != img->cr_data) return 1; @@ -4850,7 +4762,7 @@ find_icon_from_name (char *name, GtkIconTheme *icon_theme, char **icon_name) { -#if ! GTK_CHECK_VERSION (3, 10, 0) +#ifndef HAVE_GTK3 GtkStockItem stock_item; #endif @@ -4863,7 +4775,7 @@ find_icon_from_name (char *name, *icon_name = NULL; } -#if ! GTK_CHECK_VERSION (3, 10, 0) +#ifndef HAVE_GTK3 else if (gtk_stock_lookup (name, &stock_item)) *icon_name = NULL; #endif @@ -5078,7 +4990,7 @@ update_frame_tool_bar (struct frame *f) prepare_image_for_display (f, img); if (img->load_failed_p -#if defined USE_CAIRO && GTK_CHECK_VERSION (3, 10, 0) +#if defined USE_CAIRO && defined HAVE_GTK3 || img->cr_data == NULL #else || img->pixmap == None @@ -5113,7 +5025,7 @@ update_frame_tool_bar (struct frame *f) else if (stock_name) { -#if GTK_CHECK_VERSION (3, 10, 0) +#ifdef HAVE_GTK3 w = gtk_image_new_from_icon_name (stock_name, icon_size); #else w = gtk_image_new_from_stock (stock_name, icon_size); @@ -5133,7 +5045,7 @@ update_frame_tool_bar (struct frame *f) { w = xg_get_image_for_pixmap (f, img, x->widget, NULL); g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA, -#if defined USE_CAIRO && GTK_CHECK_VERSION (3, 10, 0) +#if defined USE_CAIRO && defined HAVE_GTK3 (gpointer)img->cr_data #else (gpointer)img->pixmap @@ -5309,7 +5221,7 @@ xg_initialize (void) settings = gtk_settings_get_for_screen (gdk_display_get_default_screen (gdk_display_get_default ())); -#if ! GTK_CHECK_VERSION (3, 10, 0) +#ifndef HAVE_GTK3 /* Remove F10 as a menu accelerator, it does not mix well with Emacs key bindings. It doesn't seem to be any way to remove properties, so we set it to "" which in means "no key". */ diff --git a/src/xfns.c b/src/xfns.c index e521ed12e4..dbc5e10c41 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -4496,7 +4496,7 @@ On MS Windows, this just returns nil. */) Return false if and only if the workarea information cannot be obtained via the _NET_WORKAREA root window property. */ -#if ! GTK_CHECK_VERSION (3, 4, 0) +#ifndef HAVE_GTK3 static bool x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect) { @@ -4906,9 +4906,9 @@ Internal use only, use `display-monitor-attributes-list' instead. */) Lisp_Object attributes_list = Qnil; #ifdef USE_GTK - double mm_width_per_pixel, mm_height_per_pixel; GdkDisplay *gdpy; #if ! GTK_CHECK_VERSION (3, 22, 0) + double mm_width_per_pixel, mm_height_per_pixel; GdkScreen *gscreen; #endif gint primary_monitor = 0, n_monitors, i; @@ -4917,19 +4917,18 @@ Internal use only, use `display-monitor-attributes-list' instead. */) struct MonitorInfo *monitors; block_input (); - mm_width_per_pixel = ((double) WidthMMOfScreen (dpyinfo->screen) - / x_display_pixel_width (dpyinfo)); - mm_height_per_pixel = ((double) HeightMMOfScreen (dpyinfo->screen) - / x_display_pixel_height (dpyinfo)); gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display); #if GTK_CHECK_VERSION (3, 22, 0) n_monitors = gdk_display_get_n_monitors (gdpy); #else gscreen = gdk_display_get_default_screen (gdpy); -#if GTK_CHECK_VERSION (2, 20, 0) - primary_monitor = gdk_screen_get_primary_monitor (gscreen); -#endif n_monitors = gdk_screen_get_n_monitors (gscreen); + primary_monitor = gdk_screen_get_primary_monitor (gscreen); + /* Fallback if gdk_screen_get_monitor_{width,height}_mm fail */ + mm_width_per_pixel = ((double) WidthMMOfScreen (dpyinfo->screen) + / x_display_pixel_width (dpyinfo)); + mm_height_per_pixel = ((double) HeightMMOfScreen (dpyinfo->screen) + / x_display_pixel_height (dpyinfo)); #endif monitor_frames = make_nil_vector (n_monitors); monitors = xzalloc (n_monitors * sizeof *monitors); @@ -4958,7 +4957,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) for (i = 0; i < n_monitors; ++i) { - gint width_mm = -1, height_mm = -1; + gint width_mm, height_mm; GdkRectangle rec, work; struct MonitorInfo *mi = &monitors[i]; int scale = 1; @@ -4975,18 +4974,17 @@ Internal use only, use `display-monitor-attributes-list' instead. */) #if GTK_CHECK_VERSION (3, 22, 0) width_mm = gdk_monitor_get_width_mm (monitor); height_mm = gdk_monitor_get_height_mm (monitor); -#elif GTK_CHECK_VERSION (2, 14, 0) +#else width_mm = gdk_screen_get_monitor_width_mm (gscreen, i); height_mm = gdk_screen_get_monitor_height_mm (gscreen, i); -#endif if (width_mm < 0) width_mm = rec.width * mm_width_per_pixel + 0.5; if (height_mm < 0) height_mm = rec.height * mm_height_per_pixel + 0.5; - +#endif #if GTK_CHECK_VERSION (3, 22, 0) gdk_monitor_get_workarea (monitor, &work); -#elif GTK_CHECK_VERSION (3, 4, 0) +#elif defined HAVE_GTK3 gdk_screen_get_monitor_workarea (gscreen, i, &work); #else /* Emulate the behavior of GTK+ 3.4. */ @@ -5010,7 +5008,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) /* GTK returns scaled sizes for the workareas. */ #if GTK_CHECK_VERSION (3, 22, 0) scale = gdk_monitor_get_scale_factor (monitor); -#elif GTK_CHECK_VERSION (3, 10, 0) +#elif defined HAVE_GTK3 scale = gdk_screen_get_monitor_scale_factor (gscreen, i); #endif rec.width *= scale; @@ -5031,7 +5029,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) #if GTK_CHECK_VERSION (3, 22, 0) dupstring (&mi->name, (gdk_monitor_get_model (monitor))); -#elif GTK_CHECK_VERSION (2, 14, 0) +#else mi->name = gdk_screen_get_monitor_plug_name (gscreen, i); #endif } @@ -5041,11 +5039,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) primary_monitor, monitor_frames, source); -#if GTK_CHECK_VERSION (2, 14, 0) free_monitors (monitors, n_monitors); -#else - xfree (monitors); -#endif unblock_input (); #else /* not USE_GTK */ @@ -5380,7 +5374,7 @@ Frames are listed from topmost (first) to bottommost (last). */) static void x_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) { -#if defined (USE_GTK) && GTK_CHECK_VERSION (2, 18, 0) +#ifdef USE_GTK block_input (); xg_frame_restack (f1, f2, above_flag); unblock_input (); diff --git a/src/xterm.c b/src/xterm.c index def6915d62..b9f4a1fc30 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -12514,7 +12514,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) dpy = DEFAULT_GDK_DISPLAY (); -#if ! GTK_CHECK_VERSION (2, 90, 0) +#ifndef HAVE_GTK3 /* Load our own gtkrc if it exists. */ { const char *file = "~/.emacs.d/gtkrc"; diff --git a/src/xterm.h b/src/xterm.h index c5ad38650c..bb7631a3f4 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -50,17 +50,8 @@ typedef Widget xt_or_gtk_widget; #include #endif /* USE_GTK */ -/* True iff GTK's version is at least I.J.K. */ -#ifndef GTK_CHECK_VERSION -# ifdef USE_GTK -# define GTK_CHECK_VERSION(i, j, k) \ - ((i) \ - < GTK_MAJOR_VERSION + ((j) \ - < GTK_MINOR_VERSION + ((k) \ - <= GTK_MICRO_VERSION))) -# else -# define GTK_CHECK_VERSION(i, j, k) false -# endif +#ifndef USE_GTK +#define GTK_CHECK_VERSION(i, j, k) false #endif #ifdef USE_GTK @@ -76,11 +67,6 @@ typedef GtkWidget *xt_or_gtk_widget; #endif #endif /* USE_GTK */ -/* The GtkTooltip API came in 2.12, but gtk-enable-tooltips in 2.14. */ -#if GTK_CHECK_VERSION (2, 14, 0) -#define USE_GTK_TOOLTIP -#endif - #ifdef USE_CAIRO #include #ifdef CAIRO_HAS_PDF_SURFACE @@ -594,12 +580,9 @@ struct x_output GdkGeometry size_hints; long hint_flags; -#ifdef USE_GTK_TOOLTIP GtkTooltip *ttip_widget; GtkWidget *ttip_lbl; GtkWindow *ttip_window; -#endif /* USE_GTK_TOOLTIP */ - #endif /* USE_GTK */ /* If >=0, a bitmap index. The indicated bitmap is used for the @@ -793,18 +776,6 @@ extern void x_mark_frame_dirty (struct frame *f); FRAME_X_WINDOW (f)) #else #ifdef USE_GTK -/* Functions not present in older Gtk+ */ - -#ifndef HAVE_GTK_WIDGET_GET_WINDOW -#define gtk_widget_get_window(w) ((w)->window) -#endif -#ifndef HAVE_GTK_WIDGET_GET_MAPPED -#define gtk_widget_get_mapped(w) (GTK_WIDGET_MAPPED (w)) -#endif -#ifndef HAVE_GTK_ADJUSTMENT_GET_PAGE_SIZE -#define gtk_adjustment_get_page_size(w) ((w)->page_size) -#define gtk_adjustment_get_upper(w) ((w)->upper) -#endif #ifdef HAVE_GTK3 #define DEFAULT_GDK_DISPLAY() \ commit 5c2f94a182a1154766154040eb5b4b39275fd3b6 Author: Paul Eggert Date: Sun Apr 14 16:31:24 2019 -0700 Replace executable’s fingerprint in place * admin/merge-gnulib (GNULIB_MODULES): Add memmem-simple. (AVOIDED_MODULES): Add memchr. * configure.ac (HAVE_PDUMPER): AC_SUBST it, too, for use in makefiles. * lib/Makefile.in (libgnu_a_OBJECTS): Add fingerprint.o. * lib/fingerprint.c: New file. * lib/memmem.c, lib/str-two-way.h, m4/memmem.m4: New files, copied from Gnulib. * lib/fingerprint.h: Rename from src/fingerprint.h. * lib-src/make-fingerprint.c: Include limits.h, sys/stat.h, fingerprint.h, intprops.h, min-max.h. (SSIZE_MAX): New macro, if not already defined. (main): Without -r, Replace the fingerprint in the input file instead of generating a fingerprint.c. * lib/Makefile.in (libgnu_a_OBJECTS): Add fingerprint.o. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * src/Makefile.in (HAVE_PDUMPER, MAKE_PDUMPER_FINGERPRINT): New macros. (temacs$(EXEEXT)): Use them to replace the fingerprint instead of precalculating it. (mostlyclean, ctagsfiles1): Do not worry about fingerprint.c. diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 055e791d62..4a69310d83 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -36,7 +36,7 @@ GNULIB_MODULES=' filemode filevercmp flexmember fpieee fstatat fsusage fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ieee754-h ignore-value intprops largefile lstat - manywarnings memrchr minmax mkostemp mktime nstrftime + manywarnings memmem-simple memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat regex sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time @@ -47,7 +47,7 @@ GNULIB_MODULES=' AVOIDED_MODULES=' btowc close dup fchdir fstat langinfo lock - malloc-posix mbrtowc mbsinit mkdir msvc-inval msvc-nothrow nl_langinfo + malloc-posix mbrtowc mbsinit memchr mkdir msvc-inval msvc-nothrow nl_langinfo openat-die opendir raise save-cwd select setenv sigprocmask stat stdarg stdbool threadlib tzset unsetenv utime utime-h diff --git a/configure.ac b/configure.ac index 1814a30cbc..cff9a27422 100644 --- a/configure.ac +++ b/configure.ac @@ -379,8 +379,12 @@ if test "$with_dumping" = "unexec" && test "$with_unexec" = "no"; then fi if test "$with_pdumper" = "yes"; then - AC_DEFINE(HAVE_PDUMPER, 1, [Define to build with portable dumper support]) + AC_DEFINE([HAVE_PDUMPER], 1, [Define to build with portable dumper support]) + HAVE_PDUMPER=yes +else + HAVE_PDUMPER=no fi +AC_SUBST([HAVE_PDUMPER]) DUMPING=$with_dumping AC_SUBST(DUMPING) diff --git a/lib-src/make-fingerprint.c b/lib-src/make-fingerprint.c index 35bb8b98a0..dc21fc2aa9 100644 --- a/lib-src/make-fingerprint.c +++ b/lib-src/make-fingerprint.c @@ -25,14 +25,25 @@ along with GNU Emacs. If not, see . */ #include +#include #include #include #include #include #include +#include + #include -#include + +#include #include +#include +#include +#include + +#ifndef SSIZE_MAX +# define SSIZE_MAX TYPE_MAXIMUM (ssize_t) +#endif #ifdef WINDOWSNT /* Defined to be sys_fopen in ms-w32.h, but only #ifdef emacs, so this @@ -54,41 +65,62 @@ main (int argc, char **argv) raw = true; break; case 'h': - printf ("make-fingerprint [-r] FILES...: compute a hash\n"); - return 0; + printf ("make-fingerprint [-r] FILE: replace or compute a hash\n"); + return EXIT_SUCCESS; default: - return 1; + return EXIT_FAILURE; } } struct sha256_ctx ctx; sha256_init_ctx (&ctx); - for (int i = optind; i < argc; ++i) + if (argc - optind != 1) { - FILE *f = fopen (argv[i], "r" FOPEN_BINARY); - if (!f) - { - fprintf (stderr, "%s: Error: could not open %s\n", - argv[0], argv[i]); - return 1; - } + fprintf (stderr, "%s: missing or extra file operand\n", argv[0]); + return EXIT_FAILURE; + } - char buf[128*1024]; - do - { - size_t chunksz = fread (buf, 1, sizeof (buf), f); - if (ferror (f)) - { - fprintf (stderr, "%s: Error: could not read %s\n", - argv[0], argv[i]); - return 1; - } - sha256_process_bytes (buf, chunksz, &ctx); - } while (!feof (f)); - fclose (f); + FILE *f = fopen (argv[1], raw ? "r" FOPEN_BINARY : "r+" FOPEN_BINARY); + struct stat st; + if (!f || fstat (fileno (f), &st) != 0) + { + perror (argv[1]); + return EXIT_FAILURE; } + if (!S_ISREG (st.st_mode)) + { + fprintf (stderr, "%s: Error: %s is not a regular file\n", + argv[0], argv[1]); + return EXIT_FAILURE; + } + + ptrdiff_t maxlen = min (min (TYPE_MAXIMUM (off_t), PTRDIFF_MAX), + min (SIZE_MAX, SSIZE_MAX)); + if (maxlen <= st.st_size) + { + fprintf (stderr, "%s: %s: file too big\n", argv[0], argv[1]); + return EXIT_FAILURE; + } + + char *buf = malloc (st.st_size + 1); + if (!buf) + { + perror ("malloc"); + return EXIT_FAILURE; + } + + size_t chunksz = fread (buf, 1, st.st_size + 1, f); + if (ferror (f) || chunksz != st.st_size) + { + fprintf (stderr, "%s: Error: could not read %s\n", + argv[0], argv[1]); + return EXIT_FAILURE; + } + + sha256_process_bytes (buf, chunksz, &ctx); + unsigned char digest[32]; sha256_finish_ctx (&ctx, digest); @@ -99,12 +131,37 @@ main (int argc, char **argv) } else { - puts ("#include \"fingerprint.h\"\n" - "unsigned char const fingerprint[] =\n" - "{"); - for (int i = 0; i < 32; ++i) - printf ("\t0x%02X,\n", digest[i]); - puts ("};"); + char *finger = memmem (buf, chunksz, fingerprint, sizeof fingerprint); + if (!finger) + { + fprintf (stderr, "%s: %s: missing fingerprint\n", argv[0], argv[1]); + return EXIT_FAILURE; + } + else if (memmem (finger + 1, buf + chunksz - (finger + 1), + fingerprint, sizeof fingerprint)) + { + fprintf (stderr, "%s: %s: two occurrences of fingerprint\n", + argv[0], argv[1]); + return EXIT_FAILURE; + } + + if (fseeko (f, finger - buf, SEEK_SET) != 0) + { + perror (argv[1]); + return EXIT_FAILURE; + } + + if (fwrite (digest, 1, sizeof digest, f) != sizeof digest) + { + perror (argv[1]); + return EXIT_FAILURE; + } + } + + if (fclose (f) != 0) + { + perror (argv[1]); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/lib/Makefile.in b/lib/Makefile.in index f2d203564a..ac32c7070f 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -84,7 +84,7 @@ Makefile: ../config.status $(srcdir)/Makefile.in # and building it would just waste time. not_emacs_OBJECTS = regex.o -libgnu_a_OBJECTS = $(gl_LIBOBJS) \ +libgnu_a_OBJECTS = fingerprint.o $(gl_LIBOBJS) \ $(patsubst %.c,%.o,$(filter %.c,$(libgnu_a_SOURCES))) for_emacs_OBJECTS = $(filter-out $(not_emacs_OBJECTS),$(libgnu_a_OBJECTS)) libegnu_a_OBJECTS = $(patsubst %.o,e-%.o,$(for_emacs_OBJECTS)) diff --git a/lib/fingerprint.c b/lib/fingerprint.c new file mode 100644 index 0000000000..e55de9c6da --- /dev/null +++ b/lib/fingerprint.c @@ -0,0 +1,66 @@ +/* Placeholder fingerprint for Emacs + +Copyright 2019 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +#include + +#include "fingerprint.h" + +/* This random fingerprint was generated by the shell command: + + shuf -i 0-255 -n 32 -r | awk '{printf " 0x%.02X,\n", $0}' + + In the final Emacs executable, this random fingerprint is replaced + by a fingerprint of the temporary Emacs executable that was built + along the way. */ + +unsigned char const fingerprint[] = + { + 0xDE, + 0x86, + 0xBB, + 0x99, + 0xFF, + 0xF5, + 0x46, + 0x9A, + 0x9E, + 0x3F, + 0x9F, + 0x5D, + 0x9A, + 0xDF, + 0xF0, + 0x91, + 0xBD, + 0xCD, + 0xC1, + 0xE8, + 0x0C, + 0x16, + 0x1E, + 0xAF, + 0xB8, + 0x6C, + 0xE2, + 0x2B, + 0xB1, + 0x24, + 0xCE, + 0xB0, + }; diff --git a/src/fingerprint.h b/lib/fingerprint.h similarity index 100% rename from src/fingerprint.h rename to lib/fingerprint.h diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 1450df9f63..03160340c8 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -44,6 +44,7 @@ # --avoid=malloc-posix \ # --avoid=mbrtowc \ # --avoid=mbsinit \ +# --avoid=memchr \ # --avoid=mkdir \ # --avoid=msvc-inval \ # --avoid=msvc-nothrow \ @@ -111,6 +112,7 @@ # largefile \ # lstat \ # manywarnings \ +# memmem-simple \ # memrchr \ # minmax \ # mkostemp \ @@ -1053,7 +1055,6 @@ gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7 = @gl_GNULIB_ENABLED_03e0aaad gl_GNULIB_ENABLED_2049e887c7e5308faad27b3f894bb8c9 = @gl_GNULIB_ENABLED_2049e887c7e5308faad27b3f894bb8c9@ gl_GNULIB_ENABLED_21ee726a3540c09237a8e70c0baf7467 = @gl_GNULIB_ENABLED_21ee726a3540c09237a8e70c0baf7467@ gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b = @gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b@ -gl_GNULIB_ENABLED_37f71b604aa9c54446783d80f42fe547 = @gl_GNULIB_ENABLED_37f71b604aa9c54446783d80f42fe547@ gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31 = @gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31@ gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c = @gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c@ gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec = @gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec@ @@ -1963,6 +1964,17 @@ EXTRA_libgnu_a_SOURCES += lstat.c endif ## end gnulib module lstat +## begin gnulib module memmem-simple +ifeq (,$(OMIT_GNULIB_MODULE_memmem-simple)) + + +EXTRA_DIST += memmem.c str-two-way.h + +EXTRA_libgnu_a_SOURCES += memmem.c + +endif +## end gnulib module memmem-simple + ## begin gnulib module memrchr ifeq (,$(OMIT_GNULIB_MODULE_memrchr)) diff --git a/lib/memmem.c b/lib/memmem.c new file mode 100644 index 0000000000..12ae24f41b --- /dev/null +++ b/lib/memmem.c @@ -0,0 +1,71 @@ +/* Copyright (C) 1991-1994, 1996-1998, 2000, 2004, 2007-2019 Free Software + Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . */ + +/* This particular implementation was written by Eric Blake, 2008. */ + +#ifndef _LIBC +# include +#endif + +/* Specification of memmem. */ +#include + +#define RETURN_TYPE void * +#define AVAILABLE(h, h_l, j, n_l) ((j) <= (h_l) - (n_l)) +#include "str-two-way.h" + +/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK + if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in + HAYSTACK. */ +void * +memmem (const void *haystack_start, size_t haystack_len, + const void *needle_start, size_t needle_len) +{ + /* Abstract memory is considered to be an array of 'unsigned char' values, + not an array of 'char' values. See ISO C 99 section 6.2.6.1. */ + const unsigned char *haystack = (const unsigned char *) haystack_start; + const unsigned char *needle = (const unsigned char *) needle_start; + + if (needle_len == 0) + /* The first occurrence of the empty string is deemed to occur at + the beginning of the string. */ + return (void *) haystack; + + /* Sanity check, otherwise the loop might search through the whole + memory. */ + if (__builtin_expect (haystack_len < needle_len, 0)) + return NULL; + + /* Use optimizations in memchr when possible, to reduce the search + size of haystack using a linear algorithm with a smaller + coefficient. However, avoid memchr for long needles, since we + can often achieve sublinear performance. */ + if (needle_len < LONG_NEEDLE_THRESHOLD) + { + haystack = memchr (haystack, *needle, haystack_len); + if (!haystack || __builtin_expect (needle_len == 1, 0)) + return (void *) haystack; + haystack_len -= haystack - (const unsigned char *) haystack_start; + if (haystack_len < needle_len) + return NULL; + return two_way_short_needle (haystack, haystack_len, needle, needle_len); + } + else + return two_way_long_needle (haystack, haystack_len, needle, needle_len); +} + +#undef LONG_NEEDLE_THRESHOLD diff --git a/lib/str-two-way.h b/lib/str-two-way.h new file mode 100644 index 0000000000..9155e6b560 --- /dev/null +++ b/lib/str-two-way.h @@ -0,0 +1,452 @@ +/* Byte-wise substring search, using the Two-Way algorithm. + Copyright (C) 2008-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Eric Blake , 2008. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . */ + +/* Before including this file, you need to include and + , and define: + RESULT_TYPE A macro that expands to the return type. + AVAILABLE(h, h_l, j, n_l) + A macro that returns nonzero if there are + at least N_L bytes left starting at H[J]. + H is 'unsigned char *', H_L, J, and N_L + are 'size_t'; H_L is an lvalue. For + NUL-terminated searches, H_L can be + modified each iteration to avoid having + to compute the end of H up front. + + For case-insensitivity, you may optionally define: + CMP_FUNC(p1, p2, l) A macro that returns 0 iff the first L + characters of P1 and P2 are equal. + CANON_ELEMENT(c) A macro that canonicalizes an element right after + it has been fetched from one of the two strings. + The argument is an 'unsigned char'; the result + must be an 'unsigned char' as well. + + This file undefines the macros documented above, and defines + LONG_NEEDLE_THRESHOLD. +*/ + +#include +#include + +/* We use the Two-Way string matching algorithm (also known as + Chrochemore-Perrin), which guarantees linear complexity with + constant space. Additionally, for long needles, we also use a bad + character shift table similar to the Boyer-Moore algorithm to + achieve improved (potentially sub-linear) performance. + + See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260, + https://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm, + https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.34.6641&rep=rep1&type=pdf +*/ + +/* Point at which computing a bad-byte shift table is likely to be + worthwhile. Small needles should not compute a table, since it + adds (1 << CHAR_BIT) + NEEDLE_LEN computations of preparation for a + speedup no greater than a factor of NEEDLE_LEN. The larger the + needle, the better the potential performance gain. On the other + hand, on non-POSIX systems with CHAR_BIT larger than eight, the + memory required for the table is prohibitive. */ +#if CHAR_BIT < 10 +# define LONG_NEEDLE_THRESHOLD 32U +#else +# define LONG_NEEDLE_THRESHOLD SIZE_MAX +#endif + +#ifndef MAX +# define MAX(a, b) ((a < b) ? (b) : (a)) +#endif + +#ifndef CANON_ELEMENT +# define CANON_ELEMENT(c) c +#endif +#ifndef CMP_FUNC +# define CMP_FUNC memcmp +#endif + +/* Perform a critical factorization of NEEDLE, of length NEEDLE_LEN. + Return the index of the first byte in the right half, and set + *PERIOD to the global period of the right half. + + The global period of a string is the smallest index (possibly its + length) at which all remaining bytes in the string are repetitions + of the prefix (the last repetition may be a subset of the prefix). + + When NEEDLE is factored into two halves, a local period is the + length of the smallest word that shares a suffix with the left half + and shares a prefix with the right half. All factorizations of a + non-empty NEEDLE have a local period of at least 1 and no greater + than NEEDLE_LEN. + + A critical factorization has the property that the local period + equals the global period. All strings have at least one critical + factorization with the left half smaller than the global period. + And while some strings have more than one critical factorization, + it is provable that with an ordered alphabet, at least one of the + critical factorizations corresponds to a maximal suffix. + + Given an ordered alphabet, a critical factorization can be computed + in linear time, with 2 * NEEDLE_LEN comparisons, by computing the + shorter of two ordered maximal suffixes. The ordered maximal + suffixes are determined by lexicographic comparison while tracking + periodicity. */ +static size_t +critical_factorization (const unsigned char *needle, size_t needle_len, + size_t *period) +{ + /* Index of last byte of left half, or SIZE_MAX. */ + size_t max_suffix, max_suffix_rev; + size_t j; /* Index into NEEDLE for current candidate suffix. */ + size_t k; /* Offset into current period. */ + size_t p; /* Intermediate period. */ + unsigned char a, b; /* Current comparison bytes. */ + + /* Special case NEEDLE_LEN of 1 or 2 (all callers already filtered + out 0-length needles. */ + if (needle_len < 3) + { + *period = 1; + return needle_len - 1; + } + + /* Invariants: + 0 <= j < NEEDLE_LEN - 1 + -1 <= max_suffix{,_rev} < j (treating SIZE_MAX as if it were signed) + min(max_suffix, max_suffix_rev) < global period of NEEDLE + 1 <= p <= global period of NEEDLE + p == global period of the substring NEEDLE[max_suffix{,_rev}+1...j] + 1 <= k <= p + */ + + /* Perform lexicographic search. */ + max_suffix = SIZE_MAX; + j = 0; + k = p = 1; + while (j + k < needle_len) + { + a = CANON_ELEMENT (needle[j + k]); + b = CANON_ELEMENT (needle[max_suffix + k]); + if (a < b) + { + /* Suffix is smaller, period is entire prefix so far. */ + j += k; + k = 1; + p = j - max_suffix; + } + else if (a == b) + { + /* Advance through repetition of the current period. */ + if (k != p) + ++k; + else + { + j += p; + k = 1; + } + } + else /* b < a */ + { + /* Suffix is larger, start over from current location. */ + max_suffix = j++; + k = p = 1; + } + } + *period = p; + + /* Perform reverse lexicographic search. */ + max_suffix_rev = SIZE_MAX; + j = 0; + k = p = 1; + while (j + k < needle_len) + { + a = CANON_ELEMENT (needle[j + k]); + b = CANON_ELEMENT (needle[max_suffix_rev + k]); + if (b < a) + { + /* Suffix is smaller, period is entire prefix so far. */ + j += k; + k = 1; + p = j - max_suffix_rev; + } + else if (a == b) + { + /* Advance through repetition of the current period. */ + if (k != p) + ++k; + else + { + j += p; + k = 1; + } + } + else /* a < b */ + { + /* Suffix is larger, start over from current location. */ + max_suffix_rev = j++; + k = p = 1; + } + } + + /* Choose the shorter suffix. Return the index of the first byte of + the right half, rather than the last byte of the left half. + + For some examples, 'banana' has two critical factorizations, both + exposed by the two lexicographic extreme suffixes of 'anana' and + 'nana', where both suffixes have a period of 2. On the other + hand, with 'aab' and 'bba', both strings have a single critical + factorization of the last byte, with the suffix having a period + of 1. While the maximal lexicographic suffix of 'aab' is 'b', + the maximal lexicographic suffix of 'bba' is 'ba', which is not a + critical factorization. Conversely, the maximal reverse + lexicographic suffix of 'a' works for 'bba', but not 'ab' for + 'aab'. The shorter suffix of the two will always be a critical + factorization. */ + if (max_suffix_rev + 1 < max_suffix + 1) + return max_suffix + 1; + *period = p; + return max_suffix_rev + 1; +} + +/* Return the first location of non-empty NEEDLE within HAYSTACK, or + NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This + method is optimized for NEEDLE_LEN < LONG_NEEDLE_THRESHOLD. + Performance is guaranteed to be linear, with an initialization cost + of 2 * NEEDLE_LEN comparisons. + + If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */ +static RETURN_TYPE +two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) +{ + size_t i; /* Index into current byte of NEEDLE. */ + size_t j; /* Index into current window of HAYSTACK. */ + size_t period; /* The period of the right half of needle. */ + size_t suffix; /* The index of the right half of needle. */ + + /* Factor the needle into two halves, such that the left half is + smaller than the global period, and the right half is + periodic (with a period as large as NEEDLE_LEN - suffix). */ + suffix = critical_factorization (needle, needle_len, &period); + + /* Perform the search. Each iteration compares the right half + first. */ + if (CMP_FUNC (needle, needle + period, suffix) == 0) + { + /* Entire needle is periodic; a mismatch in the left half can + only advance by the period, so use memory to avoid rescanning + known occurrences of the period in the right half. */ + size_t memory = 0; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Scan for matches in right half. */ + i = MAX (suffix, memory); + while (i < needle_len && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (memory < i + 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i + 1 < memory + 1) + return (RETURN_TYPE) (haystack + j); + /* No match, so remember how many repetitions of period + on the right half were scanned. */ + j += period; + memory = needle_len - period; + } + else + { + j += i - suffix + 1; + memory = 0; + } + } + } + else + { + /* The two halves of needle are distinct; no extra memory is + required, and any mismatch results in a maximal shift. */ + period = MAX (suffix, needle_len - suffix) + 1; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Scan for matches in right half. */ + i = suffix; + while (i < needle_len && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (i != SIZE_MAX && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i == SIZE_MAX) + return (RETURN_TYPE) (haystack + j); + j += period; + } + else + j += i - suffix + 1; + } + } + return NULL; +} + +/* Return the first location of non-empty NEEDLE within HAYSTACK, or + NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This + method is optimized for LONG_NEEDLE_THRESHOLD <= NEEDLE_LEN. + Performance is guaranteed to be linear, with an initialization cost + of 3 * NEEDLE_LEN + (1 << CHAR_BIT) operations. + + If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, + and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and + sublinear performance is not possible. */ +static RETURN_TYPE +two_way_long_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) +{ + size_t i; /* Index into current byte of NEEDLE. */ + size_t j; /* Index into current window of HAYSTACK. */ + size_t period; /* The period of the right half of needle. */ + size_t suffix; /* The index of the right half of needle. */ + size_t shift_table[1U << CHAR_BIT]; /* See below. */ + + /* Factor the needle into two halves, such that the left half is + smaller than the global period, and the right half is + periodic (with a period as large as NEEDLE_LEN - suffix). */ + suffix = critical_factorization (needle, needle_len, &period); + + /* Populate shift_table. For each possible byte value c, + shift_table[c] is the distance from the last occurrence of c to + the end of NEEDLE, or NEEDLE_LEN if c is absent from the NEEDLE. + shift_table[NEEDLE[NEEDLE_LEN - 1]] contains the only 0. */ + for (i = 0; i < 1U << CHAR_BIT; i++) + shift_table[i] = needle_len; + for (i = 0; i < needle_len; i++) + shift_table[CANON_ELEMENT (needle[i])] = needle_len - i - 1; + + /* Perform the search. Each iteration compares the right half + first. */ + if (CMP_FUNC (needle, needle + period, suffix) == 0) + { + /* Entire needle is periodic; a mismatch in the left half can + only advance by the period, so use memory to avoid rescanning + known occurrences of the period in the right half. */ + size_t memory = 0; + size_t shift; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Check the last byte first; if it does not match, then + shift to the next possible match location. */ + shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; + if (0 < shift) + { + if (memory && shift < period) + { + /* Since needle is periodic, but the last period has + a byte out of place, there can be no match until + after the mismatch. */ + shift = needle_len - period; + } + memory = 0; + j += shift; + continue; + } + /* Scan for matches in right half. The last byte has + already been matched, by virtue of the shift table. */ + i = MAX (suffix, memory); + while (i < needle_len - 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len - 1 <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (memory < i + 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i + 1 < memory + 1) + return (RETURN_TYPE) (haystack + j); + /* No match, so remember how many repetitions of period + on the right half were scanned. */ + j += period; + memory = needle_len - period; + } + else + { + j += i - suffix + 1; + memory = 0; + } + } + } + else + { + /* The two halves of needle are distinct; no extra memory is + required, and any mismatch results in a maximal shift. */ + size_t shift; + period = MAX (suffix, needle_len - suffix) + 1; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Check the last byte first; if it does not match, then + shift to the next possible match location. */ + shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; + if (0 < shift) + { + j += shift; + continue; + } + /* Scan for matches in right half. The last byte has + already been matched, by virtue of the shift table. */ + i = suffix; + while (i < needle_len - 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len - 1 <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (i != SIZE_MAX && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i == SIZE_MAX) + return (RETURN_TYPE) (haystack + j); + j += period; + } + else + j += i - suffix + 1; + } + } + return NULL; +} + +#undef AVAILABLE +#undef CANON_ELEMENT +#undef CMP_FUNC +#undef MAX +#undef RETURN_TYPE diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index f25a0e4081..f648b7a495 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -113,6 +113,7 @@ AC_DEFUN([gl_EARLY], # Code from module localtime-buffer: # Code from module lstat: # Code from module manywarnings: + # Code from module memmem-simple: # Code from module memrchr: # Code from module minmax: # Code from module mkostemp: @@ -195,6 +196,7 @@ AC_DEFUN([gl_INIT], gl_source_base='lib' gl_FUNC_ACL gl_FUNC_ALLOCA + gl___BUILTIN_EXPECT gl_BYTESWAP AC_CHECK_FUNCS_ONCE([readlinkat]) gl_CLOCK_TIME @@ -302,6 +304,11 @@ AC_DEFUN([gl_INIT], gl_PREREQ_LSTAT fi gl_SYS_STAT_MODULE_INDICATOR([lstat]) + gl_FUNC_MEMMEM_SIMPLE + if test $HAVE_MEMMEM = 0 || test $REPLACE_MEMMEM = 1; then + AC_LIBOBJ([memmem]) + fi + gl_STRING_MODULE_INDICATOR([memmem]) gl_FUNC_MEMRCHR if test $ac_cv_func_memrchr = no; then AC_LIBOBJ([memrchr]) @@ -426,7 +433,6 @@ AC_DEFUN([gl_INIT], gl_UTIMENS AC_C_VARARRAYS gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=false - gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547=false gl_gnulib_enabled_cloexec=false gl_gnulib_enabled_dirfd=false gl_gnulib_enabled_euidaccess=false @@ -450,13 +456,6 @@ AC_DEFUN([gl_INIT], func_gl_gnulib_m4code_open fi } - func_gl_gnulib_m4code_37f71b604aa9c54446783d80f42fe547 () - { - if ! $gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547; then - gl___BUILTIN_EXPECT - gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547=true - fi - } func_gl_gnulib_m4code_cloexec () { if ! $gl_gnulib_enabled_cloexec; then @@ -652,9 +651,6 @@ AC_DEFUN([gl_INIT], if test $HAVE_READLINKAT = 0; then func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 fi - if test $ac_use_included_regex = yes; then - func_gl_gnulib_m4code_37f71b604aa9c54446783d80f42fe547 - fi if test $ac_use_included_regex = yes; then func_gl_gnulib_m4code_21ee726a3540c09237a8e70c0baf7467 fi @@ -666,7 +662,6 @@ AC_DEFUN([gl_INIT], fi m4_pattern_allow([^gl_GNULIB_ENABLED_]) AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], [$gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b]) - AM_CONDITIONAL([gl_GNULIB_ENABLED_37f71b604aa9c54446783d80f42fe547], [$gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547]) AM_CONDITIONAL([gl_GNULIB_ENABLED_cloexec], [$gl_gnulib_enabled_cloexec]) AM_CONDITIONAL([gl_GNULIB_ENABLED_dirfd], [$gl_gnulib_enabled_dirfd]) AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess]) @@ -916,6 +911,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/lstat.c lib/md5.c lib/md5.h + lib/memmem.c lib/memrchr.c lib/minmax.h lib/mkostemp.c @@ -959,6 +955,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/stdio.in.h lib/stdlib.in.h lib/stpcpy.c + lib/str-two-way.h lib/strftime.h lib/string.in.h lib/strtoimax.c @@ -1049,6 +1046,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/manywarnings.m4 m4/mbstate_t.m4 m4/md5.m4 + m4/memmem.m4 m4/memrchr.m4 m4/minmax.m4 m4/mkostemp.m4 diff --git a/m4/memmem.m4 b/m4/memmem.m4 new file mode 100644 index 0000000000..af2d5bbcf5 --- /dev/null +++ b/m4/memmem.m4 @@ -0,0 +1,154 @@ +# memmem.m4 serial 25 +dnl Copyright (C) 2002-2004, 2007-2019 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Check that memmem is present and functional. +AC_DEFUN([gl_FUNC_MEMMEM_SIMPLE], +[ + dnl Persuade glibc to declare memmem(). + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS]) + AC_CHECK_FUNCS([memmem]) + if test $ac_cv_func_memmem = yes; then + HAVE_MEMMEM=1 + else + HAVE_MEMMEM=0 + fi + AC_CHECK_DECLS_ONCE([memmem]) + if test $ac_cv_have_decl_memmem = no; then + HAVE_DECL_MEMMEM=0 + else + dnl Detect https://sourceware.org/bugzilla/show_bug.cgi?id=12092. + dnl Also check that we handle empty needles correctly. + AC_CACHE_CHECK([whether memmem works], + [gl_cv_func_memmem_works_always], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include /* for memmem */ +#define P "_EF_BF_BD" +#define HAYSTACK "F_BD_CE_BD" P P P P "_C3_88_20" P P P "_C3_A7_20" P +#define NEEDLE P P P P P +]], [[ + int result = 0; + if (memmem (HAYSTACK, strlen (HAYSTACK), NEEDLE, strlen (NEEDLE))) + result |= 1; + /* Check for empty needle behavior. */ + { + const char *haystack = "AAA"; + if (memmem (haystack, 3, NULL, 0) != haystack) + result |= 2; + } + return result; + ]])], + [gl_cv_func_memmem_works_always=yes], + [gl_cv_func_memmem_works_always=no], + [dnl glibc 2.9..2.12 and cygwin 1.7.7 have issue #12092 above. + dnl Also empty needles work on glibc >= 2.1 and cygwin >= 1.7.0. + dnl uClibc is not affected, since it uses different source code. + dnl Assume that it works on all other platforms (even if not linear). + AC_EGREP_CPP([Lucky user], + [ +#ifdef __GNU_LIBRARY__ + #include + #if ((__GLIBC__ == 2 && ((__GLIBC_MINOR > 0 && __GLIBC_MINOR__ < 9) \ + || __GLIBC_MINOR__ > 12)) \ + || (__GLIBC__ > 2)) \ + || defined __UCLIBC__ + Lucky user + #endif +#elif defined __CYGWIN__ + #include + #if CYGWIN_VERSION_DLL_COMBINED > CYGWIN_VERSION_DLL_MAKE_COMBINED (1007, 7) + Lucky user + #endif +#else + Lucky user +#endif + ], + [gl_cv_func_memmem_works_always="guessing yes"], + [gl_cv_func_memmem_works_always="guessing no"]) + ]) + ]) + case "$gl_cv_func_memmem_works_always" in + *yes) ;; + *) + REPLACE_MEMMEM=1 + ;; + esac + fi + gl_PREREQ_MEMMEM +]) # gl_FUNC_MEMMEM_SIMPLE + +dnl Additionally, check that memmem has linear performance characteristics +AC_DEFUN([gl_FUNC_MEMMEM], +[ + AC_REQUIRE([gl_FUNC_MEMMEM_SIMPLE]) + if test $HAVE_DECL_MEMMEM = 1 && test $REPLACE_MEMMEM = 0; then + AC_CACHE_CHECK([whether memmem works in linear time], + [gl_cv_func_memmem_works_fast], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include /* for signal */ +#include /* for memmem */ +#include /* for malloc */ +#include /* for alarm */ +static void quit (int sig) { _exit (sig + 128); } +]], [[ + int result = 0; + size_t m = 1000000; + char *haystack = (char *) malloc (2 * m + 1); + char *needle = (char *) malloc (m + 1); + /* Failure to compile this test due to missing alarm is okay, + since all such platforms (mingw) also lack memmem. */ + signal (SIGALRM, quit); + alarm (5); + /* Check for quadratic performance. */ + if (haystack && needle) + { + memset (haystack, 'A', 2 * m); + haystack[2 * m] = 'B'; + memset (needle, 'A', m); + needle[m] = 'B'; + if (!memmem (haystack, 2 * m + 1, needle, m + 1)) + result |= 1; + } + /* Free allocated memory, in case some sanitizer is watching. */ + free (haystack); + free (needle); + return result; + ]])], + [gl_cv_func_memmem_works_fast=yes], [gl_cv_func_memmem_works_fast=no], + [dnl Only glibc >= 2.9 and cygwin > 1.7.0 are known to have a + dnl memmem that works in linear time. + AC_EGREP_CPP([Lucky user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 9) || (__GLIBC__ > 2)) \ + && !defined __UCLIBC__ + Lucky user + #endif +#endif +#ifdef __CYGWIN__ + #include + #if CYGWIN_VERSION_DLL_COMBINED > CYGWIN_VERSION_DLL_MAKE_COMBINED (1007, 0) + Lucky user + #endif +#endif + ], + [gl_cv_func_memmem_works_fast="guessing yes"], + [gl_cv_func_memmem_works_fast="guessing no"]) + ]) + ]) + case "$gl_cv_func_memmem_works_fast" in + *yes) ;; + *) + REPLACE_MEMMEM=1 + ;; + esac + fi +]) # gl_FUNC_MEMMEM + +# Prerequisites of lib/memmem.c. +AC_DEFUN([gl_PREREQ_MEMMEM], [:]) diff --git a/src/Makefile.in b/src/Makefile.in index 2348c8dae4..3aab5270a4 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -332,6 +332,7 @@ UNEXEC_OBJ = @UNEXEC_OBJ@ DUMPING=@DUMPING@ CHECK_STRUCTS = @CHECK_STRUCTS@ +HAVE_PDUMPER = @HAVE_PDUMPER@ # 'make' verbosity. AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ @@ -627,19 +628,25 @@ LIBEGNU_ARCHIVE = $(lib)/lib$(if $(HYBRID_MALLOC),e)gnu.a $(LIBEGNU_ARCHIVE): $(config_h) $(MAKE) -C $(dir $@) all -FINGERPRINTED = $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) -fingerprint.c: $(FINGERPRINTED) $(libsrc)/make-fingerprint$(EXEEXT) - $(AM_V_GEN)$(libsrc)/make-fingerprint$(EXEEXT) $(FINGERPRINTED) >$@.tmp - $(AM_V_at)mv $@.tmp $@ +ifeq ($(HAVE_PDUMPER),yes) + MAKE_PDUMPER_FINGERPRINT = $(libsrc)/make-fingerprint$(EXEEXT) +else + MAKE_PDUMPER_FINGERPRINT = +endif ## We have to create $(etc) here because init_cmdargs tests its ## existence when setting Vinstallation_directory (FIXME?). ## This goes on to affect various things, and the emacs binary fails ## to start if Vinstallation_directory has the wrong value. -temacs$(EXEEXT): fingerprint.o $(charsets) $(charscript) - $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ - $(ALLOBJS) fingerprint.o \ - $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) +temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ + $(charsets) $(charscript) $(MAKE_PDUMPER_FINGERPRINT) + $(AM_V_CCLD)$(CC) -o $@.tmp \ + $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ + $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) +ifeq ($(HAVE_PDUMPER),yes) + $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@.tmp +endif + $(AM_V_at)mv $@.tmp $@ $(MKDIR_P) $(etc) ifeq ($(DUMPING),unexec) ifneq ($(PAXCTL_notdumped),) @@ -676,7 +683,7 @@ ns-app: emacs$(EXEEXT) $(pdmp) mostlyclean: rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o - rm -f dmpstruct.h fingerprint.c + rm -f dmpstruct.h rm -f emacs.pdmp rm -f ../etc/DOC rm -f bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) @@ -716,10 +723,9 @@ ETAGS = ../lib-src/etags${EXEEXT} ${ETAGS}: FORCE $(MAKE) -C $(dir $@) $(notdir $@) -# Remove macuvs.h and fingerprint.c since they'd cause `src/emacs` +# Remove macuvs.h since it'd cause `src/emacs` # to be built before we can get TAGS. -ctagsfiles1 = $(filter-out ${srcdir}/macuvs.h ${srcdir}/fingerprint.c, \ - $(wildcard ${srcdir}/*.[hc])) +ctagsfiles1 = $(filter-out ${srcdir}/macuvs.h, $(wildcard ${srcdir}/*.[hc])) ctagsfiles2 = $(wildcard ${srcdir}/*.m) ## In out-of-tree builds, TAGS are generated in the build dir, like commit 661f44946d2bba21d16d718cf86372345c929a39 Author: Paul Eggert Date: Sun Apr 14 16:23:54 2019 -0700 * m4/utimbuf.m4: Remove unused file. diff --git a/m4/utimbuf.m4 b/m4/utimbuf.m4 deleted file mode 100644 index a950aa9f0e..0000000000 --- a/m4/utimbuf.m4 +++ /dev/null @@ -1,39 +0,0 @@ -# serial 9 - -# Copyright (C) 1998-2001, 2003-2004, 2007, 2009-2019 Free Software -# Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -dnl From Jim Meyering - -dnl Define HAVE_STRUCT_UTIMBUF if 'struct utimbuf' is declared -- -dnl usually in . -dnl Some systems have utime.h but don't declare the struct anywhere. - -AC_DEFUN([gl_CHECK_TYPE_STRUCT_UTIMBUF], -[ - AC_CHECK_HEADERS_ONCE([sys/time.h utime.h]) - AC_CACHE_CHECK([for struct utimbuf], [gl_cv_sys_struct_utimbuf], - [AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[#if HAVE_SYS_TIME_H - #include - #endif - #include - #ifdef HAVE_UTIME_H - #include - #endif - ]], - [[static struct utimbuf x; x.actime = x.modtime;]])], - [gl_cv_sys_struct_utimbuf=yes], - [gl_cv_sys_struct_utimbuf=no])]) - - if test $gl_cv_sys_struct_utimbuf = yes; then - AC_DEFINE([HAVE_STRUCT_UTIMBUF], [1], - [Define if struct utimbuf is declared -- usually in . - Some systems have utime.h but don't declare the struct anywhere. ]) - fi -]) commit ae78bda5b88a912a1d2a4b62691dce3efa967047 Author: Dmitry Gutov Date: Mon Apr 15 00:39:29 2019 +0300 Sort files in the default impl of project-files alphabetically * lisp/progmodes/project.el (project--files-in-directory): Sort the files alphabetically (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=23179#296). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index dabc4ab6b4..b8a58ed317 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -209,7 +209,8 @@ to find the list of ignores for each directory." (shell-quote-argument ")"))"") ))) (project--remote-file-names - (split-string (shell-command-to-string command) "\0" t)))) + (sort (split-string (shell-command-to-string command) "\0" t) + #'string<)))) (defun project--remote-file-names (local-files) "Return LOCAL-FILES as if they were on the system of `default-directory'." commit 05d53d88865d0287412c0f52a421cbf96a4d425d Author: Michael Albinus Date: Sun Apr 14 19:53:38 2019 +0200 Some rearragements for remote tests in filenotify-tests.el * test/lisp/filenotify-tests.el (file-notify--deftest-remote): Change argument list, EXPECTED is not needed. (file-notify-test07-many-events-remote) (file-notify-test09-watched-file-in-watched-dir-remote): Adapt declaration accordingly. diff --git a/test/lisp/filenotify-tests.el b/test/lisp/filenotify-tests.el index 842d66d778..a40dc72078 100644 --- a/test/lisp/filenotify-tests.el +++ b/test/lisp/filenotify-tests.el @@ -261,13 +261,13 @@ This returns only for the local case and gfilenotify; otherwise it is nil. (gfile-monitor-name file-notify--test-desc))) (cdr (assq file-notify--test-desc file-notify--test-monitors)))))) -(defmacro file-notify--deftest-remote (test docstring &optional expected skip) - "Define ert `TEST-remote' for remote files." +(defmacro file-notify--deftest-remote (test docstring &optional unstable) + "Define ert `TEST-remote' for remote files. +If UNSTABLE is non-nil, the test is tagged as `:unstable'." (declare (indent 1)) `(ert-deftest ,(intern (concat (symbol-name test) "-remote")) () ,docstring - :expected-result (or ,expected :passed) - :tags ,(if skip ''(:expensive-test :unstable) ''(:expensive-test)) + :tags (if ,unstable '(:expensive-test :unstable) '(:expensive-test)) (let* ((temporary-file-directory file-notify-test-remote-temporary-file-directory) (ert-test (ert-get-test ',test)) @@ -1203,8 +1203,8 @@ delivered." ;; Unpredictable failures, eg https://hydra.nixos.org/build/86016286 (file-notify--deftest-remote file-notify-test07-many-events - "Check that events are not dropped for remote directories." - :passed (getenv "EMACS_HYDRA_CI")) + "Check that events are not dropped for remote directories." + (getenv "EMACS_HYDRA_CI")) (ert-deftest file-notify-test08-backup () "Check that backup keeps file notification." @@ -1421,8 +1421,8 @@ the file watch." ;; Cleanup. (file-notify--test-cleanup))) -;(file-notify--deftest-remote file-notify-test09-watched-file-in-watched-dir -; "Check `file-notify-test09-watched-file-in-watched-dir' for remote files.") +(file-notify--deftest-remote file-notify-test09-watched-file-in-watched-dir + "Check `file-notify-test09-watched-file-in-watched-dir' for remote files." t) (ert-deftest file-notify-test10-sufficient-resources () "Check that file notification does not use too many resources." commit 98a5958f77f56c3de529fe04d3f1c85c037f49e6 Author: Michael Albinus Date: Sun Apr 14 19:53:02 2019 +0200 Explain ad-hoc multi-hop in the Tramp Quick Start Guide * doc/misc/tramp.texi (Quick Start Guide): New section "Combining @option{ssh} or @option{plink} with @option{su} or @option{sudo}". diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 3dfd5224ec..b272c385d1 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -467,6 +467,27 @@ The method @option{sg} stands for ``switch group''; the changed group must be used here as user name. The default host name is the same. +@anchor{Quick Start Guide: @option{ssh}, @option{plink}, @option{su}, @option{sudo} and @option{sg} methods} +@section Combining @option{ssh} or @option{plink} with @option{su} or @option{sudo} +@cindex method @option{ssh} +@cindex @option{ssh} method +@cindex method @option{plink} +@cindex @option{plink} method +@cindex method @option{su} +@cindex @option{su} method +@cindex method @option{sudo} +@cindex @option{sudo} method + +If the @option{su} or @option{sudo} option shall be performed on +another host, it could be comnbined with a leading @option{ssh} or +@option{plink} option. That means, @value{tramp} connects first to +the other host with non-administrative credentials, and changes to +administrative credentials on that host afterwards. In a simple case, +the syntax looks like +@file{@value{prefix}ssh@value{postfixhop}user@@host|sudo@value{postfixhop}@value{postfix}/path/to/file}. +@xref{Ad-hoc multi-hops}. + + @anchor{Quick Start Guide: @option{sudoedit} method} @section Using @command{sudoedit} @cindex method @option{sudoedit} commit dcfe1c4aba3f54cdd0295e0e21db86143f7cb705 Author: Michael Albinus Date: Sun Apr 14 19:52:12 2019 +0200 Fix Bug#35055 * lisp/net/tramp.el (tramp-handle-shell-command): Handle `shell-command-width'. (Bug#35055) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 32963ac543..2e1a0960d7 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -3638,17 +3638,24 @@ support symbolic links." (erase-buffer))) (if (and (not current-buffer-p) (integerp asynchronous)) - (prog1 - ;; Run the process. - (setq p (start-file-process-shell-command - (buffer-name output-buffer) buffer command)) - ;; Display output. - (with-current-buffer output-buffer - (display-buffer output-buffer '(nil (allow-no-window . t))) - (setq mode-line-process '(":%s")) - (shell-mode) - (set-process-sentinel p #'shell-command-sentinel) - (set-process-filter p #'comint-output-filter))) + (let ((tramp-remote-process-environment + ;; `shell-command-width' has been introduced with Emacs 27.1. + (if (natnump (bound-and-true-p shell-command-width)) + (cons (format "COLUMNS=%d" + (bound-and-true-p shell-command-width)) + tramp-remote-process-environment) + tramp-remote-process-environment))) + (prog1 + ;; Run the process. + (setq p (start-file-process-shell-command + (buffer-name output-buffer) buffer command)) + ;; Display output. + (with-current-buffer output-buffer + (display-buffer output-buffer '(nil (allow-no-window . t))) + (setq mode-line-process '(":%s")) + (shell-mode) + (set-process-sentinel p #'shell-command-sentinel) + (set-process-filter p #'comint-output-filter)))) (prog1 ;; Run the process. commit e233dedde2e79b72ce158e087f29fb6d2ac8453a Author: Alexander Gramiak Date: Sun Apr 14 09:27:50 2019 -0600 * lisp/frame.el (frame--size-history): Fix infloop. (Bug#35272) diff --git a/lisp/frame.el b/lisp/frame.el index b5c936a51e..539a0f4dfc 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1610,14 +1610,16 @@ selected frame." (with-current-buffer (get-buffer-create "*frame-size-history*") (erase-buffer) (insert (format "Frame size history of %s\n" frame)) - (while (listp (setq entry (pop history))) + (while (consp (setq entry (pop history))) (when (eq (car entry) frame) (pop entry) (insert (format "%s" (pop entry))) (move-to-column 24 t) (while entry (insert (format " %s" (pop entry)))) - (insert "\n")))))) + (insert "\n"))) + (unless frame-size-history + (insert "Frame size history is nil.\n"))))) (declare-function x-frame-edges "xfns.c" (&optional frame type)) (declare-function w32-frame-edges "w32fns.c" (&optional frame type)) commit 5ee5895f9b7b829783bc0f217095748076cc77e9 Merge: ca449fb1c1 890440a44c Author: Stephen Leake Date: Sun Apr 14 09:24:42 2019 -0700 Merge commit '890440a44cd5f4f09742f521c7783785d114fffc' commit ca449fb1c1f86589cbf4da49cda1750ffdb2cad4 Author: Stephen Leake Date: Sun Apr 14 09:23:24 2019 -0700 Rename new user variable `next-error-verbosity' to `next-error-verbose' * etc/NEWS: Update entry to match renaming. * lisp/simple.el (next-error-verbose): Rename. (next-error, next-error-internal): Match rename. diff --git a/etc/NEWS b/etc/NEWS index 9e3d993cab..f41db027b2 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -309,7 +309,7 @@ and directory-local variables. longer. --- -** next-error-verbosity controls when `next-error' outputs a message +** next-error-verbose controls when `next-error' outputs a message about the error locus. diff --git a/lisp/simple.el b/lisp/simple.el index 37f92540dd..fb667350dc 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -110,9 +110,9 @@ If non-nil, the value is passed directly to `recenter'." :type 'hook :group 'next-error) -(defcustom next-error-verbosity nil - "If nil, `next-error' always outputs the current error buffer. -If non-nil, the message is output only when the error buffer +(defcustom next-error-verbose t + "If non-nil, `next-error' always outputs the current error buffer. +If nil, the message is output only when the error buffer changes." :group 'next-error :type 'boolean @@ -323,7 +323,7 @@ To control which errors are matched, customize the variable (funcall next-error-function (prefix-numeric-value arg) reset) (let ((prev next-error-last-buffer)) (next-error-found buffer (current-buffer)) - (when (or (not next-error-verbosity) + (when (or next-error-verbose (not (eq prev next-error-last-buffer))) (message "%s locus from %s" (cond (reset "First") @@ -339,7 +339,7 @@ To control which errors are matched, customize the variable (funcall next-error-function 0 nil) (let ((prev next-error-last-buffer)) (next-error-found buffer (current-buffer)) - (when (or (not next-error-verbosity) + (when (or next-error-verbose (not (eq prev next-error-last-buffer))) (message "Current locus from %s" next-error-last-buffer))))) commit 890440a44cd5f4f09742f521c7783785d114fffc Author: Alexander Gramiak Date: Sun Apr 14 08:41:48 2019 -0600 Simplify gdk_monitor_get_model string duplication * src/xfns.c (x-display-monitor-attributes-list): Use dupstring over explicit if/xstrdup. * src/frame.c (free_monitors): Remove redundant check for NULL. diff --git a/src/frame.c b/src/frame.c index 22a3996af7..192ef4244f 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5670,8 +5670,7 @@ free_monitors (struct MonitorInfo *monitors, int n_monitors) { int i; for (i = 0; i < n_monitors; ++i) - if (monitors[i].name) - xfree (monitors[i].name); + xfree (monitors[i].name); xfree (monitors); } # endif diff --git a/src/xfns.c b/src/xfns.c index dd1d8993f5..e521ed12e4 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -5030,8 +5030,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) mi->mm_height = height_mm; #if GTK_CHECK_VERSION (3, 22, 0) - if (gdk_monitor_get_model (monitor)) - mi->name = xstrdup (gdk_monitor_get_model (monitor)); + dupstring (&mi->name, (gdk_monitor_get_model (monitor))); #elif GTK_CHECK_VERSION (2, 14, 0) mi->name = gdk_screen_get_monitor_plug_name (gscreen, i); #endif commit 29b36a007ae04839a4c29c62b2b1ee7940a8539a Author: Eli Zaretskii Date: Sun Apr 14 17:50:12 2019 +0300 Improve documentation of a recent commit * etc/NEWS: Fix the description of 'shell-command-width'. Mark the entry as not needing the manual update. * lisp/simple.el (shell-command-width): Doc fix. (Bug#35055) diff --git a/etc/NEWS b/etc/NEWS index d34fb3bb12..2421b78152 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1066,8 +1066,9 @@ variable for remote shells. It still defaults to "/bin/sh". ** Single shell commands -*** 'shell-command-width' defines the number of output columns -for asynchronous shell command. +--- +*** 'shell-command-width' defines the number of display columns +available for output of asynchronous shell commands. ** Pcomplete diff --git a/lisp/simple.el b/lisp/simple.el index 017ba51000..8647d0985f 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -3352,9 +3352,10 @@ is output." :version "26.1") (defcustom shell-command-width nil - "Number of columns available for asynchronous shell command output. + "Number of display columns available for asynchronous shell command output. If nil, use the shell default number (usually 80 columns). -If a positive integer, use a fixed width for command output." +If a positive integer, tell the shell to use that number of columns for +command output." :type '(choice (const :tag "Use system limit" nil) (integer :tag "Fixed width" :value 80)) :group 'shell