commit da0165a01e01dcb4334feee03b462ac09ceb0f8c (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Mon Jul 22 09:56:08 2024 +0800 Prohibit unbinding of built-in variables * src/data.c (set_internal): Signal error if a BLV with a redirect or a forwarded symbol is being unbound. * test/src/data-tests.el (binding-test-makunbound-built-in): New test. diff --git a/src/data.c b/src/data.c index 3490d4985c9..752856abf09 100644 --- a/src/data.c +++ b/src/data.c @@ -1642,7 +1642,7 @@ void set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, enum Set_Internal_Bind bindflag) { - bool voide = BASE_EQ (newval, Qunbound); + bool unbinding_p = BASE_EQ (newval, Qunbound); /* If restoring in a dead buffer, do nothing. */ @@ -1661,10 +1661,13 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, case SYMBOL_TRAPPED_WRITE: /* Setting due to thread-switching doesn't count. */ if (bindflag != SET_INTERNAL_THREAD_SWITCH) - notify_variable_watchers (symbol, voide? Qnil : newval, - (bindflag == SET_INTERNAL_BIND? Qlet : - bindflag == SET_INTERNAL_UNBIND? Qunlet : - voide? Qmakunbound : Qset), + notify_variable_watchers (symbol, (unbinding_p ? Qnil : newval), + (bindflag == SET_INTERNAL_BIND + ? Qlet + : (bindflag == SET_INTERNAL_UNBIND + ? Qunlet + : (unbinding_p + ? Qmakunbound : Qset))), where); break; @@ -1682,6 +1685,11 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, case SYMBOL_LOCALIZED: { struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym); + + if (unbinding_p && blv->fwd.fwdptr) + /* Forbid unbinding built-in variables. */ + error ("Built-in variables may not be unbound"); + if (NILP (where)) XSETBUFFER (where, current_buffer); @@ -1746,16 +1754,9 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, set_blv_value (blv, newval); if (blv->fwd.fwdptr) - { - if (voide) - /* If storing void (making the symbol void), forward only through - buffer-local indicator, not through Lisp_Objfwd, etc. */ - blv->fwd.fwdptr = NULL; - else - store_symval_forwarding (blv->fwd, newval, - BUFFERP (where) - ? XBUFFER (where) : current_buffer); - } + store_symval_forwarding (blv->fwd, newval, (BUFFERP (where) + ? XBUFFER (where) + : current_buffer)); break; } case SYMBOL_FORWARDED: @@ -1763,6 +1764,11 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, struct buffer *buf = BUFFERP (where) ? XBUFFER (where) : current_buffer; lispfwd innercontents = SYMBOL_FWD (sym); + + if (unbinding_p) + /* Forbid unbinding built-in variables. */ + error ("Built-in variables may not be unbound"); + if (BUFFER_OBJFWDP (innercontents)) { int offset = XBUFFER_OBJFWD (innercontents)->offset; @@ -1778,14 +1784,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, } } - if (voide) - { /* If storing void (making the symbol void), forward only through - buffer-local indicator, not through Lisp_Objfwd, etc. */ - sym->u.s.redirect = SYMBOL_PLAINVAL; - SET_SYMBOL_VAL (sym, newval); - } - else - store_symval_forwarding (/* sym, */ innercontents, newval, buf); + store_symval_forwarding (/* sym, */ innercontents, newval, buf); break; } default: emacs_abort (); diff --git a/test/src/data-tests.el b/test/src/data-tests.el index a1959f62fd3..a631aabb605 100644 --- a/test/src/data-tests.el +++ b/test/src/data-tests.el @@ -219,6 +219,16 @@ comparing the subr with a much slower Lisp implementation." do (error "FAILED testcase %S %3S %3S %3S" pos lf cnt rcnt))))) +(ert-deftest binding-test-makunbound-built-in () + "Verify that attempts to `makunbound' built-in symbols are rejected." + (should-error (makunbound 'initial-window-system)) + (let ((initial-window-system 'x)) + (should-error (makunbound 'initial-window-system))) + (should-error + (makunbound (make-local-variable 'initial-window-system))) + (let ((initial-window-system 'x)) + (should-error (makunbound 'initial-window-system)))) + (defconst bool-vector-test-vectors '("" "0" @@ -874,5 +884,4 @@ comparing the subr with a much slower Lisp implementation." ((eq subtype 'function) (cl-functionp val)) (t (should-not (cl-typep val subtype)))))))))) - ;;; data-tests.el ends here commit 4868a17396b6796b77285a3608b383aac32aee4f Author: Yuan Fu Date: Sun Jul 21 16:50:59 2024 -0700 Fix segfault when deleting tree-sitter query (bug#72238) * src/treesit.c (treesit_delete_query): Only delete query and cursor when they are non-NULL. diff --git a/src/treesit.c b/src/treesit.c index 5ed15bca788..a420ef77b2d 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -1224,8 +1224,10 @@ treesit_delete_parser (struct Lisp_TS_Parser *lisp_parser) void treesit_delete_query (struct Lisp_TS_Query *lisp_query) { - ts_query_delete (lisp_query->query); - ts_query_cursor_delete (lisp_query->cursor); + if (lisp_query->query) + ts_query_delete (lisp_query->query); + if (lisp_query->cursor) + ts_query_cursor_delete (lisp_query->cursor); } /* The following function is called from print.c:print_vectorlike. */ commit ccb856189f483abfaa584f428b09a863f816a040 Author: Theodor Thornhill Date: Sun Jul 21 14:56:52 2024 +0200 Add link to commit compatibility function handles * lisp/progmodes/typescript-ts-mode.el (tsx-ts-mode--indent-compatibility-b893426): Add link to GitHub. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 2c3d97efb69..b1288f17d86 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -92,7 +92,7 @@ (defun tsx-ts-mode--indent-compatibility-b893426 () "Indent rules helper, to handle different releases of tree-sitter-tsx. Check if a node type is available, then return the right indent rules." - ;; handle commit b893426 + ;; handle https://github.com/tree-sitter/tree-sitter-typescript/commit/b893426b82492e59388a326b824a346d829487e8 (condition-case nil (progn (treesit-query-capture 'tsx '((jsx_fragment) @capture)) `(((match "<" "jsx_fragment") parent 0) commit bb0f0c04a3985649f8ef86d9c3cbe68b78bee1aa Author: Theodor Thornhill Date: Sun Jul 21 14:55:06 2024 +0200 Improve one test (bug#71998) * test/lisp/progmodes/typescript-ts-mode-resources/indent.erts (Name): Add pre-indent state. diff --git a/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts index 877382953c1..343eababf54 100644 --- a/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts @@ -102,6 +102,24 @@ Code: Name: JSX indentation +=-= +const foo = (props) => { +return ( +
+
+
+
+{ +props.foo +? Hello, foo! +: Hello, World!; +} +
+
+
+
+); +} =-= const foo = (props) => { return ( commit 810be9cf863ecf74d6ca649ce38450a44ae55719 Author: Theodor Thornhill Date: Sun Jul 21 13:58:14 2024 +0200 ; Minor whitespace fix * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--font-lock-settings): Tabs to spaces. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 93a871e55d5..2c3d97efb69 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -393,7 +393,7 @@ Argument LANGUAGE is either `typescript' or `tsx'." :language language :feature 'jsx (append (tsx-ts-mode--font-lock-compatibility-bb1f97b language) - `((jsx_attribute (property_identifier) @typescript-ts-jsx-attribute-face))) + `((jsx_attribute (property_identifier) @typescript-ts-jsx-attribute-face))) :language language :feature 'number commit 7a059ed88a13d660cc5eb20f5fa6a2903ed23247 Author: Theodor Thornhill Date: Sun Jul 21 13:55:49 2024 +0200 Signal error on wrong typescript dialect * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode-wrong-dialect-error): New error. * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--check-dialect): Helper function. * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--indent-rules, tsx-ts-mode--font-lock-compatibility-bb1f97b, tsx-ts-mode--font-lock-compatibility-function-expression, tsx-ts-mode--font-lock-compatibility-function-expression, typescript-ts-mode--font-lock-settings): Use the new helper. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 3606a139d50..93a871e55d5 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -80,6 +80,15 @@ table) "Syntax table for `typescript-ts-mode'.") +(define-error 'typescript-ts-mode-wrong-dialect-error + "Wrong typescript dialect" + 'error) + +(defun typescript-ts-mode--check-dialect (dialect) + (unless (or (eq dialect 'typescript) (eq dialect 'tsx)) + (signal 'typescript-ts-mode-wrong-dialect-error + (list "Unsupported dialect for typescript-ts-mode suplied" dialect)))) + (defun tsx-ts-mode--indent-compatibility-b893426 () "Indent rules helper, to handle different releases of tree-sitter-tsx. Check if a node type is available, then return the right indent rules." @@ -106,6 +115,7 @@ declarations, accounting for the length of keyword (var, let, or const)." (defun typescript-ts-mode--indent-rules (language) "Rules used for indentation. Argument LANGUAGE is either `typescript' or `tsx'." + (typescript-ts-mode--check-dialect language) `((,language ((parent-is "program") column-0 0) ((node-is "}") parent-bol 0) @@ -188,6 +198,7 @@ Argument LANGUAGE is either `typescript' or `tsx'." ;; Warning: treesitter-query-capture says both node types are valid, ;; but then raises an error if the wrong node type is used. So it is ;; important to check with the new node type (member_expression) + (typescript-ts-mode--check-dialect language) (condition-case nil (progn (treesit-query-capture language '((jsx_opening_element (member_expression) @capture))) '((jsx_opening_element @@ -219,6 +230,7 @@ Argument LANGUAGE is either `typescript' or `tsx'." LANGUAGE can be `typescript' or `tsx'. Starting from version 0.20.4 of the typescript/tsx grammar, `function' becomes `function_expression'." + (typescript-ts-mode--check-dialect language) (condition-case nil (progn (treesit-query-capture language '((function_expression) @cap)) ;; New version of the grammar @@ -230,6 +242,7 @@ typescript/tsx grammar, `function' becomes `function_expression'." (defun typescript-ts-mode--font-lock-settings (language) "Tree-sitter font-lock settings. Argument LANGUAGE is either `typescript' or `tsx'." + (typescript-ts-mode--check-dialect language) (let ((func-exp (tsx-ts-mode--font-lock-compatibility-function-expression language))) (treesit-font-lock-rules :language language commit cdca1ba2e9dbbe2bb469c91179cdda4fd4585bb0 Author: Theodor Thornhill Date: Sun Jul 21 12:51:42 2024 +0200 ; Fix typo * lisp/treesit.el (treesit-ready-p): Minor typo fix. diff --git a/lisp/treesit.el b/lisp/treesit.el index 42215333699..c91864725da 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2977,7 +2977,7 @@ instead of emitting a warning." (catch 'term (when (not (treesit-available-p)) (setq msg (if (fboundp 'treesit-node-p) - ;; Windows loads tree-sitter dynakically. + ;; Windows loads tree-sitter dynamically. "tree-sitter library is not available or failed to load" "Emacs is not compiled with tree-sitter library")) (throw 'term nil)) commit 5c08fd80d27c61512d1f3f5cf9c38e2d5c3a5c18 Author: Michael Albinus Date: Sun Jul 21 11:13:35 2024 +0200 * lisp/progmodes/go-ts-mode.el (go-ts-mode-build-tags): Fix :version. diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 3fe427fa911..cb9a58e33b5 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -48,7 +48,7 @@ (defcustom go-ts-mode-build-tags nil "List of Go build tags for the test commands." - :version "30.1" + :version "31.1" :type '(repeat string) :group 'go) commit f249c81f868e8fea9d2a05ce258b3ebefba6620f Author: Ankit R Gadiya Date: Tue May 14 00:14:03 2024 +0530 Add commands to run unit tests in 'go-ts-mode' * lisp/progmodes/go-ts-mode.el (go-ts-mode-build-tags): New variable. (go-ts-mode-map): Add new bindings. (go-ts-mode--get-build-tags-flag, go-ts-mode--compile-test) (go-ts-mode--find-defun-at, go-ts-mode--get-function-regexp) (go-ts-mode--get-functions-in-range) (go-ts-mode--get-test-regexp-at-point) (go-ts-mode-test-function-at-point, go-ts-mode-test-this-file) (go-ts-mode-test-this-package): New functions. * etc/NEWS: Mention the change. (Bug#70939) diff --git a/etc/NEWS b/etc/NEWS index 0e13f471c74..d683db606ec 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -100,6 +100,25 @@ Advanced" node in the EWW manual. By customizing 'shr-image-zoom-levels', you can change the list of zoom levels that SHR cycles through when calling 'shr-zoom-image'. +** Go-ts mode + ++++ +*** New unit test commands. +Three new commands are now available to run unit tests. + +The 'go-ts-mode-test-function-at-point' command runs the unit test at +point. If a region is active, it runs all the unit tests under the +region. It is bound to 'C-c C-t t' in 'go-ts-mode'. + +The 'go-ts-mode-test-this-file' command runs all unit tests in the current +file. It is bound to 'C-c C-t f' in 'go-ts-mode'. + +The 'go-ts-mode-test-this-package' command runs all unit tests under the +package of the current buffer. It is bound to 'C-c C-t p' in 'go-ts-mode'. + +The 'go-ts-mode-build-tags' variable is available to set a list of build +tags for the test commands. + ** Emacs Lisp mode --- diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 2d3e6aac090..3fe427fa911 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -46,6 +46,12 @@ :safe 'integerp :group 'go) +(defcustom go-ts-mode-build-tags nil + "List of Go build tags for the test commands." + :version "30.1" + :type '(repeat string) + :group 'go) + (defvar go-ts-mode--syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?+ "." table) @@ -242,7 +248,10 @@ (defvar-keymap go-ts-mode-map :doc "Keymap used in Go mode, powered by tree-sitter" :parent prog-mode-map - "C-c C-d" #'go-ts-mode-docstring) + "C-c C-d" #'go-ts-mode-docstring + "C-c C-t t" #'go-ts-mode-test-function-at-point + "C-c C-t f" #'go-ts-mode-test-this-file + "C-c C-t p" #'go-ts-mode-test-this-package) ;;;###autoload (define-derived-mode go-ts-mode prog-mode "Go" @@ -375,6 +384,83 @@ comment already exists, jump to it." (<= (treesit-node-start node) point (treesit-node-end node)) (string-equal "comment" (treesit-node-type node))))) +(defun go-ts-mode--get-build-tags-flag () + "Return the compile flag for build tags. +This function respects the `go-ts-mode-build-tags' variable for +specifying build tags." + (if go-ts-mode-build-tags + (format "-tags %s" (string-join go-ts-mode-build-tags ",")) + "")) + +(defun go-ts-mode--compile-test (regexp) + "Compile the tests matching REGEXP. +This function respects the `go-ts-mode-build-tags' variable for +specifying build tags." + (compile (format "go test -v %s -run '%s'" + (go-ts-mode--get-build-tags-flag) + regexp))) + +(defun go-ts-mode--find-defun-at (start) + "Return the first defun node from START." + (let ((thing (or treesit-defun-type-regexp 'defun))) + (or (treesit-thing-at start thing) + (treesit-thing-next start thing)))) + +(defun go-ts-mode--get-function-regexp (name) + (if name + (format "^%s$" name) + (error "No test function found"))) + +(defun go-ts-mode--get-functions-in-range (start end) + "Return a list with the names of all defuns in the range START to END." + (let* ((node (go-ts-mode--find-defun-at start)) + (name (treesit-defun-name node)) + (node-start (treesit-node-start node)) + (node-end (treesit-node-end node))) + (cond ((or (not node) + (> start node-end) + (< end node-start)) + nil) + ((or (not (equal (treesit-node-type node) "function_declaration")) + (not (string-prefix-p "Test" name))) + (go-ts-mode--get-functions-in-range (treesit-node-end node) end)) + (t + (cons (go-ts-mode--get-function-regexp name) + (go-ts-mode--get-functions-in-range (treesit-node-end node) end)))))) + +(defun go-ts-mode--get-test-regexp-at-point () + "Return a regular expression for the tests at point. +If region is active, the regexp will include all the functions under the +region." + (if-let ((range (if (region-active-p) + (list (region-beginning) (region-end)) + (list (point) (point)))) + (funcs (apply #'go-ts-mode--get-functions-in-range range))) + (string-join funcs "|") + (error "No test function found"))) + +(defun go-ts-mode-test-function-at-point () + "Run the unit test at point. +If the point is anywhere in the test function, that function will be +run. If the region is selected, all the functions under the region will +be run." + (interactive) + (go-ts-mode--compile-test (go-ts-mode--get-test-regexp-at-point))) + +(defun go-ts-mode-test-this-file () + "Run all the unit tests in the current file." + (interactive) + (if-let ((defuns (go-ts-mode--get-functions-in-range (point-min) (point-max)))) + (go-ts-mode--compile-test (string-join defuns "|")) + (error "No test functions found in the current file"))) + +(defun go-ts-mode-test-this-package () + "Run all the unit tests under the current package." + (interactive) + (compile (format "go test -v %s -run %s" + (go-ts-mode--get-build-tags-flag) + default-directory))) + ;; go.mod support. (defvar go-mod-ts-mode--syntax-table commit e63fa29b98f3be18b7c66c9ca289e787b172ec37 Author: Eli Zaretskii Date: Sun Jul 21 07:27:38 2024 +0300 ; Fix recent changes in pdumper.c * src/pdumper.c (dump_treesit_compiled_query, dump_vectorlike): Minor copyedits. diff --git a/src/pdumper.c b/src/pdumper.c index 07fb1d569da..53bddf91f04 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -2223,7 +2223,7 @@ dump_treesit_compiled_query (struct dump_context *ctx, START_DUMP_PVEC (ctx, &query->header, struct Lisp_TS_Query, out); dump_field_lv (ctx, &out->language, query, &query->language, WEIGHT_STRONG); dump_field_lv (ctx, &out->source, query, &query->source, WEIGHT_STRONG); - /* Recompile these after load */ + /* These will be recompiled after load from dump. */ out->query = NULL; out->cursor = NULL; return finish_dump_pvec (ctx, &out->header); @@ -3123,11 +3123,9 @@ dump_vectorlike (struct dump_context *ctx, return DUMP_OBJECT_IS_RUNTIME_MAGIC; } break; -#ifdef HAVE_TREE_SITTER case PVEC_TS_COMPILED_QUERY: +#ifdef HAVE_TREE_SITTER return dump_treesit_compiled_query (ctx, XTS_COMPILED_QUERY (lv)); -#else - case PVEC_TS_COMPILED_QUERY: #endif case PVEC_WINDOW_CONFIGURATION: case PVEC_OTHER: commit 515e5ad0de133f0a3d501bd6290ccc51d8462955 Author: Paul Eggert Date: Sat Jul 20 15:52:05 2024 -0700 Fix bool vector length overflow * src/alloc.c (make_clear_bool_vector): It’s now the caller’s responsibility to make sure the bool vector length is in range. Add an eassert to double-check this. This lets some locals be ptrdiff_t not EMACS_INT. (Fmake_bool_vector, Fbool_vector): Check that bool vector lengths are in range. * src/lisp.h (BOOL_VECTOR_LENGTH_MAX): New macro. (bool_vector_words, bool_vector_bytes): Avoid undefined behavior if size == EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1). This is mostly theoretical but it’s easy to do it right. * src/lread.c (read_bool_vector): Use EMACS_INT, not just ptrdiff_t. Check that length doesn’t exceed BOOL_VECTOR_LENGTH_MAX. This fixes an unlikely integer overflow where the calculated size went negative. diff --git a/src/alloc.c b/src/alloc.c index 41679b52707..48b170b866f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -2413,14 +2413,13 @@ bool_vector_fill (Lisp_Object a, Lisp_Object init) Lisp_Object make_clear_bool_vector (EMACS_INT nbits, bool clearit) { + eassert (0 <= nbits && nbits <= BOOL_VECTOR_LENGTH_MAX); Lisp_Object val; - EMACS_INT words = bool_vector_words (nbits); - EMACS_INT word_bytes = words * sizeof (bits_word); - EMACS_INT needed_elements = ((bool_header_size - header_size + word_bytes + ptrdiff_t words = bool_vector_words (nbits); + ptrdiff_t word_bytes = words * sizeof (bits_word); + ptrdiff_t needed_elements = ((bool_header_size - header_size + word_bytes + word_size - 1) / word_size); - if (PTRDIFF_MAX < needed_elements) - memory_full (SIZE_MAX); struct Lisp_Bool_Vector *p = (struct Lisp_Bool_Vector *) allocate_clear_vector (needed_elements, clearit); @@ -2449,7 +2448,10 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) (Lisp_Object length, Lisp_Object init) { CHECK_FIXNAT (length); - Lisp_Object val = make_clear_bool_vector (XFIXNAT (length), NILP (init)); + EMACS_INT len = XFIXNAT (length); + if (BOOL_VECTOR_LENGTH_MAX < len) + memory_full (SIZE_MAX); + Lisp_Object val = make_clear_bool_vector (len, NILP (init)); return NILP (init) ? val : bool_vector_fill (val, init); } @@ -2459,6 +2461,8 @@ Allows any number of arguments, including zero. usage: (bool-vector &rest OBJECTS) */) (ptrdiff_t nargs, Lisp_Object *args) { + if (BOOL_VECTOR_LENGTH_MAX < nargs) + memory_full (SIZE_MAX); Lisp_Object vector = make_clear_bool_vector (nargs, true); for (ptrdiff_t i = 0; i < nargs; i++) if (!NILP (args[i])) diff --git a/src/lisp.h b/src/lisp.h index 79eade2f5ae..976b7a15251 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -1840,7 +1840,7 @@ struct Lisp_Bool_Vector /* HEADER.SIZE is the vector's size field. It doesn't have the real size, just the subtype information. */ union vectorlike_header header; - /* This is the size in bits. */ + /* The size in bits; at most BOOL_VECTOR_LENGTH_MAX. */ EMACS_INT size; /* The actual bits, packed into bytes. Zeros fill out the last word if needed. @@ -1868,20 +1868,32 @@ enum word_size = sizeof (Lisp_Object) }; +/* A bool vector's length must be a fixnum for XFIXNUM (Flength (...)). + Also, it is limited object size, which must fit in both ptrdiff_t and + size_t including header overhead and trailing alignment. */ +#define BOOL_VECTOR_LENGTH_MAX \ + min (MOST_POSITIVE_FIXNUM, \ + ((INT_MULTIPLY_OVERFLOW (min (PTRDIFF_MAX, SIZE_MAX) - bool_header_size,\ + (EMACS_INT) BOOL_VECTOR_BITS_PER_CHAR) \ + ? EMACS_INT_MAX \ + : ((min (PTRDIFF_MAX, SIZE_MAX) - bool_header_size) \ + * (EMACS_INT) BOOL_VECTOR_BITS_PER_CHAR)) \ + - (BITS_PER_BITS_WORD - 1))) + /* The number of data words and bytes in a bool vector with SIZE bits. */ INLINE EMACS_INT bool_vector_words (EMACS_INT size) { eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1)); - return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD; + return (size + (BITS_PER_BITS_WORD - 1)) / BITS_PER_BITS_WORD; } INLINE EMACS_INT bool_vector_bytes (EMACS_INT size) { eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1)); - return (size + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR; + return (size + (BOOL_VECTOR_BITS_PER_CHAR - 1)) / BOOL_VECTOR_BITS_PER_CHAR; } INLINE bits_word diff --git a/src/lread.c b/src/lread.c index c1f309866c8..ace7abd80c8 100644 --- a/src/lread.c +++ b/src/lread.c @@ -3568,7 +3568,7 @@ string_props_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) static Lisp_Object read_bool_vector (Lisp_Object readcharfun) { - ptrdiff_t length = 0; + EMACS_INT length = 0; for (;;) { int c = READCHAR; @@ -3582,6 +3582,8 @@ read_bool_vector (Lisp_Object readcharfun) || ckd_add (&length, length, c - '0')) invalid_syntax ("#&", readcharfun); } + if (BOOL_VECTOR_LENGTH_MAX < length) + invalid_syntax ("#&", readcharfun); ptrdiff_t size_in_chars = bool_vector_bytes (length); Lisp_Object str = read_string_literal (readcharfun); commit 76497a01425e19a6c3a02c1e3031061fa0e7885b Author: Paul Eggert Date: Sat Jul 20 09:03:24 2024 -0700 Change list-length intptr_t to ptrdiff_t * src/fns.c (list_length, Fsafe_length, Fproper_list_p): Use ptrdiff_t not intptr_t for accumulator, since result is ptrdiff_t. This fixes a minor glitch in 2019-01-11T05:35:31!eggert@cs.ucla.edu where I removed unnecessary overflow checks but forgot to change types. This change should alter generated code only on oddball platforms where ptrdiff_t is narrower than intptr_t, e.g., CheriBSD. diff --git a/src/fns.c b/src/fns.c index f16e3c1921d..c788ea54ec7 100644 --- a/src/fns.c +++ b/src/fns.c @@ -117,7 +117,7 @@ See Info node `(elisp)Random Numbers' for more details. */) ptrdiff_t list_length (Lisp_Object list) { - intptr_t i = 0; + ptrdiff_t i = 0; FOR_EACH_TAIL (list) i++; CHECK_LIST_END (list, list); @@ -167,7 +167,7 @@ it returns 0. If LIST is circular, it returns an integer that is at least the number of distinct elements. */) (Lisp_Object list) { - intptr_t len = 0; + ptrdiff_t len = 0; FOR_EACH_TAIL_SAFE (list) len++; return make_fixnum (len); @@ -248,7 +248,7 @@ A proper list is neither circular nor dotted (i.e., its last cdr is nil). */ attributes: const) (Lisp_Object object) { - intptr_t len = 0; + ptrdiff_t len = 0; Lisp_Object last_tail = object; Lisp_Object tail = object; FOR_EACH_TAIL_SAFE (tail) commit 55fefe06ef00cbe3e27a111a229a2622ae487c74 Author: Jim Porter Date: Sat Jul 20 14:46:14 2024 -0700 ; * lisp/eshell/esh-io.el (eshell-close-handles): Fix version annotation. diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el index cf7336bd70d..5fccc4fe82f 100644 --- a/lisp/eshell/esh-io.el +++ b/lisp/eshell/esh-io.el @@ -381,7 +381,7 @@ is not shared with the original handles." (defun eshell-close-handles (&optional handles obsolete-1 obsolete-2) "Close all of the current HANDLES, taking refcounts into account. If HANDLES is nil, use `eshell-current-handles'." - (declare (advertised-calling-convention (&optional handles) "30.1")) + (declare (advertised-calling-convention (&optional handles) "31.1")) (when (or obsolete-1 obsolete-2 (numberp handles)) (declare-function eshell-set-exit-info "esh-cmd" (&optional exit-code result)) commit 1abf3bdd7edcd405d4ccb4ef4de38068348f4b95 Author: Yuan Fu Date: Sat Jul 20 13:56:32 2024 -0700 Support dumping tree-sitter query (bug#69952) Previous commit allows Emacs to dump tree-sitter queries by simply dumping the query string and language symbol, and left the query object and cursor object as NULL. This commit makes sure Emacs doesn't crash when loading the dumped query, by make sure Emacs can handle the case where the cursor is NULL. * src/treesit.c (make_treesit_query): Initialize query with null cursor. (treesit_ensure_query_cursor): New function. (treesit_initialize_query): Ensure cursor is non-null. * src/treesit.h (Lisp_TS_Query): Update documentation. diff --git a/src/treesit.c b/src/treesit.c index a0e41add475..5ed15bca788 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -1201,7 +1201,6 @@ make_treesit_node (Lisp_Object parser, TSNode node) static Lisp_Object make_treesit_query (Lisp_Object query, Lisp_Object language) { - TSQueryCursor *treesit_cursor = ts_query_cursor_new (); struct Lisp_TS_Query *lisp_query; lisp_query = ALLOCATE_PSEUDOVECTOR (struct Lisp_TS_Query, @@ -1210,7 +1209,7 @@ make_treesit_query (Lisp_Object query, Lisp_Object language) lisp_query->language = language; lisp_query->source = query; lisp_query->query = NULL; - lisp_query->cursor = treesit_cursor; + lisp_query->cursor = NULL; return make_lisp_ptr (lisp_query, Lisp_Vectorlike); } @@ -1269,6 +1268,16 @@ treesit_compose_query_signal_data (uint32_t error_offset, build_string ("Debug the query with `treesit-query-validate'")); } +/* Ensure QUERY has a non-NULL cursor, and return it. */ +static TSQueryCursor * +treesit_ensure_query_cursor (Lisp_Object query) +{ + if (!XTS_COMPILED_QUERY (query)->cursor) + XTS_COMPILED_QUERY (query)->cursor = ts_query_cursor_new (); + + return XTS_COMPILED_QUERY (query)->cursor; +} + /* Ensure the QUERY is compiled. Return the TSQuery. It could be NULL if error occurs, in which case ERROR_OFFSET and ERROR_TYPE are bound. If error occurs, return NULL, and assign SIGNAL_SYMBOL and @@ -2865,7 +2874,7 @@ treesit_initialize_query (Lisp_Object query, const TSLanguage *lang, { *ts_query = treesit_ensure_query_compiled (query, signal_symbol, signal_data); - *cursor = XTS_COMPILED_QUERY (query)->cursor; + *cursor = treesit_ensure_query_cursor (query); /* We don't need to free ts_query and cursor because they are stored in a lisp object, which is tracked by gc. */ *need_free = false; diff --git a/src/treesit.h b/src/treesit.h index d3c6aa4c250..3da4cc155ea 100644 --- a/src/treesit.h +++ b/src/treesit.h @@ -119,12 +119,15 @@ struct Lisp_TS_Query Lisp_Object language; /* Source lisp (sexp or string) query. */ Lisp_Object source; - /* Pointer to the query object. This can be NULL, meaning this - query is not initialized/compiled. We compile the query when - it is used the first time (in treesit-query-capture). */ + /* Pointer to the query object. This can be NULL, meaning this query + is not initialized/compiled. We compile the query when it is used + the first time. (See treesit_ensure_query_compiled.) */ TSQuery *query; - /* Pointer to a cursor. If we are storing the query object, we - might as well store a cursor, too. */ + /* Pointer to a cursor. If we are storing the query object, we might + as well store a cursor, too. This can be NULL; caller should use + treesit_ensure_query_cursor to access the cursor. We made cursor + to be NULL-able because it makes dumping and loading queries + easy. */ TSQueryCursor *cursor; }; commit 1eca867e1b60acef7f4343bc5c70340de58f1079 Author: Sergey Vinokurov Date: Sun Aug 6 16:24:29 2023 +0100 Support compiled queries in pdump by dumping source (bug#69952) * src/pdumper.c (dump_vectorlike): Dump compiled queries. * src/pdumper.c (dump_treesit_compiled_query): New function. diff --git a/src/pdumper.c b/src/pdumper.c index bc5748c8c47..07fb1d569da 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -44,6 +44,7 @@ along with GNU Emacs. If not, see . */ #include "systime.h" #include "thread.h" #include "bignum.h" +#include "treesit.h" #ifdef CHECK_STRUCTS # include "dmpstruct.h" @@ -2214,6 +2215,21 @@ dump_finalizer (struct dump_context *ctx, return finish_dump_pvec (ctx, &out->header); } +#ifdef HAVE_TREE_SITTER +static dump_off +dump_treesit_compiled_query (struct dump_context *ctx, + struct Lisp_TS_Query *query) +{ + START_DUMP_PVEC (ctx, &query->header, struct Lisp_TS_Query, out); + dump_field_lv (ctx, &out->language, query, &query->language, WEIGHT_STRONG); + dump_field_lv (ctx, &out->source, query, &query->source, WEIGHT_STRONG); + /* Recompile these after load */ + out->query = NULL; + out->cursor = NULL; + return finish_dump_pvec (ctx, &out->header); +} +#endif + struct bignum_reload_info { dump_off data_location; @@ -3107,6 +3123,12 @@ dump_vectorlike (struct dump_context *ctx, return DUMP_OBJECT_IS_RUNTIME_MAGIC; } break; +#ifdef HAVE_TREE_SITTER + case PVEC_TS_COMPILED_QUERY: + return dump_treesit_compiled_query (ctx, XTS_COMPILED_QUERY (lv)); +#else + case PVEC_TS_COMPILED_QUERY: +#endif case PVEC_WINDOW_CONFIGURATION: case PVEC_OTHER: case PVEC_XWIDGET: @@ -3121,7 +3143,6 @@ dump_vectorlike (struct dump_context *ctx, case PVEC_FREE: case PVEC_TS_PARSER: case PVEC_TS_NODE: - case PVEC_TS_COMPILED_QUERY: break; } char msg[60]; commit 101ec1430128a0b1d9e7d54cbd9c0add8f446f25 Author: Paul Eggert Date: Sat Jul 20 08:52:55 2024 -0700 SAFE_ALLOCA fixes * src/comp.c (declare_imported_func, emit_simple_limple_call) (declare_lex_function, compile_function): * src/emacs-module.c (funcall_module): * src/fns.c (Fstring_distance): * src/font.c (font_sort_entities): * src/haikumenu.c (digest_menu_items, haiku_menu_show): * src/pgtkselect.c (Fpgtk_register_dnd_targets): * src/xfns.c (Fx_begin_drag): * src/xmenu.c (x_menu_show): * src/xterm.c (x_dnd_compute_toplevels, handle_one_xevent) (x_term_init): Prefer SAFE_NALLOCA to doing size multiplication by hand, to catch unlikely integer overflows. * src/comp.c (emit_simple_limple_call): Fix bug where SAFE_FREE was called too early, leading to unlikely use of freed storage. * src/xterm.c (handle_one_xevent): Remove side effects from SAFE_ALLOCA args, as the args are evaluated twice. diff --git a/src/comp.c b/src/comp.c index 41aa2c4c9b0..08c272bed70 100644 --- a/src/comp.c +++ b/src/comp.c @@ -1009,7 +1009,7 @@ declare_imported_func (Lisp_Object subr_sym, gcc_jit_type *ret_type, } else if (!types) { - types = SAFE_ALLOCA (nargs * sizeof (* types)); + SAFE_NALLOCA (types, 1, nargs); for (ptrdiff_t i = 0; i < nargs; i++) types[i] = comp.lisp_obj_type; } @@ -2096,16 +2096,17 @@ static gcc_jit_rvalue * emit_simple_limple_call (Lisp_Object args, gcc_jit_type *ret_type, bool direct) { USE_SAFE_ALLOCA; - int i = 0; Lisp_Object callee = FIRST (args); args = XCDR (args); - ptrdiff_t nargs = list_length (args); - gcc_jit_rvalue **gcc_args = SAFE_ALLOCA (nargs * sizeof (*gcc_args)); + ptrdiff_t i = 0, nargs = list_length (args); + gcc_jit_rvalue **gcc_args; + SAFE_NALLOCA (gcc_args, 1, nargs); FOR_EACH_TAIL (args) gcc_args[i++] = emit_mvar_rval (XCAR (args)); + gcc_jit_rvalue *res = emit_call (callee, ret_type, nargs, gcc_args, direct); SAFE_FREE (); - return emit_call (callee, ret_type, nargs, gcc_args, direct); + return res; } static gcc_jit_rvalue * @@ -4213,11 +4214,13 @@ declare_lex_function (Lisp_Object func) { EMACS_INT max_args = XFIXNUM (CALL1I (comp-args-max, args)); eassert (max_args < INT_MAX); - gcc_jit_type **type = SAFE_ALLOCA (max_args * sizeof (*type)); + gcc_jit_type **type; + SAFE_NALLOCA (type, 1, max_args); for (ptrdiff_t i = 0; i < max_args; i++) type[i] = comp.lisp_obj_type; - gcc_jit_param **params = SAFE_ALLOCA (max_args * sizeof (*params)); + gcc_jit_param **params; + SAFE_NALLOCA (params, 1, max_args); for (int i = 0; i < max_args; ++i) params[i] = gcc_jit_context_new_param (comp.ctxt, NULL, @@ -4293,7 +4296,7 @@ compile_function (Lisp_Object func) comp.func_relocs_ptr_type, "freloc"); - comp.frame = SAFE_ALLOCA (comp.frame_size * sizeof (*comp.frame)); + SAFE_NALLOCA (comp.frame, 1, comp.frame_size); if (comp.func_has_non_local || !comp.func_speed) { /* FIXME: See bug#42360. */ diff --git a/src/emacs-module.c b/src/emacs-module.c index 08db39b0b0d..05aa0baef74 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -1266,7 +1266,15 @@ funcall_module (Lisp_Object function, ptrdiff_t nargs, Lisp_Object *arglist) record_unwind_protect_module (SPECPDL_MODULE_ENVIRONMENT, env); USE_SAFE_ALLOCA; - emacs_value *args = nargs > 0 ? SAFE_ALLOCA (nargs * sizeof *args) : NULL; + emacs_value *args; + /* FIXME: Is this (nargs <= 0) test needed? Either omit it and call + SAFE_NALLOCA unconditionally, or fix this comment to explain why + the test is needed. */ + if (nargs <= 0) + args = NULL; + else + SAFE_NALLOCA (args, 1, nargs); + for (ptrdiff_t i = 0; i < nargs; ++i) { args[i] = lisp_to_value (env, arglist[i]); diff --git a/src/fns.c b/src/fns.c index bb292987db0..f16e3c1921d 100644 --- a/src/fns.c +++ b/src/fns.c @@ -292,7 +292,8 @@ Letter-case is significant, but text properties are ignored. */) ptrdiff_t x, y, lastdiag, olddiag; USE_SAFE_ALLOCA; - ptrdiff_t *column = SAFE_ALLOCA ((len1 + 1) * sizeof (ptrdiff_t)); + ptrdiff_t *column; + SAFE_NALLOCA (column, 1, len1 + 1); for (y = 0; y <= len1; y++) column[y] = y; diff --git a/src/font.c b/src/font.c index 0a0ac5f8030..246fe1c4426 100644 --- a/src/font.c +++ b/src/font.c @@ -2230,7 +2230,7 @@ font_sort_entities (Lisp_Object list, Lisp_Object prefer, maxlen = ASIZE (vec); } - data = SAFE_ALLOCA (maxlen * sizeof *data); + SAFE_NALLOCA (data, 1, maxlen); best_score = 0xFFFFFFFF; best_entity = Qnil; diff --git a/src/haikumenu.c b/src/haikumenu.c index 2e00b1803ae..f159d0e5638 100644 --- a/src/haikumenu.c +++ b/src/haikumenu.c @@ -38,8 +38,6 @@ digest_menu_items (void *first_menu, int start, int menu_items_used, bool is_menu_bar) { void **menus, **panes; - ssize_t menu_len; - ssize_t pane_len; int i, menu_depth; void *menu, *window, *view; Lisp_Object pane_name, prefix; @@ -48,18 +46,18 @@ digest_menu_items (void *first_menu, int start, int menu_items_used, USE_SAFE_ALLOCA; - menu_len = (menu_items_used + 1 - start) * sizeof *menus; - pane_len = (menu_items_used + 1 - start) * sizeof *panes; + int menu_len = menu_items_used - start + 1; + int pane_len = menu_items_used - start + 1; menu = first_menu; i = start; menu_depth = 0; - menus = SAFE_ALLOCA (menu_len); - panes = SAFE_ALLOCA (pane_len); - memset (menus, 0, menu_len); - memset (panes, 0, pane_len); + SAFE_NALLOCA (menus, 1, menu_len); + SAFE_NALLOCA (panes, 1, pane_len); + memset (menus, 0, menu_len * sizeof *menus); menus[0] = first_menu; + memset (panes, 0, pane_len * sizeof *panes); window = NULL; view = NULL; @@ -393,8 +391,7 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags, view = FRAME_HAIKU_VIEW (f); i = 0; submenu_depth = 0; - subprefix_stack - = SAFE_ALLOCA (menu_items_used * sizeof (Lisp_Object)); + SAFE_NALLOCA (subprefix_stack, 1, menu_items_used); eassert (FRAME_HAIKU_P (f)); diff --git a/src/pgtkselect.c b/src/pgtkselect.c index 271411b87ca..c9f117126b2 100644 --- a/src/pgtkselect.c +++ b/src/pgtkselect.c @@ -1808,7 +1808,7 @@ targets) that can be dropped on top of FRAME. */) CHECK_LIST (targets); length = list_length (targets); n = 0; - entries = SAFE_ALLOCA (sizeof *entries * length); + SAFE_NALLOCA (entries, 1, length); memset (entries, 0, sizeof *entries * length); tem = targets; diff --git a/src/xfns.c b/src/xfns.c index 917b82ff8da..3187bcfa2cf 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -7361,7 +7361,7 @@ that mouse buttons are being held down, such as immediately after a else signal_error ("Invalid drag-and-drop action", action); - target_atoms = SAFE_ALLOCA (ntargets * sizeof *target_atoms); + SAFE_NALLOCA (target_atoms, 1, ntargets); /* Catch errors since interning lots of targets can potentially generate a BadAlloc error. */ diff --git a/src/xmenu.c b/src/xmenu.c index 6dd7b3f37a0..0a41c47d527 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -1902,10 +1902,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags, USE_SAFE_ALLOCA; - submenu_stack = SAFE_ALLOCA (menu_items_used - * sizeof *submenu_stack); - subprefix_stack = SAFE_ALLOCA (menu_items_used - * sizeof *subprefix_stack); + SAFE_NALLOCA (submenu_stack, 1, menu_items_used); + SAFE_NALLOCA (subprefix_stack, 1, menu_items_used); specpdl_count = SPECPDL_INDEX (); diff --git a/src/xterm.c b/src/xterm.c index 5e200203f64..29f94dd196d 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3099,27 +3099,19 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) #ifdef USE_XCB USE_SAFE_ALLOCA; - window_attribute_cookies - = SAFE_ALLOCA (sizeof *window_attribute_cookies * nitems); - translate_coordinate_cookies - = SAFE_ALLOCA (sizeof *translate_coordinate_cookies * nitems); - get_property_cookies - = SAFE_ALLOCA (sizeof *get_property_cookies * nitems); - xm_property_cookies - = SAFE_ALLOCA (sizeof *xm_property_cookies * nitems); - extent_property_cookies - = SAFE_ALLOCA (sizeof *extent_property_cookies * nitems); - get_geometry_cookies - = SAFE_ALLOCA (sizeof *get_geometry_cookies * nitems); + SAFE_NALLOCA (window_attribute_cookies, 1, nitems); + SAFE_NALLOCA (translate_coordinate_cookies, 1, nitems); + SAFE_NALLOCA (get_property_cookies, 1, nitems); + SAFE_NALLOCA (xm_property_cookies, 1, nitems); + SAFE_NALLOCA (extent_property_cookies, 1, nitems); + SAFE_NALLOCA (get_geometry_cookies, 1, nitems); #ifdef HAVE_XCB_SHAPE - bounding_rect_cookies - = SAFE_ALLOCA (sizeof *bounding_rect_cookies * nitems); + SAFE_NALLOCA (bounding_rect_cookies, 1, nitems); #endif #ifdef HAVE_XCB_SHAPE_INPUT_RECTS - input_rect_cookies - = SAFE_ALLOCA (sizeof *input_rect_cookies * nitems); + SAFE_NALLOCA (input_rect_cookies, 1, nitems); #endif for (i = 0; i < nitems; ++i) @@ -20410,8 +20402,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (overflow) { - copy_bufptr = SAFE_ALLOCA ((copy_bufsiz += overflow) - * sizeof *copy_bufptr); + copy_bufsiz += overflow; + copy_bufptr = SAFE_ALLOCA (copy_bufsiz); overflow = 0; /* Use the original keysym derived from the @@ -24325,9 +24317,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, &overflow); if (overflow) { - copy_bufptr - = SAFE_ALLOCA ((copy_bufsiz += overflow) - * sizeof *copy_bufptr); + copy_bufsiz += overflow; + copy_bufptr = SAFE_ALLOCA (copy_bufsiz); overflow = 0; /* Use the original keysym derived from @@ -24668,7 +24659,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, any_changed = false; #endif /* !USE_X_TOOLKIT && (!USE_GTK || HAVE_GTK3) */ hev = (XIHierarchyEvent *) xi_event; - disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info); + SAFE_NALLOCA (disabled, 1, hev->num_info); n_disabled = 0; for (i = 0; i < hev->num_info; ++i) @@ -31690,8 +31681,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) } #ifdef USE_XCB - selection_cookies = SAFE_ALLOCA (sizeof *selection_cookies - * num_fast_selections); + SAFE_NALLOCA (selection_cookies, 1, num_fast_selections); #endif /* Now, ask for the current owners of all those selections. */ commit 301b97eb24ad280bdf36f562d5a95e9aff7f4a65 Author: Po Lu Date: Sat Jul 20 21:48:08 2024 +0800 ; Fix typo in xfont.c * src/xfont.c (xfont_list): Subtract 9 from name, not 10 + 1. diff --git a/src/xfont.c b/src/xfont.c index e439b954c5e..09b5e640dde 100644 --- a/src/xfont.c +++ b/src/xfont.c @@ -487,9 +487,9 @@ xfont_list (struct frame *f, Lisp_Object spec) if (NILP (list) && NILP (registry)) { /* Try iso10646-1 */ - char *r = name + len - sizeof "iso8859-1" - 1; + char *r = name + len - (sizeof "iso8859-1" - 1); - if (r - name + sizeof "iso10646-1" - 1 < 256) + if (r - name + (sizeof "iso10646-1" - 1) < 256) { strcpy (r, "iso10646-1"); list = xfont_list_pattern (display, name, Qiso10646_1, script); commit 2f875ead59abe16c4559d26883ff1db524fa22f7 Author: Stefan Kangas Date: Sat Jul 20 15:12:50 2024 +0200 Avoid magic values in xfont_list * src/xfont.c (xfont_list): Avoid magic values. diff --git a/src/xfont.c b/src/xfont.c index b112bb4fb39..e439b954c5e 100644 --- a/src/xfont.c +++ b/src/xfont.c @@ -487,9 +487,9 @@ xfont_list (struct frame *f, Lisp_Object spec) if (NILP (list) && NILP (registry)) { /* Try iso10646-1 */ - char *r = name + len - 9; /* 9 == strlen (iso8859-1) */ + char *r = name + len - sizeof "iso8859-1" - 1; - if (r - name + 10 < 256) /* 10 == strlen (iso10646-1) */ + if (r - name + sizeof "iso10646-1" - 1 < 256) { strcpy (r, "iso10646-1"); list = xfont_list_pattern (display, name, Qiso10646_1, script); commit b21e749a7c67614110c168299e9b36ac27e9f97a Merge: 79b9f05d3a4 816c53c2d9d Author: Eli Zaretskii Date: Sat Jul 20 06:32:17 2024 -0400 Merge from origin/emacs-30 816c53c2d9d Fix bibtex validation for non-file buffers ab7c40ea52a Fix Imenu in 'emacs-news-view-mode' ea30ffc52b3 ; * doc/misc/gnus.texi (Agent Caveats): Fix doc 07b1a36f78c ; * src/sqlite.c (Fsqlite_load_extension): Add "vec0" to ... 96f1db89ee7 Avoid errors in 'icomplete-vertical-mode' 55110d1fda2 Document GNU ELPA copyright in tips.texi 079e5a03156 Improve register-use-preview docstring e4760109ac8 Miscellaneous checkdoc fixes commit 816c53c2d9d6f2aabffdced23d10a0c902193235 Author: Liu Hui Date: Fri Jul 5 17:50:08 2024 +0800 Fix bibtex validation for non-file buffers * lisp/textmodes/bibtex.el (bibtex-validate): Use buffer name to show errors in non-file buffers. (Bug#71946) diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el index a6da34d6a41..1473fc2bd6b 100644 --- a/lisp/textmodes/bibtex.el +++ b/lisp/textmodes/bibtex.el @@ -4638,13 +4638,16 @@ Return t if test was successful, nil otherwise." (bibtex-progress-message 'done))))) (if error-list - (let ((file (file-name-nondirectory (buffer-file-name))) - (dir default-directory) - (err-buf "*BibTeX validation errors*")) + (let* ((file-p (buffer-file-name)) + (file (if file-p (file-name-nondirectory file-p) (buffer-name))) + (dir default-directory) + (err-buf "*BibTeX validation errors*")) (setq error-list (sort error-list #'car-less-than-car)) (with-current-buffer (get-buffer-create err-buf) (setq default-directory dir) (unless (eq major-mode 'compilation-mode) (compilation-mode)) + (setq-local compilation-parse-errors-filename-function + (if file-p #'identity #'get-buffer)) (let ((inhibit-read-only t)) (delete-region (point-min) (point-max)) (insert (substitute-command-keys commit ab7c40ea52a1db0cfc8b6605363f4e1378c9b471 Author: Eli Zaretskii Date: Sat Jul 20 12:33:23 2024 +0300 Fix Imenu in 'emacs-news-view-mode' * lisp/textmodes/emacs-news-mode.el (emacs-news-view-mode): Make it derived from emacs-news-mode. Add useful key bindings. (Bug#72080) diff --git a/lisp/textmodes/emacs-news-mode.el b/lisp/textmodes/emacs-news-mode.el index 1dd017abb01..ca897ec4567 100644 --- a/lisp/textmodes/emacs-news-mode.el +++ b/lisp/textmodes/emacs-news-mode.el @@ -107,12 +107,21 @@ (emacs-news--mode-common)) ;;;###autoload -(define-derived-mode emacs-news-view-mode special-mode "NEWS" +(define-derived-mode emacs-news-view-mode emacs-news-mode "NEWS" "Major mode for viewing the Emacs NEWS file." (setq buffer-read-only t) (emacs-news--buttonize) (button-mode) - (emacs-news--mode-common)) + ;; Bind useful browsing keys. + (keymap-local-set "q" 'quit-window) + (keymap-local-set "SPC" 'scroll-up-command) + (keymap-local-set "S-SPC" 'scroll-down-command) + (keymap-local-set "DEL" 'scroll-down-command) + (keymap-local-set "?" 'describe-mode) + (keymap-local-set "h" 'describe-mode) + (keymap-local-set ">" 'end-of-buffer) + (keymap-local-set "<" 'beginning-of-buffer) + (keymap-local-set "g" 'revert-buffer)) (defun emacs-news--fill-paragraph (&optional justify) (cond commit ea30ffc52b3297b4fbefa1fd591b8d0eece5bfc6 Author: James Thomas Date: Tue Jul 16 07:04:23 2024 +0530 ; * doc/misc/gnus.texi (Agent Caveats): Fix doc * doc/misc/gnus.texi (Agent Caveats): Change doc due to commit 2020-10-16 "Add a new variable to control Gnus Agent caching" (41d220dc6085, bug#43356). (Bug#72134) diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi index 72a16a179b5..d0ede930996 100644 --- a/doc/misc/gnus.texi +++ b/doc/misc/gnus.texi @@ -19842,7 +19842,8 @@ may ask: @table @dfn @item If I read an article while plugged, do they get entered into the Agent? -@strong{No}. If you want this behavior, add +Yes, because of the default value of +@code{gnus-agent-eagerly-store-articles}. An alternative is to add @code{gnus-agent-fetch-selected-article} to @code{gnus-select-article-hook}. commit 07b1a36f78c33d111da9a59d6f92ee6d0395d816 Author: Eli Zaretskii Date: Sat Jul 20 10:27:52 2024 +0300 ; * src/sqlite.c (Fsqlite_load_extension): Add "vec0" to allowed extensions. diff --git a/src/sqlite.c b/src/sqlite.c index 53f9d095114..32482b30f35 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -722,6 +722,7 @@ Only modules on Emacs' list of allowed modules can be loaded. */) "rtree", "sha1", "uuid", + "vec0", "vector0", "vfslog", "vss0", commit 79b9f05d3a44b25db9fd3eff9cc002324cfa790c Author: Paul Eggert Date: Sat Jul 20 00:17:14 2024 -0700 Avoid accessing uninitialized bool_vector words Although loading uninitialized works from memory and then ignoring the result works fine on conventional architectures, it technically has undefined behavior in C, so redo bool_vector allocation so that the code never does that. This can improve performance when allocating large vectors of nil, since calloc can clear the memory lazily. * src/alloc.c (make_clear_bool_vector): New function, a generalization of make_uninit_bool_vector. (make_uninit_bool_vector): Use it. (Fmake_bool_vector): If !INIT, rely on make_clear_bool_vector. * src/alloc.c (Fbool_vector): * src/fns.c (Freverse): Don’t access uninitialized bool_vector words. diff --git a/src/alloc.c b/src/alloc.c index 52f8a65d59d..41679b52707 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -453,6 +453,7 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size) #endif /* MAX_SAVE_STACK > 0 */ +static struct Lisp_Vector *allocate_clear_vector (ptrdiff_t, bool); static void unchain_finalizer (struct Lisp_Finalizer *); static void mark_terminals (void); static void gc_sweep (void); @@ -2406,10 +2407,11 @@ bool_vector_fill (Lisp_Object a, Lisp_Object init) return a; } -/* Return a newly allocated, uninitialized bool vector of size NBITS. */ +/* Return a newly allocated, bool vector of size NBITS. If CLEARIT, + clear its slots; otherwise the vector's slots are uninitialized. */ Lisp_Object -make_uninit_bool_vector (EMACS_INT nbits) +make_clear_bool_vector (EMACS_INT nbits, bool clearit) { Lisp_Object val; EMACS_INT words = bool_vector_words (nbits); @@ -2420,16 +2422,25 @@ make_uninit_bool_vector (EMACS_INT nbits) if (PTRDIFF_MAX < needed_elements) memory_full (SIZE_MAX); struct Lisp_Bool_Vector *p - = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements); + = (struct Lisp_Bool_Vector *) allocate_clear_vector (needed_elements, + clearit); + /* Clear padding at end; but only if necessary, to avoid polluting the + data cache. */ + if (!clearit && nbits % BITS_PER_BITS_WORD != 0) + p->data[words - 1] = 0; + XSETVECTOR (val, p); XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); p->size = nbits; + return val; +} - /* Clear padding at the end. */ - if (words) - p->data[words - 1] = 0; +/* Return a newly allocated, uninitialized bool vector of size NBITS. */ - return val; +Lisp_Object +make_uninit_bool_vector (EMACS_INT nbits) +{ + return make_clear_bool_vector (nbits, false); } DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, @@ -2437,11 +2448,9 @@ DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, LENGTH must be a number. INIT matters only in whether it is t or nil. */) (Lisp_Object length, Lisp_Object init) { - Lisp_Object val; - CHECK_FIXNAT (length); - val = make_uninit_bool_vector (XFIXNAT (length)); - return bool_vector_fill (val, init); + Lisp_Object val = make_clear_bool_vector (XFIXNAT (length), NILP (init)); + return NILP (init) ? val : bool_vector_fill (val, init); } DEFUN ("bool-vector", Fbool_vector, Sbool_vector, 0, MANY, 0, @@ -2450,13 +2459,10 @@ Allows any number of arguments, including zero. usage: (bool-vector &rest OBJECTS) */) (ptrdiff_t nargs, Lisp_Object *args) { - ptrdiff_t i; - Lisp_Object vector; - - vector = make_uninit_bool_vector (nargs); - for (i = 0; i < nargs; i++) - bool_vector_set (vector, i, !NILP (args[i])); - + Lisp_Object vector = make_clear_bool_vector (nargs, true); + for (ptrdiff_t i = 0; i < nargs; i++) + if (!NILP (args[i])) + bool_vector_set (vector, i, true); return vector; } diff --git a/src/fns.c b/src/fns.c index f623ff96c25..bb292987db0 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2309,12 +2309,12 @@ See also the function `nreverse', which is used more often. */) } else if (BOOL_VECTOR_P (seq)) { - ptrdiff_t i; EMACS_INT nbits = bool_vector_size (seq); - new = make_uninit_bool_vector (nbits); - for (i = 0; i < nbits; i++) - bool_vector_set (new, i, bool_vector_bitref (seq, nbits - i - 1)); + new = make_clear_bool_vector (nbits, true); + for (ptrdiff_t i = 0; i < nbits; i++) + if (bool_vector_bitref (seq, nbits - i - 1)) + bool_vector_set (new, i, true); } else if (STRINGP (seq)) { diff --git a/src/lisp.h b/src/lisp.h index 68b77a88aa7..79eade2f5ae 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4578,6 +4578,7 @@ list4i (intmax_t a, intmax_t b, intmax_t c, intmax_t d) return list4 (make_int (a), make_int (b), make_int (c), make_int (d)); } +extern Lisp_Object make_clear_bool_vector (EMACS_INT, bool); extern Lisp_Object make_uninit_bool_vector (EMACS_INT); extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object); extern AVOID string_overflow (void); commit cb78b43f39432af3301a39507eac23f5f1e9fbf3 Author: Eli Zaretskii Date: Sat Jul 20 09:46:21 2024 +0300 Fix setup of fonts for 'han' script. * lisp/international/fontset.el (script-representative-chars): Add more CJK representative characters to 'han' script. (Bug#72188) diff --git a/lisp/international/fontset.el b/lisp/international/fontset.el index a6129cbc8f0..d4e24899d11 100644 --- a/lisp/international/fontset.el +++ b/lisp/international/fontset.el @@ -208,7 +208,9 @@ (kana #x304B) (bopomofo #x3105) (kanbun #x319D) - (han #x5B57) + (han #x2e90 #x2f00 #x3010 #x3200 #x3300 #x3400 #x31c0 #x4e10 + #x5B57 #xfe30 #xf900 + #x1f210 #x20000 #x2a700 #x2b740 #x2b820 #x2ceb0 #x2f804) (yi #xA288) (syloti-nagri #xA807 #xA823 #xA82C) (rejang #xA930 #xA947 #xA95F) commit 96f1db89ee7d3696d27a5bf044ada7942e354fda Author: Eli Zaretskii Date: Sat Jul 20 08:58:39 2024 +0300 Avoid errors in 'icomplete-vertical-mode' * lisp/minibuffer.el (completion--hilit-from-re): Avoid signaling an error if STRING does not match REGEXP. Fix doc string and indentation. (Bug#72176) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 0f6e3518758..baed4edcf89 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -4051,24 +4051,26 @@ details." (defun completion--hilit-from-re (string regexp &optional point-idx) "Fontify STRING using REGEXP POINT-IDX. -`completions-common-part' and `completions-first-difference' are -used. POINT-IDX is the position of point in the presumed \"PCM\" -pattern that was used to generate derive REGEXP from." -(let* ((md (and regexp (string-match regexp string) (cddr (match-data t)))) - (pos (if point-idx (match-beginning point-idx) (match-end 0))) - (me (and md (match-end 0))) - (from 0)) - (while md - (add-face-text-property from (pop md) 'completions-common-part nil string) - (setq from (pop md))) - (if (> (length string) pos) - (add-face-text-property - pos (1+ pos) - 'completions-first-difference - nil string)) - (unless (or (not me) (= from me)) - (add-face-text-property from me 'completions-common-part nil string)) - string)) +Uses `completions-common-part' and `completions-first-difference' +faces to fontify STRING. +POINT-IDX is the position of point in the presumed \"PCM\" pattern +from which REGEXP was generated." + (let* ((md (and regexp (string-match regexp string) (cddr (match-data t)))) + (pos (if point-idx (match-beginning point-idx) (match-end 0))) + (me (and md (match-end 0))) + (from 0)) + (while md + (add-face-text-property from (pop md) + 'completions-common-part nil string) + (setq from (pop md))) + (if (and (numberp pos) (> (length string) pos)) + (add-face-text-property + pos (1+ pos) + 'completions-first-difference + nil string)) + (unless (or (not me) (= from me)) + (add-face-text-property from me 'completions-common-part nil string)) + string)) (defun completion--flex-score-1 (md-groups match-end len) "Compute matching score of completion. commit 55110d1fda2daa204d98f93872577cca81733ad4 Author: Stefan Kangas Date: Sat Jul 20 07:46:37 2024 +0200 Document GNU ELPA copyright in tips.texi * doc/lispref/tips.texi (Library Headers): Document that GNU ELPA packages should have their copyright assigned to the FSF. diff --git a/doc/lispref/tips.texi b/doc/lispref/tips.texi index 802fa0febed..dc0679ed3a1 100644 --- a/doc/lispref/tips.texi +++ b/doc/lispref/tips.texi @@ -1087,11 +1087,11 @@ set more variables in the @samp{-*-} specification, add it after @code{lexical-binding}. If this would make the first line too long, use a Local Variables section at the end of the file. - The copyright notice usually lists your name (if you wrote the -file). If you have an employer who claims copyright on your work, you -might need to list them instead. Do not say that the copyright holder -is the Free Software Foundation (or that the file is part of GNU -Emacs) unless your file has been accepted into the Emacs distribution. + The copyright notice usually lists your name (if you wrote the file). +If you have an employer who claims copyright on your work, you might +need to list them instead. Do not say that the copyright holder is the +Free Software Foundation (or that the file is part of GNU Emacs) unless +your file has been accepted into the Emacs distribution or GNU ELPA. For more information on the form of copyright and license notices, see @uref{https://www.gnu.org/licenses/gpl-howto.html, the guide on the GNU website}. commit 358dbbb723b735eddd3f821ffeaf5382778433bd Author: Po Lu Date: Sat Jul 20 12:39:33 2024 +0800 Fix compilation on builds with native rectangle structures * src/androidgui.h (CONVERT_TO_NATIVE_RECT) (CONVERT_FROM_EMACS_RECT): Delete redundant macro definitions. * src/xdisp.c (Fremember_mouse_glyph) [CONVERT_TO_EMACS_RECT]: Expand CONVERT_TO_EMACS_RECT to convert native rectangles into a readable format if required. Reported by Stefan Kangas . diff --git a/src/androidgui.h b/src/androidgui.h index 79e42c7947c..2bd9d3741da 100644 --- a/src/androidgui.h +++ b/src/androidgui.h @@ -216,8 +216,6 @@ struct android_swap_info }; #define NativeRectangle Emacs_Rectangle -#define CONVERT_TO_NATIVE_RECT(xr, nr) ((xr) = (nr)) -#define CONVERT_FROM_EMACS_RECT(xr, nr) ((nr) = (xr)) #define STORE_NATIVE_RECT(nr, rx, ry, rwidth, rheight) \ ((nr).x = (rx), (nr).y = (ry), \ diff --git a/src/xdisp.c b/src/xdisp.c index 74ccfd9e745..4185e368c96 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3017,12 +3017,20 @@ point of FRAME. */) (Lisp_Object frame, Lisp_Object x, Lisp_Object y) { struct frame *f = decode_window_system_frame (frame); - NativeRectangle r; + NativeRectangle rect; +#ifdef CONVERT_TO_EMACS_RECT + Emacs_Rectangle xrect; +#endif /* CONVERT_TO_EMACS_RECT */ CHECK_FIXNUM (x); CHECK_FIXNUM (y); - remember_mouse_glyph (f, XFIXNUM (x), XFIXNUM (y), &r); - return list4i (r.x, r.y, r.width, r.height); + remember_mouse_glyph (f, XFIXNUM (x), XFIXNUM (y), &rect); +#ifdef CONVERT_TO_EMACS_RECT + CONVERT_TO_EMACS_RECT (xrect, rect); + return list4i (xrect.x, xrect.y, xrect.width, xrect.height); +#else /* !defined CONVERT_TO_EMACS_RECT */ + return list4i (rect.x, rect.y, rect.width, rect.height); +#endif /* !defined CONVERT_TO_EMACS_RECT */ } #endif /* HAVE_WINDOW_SYSTEM */ commit 892abde34e052f7a9b1b27fcb27ded13b4ba3c04 Author: Po Lu Date: Sat Jul 20 11:28:47 2024 +0800 Respect mouse-fine-graned-tracking in touch screen simple translation * lisp/touch-screen.el (touch-screen-current-tool): Expand doc string. (touch-screen-handle-point-update): Record extents of glyph beneath the mouse as computed by `remember_mouse_glyph' if necessary, and defer generation of mouse-movement events till the mouse exit it. * src/xdisp.c (Fremember_mouse_glyph): New function. (syms_of_xdisp): Define new subr. diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index ebf20018164..58f47a19bbe 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el @@ -33,13 +33,35 @@ (defvar touch-screen-current-tool nil "The touch point currently being tracked, or nil. -If non-nil, this is a list of ten elements: the ID of the touch -point being tracked, the window where the touch began, a cons -holding the last registered position of the touch point, relative -to that window, a field used to store data while tracking the -touch point, the initial position of the touchpoint, another four -fields to used store data while tracking the touch point, and the -last known position of the touch point. +If non-nil, this is a list of ten elements, which might be +accessed as follows: + + (nth 0 touch-screen-current-tool) + The ID of the touch point being tracked. + + (nth 1 touch-screen-current-tool) + The window where the touch sequence being monitored commenced. + + (nth 2 touch-screen-current-tool) + A cons holding the last registered position of the touch + point, relative to that window. + + (nth 3 touch-screen-current-tool) + A field holding a symbol identifying the gesture being + observed while tracking the said touch point. + + (nth 4 touch-screen-current-tool) + The initial position of the touchpoint. + + (nth 5 touch-screen-current-tool) + (nth 6 touch-screen-current-tool) + (nth 7 touch-screen-current-tool) + (nth 8 touch-screen-current-tool) + A further four fields to used store data while tracking the + touch point. + + (nth 9 touch-screen-current-tool) + The last known position of the touch point. See `touch-screen-handle-point-update' and `touch-screen-handle-point-up' for the meanings of the fourth @@ -1027,6 +1049,8 @@ When ARG is t, set the fourth element of (let ((posn (nth 4 touch-screen-current-tool))) (throw 'input-event (list 'touchscreen-hold posn)))))) +(declare-function remember-mouse-glyph "xdisp.c") + (defun touch-screen-handle-point-update (point) "Notice that the touch point POINT has changed position. Perform the editing operations or throw to the input translation @@ -1077,8 +1101,7 @@ then move point to the position of POINT." (what (nth 3 touch-screen-current-tool)) (posn (cdr point)) ;; Now get the position of X and Y relative to WINDOW. - (relative-xy - (touch-screen-relative-xy posn window))) + (relative-xy (touch-screen-relative-xy posn window))) ;; Update the 10th field of the tool list with RELATIVE-XY. (setcar (nthcdr 9 touch-screen-current-tool) relative-xy) (cond ((or (null what) @@ -1128,8 +1151,43 @@ then move point to the position of POINT." ;; point of the event. Generate a mouse-motion event if ;; mouse movement is being tracked. (when track-mouse - (throw 'input-event (list 'mouse-movement - (cdr point))))) + (let ((mouse-rect (nth 5 touch-screen-current-tool)) + (edges (window-inside-pixel-edges window))) + ;; If fine-grained tracking is enabled, disregard the + ;; mouse rect. Apply the same criteria as + ;; `remember_mouse_glyph', which see. + (if (or mouse-fine-grained-tracking + window-resize-pixelwise) + (throw 'input-event (list 'mouse-movement posn)) + ;; Otherwise, generate an event only if POINT falls + ;; outside the extents of the mouse rect, and record + ;; the extents of the glyph beneath point as the next + ;; mouse rect. + (let ((point relative-xy) + (frame-offsets (if (framep window) + '(0 . 0) + (cons (car edges) (cadr edges))))) + (when (or (not mouse-rect) + (< (car point) (- (car mouse-rect) + (car frame-offsets))) + (> (car point) (+ (- (car mouse-rect) 1 + (car frame-offsets)) + (caddr mouse-rect))) + (< (cdr point) (- (cadr mouse-rect) + (cdr frame-offsets))) + (> (cdr point) (+ (- (cadr mouse-rect) 1 + (cdr frame-offsets)) + (cadddr mouse-rect)))) + ;; Record the extents of this glyph. + (setcar (nthcdr 5 touch-screen-current-tool) + (remember-mouse-glyph (or (and (framep window) window) + (window-frame window)) + (+ (car point) + (car frame-offsets)) + (+ (cdr point) + (cdr frame-offsets)))) + ;; Generate the movement. + (throw 'input-event (list 'mouse-movement posn)))))))) ((eq what 'held) (let* ((posn (cdr point))) ;; Now start dragging. diff --git a/src/xdisp.c b/src/xdisp.c index 8c7e8e5cb43..74ccfd9e745 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3006,6 +3006,24 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) #endif } +DEFUN ("remember-mouse-glyph", Fremember_mouse_glyph, Sremember_mouse_glyph, + 3, 3, 0, + doc: /* Return the extents of glyph in FRAME for mouse event generation. +Return a rectangle (X Y WIDTH HEIGHT) representing the confines, in +pixel coordinates, of the glyph at X, Y and in FRAME, or, should +`mouse-fine-grained-tracking' or `window-resize-pixelwise` be enabled, +an approximation thereof. All coordinates are relative to the origin +point of FRAME. */) + (Lisp_Object frame, Lisp_Object x, Lisp_Object y) +{ + struct frame *f = decode_window_system_frame (frame); + NativeRectangle r; + + CHECK_FIXNUM (x); + CHECK_FIXNUM (y); + remember_mouse_glyph (f, XFIXNUM (x), XFIXNUM (y), &r); + return list4i (r.x, r.y, r.width, r.height); +} #endif /* HAVE_WINDOW_SYSTEM */ @@ -37263,6 +37281,7 @@ be let-bound around code that needs to disable messages temporarily. */); defsubr (&Strace_to_stderr); #endif #ifdef HAVE_WINDOW_SYSTEM + defsubr (&Sremember_mouse_glyph); defsubr (&Stab_bar_height); defsubr (&Stool_bar_height); defsubr (&Slookup_image_map); commit 079e5a03156f7461d1c8f008663404277cac9ade Author: Stefan Kangas Date: Sat Jul 20 02:37:38 2024 +0200 Improve register-use-preview docstring * lisp/register.el (register-use-preview): Improve docstring. diff --git a/lisp/register.el b/lisp/register.el index df00c9dc24f..497848ded1e 100644 --- a/lisp/register.el +++ b/lisp/register.el @@ -131,17 +131,20 @@ to the value of `register--read-with-preview-function'.") (defcustom register-use-preview 'traditional "Whether to show register preview when modifying registers. -When set to t, show a preview buffer with navigation and -highlighting. -When set to \\='insist, behave as with t, but allow exiting the -minibuffer by pressing the register name a second time. E.g., -press \"a\" to select register \"a\", then press \"a\" again to -exit the minibuffer. -When nil, show a preview buffer without navigation and highlighting, and -exit the minibuffer immediately after inserting response in minibuffer. -When set to \\='never, behave as with nil, but with no preview buffer at +When set to t, show a preview buffer with navigation and highlighting. + +When set `insist', behave as with t, but allow exiting the minibuffer by +pressing the register name a second time. For example, press \\`a' to +select register \"a\", then press \\`a' again to exit the minibuffer. + +When set to nil, show a preview buffer without navigation and +highlighting, and exit the minibuffer immediately after inserting +response in minibuffer. + +When set to `never', behave as with nil, but with no preview buffer at all; the preview buffer is still accessible with `help-char' (\\`C-h'). -When set to \\='traditional (the default), provide a more basic preview + +When set to `traditional' (the default), provide a more basic preview according to `register-preview-delay'; this preserves the traditional behavior of Emacs 29 and before." :type '(choice commit e4760109ac8e3b0d73dd37e11121a01362542364 Author: Stefan Kangas Date: Sat Jul 20 02:22:49 2024 +0200 Miscellaneous checkdoc fixes * lisp/ansi-color.el (ansi-color--ensure-context): * lisp/doc-view.el (doc-view-svg-face): * lisp/external-completion.el (external-completion-table): * lisp/ffap.el (ffap-ro-mode-hook, ffap-gnus-hook): * lisp/find-file.el: * lisp/flow-ctrl.el (flow-control-c-s-replacement) (flow-control-c-q-replacement): * lisp/forms.el (forms-multi-line): * lisp/help.el (search-forward-help-for-help): * lisp/hi-lock.el (hi-lock-use-overlays): * lisp/image.el (find-image): * lisp/isearch.el (isearch-forward, isearch-forward-regexp) (isearch-lazy-count-format): * lisp/jsonrpc.el (jsonrpc--continue, initialize-instance): * lisp/mouse-copy.el (mouse-kill-preserving-secondary): * lisp/pixel-scroll.el (pixel-bob-at-top-p) (pixel-scroll-down-and-set-window-vscroll): * lisp/printing.el (pr-gv-command, pr-gs-command) (pr-gs-switches): * lisp/register.el (register-use-preview): * lisp/repeat.el (repeat-check-key): * lisp/saveplace.el (save-place-abbreviate-file-names): * lisp/select.el (gui--clipboard-selection-unchanged-p): * lisp/ses.el (ses-header-row): * lisp/simple.el (transpose-sexps-default-function) (normal-erase-is-backspace, normal-erase-is-backspace-mode): * lisp/sqlite-mode.el (sqlite-mode): * lisp/tempo.el (tempo-insert-region): * lisp/term.el (term-mode-map, term-mode, term-char-mode): Checkdoc fixes. diff --git a/lisp/ansi-color.el b/lisp/ansi-color.el index 1d053f718f8..b492eb8f07c 100644 --- a/lisp/ansi-color.el +++ b/lisp/ansi-color.el @@ -565,12 +565,11 @@ This function can be added to `comint-preoutput-filter-functions'." (defun ansi-color--ensure-context (context-sym position) "Return CONTEXT-SYM's value as a valid context. -If it is nil, set CONTEXT-SYM's value to a new context and return -it. Context is a list of the form as described in -`ansi-color-context' if POSITION is nil, or -`ansi-color-context-region' if POSITION is non-nil. +If it is nil, set CONTEXT-SYM's value to a new context and return it. +Context is a list of the form as described in `ansi-color-context' if +POSITION is nil, or `ansi-color-context-region' if POSITION is non-nil. -If CONTEXT-SYM's value is already non-nil, return it. If its +If CONTEXT-SYM's value is already non-nil, return it. If its marker doesn't point anywhere yet, position it before character number POSITION, if non-nil." (let ((context (symbol-value context-sym))) diff --git a/lisp/doc-view.el b/lisp/doc-view.el index 4ae9a5e6629..b0b2fc43737 100644 --- a/lisp/doc-view.el +++ b/lisp/doc-view.el @@ -51,7 +51,7 @@ ;; subdirectory of `doc-view-cache-directory' and reused when you want to view ;; that file again. To reconvert a document hit `g' (`doc-view-reconvert-doc') ;; when displaying the document. To delete all cached files use -;; `doc-view-clear-cache'. To open the cache with dired, so that you can tidy +;; `doc-view-clear-cache'. To open the cache with Dired, so that you can tidy ;; it out use `doc-view-dired-cache'. ;; ;; When conversion is underway the first page will be displayed as soon as it @@ -239,8 +239,8 @@ showing only titles and no page number." :version "29.1") (defface doc-view-svg-face '((t :inherit default)) - "Face used for SVG images. Only background and foreground colors -are used. + "Face used for SVG images. +Only background and foreground colors are used. See `doc-view-mupdf-use-svg'." :version "30.1") diff --git a/lisp/external-completion.el b/lisp/external-completion.el index a9d394c61d4..4588640d0ad 100644 --- a/lisp/external-completion.el +++ b/lisp/external-completion.el @@ -75,7 +75,7 @@ function links CATEGORY to the style `external', by modifying set in `completion-styles'. LOOKUP is a function taking a string PATTERN and a number -POINT. The function should contact the tool and return a list of +POINT. The function should contact the tool and return a list of strings representing the completions for PATTERN given that POINT is the location of point within it. LOOKUP decides if PATTERN is interpreted as a substring, a regular expression, or any other diff --git a/lisp/ffap.el b/lisp/ffap.el index 9fd753fc0e5..e431aeed8b1 100644 --- a/lisp/ffap.el +++ b/lisp/ffap.el @@ -1953,12 +1953,12 @@ Only intended for interactive use." ;; bindings you would prefer. (defun ffap-ro-mode-hook () - "Bind `ffap-next' and `ffap-menu' to M-l and M-m, resp." + "Bind `ffap-next' and `ffap-menu' to \\`M-l' and \\`M-m', resp." (local-set-key "\M-l" 'ffap-next) (local-set-key "\M-m" 'ffap-menu)) (defun ffap-gnus-hook () - "Bind `ffap-gnus-next' and `ffap-gnus-menu' to M-l and M-m, resp." + "Bind `ffap-gnus-next' and `ffap-gnus-menu' to \\`M-l' and \\`M-m', resp." ;; message-id's (setq-local thing-at-point-default-mail-uri-scheme "news") ;; Note "l", "L", "m", "M" are taken: diff --git a/lisp/find-file.el b/lisp/find-file.el index c4c61e6abe6..23e0c12ad2c 100644 --- a/lisp/find-file.el +++ b/lisp/find-file.el @@ -93,7 +93,7 @@ ;; ;; GIVEN AN ARGUMENT (with the ^U prefix), ff-find-other-file will get the ;; other file in another (the other?) window (see find-file-other-window and -;; switch-to-buffer-other-window). This can be set on a more permanent basis +;; switch-to-buffer-other-window). This can be set on a more permanent basis ;; by setting ff-always-in-other-window to t in which case the ^U prefix will ;; do the opposite of what was described above. ;; diff --git a/lisp/flow-ctrl.el b/lisp/flow-ctrl.el index 55ffe1cf14f..f92e666d7da 100644 --- a/lisp/flow-ctrl.el +++ b/lisp/flow-ctrl.el @@ -44,9 +44,9 @@ ;;; Code: (defvar flow-control-c-s-replacement ?\034 - "Character that replaces C-s, when flow control handling is enabled.") + "Character that replaces \\`C-s', when flow control handling is enabled.") (defvar flow-control-c-q-replacement ?\036 - "Character that replaces C-q, when flow control handling is enabled.") + "Character that replaces \\`C-q', when flow control handling is enabled.") (put 'keyboard-translate-table 'char-table-extra-slots 0) diff --git a/lisp/forms.el b/lisp/forms.el index 3a3160a0c8b..f3772582b40 100644 --- a/lisp/forms.el +++ b/lisp/forms.el @@ -323,8 +323,8 @@ "Non-nil means: visit the file in view (read-only) mode. This is set automatically if the file permissions don't let you write it.") -(defvar forms-multi-line "\C-k" "\ -If not nil: use this character to separate multi-line fields (default C-k).") +(defvar forms-multi-line "\C-k" + "If non-nil, use this character to separate multi-line fields (default \\`C-k').") (defcustom forms-forms-scroll nil "Non-nil means replace scroll-up/down commands in Forms mode. diff --git a/lisp/help.el b/lisp/help.el index adc1724d504..5efe207c624 100644 --- a/lisp/help.el +++ b/lisp/help.el @@ -1205,7 +1205,7 @@ current buffer." (describe-function-1 defn))))))) (defun search-forward-help-for-help () - "Search forward in the help-for-help window. + "Search forward in the `help-for-help' window. This command is meant to be used after issuing the \\[help-for-help] command." (interactive) (unless (get-buffer help-for-help-buffer-name) diff --git a/lisp/hi-lock.el b/lisp/hi-lock.el index f595c92041a..6d827a055a5 100644 --- a/lisp/hi-lock.el +++ b/lisp/hi-lock.el @@ -751,7 +751,7 @@ with completion and history." (defvar hi-lock-use-overlays nil "Whether to always use overlays instead of font-lock rules. -When font-lock-mode is enabled and the buffer specifies font-lock rules, +When `font-lock-mode' is enabled and the buffer specifies font-lock rules, highlighting is performed by adding new font-lock rules to the existing ones, so when new matching strings are added, they are highlighted by font-lock. Otherwise, overlays are used, but new highlighting overlays are not added diff --git a/lisp/image.el b/lisp/image.el index e16bd989ce7..3d60b485c6b 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -815,7 +815,7 @@ string containing the actual image data. If the property `:type TYPE' is omitted or nil, try to determine the image type from its first few bytes of image data. If that doesn't work, and the property `:file FILE' provide a file name, use its file extension as indication of the -image type. If `:type TYPE' is provided, it must match the actual type +image type. If `:type TYPE' is provided, it must match the actual type determined for FILE or DATA by `create-image'. The function returns the image specification for the first specification diff --git a/lisp/isearch.el b/lisp/isearch.el index e8fb33ef6ea..dc9edf267f2 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -1003,8 +1003,7 @@ Each element is an `isearch--state' struct where the slots are ;; Entry points to isearch-mode. (defun isearch-forward (&optional regexp-p no-recursive-edit) - "\ -Do incremental search forward. + "Do incremental search forward. With a prefix argument, do an incremental regular expression search instead. \\ As you type characters, they add to the search string and are found. @@ -1012,7 +1011,7 @@ The following non-printing keys are bound in `isearch-mode-map'. Type \\[isearch-delete-char] to cancel last input item from end of search string. Type \\[isearch-exit] to exit, leaving point at location found. -Type LFD (C-j) to match end of line. +Type LFD (\\`C-j') to match end of line. Type \\[isearch-repeat-forward] to search again forward,\ \\[isearch-repeat-backward] to search again backward. Type \\[isearch-beginning-of-buffer] to go to the first match,\ @@ -1110,7 +1109,7 @@ as a regexp. See the command `isearch-forward' for more information. In incremental searches, a space or spaces normally matches any whitespace defined by the variable `search-whitespace-regexp'. -To search for a literal space and nothing else, enter C-q SPC. +To search for a literal space and nothing else, enter \\`C-q SPC'. To toggle whitespace matching, use `isearch-toggle-lax-whitespace', usually bound to \\`M-s SPC' during isearch. This command does not support character folding." @@ -3557,7 +3556,8 @@ the word mode." (defun isearch-lazy-count-format (&optional suffix-p) "Format the current match number and the total number of matches. When SUFFIX-P is non-nil, the returned string is intended for -isearch-message-suffix prompt. Otherwise, for isearch-message-prefix." +`isearch-message-suffix' prompt. Otherwise, for +`isearch-message-prefix'." (let ((format-string (if suffix-p lazy-count-suffix-format lazy-count-prefix-format))) diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el index e6c2b9e05c0..77efcf0b590 100644 --- a/lisp/jsonrpc.el +++ b/lisp/jsonrpc.el @@ -125,7 +125,7 @@ size of the log buffer (0 disables, nil means infinite). The t)) (when e-b-s-s-supplied-p (warn - "`:events-buffer-scrollback-size' deprecated. Use `events-buffer-config'.") + "`:events-buffer-scrollback-size' deprecated. Use `events-buffer-config'.") (with-slots ((plist -events-buffer-config)) c (setf plist (copy-sequence plist) plist (plist-put plist :size events-buffer-scrollback-size))))) @@ -825,7 +825,7 @@ Return the full continuation (ID SUCCESS-FN ERROR-FN TIMER)" (cond (anxious (when (not (= (car head) id)) ; sanity check - (error "internal error: please report this bug")) + (error "Internal error: please report this bug")) ;; If there are "anxious" `jsonrpc-request' continuations ;; that should already have been run, they should run now. ;; The main continuation -- if it exists -- should run diff --git a/lisp/mouse-copy.el b/lisp/mouse-copy.el index 0c4e7bcb566..91024d6a447 100644 --- a/lisp/mouse-copy.el +++ b/lisp/mouse-copy.el @@ -184,10 +184,9 @@ put the point at one place, then click and drag over some other region." This command is like \\[mouse-kill-secondary] (that is, the secondary selection is deleted and placed in the kill ring), except that it also -leaves the secondary buffer active on exit. - -This command was derived from mouse-kill-secondary in emacs-19.28 -by johnh@ficus.cs.ucla.edu." +leaves the secondary buffer active on exit." + ;; This command was derived from mouse-kill-secondary in emacs-19.28 + ;; by johnh@ficus.cs.ucla.edu. (interactive) (let* ((keys (this-command-keys)) (click (elt keys (1- (length keys))))) @@ -202,7 +201,7 @@ by johnh@ficus.cs.ucla.edu." ;; (delete-overlay mouse-secondary-overlay) ;; (gui-set-selection 'SECONDARY nil) ;; (setq mouse-secondary-overlay nil) -) + ) (defun mouse-drag-secondary-moving (start-event) "Sweep out a secondary selection, then move it to the current point." diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el index 1f963ee8114..5b2dc089a52 100644 --- a/lisp/pixel-scroll.el +++ b/lisp/pixel-scroll.el @@ -289,7 +289,7 @@ This is and alternative of `scroll-down'. Scope moves upward." (put 'pixel-scroll-down 'scroll-command t) (defun pixel-bob-at-top-p (amt) - "Return non-nil if window-start is at beginning of the current buffer. + "Return non-nil if `window-start' is at beginning of the current buffer. Window must be vertically scrolled by not more than AMT pixels." (and (equal (window-start) (point-min)) (< (window-vscroll nil t) amt))) @@ -492,8 +492,8 @@ unseen line just above the scope of current window." (defun pixel-scroll-down-and-set-window-vscroll (vscroll) "Scroll down a line and set VSCROLL in pixels. -It is important to call `set-window-start' to force the display -engine use that particular position as the window-start point. +It is important to call `set-window-start' to force the display engine +to use that particular position as the `window-start' point. Otherwise, redisplay will reset the window's vscroll." (set-window-start nil (pixel-point-at-unseen-line) t) (set-window-vscroll nil vscroll t)) diff --git a/lisp/printing.el b/lisp/printing.el index cbb78265f3c..b4c57fdbbde 100644 --- a/lisp/printing.el +++ b/lisp/printing.el @@ -1858,8 +1858,7 @@ Useful links: `http://pages.cs.wisc.edu/~ghost/gv/gv_doc/gv.html' * MacGSView (Mac OS) - `http://pages.cs.wisc.edu/~ghost/macos/index.htm' -" + `http://pages.cs.wisc.edu/~ghost/macos/index.htm'" :type '(string :tag "Ghostview Utility")) @@ -1883,8 +1882,7 @@ Useful links: `https://www.cs.wisc.edu/~ghost/doc/cvs/Use.htm' * Printer compatibility - `https://www.cs.wisc.edu/~ghost/doc/printer.htm' -" + `https://www.cs.wisc.edu/~ghost/doc/printer.htm'" :type '(string :tag "Ghostscript Utility")) @@ -1924,8 +1922,7 @@ Useful links: `https://www.cs.wisc.edu/~ghost/doc/cvs/Use.htm' * Printer compatibility - `https://www.cs.wisc.edu/~ghost/doc/printer.htm' -" + `https://www.cs.wisc.edu/~ghost/doc/printer.htm'" :type '(repeat (string :tag "Ghostscript Switch"))) diff --git a/lisp/register.el b/lisp/register.el index 822467a0d72..df00c9dc24f 100644 --- a/lisp/register.el +++ b/lisp/register.el @@ -131,16 +131,16 @@ to the value of `register--read-with-preview-function'.") (defcustom register-use-preview 'traditional "Whether to show register preview when modifying registers. -When set to `t', show a preview buffer with navigation and +When set to t, show a preview buffer with navigation and highlighting. -When set to \\='insist, behave as with `t', but allow exiting the +When set to \\='insist, behave as with t, but allow exiting the minibuffer by pressing the register name a second time. E.g., press \"a\" to select register \"a\", then press \"a\" again to exit the minibuffer. When nil, show a preview buffer without navigation and highlighting, and exit the minibuffer immediately after inserting response in minibuffer. When set to \\='never, behave as with nil, but with no preview buffer at -all; the preview buffer is still accessible with `help-char' (C-h). +all; the preview buffer is still accessible with `help-char' (\\`C-h'). When set to \\='traditional (the default), provide a more basic preview according to `register-preview-delay'; this preserves the traditional behavior of Emacs 29 and before." diff --git a/lisp/repeat.el b/lisp/repeat.el index 374a925d70c..1de26826ea1 100644 --- a/lisp/repeat.el +++ b/lisp/repeat.el @@ -384,14 +384,14 @@ When non-nil, and the last typed key (with or without modifiers) doesn't exist in the keymap specified by the `repeat-map' property of the command, don't activate that keymap for the next command. Thus, when this is non-nil, only the same keys among repeatable -keys are allowed in the repeating sequence. For example, with a +keys are allowed in the repeating sequence. For example, with a non-nil value, only \\`C-x u u' repeats undo, whereas \\`C-/ u' doesn't. You can also set the property `repeat-check-key' on the command symbol. This property can override the value of this variable. When the variable value is non-nil, but the property value is `no', then don't check the last key. Also when the variable value is nil, -but the property value is `t', then check the last key." +but the property value is t, then check the last key." :type 'boolean :group 'repeat :version "28.1") diff --git a/lisp/saveplace.el b/lisp/saveplace.el index a4942cb484b..012e305f7f4 100644 --- a/lisp/saveplace.el +++ b/lisp/saveplace.el @@ -151,7 +151,7 @@ different hosts. Changing this option requires rewriting `save-place-alist' with corresponding file name format, therefore setting this option just using `setq' may cause out-of-sync problems. You should use -either `setopt' or M-x customize-variable to set this option." +either `setopt' or \\[customize-variable] to set this option." :type 'boolean :set (lambda (sym val) (set-default sym val) diff --git a/lisp/select.el b/lisp/select.el index ab78e88478b..77783d5e51a 100644 --- a/lisp/select.el +++ b/lisp/select.el @@ -153,7 +153,7 @@ systems that support it, save the selection timestamp too." (defun gui--clipboard-selection-unchanged-p (text) "Check whether the clipboard selection has changed. Compare the selection text, passed as argument, with the text -from the last saved selection. For window systems that support +from the last saved selection. For window systems that support it, compare the selection timestamp too." (and (equal text gui--last-selected-text-clipboard) diff --git a/lisp/ses.el b/lisp/ses.el index fcbb0567901..c9bd0ab18da 100644 --- a/lisp/ses.el +++ b/lisp/ses.el @@ -649,8 +649,8 @@ for safety. This is a macro to prevent propagate-on-load viruses." t) (defmacro ses-header-row (row) - "Load the header row from the spreadsheet file and check it -for safety. This is a macro to prevent propagate-on-load viruses." + "Load the header row from the spreadsheet file and check it for safety. +This is a macro to prevent propagate-on-load viruses." (or (and (wholenump row) (or (zerop ses--numrows) (< row ses--numrows))) (error "Bad header-row")) (setq ses--header-row row) diff --git a/lisp/simple.el b/lisp/simple.el index 17625fad66f..5961afa20e9 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -8652,7 +8652,7 @@ are interchanged." (transpose-subr 'forward-word arg)) (defun transpose-sexps-default-function (arg) - "Default method to locate a pair of points for transpose-sexps." + "Default method to locate a pair of points for `transpose-sexps'." ;; Here we should try to simulate the behavior of ;; (cons (progn (forward-sexp x) (point)) ;; (progn (forward-sexp (- x)) (point))) @@ -10733,10 +10733,10 @@ option's default value is set to t, so that Backspace can be used to delete backward, and Delete can be used to delete forward. If not running under a window system, customizing this option -accomplishes a similar effect by mapping C-h, which is usually -generated by the Backspace key, to DEL, and by mapping DEL to C-d -via `keyboard-translate'. The former functionality of C-h is -available on the F1 key. You should probably not use this +accomplishes a similar effect by mapping \\`C-h', which is usually +generated by the Backspace key, to \\`DEL', and by mapping \\`DEL' to +\\`C-d' via `keyboard-translate'. The former functionality of \\`C-h' +is available on the F1 key. You should probably not use this setting if you don't have both Backspace, Delete and F1 keys. Setting this variable with setq doesn't take effect. Programmatically, @@ -10779,27 +10779,27 @@ call `normal-erase-is-backspace-mode' (which see) instead." (define-minor-mode normal-erase-is-backspace-mode "Toggle the Erase and Delete mode of the Backspace and Delete keys. -On window systems, when this mode is on, Delete is mapped to C-d -and Backspace is mapped to DEL; when this mode is off, both -Delete and Backspace are mapped to DEL. (The remapping goes via +On window systems, when this mode is on, Delete is mapped to \\`C-d' +and Backspace is mapped to \\`DEL'; when this mode is off, both +Delete and Backspace are mapped to \\`DEL'. (The remapping goes via `local-function-key-map', so binding Delete or Backspace in the global or local keymap will override that.) In addition, on window systems, the bindings of C-Delete, M-Delete, C-M-Delete, C-Backspace, M-Backspace, and C-M-Backspace are changed in the global keymap in accordance with the functionality of Delete and -Backspace. For example, if Delete is remapped to C-d, which deletes +Backspace. For example, if Delete is remapped to \\`C-d', which deletes forward, C-Delete is bound to `kill-word', but if Delete is remapped -to DEL, which deletes backward, C-Delete is bound to +to \\`DEL', which deletes backward, C-Delete is bound to `backward-kill-word'. If not running on a window system, a similar effect is accomplished by -remapping C-h (normally produced by the Backspace key) and DEL via -`keyboard-translate': if this mode is on, C-h is mapped to DEL and DEL -to C-d; if it's off, the keys are not remapped. +remapping \\`C-h' (normally produced by the Backspace key) and \\`DEL' +via `keyboard-translate': if this mode is on, \\`C-h' is mapped to +\\`DEL' and \\`DEL' to \\`C-d'; if it's off, the keys are not remapped. When not running on a window system, and this mode is turned on, the -former functionality of C-h is available on the F1 key. You should +former functionality of \\`C-h' is available on the F1 key. You should probably not turn on this mode on a text-only terminal if you don't have both Backspace, Delete and F1 keys. diff --git a/lisp/sqlite-mode.el b/lisp/sqlite-mode.el index 7b1a9ce2e88..35ac5871799 100644 --- a/lisp/sqlite-mode.el +++ b/lisp/sqlite-mode.el @@ -42,7 +42,7 @@ "DEL" #'sqlite-mode-delete) (define-derived-mode sqlite-mode special-mode "Sqlite" - "This mode lists the contents of an .sqlite3 file" + "This mode lists the contents of an .sqlite3 file." :interactive nil (buffer-disable-undo) (setq-local buffer-read-only t diff --git a/lisp/tempo.el b/lisp/tempo.el index b7ad680c2a9..3d3a0ca54aa 100644 --- a/lisp/tempo.el +++ b/lisp/tempo.el @@ -119,7 +119,7 @@ user for text to insert in the templates." :type 'boolean) (defcustom tempo-insert-region nil - "Automatically insert current region when there is a `r' in the template + "Automatically insert current region when there is a `r' in the template. If this variable is nil, `r' elements will be treated just like `p' elements, unless the template function is given a prefix (or a non-nil argument). If this variable is non-nil, the behavior is reversed. diff --git a/lisp/term.el b/lisp/term.el index 0cfff4ef981..9a8dc25e1a2 100644 --- a/lisp/term.el +++ b/lisp/term.el @@ -658,8 +658,8 @@ executed once, when the buffer is created." ["Forward Output Group" term-next-prompt t] ["Kill Current Output Group" term-kill-output t])) map) - "Keymap for \"line mode\" in Term mode. For custom keybindings purposes -please note there is also `term-raw-map'") + "Keymap for \"line mode\" in Term mode. +For custom keybindings purposes please note there is also `term-raw-map'") (defvar term-escape-char nil "Escape character for char sub-mode of term mode. @@ -1097,7 +1097,7 @@ The interpreter name is same as buffer name, sans the asterisks. There are two submodes: line mode and char mode. By default, you are in char mode. In char sub-mode, each character (except `term-escape-char') is sent immediately to the subprocess. -The escape character is equivalent to the usual meaning of C-x. +The escape character is equivalent to the usual meaning of \\`C-x'. In line mode, you send a line of input at a time; use \\[term-send-input] to send. @@ -1459,7 +1459,7 @@ Entry to this mode runs the hooks on `term-mode-hook'." (defun term-char-mode () "Switch to char (\"raw\") sub-mode of term mode. Each character you type is sent directly to the inferior without -intervention from Emacs, except for the escape character (usually C-c)." +intervention from Emacs, except for the escape character (usually \\`C-c')." (interactive) ;; FIXME: Emit message? Cfr ilisp-raw-message (when (term-in-line-mode) commit 9f4fc6608212191e1a9e07bf89f38ba9e4ea786c Author: Paul Eggert Date: Fri Jul 19 13:39:21 2024 -0700 Work around GCC bug 58416 on 32-bit x86 * configure.ac (C_SWITCH_MATCHINE): On 32-bit x86 with GCC 4+, append -mfpmath=sse (if SSE2 is known to work) or -fno-tree-sra (otherwise) to work around GCC bug 58416. * etc/NEWS: Mention this. diff --git a/configure.ac b/configure.ac index b6acdf2e456..67da852667d 100644 --- a/configure.ac +++ b/configure.ac @@ -2333,6 +2333,51 @@ case $canonical in fi ;; esac + +AC_CACHE_CHECK([for flags to work around GCC bug 58416], + [emacs_cv_gcc_bug_58416_CFLAGS], + [emacs_cv_gcc_bug_58416_CFLAGS='none needed' + AS_CASE([$canonical], + [[i[3456]86-* | x86_64-*]], + [AS_IF([test "$GCC" = yes], + [old_CFLAGS=$CFLAGS + # If no flags are needed (e.g., not GCC 4+), don't use any. + # Otherwise, use -mfpmath=sse if already assuming SSE2. + # Otherwise, use -fno-tree-sra. + for emacs_cv_gcc_bug_58416_CFLAGS in \ + 'none needed' -mfpmath=sse -fno-tree-sra + do + AS_CASE([$emacs_cv_gcc_bug_58416_CFLAGS], + ['none needed'], [], + [-fno-tree-sra], [break], + [CFLAGS="$old_CFLAGS $emacs_cv_gcc_bug_58416_CFLAGS"]) + AC_COMPILE_IFELSE( + [AC_LANG_DEFINES_PROVIDED + [/* Work around GCC bug with double in unions on x86, + where the generated insns copy non-floating-point data + via fldl/fstpl instruction pairs. This can misbehave + the data's bit pattern looks like a NaN. See, e.g.: + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58416#c10 + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71460 + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93271 + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114659 + Problem observed with 'gcc -m32' with GCC 14.1.1 + 20240607 (Red Hat 14.1.1-5) on x86-64. */ + #include + #if \ + (4 <= __GNUC__ && !defined __clang__ \ + && (defined __i386__ || defined __x86_64__) \ + && ! (0 <= FLT_EVAL_METHOD && FLT_EVAL_METHOD <= 1)) + # error "GCC bug 58416 is possibly present" + #endif + ]], + [break]) + done + CFLAGS=$old_CFLAGS])])]) +AS_CASE([$emacs_cv_gcc_bug_58416_CFLAGS], + [-*], + [C_SWITCH_MACHINE="$C_SWITCH_MACHINE $emacs_cv_gcc_bug_58416_CFLAGS"]) + AC_SUBST([C_SWITCH_MACHINE]) C_SWITCH_SYSTEM= diff --git a/etc/NEWS b/etc/NEWS index 5429db1dded..0e13f471c74 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -24,6 +24,12 @@ applies, and please also update docstrings as needed. * Installation Changes in Emacs 31.1 +** When using GCC 4 or later to build Emacs on 32-bit x86 systems, +'configure' now defaults to using the GCC options -mfpmath=sse (if the +host system supports SSE2) or -fno-tree-sra (if not). These GCC options +work around GCC bug 58416, which can cause Emacs to behave incorrectly +in rare cases. + * Startup Changes in Emacs 31.1 commit 524e9d50a78c019ab23ecf469787d5ff6c119025 Author: Paul Eggert Date: Fri Jul 19 12:44:35 2024 -0700 In ‘INSTALL’ put configure vars in one section * INSTALL: Move description of CFLAGS etc. into the section headed “Here is a complete list of the variables you may want to set” since they are also variables one might want to set. diff --git a/INSTALL b/INSTALL index d5ce16db147..e80051faaa1 100644 --- a/INSTALL +++ b/INSTALL @@ -517,12 +517,8 @@ Some tests might fail because the compiler should look in special directories for some header files, or link against optional libraries, or use special compilation options. You can force 'configure' and the build process which follows it to do that by -setting the variables CPPFLAGS, CFLAGS, LDFLAGS, LIBS, CPP and CC -before running 'configure'. CPP is the command which invokes the -preprocessor, CPPFLAGS lists the options passed to it, CFLAGS are -compilation options, LDFLAGS are options used when linking, LIBS are -libraries to link against, and CC is the command which invokes the -compiler. By default, gcc is used if available. +setting the variables CC, CFLAGS, CPP, CPPFLAGS, LDFLAGS, and LIBS in +the 'configure' command. Here's an example of a 'configure' invocation, assuming a Bourne-like shell such as Bash, which uses these variables: @@ -689,8 +685,9 @@ configuration), type 'make distclean'. MAKE VARIABLES You can change where the build process installs Emacs and its data -files by specifying values for 'make' variables as part of the 'make' -command line. For example, if you type +files, and what programs and options the build process uses, by +specifying values for 'make' variables as part of the 'make' command +line. For example, if you type make install bindir=/usr/local/gnubin @@ -760,6 +757,19 @@ Here is a complete list of the variables you may want to set. determines the default values for the architecture-dependent path variables - 'bindir' and 'libexecdir'. +'CC' is the command which invokes the compiler. By default, gcc is used + if available. + +'CFLAGS' are compilation options. + +'CPP' is the command which invokes the preprocessor. + +'CPPFLAGS' lists the options passed to CPP. + +'LDFLAGS' are options used when linking. + +'LIBS' are libraries to link against. + The above variables serve analogous purposes in the makefiles for all GNU software; the following variables are specific to Emacs. commit 153732e63813d34b057ab24fbd9e134bd3be6eaa Merge: 6c96d062815 a478423d19f Author: Stefan Monnier Date: Fri Jul 19 14:31:53 2024 -0400 Merge from origin/emacs-30 a478423d19f * lisp/progmodes/peg.el (peg-syntax-classes): Typo (bug#7... 951fb93956d * lisp/transient.el (static-if): Remove duplicated defini... 0218fb21437 Adapt file-remote-p doc 34c1094e607 ; Fix typo in etc/ORG-NEWS (Bug#72186) 5916b172bdc * etc/TODO: Delete item about merging Magit. a6cab228d4d ; Fix typos 41dc28244f2 * doc/man/emacs.1.in: Add "No warranty" notice. b2ac3435867 ; * doc/man/emacs.1.in: Improve wording. 110b3d08d73 Improve emacs man page description of --user flag 4911f08912a Checkdoc fixes in allout-widgets.el 109b592d77b Checkdoc fixes in subr.el 46436720787 Checkdoc fixes in touch-screen.el 9889774c62e Checkdoc fixes in treesit.el # Conflicts: # etc/NEWS commit 6c96d062815b8949dc5af7d544c8aaf048433bb1 Merge: b7893e73878 c9d28a05d98 Author: Stefan Monnier Date: Fri Jul 19 14:31:50 2024 -0400 ; Merge from origin/emacs-30 The following commit was skipped: c9d28a05d98 Avoid overflow in pgtk_is_numeric_char commit b7893e73878df83043e05dc8cb811971c0e99f03 Author: Jim Porter Date: Fri Jul 19 09:34:03 2024 -0700 Don't set exit info in Eshell if the command is being piped elsewhere Previously, the exit info in Eshell was that of the last command that finished, rather than the last command in a pipeline. * lisp/eshell/esh-cmd.el (eshell-exec-lisp) (eshell-lisp-command): Check whether the command is being piped. * lisp/eshell/esh-proc.el (eshell-gather-process-output): Record whether the command is being piped... (eshell-sentinel): ... and do the right thing with that info. * test/lisp/eshell/esh-proc-tests.el (esh-proc-test/sigpipe-exits-process): Check the exit status to ensure we don't report the first process's SIGPIPE exit. diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index d21ac850c02..2b47962735a 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -1425,10 +1425,12 @@ case." ;; command status to some non-zero value to indicate an error; to ;; match GNU/Linux, we use 141, which the numeric value of ;; SIGPIPE on GNU/Linux (13) with the high bit (2^7) set. - (eshell-set-exit-info 141) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info 141)) nil) (error - (eshell-set-exit-info 1) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info 1)) (let ((msg (error-message-string err))) (if (and (not form-p) (string-match "^Wrong number of arguments" msg) @@ -1507,7 +1509,8 @@ a string naming a Lisp function." (unless eshell-allow-commands (signal 'eshell-commands-forbidden '(lisp))) (catch 'eshell-external ; deferred to an external command - (eshell-set-exit-info 0) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info 0)) (setq eshell-last-arguments args) (let* ((eshell-ensure-newline-p t) (command-form-p (functionp object)) @@ -1543,16 +1546,17 @@ a string naming a Lisp function." (eshell-eval* #'eshell-print-maybe-n #'eshell-error-maybe-n object)))) - (eshell-set-exit-info - ;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms - ;; that succeeded but have a nil result should have an exit - ;; status of 2. - (when (and eshell-lisp-form-nil-is-failure - (not command-form-p) - (= eshell-last-command-status 0) - (not result)) - 2) - result) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info + ;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms + ;; that succeeded but have a nil result should have an exit + ;; status of 2. + (when (and eshell-lisp-form-nil-is-failure + (not command-form-p) + (= eshell-last-command-status 0) + (not result)) + 2) + result)) (eshell-close-handles)))) (define-obsolete-function-alias 'eshell-lisp-command* #'eshell-lisp-command diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index 2735be882b6..dc7b497666b 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -394,6 +394,9 @@ Used only on systems which do not support async subprocesses.") (mapconcat #'shell-quote-argument (process-command proc) " ")) (eshell-record-process-object proc) (eshell-record-process-properties proc) + ;; Don't set exit info for processes being piped elsewhere. + (when (memq (bound-and-true-p eshell-in-pipeline-p) '(nil last)) + (process-put proc :eshell-set-exit-info t)) (when stderr-proc ;; Provide a shared flag between the primary and stderr ;; processes. This lets the primary process wait to clean up @@ -546,6 +549,7 @@ PROC is the process that's exiting. STRING is the exit message." (let* ((handles (process-get proc :eshell-handles)) (index (process-get proc :eshell-handle-index)) (primary (= index eshell-output-handle)) + (set-exit-info (process-get proc :eshell-set-exit-info)) (data (process-get proc :eshell-pending)) (stderr-live (process-get proc :eshell-stderr-live))) ;; Write the exit message for the last process in the @@ -576,7 +580,7 @@ PROC is the process that's exiting. STRING is the exit message." (ignore-error eshell-pipe-broken (eshell-output-object data index handles))) - (when primary + (when set-exit-info (let ((status (process-exit-status proc))) (eshell-set-exit-info status (= status 0)))) (eshell-close-handles handles) diff --git a/test/lisp/eshell/esh-proc-tests.el b/test/lisp/eshell/esh-proc-tests.el index d46004688f9..3121e751006 100644 --- a/test/lisp/eshell/esh-proc-tests.el +++ b/test/lisp/eshell/esh-proc-tests.el @@ -167,7 +167,10 @@ See bug#71778." "sh -c 'read NAME; echo ${NAME}'") "y\n") (eshell-wait-for-subprocess t) - (should (equal (process-list) starting-process-list))))) + (should (equal (process-list) starting-process-list)) + ;; Make sure the exit status is from the last command in the + ;; pipeline. + (should (= eshell-last-command-status 0))))) (ert-deftest esh-proc-test/pipeline-connection-type/no-pipeline () "Test that all streams are PTYs when a command is not in a pipeline." commit 39c704e03de59a1cc46494fb71426e7a7fe8013d Author: Jim Porter Date: Mon Jan 23 17:21:57 2023 -0800 Split out exit code parts of 'eshell-close-handles' into a new function * lisp/eshell/esh-cmd.el (eshell-last-command-status) (eshell-last-command-result): Move here from esh-io.el. (eshell-set-exit-info): New function, extracted from 'eshell-close-handles'. * lisp/eshell/esh-io.el (eshell-close-handles): Make old calling convention obsolete. Update callers to use 'eshell-set-exit-info' as needed. diff --git a/lisp/eshell/em-alias.el b/lisp/eshell/em-alias.el index ff0620702cf..aa6eb2d4efb 100644 --- a/lisp/eshell/em-alias.el +++ b/lisp/eshell/em-alias.el @@ -211,7 +211,8 @@ This is useful after manually editing the contents of the file." (let ((eshell-current-handles (eshell-create-handles eshell-aliases-file 'overwrite))) (eshell/alias) - (eshell-close-handles 0 'nil)))) + (eshell-set-exit-info 0 nil) + (eshell-close-handles)))) (defsubst eshell-lookup-alias (name) "Check whether NAME is aliased. Return the alias if there is one." diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 099e97a083d..d21ac850c02 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -104,7 +104,6 @@ (require 'esh-arg) (require 'esh-proc) (require 'esh-module) -(require 'esh-io) (require 'esh-ext) (require 'eldoc) @@ -276,8 +275,13 @@ Each element is of the form (FORM PROCESSES), as with Has the value `first', `last' for the first/last commands in the pipeline, otherwise t.") (defvar eshell-in-subcommand-p nil) + (defvar eshell-last-arguments nil) (defvar eshell-last-command-name nil) +(defvar-local eshell-last-command-status 0 + "The exit code from the last command. 0 if successful.") +(defvar-local eshell-last-command-result nil + "The result of the last command. Not related to success.") (defvar eshell-deferrable-commands '(eshell-deferrable) "A list of functions which might return a deferrable process. @@ -518,7 +522,6 @@ the second is ignored." `(eshell-commands ,(cadr (cadr arg)) ,silent)) arg)) -(defvar eshell-last-command-status) ;Define in esh-io.el. (defvar eshell--local-vars nil "List of locally bound vars that should take precedence over env-vars.") @@ -610,7 +613,13 @@ must be implemented via rewriting, rather than as a function." `(eshell-protect ,(eshell-invokify-arg (car (last terms)) t)))))) -(defvar eshell-last-command-result) ;Defined in esh-io.el. +(defun eshell-set-exit-info (status &optional result) + "Set the exit status and result for the last command. +STATUS is the process exit code (zero, if the command completed +successfully). RESULT is the value of the last command." + (when status + (setq eshell-last-command-status status)) + (setq eshell-last-command-result result)) (defun eshell-exit-success-p () "Return non-nil if the last command was successful. @@ -787,7 +796,8 @@ this grossness will be made to disappear by using `call/cc'..." (mapc #'funcall eshell-this-command-hook))) (error (eshell-errorn (error-message-string err)) - (eshell-close-handles 1)))) + (eshell-set-exit-info 1) + (eshell-close-handles)))) (define-obsolete-function-alias 'eshell-trap-errors #'eshell-do-command "31.1") @@ -1415,10 +1425,10 @@ case." ;; command status to some non-zero value to indicate an error; to ;; match GNU/Linux, we use 141, which the numeric value of ;; SIGPIPE on GNU/Linux (13) with the high bit (2^7) set. - (setq eshell-last-command-status 141) + (eshell-set-exit-info 141) nil) (error - (setq eshell-last-command-status 1) + (eshell-set-exit-info 1) (let ((msg (error-message-string err))) (if (and (not form-p) (string-match "^Wrong number of arguments" msg) @@ -1497,8 +1507,8 @@ a string naming a Lisp function." (unless eshell-allow-commands (signal 'eshell-commands-forbidden '(lisp))) (catch 'eshell-external ; deferred to an external command - (setq eshell-last-command-status 0 - eshell-last-arguments args) + (eshell-set-exit-info 0) + (setq eshell-last-arguments args) (let* ((eshell-ensure-newline-p t) (command-form-p (functionp object)) (result @@ -1533,7 +1543,7 @@ a string naming a Lisp function." (eshell-eval* #'eshell-print-maybe-n #'eshell-error-maybe-n object)))) - (eshell-close-handles + (eshell-set-exit-info ;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms ;; that succeeded but have a nil result should have an exit ;; status of 2. @@ -1542,7 +1552,8 @@ a string naming a Lisp function." (= eshell-last-command-status 0) (not result)) 2) - (list 'quote result))))) + result) + (eshell-close-handles)))) (define-obsolete-function-alias 'eshell-lisp-command* #'eshell-lisp-command "31.1") diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el index 9de9cc4509a..cf7336bd70d 100644 --- a/lisp/eshell/esh-io.el +++ b/lisp/eshell/esh-io.el @@ -200,12 +200,6 @@ describing the mode, e.g. for using with `eshell-get-target'.") (defvar eshell-current-handles nil) -(defvar-local eshell-last-command-status 0 - "The exit code from the last command. 0 if successful.") - -(defvar eshell-last-command-result nil - "The result of the last command. Not related to success.") - (defvar eshell-output-file-buffer nil "If non-nil, the current buffer is a file output buffer.") @@ -382,23 +376,27 @@ is not shared with the original handles." (cl-incf (cdar handle)))) handles) -(defun eshell-close-handles (&optional exit-code result handles) +(declare-function eshell-exit-success-p "esh-cmd") + +(defun eshell-close-handles (&optional handles obsolete-1 obsolete-2) "Close all of the current HANDLES, taking refcounts into account. -If HANDLES is nil, use `eshell-current-handles'. +If HANDLES is nil, use `eshell-current-handles'." + (declare (advertised-calling-convention (&optional handles) "30.1")) + (when (or obsolete-1 obsolete-2 (numberp handles)) + (declare-function eshell-set-exit-info "esh-cmd" + (&optional exit-code result)) + ;; In addition to setting the advertised calling convention, warn + ;; if we get here. A caller may have called with the right number + ;; of arguments but the wrong type. + (display-warning '(eshell close-handles) + "Called `eshell-close-handles' with obsolete arguments") + ;; Here, HANDLES is really the exit code. + (when (or handles obsolete-1) + (eshell-set-exit-info (or handles 0) (cadr obsolete-1))) + (setq handles obsolete-2)) -EXIT-CODE is the process exit code (zero, if the command -completed successfully). If nil, then use the exit code already -set in `eshell-last-command-status'. - -RESULT is the quoted value of the last command. If nil, then use -the value already set in `eshell-last-command-result'." - (when exit-code - (setq eshell-last-command-status exit-code)) - (when result - (cl-assert (eq (car result) 'quote)) - (setq eshell-last-command-result (cadr result))) (let ((handles (or handles eshell-current-handles)) - (succeeded (= eshell-last-command-status 0))) + (succeeded (eshell-exit-success-p))) (dotimes (idx eshell-number-of-handles) (eshell-close-handle (aref handles idx) succeeded)))) diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index ed417ab0f12..2735be882b6 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -129,6 +129,7 @@ To add or remove elements of this list, see (declare-function eshell-reset "esh-mode" (&optional no-hooks)) (declare-function eshell-send-eof-to-process "esh-mode") (declare-function eshell-interactive-filter "esh-mode" (buffer string)) +(declare-function eshell-set-exit-info "esh-cmd" (status result)) (declare-function eshell-tail-process "esh-cmd") (defvar-keymap eshell-proc-mode-map @@ -460,10 +461,11 @@ Used only on systems which do not support async subprocesses.") (setq lbeg lend) (set-buffer proc-buf)) (set-buffer oldbuf)) - ;; Simulate the effect of eshell-sentinel. - (eshell-close-handles + ;; Simulate the effect of `eshell-sentinel'. + (eshell-set-exit-info (if (numberp exit-status) exit-status -1) - (list 'quote (and (numberp exit-status) (= exit-status 0)))) + (and (numberp exit-status) (= exit-status 0))) + (eshell-close-handles) (run-hook-with-args 'eshell-kill-hook command exit-status) (or (bound-and-true-p eshell-in-pipeline-p) (setq eshell-last-sync-output-start nil)) @@ -545,9 +547,6 @@ PROC is the process that's exiting. STRING is the exit message." (index (process-get proc :eshell-handle-index)) (primary (= index eshell-output-handle)) (data (process-get proc :eshell-pending)) - ;; Only get the status for the primary subprocess, - ;; not the pipe process (if any). - (status (when primary (process-exit-status proc))) (stderr-live (process-get proc :eshell-stderr-live))) ;; Write the exit message for the last process in the ;; foreground pipeline if its status is abnormal and @@ -577,10 +576,10 @@ PROC is the process that's exiting. STRING is the exit message." (ignore-error eshell-pipe-broken (eshell-output-object data index handles))) - (eshell-close-handles - status - (when status (list 'quote (= status 0))) - handles) + (when primary + (let ((status (process-exit-status proc))) + (eshell-set-exit-info status (= status 0)))) + (eshell-close-handles handles) ;; Clear the handles to mark that we're 100% ;; finished with the I/O for this process. (process-put proc :eshell-handles nil) commit a478423d19fe320972fc319dd2cf7fdbca914754 Author: Stefan Monnier Date: Fri Jul 19 14:18:29 2024 -0400 * lisp/progmodes/peg.el (peg-syntax-classes): Typo (bug#72131) diff --git a/lisp/progmodes/peg.el b/lisp/progmodes/peg.el index d19a48c3294..96334162195 100644 --- a/lisp/progmodes/peg.el +++ b/lisp/progmodes/peg.el @@ -698,7 +698,7 @@ rulesets defined previously with `define-peg-ruleset'." (cl-defmethod peg--translate ((_ (eql guard)) exp) exp) (defvar peg-syntax-classes - '((whitespace ?-) (word ?w) (symbol ?s) (punctuation ?.) + '((whitespace ?-) (word ?w) (symbol ?_) (punctuation ?.) (open ?\() (close ?\)) (string ?\") (escape ?\\) (charquote ?/) (math ?$) (prefix ?') (comment ?<) (endcomment ?>) (comment-fence ?!) (string-fence ?|))) commit 34b832fce1d01c22aa644196cd6e6b50b1d403ee Author: Philip Kaludercic Date: Fri Jul 19 10:43:11 2024 +0200 * lisp/which-key.el: Bump version to 3.6.1 This is necessary to trigger a new ELPA release. diff --git a/lisp/which-key.el b/lisp/which-key.el index 37b42a009f7..198a92fe36c 100644 --- a/lisp/which-key.el +++ b/lisp/which-key.el @@ -4,7 +4,7 @@ ;; Author: Justin Burkett ;; Maintainer: Justin Burkett -;; Version: 3.6.0 +;; Version: 3.6.1 ;; Package-Requires: ((emacs "25.1")) ;; This file is part of GNU Emacs. commit f591f477791aafbfe1086398fefdafed213b6ced Author: Mattias Engdegård Date: Fri Jul 19 19:35:35 2024 +0200 ; * test/lisp/net/dbus-tests.el: silence compilation warnings diff --git a/test/lisp/net/dbus-tests.el b/test/lisp/net/dbus-tests.el index 040e006f688..af6a98ae033 100644 --- a/test/lisp/net/dbus-tests.el +++ b/test/lisp/net/dbus-tests.el @@ -26,6 +26,7 @@ (require 'dbus) (defvar dbus-debug) +(defvar dbus-message-type-signal) (declare-function dbus-get-unique-name "dbusbind.c" (bus)) (defconst dbus--test-enabled-session-bus @@ -732,7 +733,7 @@ is in progress." ;; Cleanup. (dbus-unregister-service :session dbus--test-service))) -(defun dbus--test-method-authorizable-handler (&rest args) +(defun dbus--test-method-authorizable-handler (&rest _args) "Method handler for `dbus-test04-call-method-authorizable'. Returns the respective error." `(:error ,dbus-error-interactive-authorization-required commit c330b97fe24088c32394fae7f52aa18315d123b0 Author: Peder O. Klingenberg Date: Thu Jul 18 22:34:54 2024 +0200 Visualize ranking of last game when adding scores * lisp/play/gamegrid.el (gamegrid-add-score-insecure): Move point to the score just added, or end of buffer if the new score did not make the list. This makes it easier to see where the last game ranked. (Bug#72185) diff --git a/lisp/play/gamegrid.el b/lisp/play/gamegrid.el index a098d0f6f69..36c72c5cff7 100644 --- a/lisp/play/gamegrid.el +++ b/lisp/play/gamegrid.el @@ -639,27 +639,31 @@ FILE is created there." (defun gamegrid-add-score-insecure (file score &optional directory reverse) (save-excursion - (setq file (expand-file-name file (or directory - temporary-file-directory))) - (unless (file-exists-p (file-name-directory file)) - (make-directory (file-name-directory file) t)) - (find-file-other-window file) - (setq buffer-read-only nil) - (goto-char (point-max)) - (insert (format "%05d\t%s\t%s <%s>\n" - score - (current-time-string) - (user-full-name) - user-mail-address)) - (sort-fields 1 (point-min) (point-max)) - (unless reverse - (reverse-region (point-min) (point-max))) - (goto-char (point-min)) - (forward-line gamegrid-score-file-length) - (delete-region (point) (point-max)) - (setq buffer-read-only t) - (save-buffer) - (view-mode))) + (let ((score-line (format "%05d\t%s\t%s <%s>\n" + score + (current-time-string) + (user-full-name) + user-mail-address))) + (setq file (expand-file-name file (or directory + temporary-file-directory))) + (unless (file-exists-p (file-name-directory file)) + (make-directory (file-name-directory file) t)) + (find-file-other-window file) + (setq buffer-read-only nil) + (goto-char (point-max)) + (insert score-line) + (sort-fields 1 (point-min) (point-max)) + (unless reverse + (reverse-region (point-min) (point-max))) + (goto-char (point-min)) + (forward-line gamegrid-score-file-length) + (delete-region (point) (point-max)) + (setq buffer-read-only t) + (save-buffer) + (view-mode) + (goto-char (point-min)) + (when (search-forward score-line nil 'end) + (forward-line -1))))) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; commit 951fb93956d3b90aa6d1fbc8c3dcd25c42fbe7dc Author: Jonas Bernoulli Date: Fri Jul 19 19:10:30 2024 +0200 * lisp/transient.el (static-if): Remove duplicated definition. (Bug#72182) This should have been removed when the standalone version was merged into Emacs. diff --git a/lisp/transient.el b/lisp/transient.el index 8788fbc834f..14a94434c12 100644 --- a/lisp/transient.el +++ b/lisp/transient.el @@ -82,17 +82,6 @@ similar defect.") :emergency)) (defvar Man-notify-method) (defvar pp-default-function) ; since Emacs 29.1 -(defmacro static-if (condition then-form &rest else-forms) - "A conditional compilation macro. -Evaluate CONDITION at macro-expansion time. If it is non-nil, -expand the macro to THEN-FORM. Otherwise expand it to ELSE-FORMS -enclosed in a `progn' form. ELSE-FORMS may be empty." - (declare (indent 2) - (debug (sexp sexp &rest sexp))) - (if (eval condition lexical-binding) - then-form - (cons 'progn else-forms))) - (defmacro transient--with-emergency-exit (id &rest body) (declare (indent defun)) (unless (keywordp id) commit 0218fb214376555df52188be4afee16249e3639c Author: Michael Albinus Date: Fri Jul 19 18:29:49 2024 +0200 Adapt file-remote-p doc * doc/lispref/files.texi (Magic File Names): Adapt file-remote-p. * lisp/files.el (file-remote-p): Adapt docstring. diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 9e7aeeecec8..1a8f3812f1e 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -3624,10 +3624,18 @@ ensure this principle is valid. @var{identification} specifies which part of the identifier shall be returned as string. @var{identification} can be the symbol -@code{method}, @code{user} or @code{host}; any other value is handled -like @code{nil} and means to return the complete identifier string. -In the example above, the remote @code{user} identifier string would -be @code{root}. +@code{method}, @code{user}, @code{host} or @code{localname}; any other +value is handled like @code{nil} and means to return the complete +identifier string. In the example above, the remote @code{user} +identifier string would be @code{root}. + +If the remote @var{file} does not contain a method, a user name, or a +host name, the respective default value is returned. The string +returned for @var{identification} @code{localname} can differ depending +on whether there is an existing connection. File name handler specific +implementations could support further @var{identification} symbols; +@xref{Top, Tramp, Tramp, tramp}, for example, knows also the @code{hop} +symbol. If @var{connected} is non-@code{nil}, this function returns @code{nil} even if @var{filename} is remote, if Emacs has no network connection diff --git a/lisp/files.el b/lisp/files.el index ca2d5b30cb4..73ad85ce854 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -1298,9 +1298,14 @@ any that are missing. IDENTIFICATION can specify which part of the identification to return. IDENTIFICATION can be the symbol `method', `user', `host', or `localname'. Any other value is handled like nil and -means to return the complete identification. The string returned -for IDENTIFICATION `localname' can differ depending on whether -there is an existing connection. +means to return the complete identification. + +If the remote FILE does not contain a method, a user name, or a host +name, the respective default value is returned. The string returned for +IDENTIFICATION `localname' can differ depending on whether there is an +existing connection. File name handler specific implementations could +support further IDENTIFICATION symbols; Tramp, for example, knows also +the `hop' symbol. If CONNECTED is non-nil, return an identification only if FILE is located on a remote system and a connection is established to commit 34c1094e607c7ec89d66702da7f298b454b7c192 Author: Stefan Kangas Date: Fri Jul 19 10:13:04 2024 +0200 ; Fix typo in etc/ORG-NEWS (Bug#72186) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 41818c76460..c5d1e872033 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -560,7 +560,7 @@ The old name is obsolete. ** New and changed options -# Chanes deadling with changing default values of customizations, +# Changes dealing with changing default values of customizations, # adding new customizations, or changing the interpretation of the # existing customizations. commit 99b360bb5aabf324cf038c27ac76ac1513319754 Author: Jim Porter Date: Fri Jun 14 20:45:44 2024 -0700 Allow specifying stdout/stderr separately in some Eshell commands * lisp/eshell/eshell.el (eshell-command): Add ERROR-TARGET. * lisp/eshell/em-script.el (eshell-execute-file): Make interactive, and add ERROR-TARGET. * doc/misc/eshell.texi (One-Off Commands, Scripts): Update documentation. * etc/NEWS: Announce this change. diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index d4e182bcbb2..8a4f460d03c 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -235,11 +235,19 @@ Start a new Eshell session, no matter if another one already exists. You can also run individual Eshell commands from anywhere within Emacs: -@deffn Command eshell-command command &optional to-current-buffer +@deffn Command eshell-command command &optional output-target error-target Execute the Eshell command string @var{command} and show the output in a -buffer. If @var{to-current-buffer} is non-@code{nil} (interactively, -with the prefix argument), then insert output into the current buffer at -point. +buffer. If @var{output-target} is @code{t} (interactively, with the +prefix argument), write the command's standard output to the current +buffer at point. If @code{nil}, write the output to a new output +buffer. For any other value, output to that Eshell target +(@pxref{Redirection}). + +@var{error-target} is similar to @var{output-target}, except that it +controls where to write standard error, and a @code{nil} value means to +write standard error to the same place as standard output. (To suppress +standard error, you can write to the Eshell virtual target +@file{/dev/null}.) When the command ends with @kbd{&}, Eshell will evaluate the command asynchronously. Otherwise, it will wait until the command has finished @@ -275,13 +283,20 @@ the special variables @code{$0}, @code{$1}, @dots{}, @code{$9}, and You can also invoke Eshell scripts from outside of Eshell: -@defun eshell-execute-file file &optional args destination +@deffn Command eshell-execute-file file &optional args output-target error-target Execute the Eshell commands contained in @var{file}, passing an optional -list of @var{args} to the script. If @var{destination} is @code{t}, -write the command output to the current buffer. If @code{nil}, don't -write the output anywhere. For any other value, output to the -corresponding Eshell target (@pxref{Redirection}). -@end defun +list of @var{args} to the script. If @var{output-target} is @code{t} +(interactively, with the prefix argument), write the command output to +the current buffer. If @code{nil}, don't write the output anywhere. +For any other value, output to the corresponding Eshell target +(@pxref{Redirection}). + +@var{error-target} is similar to @var{output-target}, except that it +controls where to write standard error, and a @code{nil} value means to +write standard error to the same place as standard output. (To suppress +standard error, you can write to the Eshell virtual target +@file{/dev/null\}.) +@end deffn @cindex batch scripts @defun eshell-batch-file diff --git a/etc/NEWS b/etc/NEWS index 60bde2abb40..5429db1dded 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -60,6 +60,18 @@ this will prompt for confirmation before creating a new buffer when necessary. To restore the previous behavior, set this option to 'confirm-kill-process'. ++++ +*** 'eshell-execute-file' is now an interactive command. +Interactively, this now prompts for a script file to execute. With the +prefix argument, it will also insert any output into the current buffer +at point. + ++++ +*** 'eshell-command' and 'eshell-execute-file' can now set where stderr goes. +These functions now take an optional ERROR-TARGET argument to control +where to send the standard error output. See the "(eshell) Entry +Points" node in the Eshell manual for more details. + +++ *** Eshell's built-in "wait" command now accepts a timeout. By passing "-t" or "--timeout", you can specify a maximum time to wait diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el index ba020d2eb5b..80dea16106b 100644 --- a/lisp/eshell/em-script.el +++ b/lisp/eshell/em-script.el @@ -106,20 +106,29 @@ Comments begin with `#'." (eshell--source-file file args subcommand-p))) ;;;###autoload -(defun eshell-execute-file (file &optional args destination) +(defun eshell-execute-file (file &optional args output-target error-target) "Execute a series of Eshell commands in FILE, passing ARGS. -If DESTINATION is t, write the command output to the current buffer. If -nil, don't write the output anywhere. For any other value, output to -the corresponding Eshell target (see `eshell-get-target'). +If OUTPUT-TARGET is t (interactively, with the prefix argument), write +the command's standard output to the current buffer at point. If nil, +don't write the output anywhere. For any other value, output to that +Eshell target (see `eshell-get-target'). + +ERROR-TARGET is similar to OUTPUT-TARGET, except that it controls where +to write standard error, and a nil value means to write standard error +to the same place as standard output. (To suppress standard error, you +can write to the Eshell virtual target \"/dev/null\".) Comments begin with `#'." + (interactive (list (read-file-name "Execute file: " nil nil t) + nil (not (not current-prefix-arg)))) (let ((eshell-non-interactive-p t) - (stdout (if (eq destination t) (current-buffer) destination))) + (stdout (if (eq output-target t) (current-buffer) output-target)) + (stderr (if (eq error-target t) (current-buffer) error-target))) (with-temp-buffer (eshell-mode) (eshell-do-eval `(let ((eshell-current-handles - (eshell-create-handles ,stdout 'insert)) + (eshell-create-handles ,stdout 'insert ,stderr 'insert)) (eshell-current-subjob-p)) ,(eshell--source-file file args)) t)))) diff --git a/lisp/eshell/eshell.el b/lisp/eshell/eshell.el index d60101d51e1..6637ff36a2c 100644 --- a/lisp/eshell/eshell.el +++ b/lisp/eshell/eshell.el @@ -327,31 +327,42 @@ information on Eshell, see Info node `(eshell)Top'." (defvar eshell-command-buffer-name-sync "*Eshell Command Output*") ;;;###autoload -(defun eshell-command (command &optional to-current-buffer) +(defun eshell-command (command &optional output-target error-target) "Execute the Eshell command string COMMAND. -If TO-CURRENT-BUFFER is non-nil (interactively, with the prefix -argument), then insert output into the current buffer at point. - -When \"&\" is added at end of command, the command is async and its output -appears in a specific buffer. You can customize +If OUTPUT-TARGET is t (interactively, with the prefix argument), write +the command's standard output to the current buffer at point. If nil, +write the output to a new output buffer. For any other value, output to +that Eshell target (see `eshell-get-target'). + +ERROR-TARGET is similar to OUTPUT-TARGET, except that it controls where +to write standard error, and a nil value means to write standard error +to the same place as standard output. (To suppress standard error, you +can write to the Eshell virtual target \"/dev/null\".) + +When \"&\" is added at end of command, the command is async and its +output appears in a specific buffer. You can customize `eshell-command-async-buffer' to specify what to do when this output buffer is already taken by another running shell command." (interactive (list (eshell-read-command) - current-prefix-arg)) + (not (not current-prefix-arg)))) (save-excursion - (let ((stdout (if to-current-buffer (current-buffer) t)) + (let ((stdout (cond ((eq output-target t) (current-buffer)) + ((not output-target) t) + (t output-target))) + (stderr (if (eq error-target t) (current-buffer) error-target)) (buf (set-buffer (generate-new-buffer " *eshell cmd*"))) (eshell-non-interactive-p t)) (eshell-mode) (let* ((proc (eshell-eval-command `(let ((eshell-current-handles - (eshell-create-handles ,stdout 'insert)) + (eshell-create-handles ,stdout 'insert + ,stderr 'insert)) (eshell-current-subjob-p)) ,(eshell-parse-command command)) command)) (async (eq (car-safe proc) :eshell-background)) (bufname (cond - (to-current-buffer nil) + ((not (eq stdout t)) nil) (async eshell-command-buffer-name-async) (t eshell-command-buffer-name-sync))) unique) @@ -394,7 +405,7 @@ buffer is already taken by another running shell command." (while (and (bolp) (not (bobp))) (delete-char -1))) (cl-assert (and buf (buffer-live-p buf))) - (unless to-current-buffer + (unless bufname (let ((len (if async 2 (count-lines (point-min) (point-max))))) (cond commit 965be7bc461b3f56d68f07f3f13fe4e3f2d7e259 Author: Jim Porter Date: Thu Jul 18 12:48:31 2024 -0700 ; * doc/misc/eshell.texi (Bugs and ideas): Remove now-implemented idea. diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 13dc29afde1..d4e182bcbb2 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -3054,8 +3054,6 @@ current interactive process. @item Display file and line number if an error occurs in a script -@item @command{wait} doesn't work with process ids at the moment - @item Enable the direct-to-process input code in @file{em-term.el} @item Problem with repeating @samp{echo $@{find /tmp@}} commit 259f4613bdea27abf330b58a9683ca4a9e936777 Author: Jim Porter Date: Thu Jul 18 11:43:34 2024 -0700 Improve implementation of built-in Eshell "kill" command * lisp/eshell/esh-proc.el (eshell/kill): Fix handling of commands like "kill 123". Use REMOTE when signalling PIDs in remote directories. Signal using process objects when possible. Report errors when failing to signal. * test/lisp/eshell/esh-proc-tests.el (esh-proc-test/kill/process-id) (esh-proc-test/kill/process-object): New tests (bug#72013). diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index fbeb13362f3..ed417ab0f12 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -237,40 +237,34 @@ Wait until PROCESS(es) have completed execution.") Usage: kill [-] | ... Accepts PIDs and process objects. Optionally accept signals and signal names." - ;; The implementation below only supports local PIDs. For remote - ;; connections, fall back to the external "kill" command. - (when (file-remote-p default-directory) - (declare-function eshell-external-command "esh-ext" (command args)) - (throw 'eshell-external (eshell-external-command "kill" args))) - ;; If the first argument starts with a dash, treat it as the signal - ;; specifier. (let ((signum 'SIGINT)) (let ((arg (car args)) (case-fold-search nil)) (when (stringp arg) + ;; If the first argument starts with a dash, treat it as the + ;; signal specifier. (cond ((string-match "\\`-[[:digit:]]+\\'" arg) - (setq signum (abs (string-to-number arg)))) + (setq signum (abs (string-to-number arg))) + (pop args)) ((string-match "\\`-\\([[:upper:]]+\\|[[:lower:]]+\\)\\'" arg) - (setq signum (intern (substring arg 1))))) - (setq args (cdr args)))) - (while args - (let ((arg (if (eshell-processp (car args)) - (process-id (car args)) - (string-to-number (car args))))) - (when arg - (cond - ((null arg) - (error "kill: null pid. Process may actually be a network connection.")) - ((not (numberp arg)) - (error "kill: invalid argument type: %s" (type-of arg))) - ((and (numberp arg) - (<= arg 0)) - (error "kill: bad pid: %d" arg)) - (t - (signal-process arg signum))))) - (setq args (cdr args)))) - nil) + (setq signum (intern (substring arg 1))) + (pop args))))) + (dolist (proc args) + (when (stringp proc) + (setq proc (string-to-number proc))) + (let ((result + (cond + ((numberp proc) + (when (<= proc 0) + (error "kill: bad pid: %d" proc)) + (signal-process proc signum (file-remote-p default-directory))) + ((eshell-processp proc) + (signal-process proc signum)) + (t + (error "kill: invalid argument type: %s" (type-of proc)))))) + (when (= result -1) + (error "kill: failed to kill process %s" proc)))))) (put 'eshell/kill 'eshell-no-numeric-conversions t) diff --git a/test/lisp/eshell/esh-proc-tests.el b/test/lisp/eshell/esh-proc-tests.el index 85b02845ab3..d46004688f9 100644 --- a/test/lisp/eshell/esh-proc-tests.el +++ b/test/lisp/eshell/esh-proc-tests.el @@ -344,6 +344,30 @@ write the exit status to the pipe. See bug#54136." output-start (eshell-end-of-output)) "")))))) +(ert-deftest esh-proc-test/kill/process-id () + "Test killing processes with the \"kill\" built-in using PIDs." + (skip-unless (executable-find "sleep")) + (with-temp-eshell + (eshell-insert-command "sleep 100 &") + (string-match (rx (group (+ digit)) eol) (eshell-last-output)) + (let ((pid (match-string 1 (eshell-last-output)))) + (should (= (length eshell-process-list) 1)) + (eshell-insert-command (format "kill %s" pid)) + (should (= eshell-last-command-status 0)) + (eshell-wait-for-subprocess t) + (should (= (length eshell-process-list) 0))))) + +(ert-deftest esh-proc-test/kill/process-object () + "Test killing processes with the \"kill\" built-in using process objects." + (skip-unless (executable-find "sleep")) + (with-temp-eshell + (eshell-insert-command "sleep 100 &") + (should (= (length eshell-process-list) 1)) + (eshell-insert-command "kill (caar eshell-process-list)") + (should (= eshell-last-command-status 0)) + (eshell-wait-for-subprocess t) + (should (= (length eshell-process-list) 0)))) + ;; Remote processes commit c7a498260ce3c016611da6e5e0aa5edeca58cd80 Author: Jim Porter Date: Sun Jul 14 22:43:54 2024 -0700 Handle broken pipes in a better way in Eshell * lisp/eshell/esh-proc.el (eshell-insertion-filter): Send SIGPIPE delaying for Tramp and falling back to SIGTERM for MS-Windows (bug#72117). diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index 0dcdf3bb76c..fbeb13362f3 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -515,23 +515,28 @@ output." "forwarding output from process `%s'\n\n%s" proc data) (condition-case nil (eshell-output-object data index handles) - ;; FIXME: We want to send SIGPIPE to the process - ;; here. However, remote processes don't currently - ;; support that, and not all systems have SIGPIPE in - ;; the first place (e.g. MS Windows). In these - ;; cases, just delete the process; this is - ;; reasonably close to the right behavior, since the - ;; default action for SIGPIPE is to terminate the - ;; process. For use cases where SIGPIPE is truly - ;; needed, using an external pipe operator (`*|') - ;; may work instead (e.g. when working with remote - ;; processes). (eshell-pipe-broken - (if (or (process-get proc 'remote-pid) - (eq system-type 'windows-nt)) - (delete-process proc) - (signal-process proc 'SIGPIPE)))))) - (process-put proc :eshell-busy nil)))))) + ;; The output pipe broke, so send SIGPIPE to the + ;; process. NOTE: Due to the additional indirection + ;; of Emacs process filters, the process will likely + ;; see the SIGPIPE later than it would in a regular + ;; shell, which could cause problems. For cases + ;; where this matters, using an external pipe + ;; operator (`*|') may work instead. + (cond + ;; Delay signalling remote processes to prevent + ;; "Forbidden reentrant call of Tramp". + ((process-get proc 'remote-pid) + (run-at-time 0 nil #'signal-process proc 'SIGPIPE)) + ;; MS-Windows doesn't support SIGPIPE, so send + ;; SIGTERM there instead; this is reasonably close + ;; to the right behavior, since the default action + ;; for SIGPIPE is to terminate the process. + ((eq system-type 'windows-nt) + (signal-process proc 'SIGTERM)) + (t + (signal-process proc 'SIGPIPE))))))) + (process-put proc :eshell-busy nil)))))) (defun eshell-sentinel (proc string) "Generic sentinel for command processes. Reports only signals. commit 1550213613b397da6e879cc0d00ede916f6c62cc Author: Jim Porter Date: Tue Jul 16 22:07:33 2024 -0700 Improve handling of deferrable Eshell commands Now, we use the 'eshell-deferrable' wrapper to wrap a form that returns a process (or list thereof). This improves upon the old method, which failed to handle 'eshell-replace-command' correctly. In that case, Eshell would fail to unmark commands as deferrable when necessary (e.g. for commands in pipelines). * lisp/eshell/esh-cmd.el (eshell-deferrable-commands): Make into a defvar. (eshell-deferrable): New function... (eshell-structure-basic-command): ... use it. (eshell-trap-errors): Rename to... (eshell-do-command): ... this, and use 'eshell-deferrable'. Update callers. (eshell--unmark-deferrable): Remove. Update callers. (eshell-execute-pipeline): Remove 'eshell-process-identity'. (eshell-process-identity, eshell-named-command*, eshell-lisp-command*): Make obsolete. * test/lisp/eshell/esh-cmd-tests.el (eshell-test-replace-command): New function. (esh-cmd-test/pipeline/replace-command): New test. diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index c8579c83405..099e97a083d 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -240,16 +240,6 @@ return non-nil if the command is complex." :version "24.1" ; removed eshell-cmd-initialize :type 'hook) -(defcustom eshell-deferrable-commands - '(eshell-named-command - eshell-lisp-command - eshell-process-identity) - "A list of functions which might return an asynchronous process. -If they return a process object, execution of the calling Eshell -command will wait for completion (in the background) before finishing -the command." - :type '(repeat function)) - (defcustom eshell-subcommand-bindings '((eshell-in-subcommand-p t) (eshell-in-pipeline-p nil) @@ -289,6 +279,12 @@ otherwise t.") (defvar eshell-last-arguments nil) (defvar eshell-last-command-name nil) +(defvar eshell-deferrable-commands '(eshell-deferrable) + "A list of functions which might return a deferrable process. +If they return a process object (or list thereof), execution of the +calling Eshell command will wait for completion (in the background) +before finishing the command.") + (defvar eshell-allow-commands t "If non-nil, allow evaluating command forms (including Lisp forms). If you want to forbid command forms, you can let-bind this to a @@ -426,7 +422,7 @@ command hooks should be run before and after the command." (error "Empty command before `&'")) (setq cmd (eshell-parse-pipeline cmd)) (unless eshell-in-pipeline-p - (setq cmd `(eshell-trap-errors ,cmd))) + (setq cmd `(eshell-do-command ,cmd))) ;; Copy I/O handles so each full statement can manipulate ;; them if they like. Steal the handles for the last ;; command (first in our reversed list); we won't use the @@ -565,7 +561,7 @@ function." ;; statement. (unless (memq (car test) '(eshell-convert eshell-escape-arg)) (setq test - `(progn ,test + `(progn (eshell-deferrable ,test) (eshell-exit-success-p)))) ;; should we reverse the sense of the test? This depends @@ -776,7 +772,7 @@ returning it as (:eshell-background . PROCESSES)." (defvar eshell-this-command-hook nil) -(defmacro eshell-trap-errors (object) +(defmacro eshell-do-command (object) "Trap any errors that occur, so they are not entirely fatal. Also, the variable `eshell-this-command-hook' is available for the duration of OBJECT's evaluation. Note that functions should be added @@ -787,12 +783,19 @@ this grossness will be made to disappear by using `call/cc'..." `(eshell-condition-case err (let ((eshell-this-command-hook '(ignore))) (unwind-protect - ,object + (eshell-deferrable ,object) (mapc #'funcall eshell-this-command-hook))) (error (eshell-errorn (error-message-string err)) (eshell-close-handles 1)))) +(define-obsolete-function-alias 'eshell-trap-errors #'eshell-do-command "31.1") + +(defalias 'eshell-deferrable 'identity + "A wrapper to mark a particular form as potentially deferrable. +If the wrapped form returns a process (or list thereof), Eshell will +wait for completion in the background for the process(es) to complete.") + (defmacro eshell-with-copied-handles (object &optional steal-p) "Duplicate current I/O handles, so OBJECT works with its own copy. If STEAL-P is non-nil, these new handles will be stolen from the @@ -810,27 +813,12 @@ current ones (see `eshell-duplicate-handles')." (eshell-protect-handles eshell-current-handles) ,object)) -(defun eshell--unmark-deferrable (command) - "If COMMAND is (or ends with) a deferrable command, unmark it as such. -This changes COMMAND in-place by converting function calls listed -in `eshell-deferrable-commands' to their non-deferrable forms so -that Eshell doesn't erroneously allow deferring it. For example, -`eshell-named-command' becomes `eshell-named-command*'." - (let ((cmd command)) - (when (memq (car cmd) '(let progn)) - (setq cmd (car (last cmd)))) - (when (memq (car cmd) eshell-deferrable-commands) - (setcar cmd (intern-soft - (concat (symbol-name (car cmd)) "*")))) - command)) - (defmacro eshell-do-pipelines (pipeline &optional notfirst) "Execute the commands in PIPELINE, connecting each to one another. Returns a list of the processes in the pipeline. This macro calls itself recursively, with NOTFIRST non-nil." (when (setq pipeline (cadr pipeline)) - (eshell--unmark-deferrable (car pipeline)) `(eshell-with-copied-handles (let ((next-procs ,(when (cdr pipeline) @@ -860,8 +848,6 @@ first command invocation in the pipeline (usually t or nil). This is used on systems where async subprocesses are not supported." (when (setq pipeline (cadr pipeline)) - ;; FIXME: is deferrable significant here? - (eshell--unmark-deferrable (car pipeline)) `(prog1 (eshell-with-copied-handles (progn @@ -879,14 +865,13 @@ supported." ,(when (cdr pipeline) `(eshell-do-pipelines-synchronously (quote ,(cdr pipeline))))))) -(defalias 'eshell-process-identity 'identity) +(define-obsolete-function-alias 'eshell-process-identity #'identity "31.1") (defmacro eshell-execute-pipeline (pipeline) "Execute the commands in PIPELINE, connecting each to one another." - `(eshell-process-identity - ,(if eshell-supports-asynchronous-processes - `(remove nil (eshell-do-pipelines ,pipeline)) - `(eshell-do-pipelines-synchronously ,pipeline)))) + (if eshell-supports-asynchronous-processes + `(remove nil (eshell-do-pipelines ,pipeline)) + `(eshell-do-pipelines-synchronously ,pipeline))) (defmacro eshell-as-subcommand (command) "Execute COMMAND as a subcommand. @@ -951,7 +936,7 @@ A command can be invoked directly if all of the following are true: * The command is of the form (eshell-with-copied-handles - (eshell-trap-errors (eshell-named-command NAME [ARGS])) _). + (eshell-do-command (eshell-named-command NAME [ARGS])) _). * NAME is a string referring to an alias function and isn't a complex command (see `eshell-complex-commands'). @@ -959,7 +944,7 @@ A command can be invoked directly if all of the following are true: * Any subcommands in ARGS can also be invoked directly." (pcase command (`(eshell-with-copied-handles - (eshell-trap-errors (eshell-named-command ,name . ,args)) + (eshell-do-command (eshell-named-command ,name . ,args)) ,_) (and name (stringp name) (not (member name eshell-complex-commands)) @@ -1360,7 +1345,8 @@ COMMAND may result in an alias being executed, or a plain command." (eshell-plain-command eshell-last-command-name eshell-last-arguments)))) -(defalias 'eshell-named-command* 'eshell-named-command) +(define-obsolete-function-alias 'eshell-named-command* #'eshell-named-command + "31.1") (defun eshell-find-alias-function (name) "Check whether a function called `eshell/NAME' exists." @@ -1558,7 +1544,8 @@ a string naming a Lisp function." 2) (list 'quote result))))) -(defalias 'eshell-lisp-command* #'eshell-lisp-command) +(define-obsolete-function-alias 'eshell-lisp-command* #'eshell-lisp-command + "31.1") (provide 'esh-cmd) diff --git a/test/lisp/eshell/em-extpipe-tests.el b/test/lisp/eshell/em-extpipe-tests.el index c5f1301cd3b..4c3adbc2d90 100644 --- a/test/lisp/eshell/em-extpipe-tests.el +++ b/test/lisp/eshell/em-extpipe-tests.el @@ -40,7 +40,7 @@ ((should-parse (expected) `(let ((shell-file-name "sh") (shell-command-switch "-c")) - ;; Strip `eshell-trap-errors'. + ;; Strip `eshell-do-command'. (should (equal ,expected (cadadr (eshell-parse-command input)))))) (with-substitute-for-temp (&rest body) diff --git a/test/lisp/eshell/em-tramp-tests.el b/test/lisp/eshell/em-tramp-tests.el index 3be5d3542ca..49dd5a78c3d 100644 --- a/test/lisp/eshell/em-tramp-tests.el +++ b/test/lisp/eshell/em-tramp-tests.el @@ -29,8 +29,7 @@ `(should (equal (catch 'eshell-replace-command ,form) (list 'eshell-with-copied-handles - (list 'eshell-trap-errors - ,replacement) + (list 'eshell-do-command ,replacement) t)))) (ert-deftest em-tramp-test/su-default () diff --git a/test/lisp/eshell/esh-cmd-tests.el b/test/lisp/eshell/esh-cmd-tests.el index d8124a19af6..18ea1f9a9d6 100644 --- a/test/lisp/eshell/esh-cmd-tests.el +++ b/test/lisp/eshell/esh-cmd-tests.el @@ -34,6 +34,10 @@ (defvar eshell-test-value nil) +(defun eshell-test-replace-command (command &rest args) + "Run COMMAND with ARGS by throwing `eshell-replace-command'." + (throw 'eshell-replace-command `(eshell-named-command ,command ',args))) + ;;; Tests: @@ -265,6 +269,20 @@ This should also wait for the subcommand." (format template "format \"%s\" eshell-in-pipeline-p") "nil"))) +(ert-deftest esh-cmd-test/pipeline/replace-command () + "Ensure that `eshell-replace-command' doesn't affect Eshell deferral. +Pipelines want to defer (yield) execution after starting all the +processes in the pipeline, not before. This lets us track all the +processes correctly." + (skip-unless (and (executable-find "sleep") + (executable-find "cat"))) + (with-temp-eshell + (eshell-insert-command "eshell-test-replace-command *sleep 1 | cat") + ;; Make sure both processes are in `eshell-foreground-command'; this + ;; makes sure that the first command (which was replaced via + ;; `eshell-replace-command' isn't deferred by `eshell-do-eval'. + (should (= (length (cadr eshell-foreground-command)) 2)))) + ;; Control flow statements commit 76874df05f7758deb4f47b7df278e54a66456fc9 Author: Stefan Kangas Date: Thu Jul 18 14:59:09 2024 +0200 Fix minor code style issue in pgtkfns.c * src/pgtkfns.c (pgtk_get_defaults_value) (pgtk_set_defaults_value): Fix code style. diff --git a/src/pgtkfns.c b/src/pgtkfns.c index f99be3bcfd1..f00fcba3b81 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -1920,9 +1920,7 @@ pgtk_get_defaults_value (const char *key) GSettings *gs = parse_resource_key (key, skey); if (gs == NULL) - { - return NULL; - } + return NULL; gchar *str = g_settings_get_string (gs, skey); @@ -1952,13 +1950,9 @@ pgtk_set_defaults_value (const char *key, const char *value) error ("Unknown resource key"); if (value != NULL) - { - g_settings_set_string (gs, skey, value); - } + g_settings_set_string (gs, skey, value); else - { - g_settings_reset (gs, skey); - } + g_settings_reset (gs, skey); g_object_unref (gs); } commit 87facc9e3da3ca70a5a75eec57e3fa22c0636c92 Author: Stefan Kangas Date: Thu Jul 18 14:48:56 2024 +0200 Avoid overflow in pgtk_is_numeric_char * src/pgtkfns.c (PATH_MAX_LEN): New macro. (parse_resource_key): Avoid overflow if a key is RESOURCE_KEY_MAX_LEN long by making the array larger. diff --git a/src/pgtkfns.c b/src/pgtkfns.c index f1c0e5da0f3..f99be3bcfd1 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -1781,6 +1781,9 @@ Some window managers may refuse to restack windows. */) #define SCHEMA_ID "org.gnu.emacs.defaults" #define PATH_FOR_CLASS_TYPE "/org/gnu/emacs/defaults-by-class/" #define PATH_PREFIX_FOR_NAME_TYPE "/org/gnu/emacs/defaults-by-name/" +#define PATH_MAX_LEN \ + (sizeof PATH_FOR_CLASS_TYPE > sizeof PATH_PREFIX_FOR_NAME_TYPE ? \ + sizeof PATH_FOR_CLASS_TYPE : sizeof PATH_PREFIX_FOR_NAME_TYPE) static inline int pgtk_is_lower_char (int c) @@ -1803,7 +1806,7 @@ pgtk_is_numeric_char (int c) static GSettings * parse_resource_key (const char *res_key, char *setting_key) { - char path[32 + RESOURCE_KEY_MAX_LEN]; + char path[PATH_MAX_LEN + RESOURCE_KEY_MAX_LEN]; const char *sp = res_key; char *dp; @@ -1822,7 +1825,7 @@ parse_resource_key (const char *res_key, char *setting_key) /* generate path */ if (pgtk_is_upper_char (*sp)) { - /* First letter is upper case. It should be "Emacs", + /* First letter is upper case. It should be "Emacs", * but don't care. */ strcpy (path, PATH_FOR_CLASS_TYPE); @@ -1964,6 +1967,7 @@ pgtk_set_defaults_value (const char *key, const char *value) #undef SCHEMA_ID #undef PATH_FOR_CLASS_TYPE #undef PATH_PREFIX_FOR_NAME_TYPE +#undef PATH_MAX_LEN #else /* not HAVE_GSETTINGS */ commit d00a10333f06d30fee93ba3ee033e74dc4ff85bc Author: Stefan Kangas Date: Tue Jul 16 04:34:53 2024 +0200 Use strnlen to avoid unnecessary work in pgtkfns.c * src/pgtkfns.c (pgtk_get_defaults_value, pgtk_set_defaults_value): Factor out new function... (pgtk_check_resource_key_length): ...to here. Avoid unnecessary work by using strnlen. diff --git a/src/pgtkfns.c b/src/pgtkfns.c index b8e65f4c052..f1c0e5da0f3 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -1901,13 +1901,19 @@ parse_resource_key (const char *res_key, char *setting_key) return gs; } +static void +pgtk_check_resource_key_length (const char *key) +{ + if (strnlen (key, RESOURCE_KEY_MAX_LEN) >= RESOURCE_KEY_MAX_LEN) + error ("Resource key too long"); +} + const char * pgtk_get_defaults_value (const char *key) { char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; - if (strlen (key) >= RESOURCE_KEY_MAX_LEN) - error ("Resource key too long"); + pgtk_check_resource_key_length (key); GSettings *gs = parse_resource_key (key, skey); if (gs == NULL) @@ -1936,8 +1942,7 @@ pgtk_set_defaults_value (const char *key, const char *value) { char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; - if (strlen (key) >= RESOURCE_KEY_MAX_LEN) - error ("Resource key too long"); + pgtk_check_resource_key_length (key); GSettings *gs = parse_resource_key (key, skey); if (gs == NULL) commit a90a1ed527e89cf26737b6a123070c55c3118923 Author: Eli Zaretskii Date: Thu Jul 18 12:59:28 2024 +0300 Minor cleanup of code in insdel.c * src/insdel.c (del_range_2): Update *_BYTE variables _after_ updating the corresponding character values. This follows what we do everywhere else, and allows to put a watchpoint on, say, Z_BYTE to check consistency between the character and byte counts. See bug#72165 for one situation where it is useful. diff --git a/src/insdel.c b/src/insdel.c index c450959eec6..26ad14948ce 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -1929,10 +1929,10 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte, offset_intervals (current_buffer, from, - nchars_del); GAP_SIZE += nbytes_del; - ZV_BYTE -= nbytes_del; - Z_BYTE -= nbytes_del; ZV -= nchars_del; Z -= nchars_del; + ZV_BYTE -= nbytes_del; + Z_BYTE -= nbytes_del; GPT = from; GPT_BYTE = from_byte; if (GAP_SIZE > 0 && !current_buffer->text->inhibit_shrinking) commit 5916b172bdcdeb96b058c2ae18455f66dd6326fb Author: Stefan Kangas Date: Thu Jul 18 11:46:56 2024 +0200 * etc/TODO: Delete item about merging Magit. Change requested by Jonas Bernoulli . diff --git a/etc/TODO b/etc/TODO index dfadbc8440c..65861f1cae5 100644 --- a/etc/TODO +++ b/etc/TODO @@ -727,11 +727,6 @@ bar. In the mean time, it should process other messages. ** Get some major packages installed -*** Magit -This needs work on getting the relevant copyright assignments. This -task should be highly doable for anyone, but will likely require some -patience. See . - *** PSGML, _possibly_ ECB https://lists.gnu.org/r/emacs-devel/2007-05/msg01493.html Check the assignments file for other packages which might go in and have been commit a6cab228d4d1a82a80eac81b057857a230eef0b5 Author: Stefan Kangas Date: Sun Jul 7 17:40:31 2024 +0200 ; Fix typos diff --git a/ChangeLog.3 b/ChangeLog.3 index 80ea900477e..6efeb8f5dd5 100644 --- a/ChangeLog.3 +++ b/ChangeLog.3 @@ -997,7 +997,7 @@ 2022-07-11 Stefan Kangas - * lisp/find-dired.el (find-dired): Doc fix; add crossreference. + * lisp/find-dired.el (find-dired): Doc fix; add cross-reference. 2022-07-08 Stefan Kangas @@ -141854,7 +141854,7 @@ client key/cert specification. * doc/misc/emacs-gnutls.texi (Help For Developers): Describe usage of - optional plist argument. Add crossreference to description of + optional plist argument. Add cross-reference to description of .authinfo format for client key/cert specification. * etc/NEWS: Describe new client certificate functionality for diff --git a/ChangeLog.4 b/ChangeLog.4 index be1eb2f80b4..1cd5568e4db 100644 --- a/ChangeLog.4 +++ b/ChangeLog.4 @@ -49037,7 +49037,7 @@ 2022-07-11 Stefan Kangas - * lisp/find-dired.el (find-dired): Doc fix; add crossreference. + * lisp/find-dired.el (find-dired): Doc fix; add cross-reference. 2022-07-11 Stefan Kangas @@ -78967,7 +78967,7 @@ This abstracts out the somewhat-unusual "insert&delete" logic in 'eshell-parse-command' so that it can be used elsewhere, and also - ensures that the deletion occurs even if an an error occurs. + ensures that the deletion occurs even if an error occurs. * lisp/eshell/esh-cmd.el (eshell-with-temp-command): New macro. (eshell-parse-command): Use it. @@ -82043,7 +82043,7 @@ (BClipboard_set_system_data) (BClipboard_set_primary_selection_data) (BClipboard_set_secondary_selection_data): Store count before - saving to the the clipboard. + saving to the clipboard. (BClipboard_owns_clipboard, BClipboard_owns_primary) (BClipboard_owns_secondary): Adjust tests accordingly. diff --git a/admin/codespell/codespell.exclude b/admin/codespell/codespell.exclude index 733e548a598..02b7c84c2f4 100644 --- a/admin/codespell/codespell.exclude +++ b/admin/codespell/codespell.exclude @@ -1684,3 +1684,4 @@ argument \\='general-category, is Decimal_Numbers (Nd). It returns ((or (string-equal tag "anc") (string-equal tag "ancestor")) ("ro" :default "Continuare de pe pagina precedentă") ("ro" :default "Continuare pe pagina următoare") +;; avk@rtsg.mot.com (Andrew V. Klein) for a Dired tip. diff --git a/admin/codespell/codespell.ignore b/admin/codespell/codespell.ignore index ebb85e510bb..4f145c290f7 100644 --- a/admin/codespell/codespell.ignore +++ b/admin/codespell/codespell.ignore @@ -9,18 +9,14 @@ blocs callint checkin clen -crossreference -crossreferences debbugs dedented dependant -doas ede grey gud ifset inout -keypair keyserver keyservers lightening @@ -28,7 +24,6 @@ mapp master mimicks mitre -msdos ot parm parms @@ -37,8 +32,6 @@ reenable reenabled requestor sie -spawnve statics -stdio texline typdef diff --git a/admin/notes/bug-triage b/admin/notes/bug-triage index 6fad55dc1e3..e3f93a508bd 100644 --- a/admin/notes/bug-triage +++ b/admin/notes/bug-triage @@ -54,7 +54,7 @@ the ones that are not reproducible on the current release. If you can reproduce, then reply on the thread (either on the original message, or anywhere you find appropriate) that you - can reproduce this on the current release. If your + can reproduce this on the current release. If your reproduction gives additional info (such as a backtrace), then add that as well, since it will help whoever attempts to fix it. @@ -79,7 +79,7 @@ the ones that are not reproducible on the current release. 3. Your changes will take some time to take effect. After a period of minutes to hours, you will get a mail telling you the control message has been processed. At this point, if there were no errors detected, you and - everyone else can see your changes. If there are errors, read the error + everyone else can see your changes. If there are errors, read the error text - if you need help, consulting the bugtracker documentation in this same directory. diff --git a/admin/notes/bugtracker b/admin/notes/bugtracker index 419d91ae854..3cbf490d6de 100644 --- a/admin/notes/bugtracker +++ b/admin/notes/bugtracker @@ -39,7 +39,7 @@ tags 123 moreinfo|unreproducible|wontfix|patch|notabug For a list of all bugs, see https://debbugs.gnu.org/db/pa/lemacs.html This is a static page, updated once a day. There is also a dynamic -list, generated on request. This accepts various options, e.g., to see +list, generated on request. This accepts various options, e.g., to see the most recent bugs: https://debbugs.gnu.org/cgi/pkgreport.cgi?newest=100 @@ -183,7 +183,7 @@ emacs-bug-tracker mailing list, just pick one or the other. ** How to avoid multiple copies of mails. If you reply to reports in the normal way, this should work fine. Basically, reply only to the numbered bug address (and any individual -people's addresses). Do not send mail direct to bug-gnu-emacs or +people's addresses). Do not send mail direct to bug-gnu-emacs or emacs-pretest-bug unless you are reporting a new bug. ** To close bug#123 (for example), send mail @@ -212,7 +212,7 @@ that the bug has been closed. This mail has a header: X-GNU-PR-Message: closed 123 4) Send a copy of your mail to the bug-gnu-emacs list in exactly the -same way as if you had sent mail to "123" (sans -done). This mail has +same way as if you had sent mail to "123" (sans -done). This mail has headers: X-GNU-PR-Message: cc-closed 123 diff --git a/admin/notes/copyright b/admin/notes/copyright index 55924157e9a..085356cfb28 100644 --- a/admin/notes/copyright +++ b/admin/notes/copyright @@ -16,10 +16,10 @@ longer, eg the text "GNU Emacs is free software...". Summary for the impatient: 1. Don't add code to Emacs written by someone other than yourself -without thinking about the legal aspect. Even if the changes are +without thinking about the legal aspect. Even if the changes are trivial, consider if they combine with previous changes by the same -author to make a non-trivial total. If so, make sure they have an -assignment. If adding a whole file adjust the copyright statements in +author to make a non-trivial total. If so, make sure they have an +assignment. If adding a whole file adjust the copyright statements in the file. 2. When installing code written by someone else, the commit @@ -38,23 +38,23 @@ right thing to do. Every non-trivial file distributed through the Emacs repository should be -self-explanatory in terms of copyright and license. This includes +self-explanatory in terms of copyright and license. This includes files that are not distributed in Emacs releases (for example, the admin/ directory), because the whole Emacs repository is publicly available. The definition of triviality is a little vague, but a rule of thumb is -that any file with less than 15 lines of actual content is trivial. If +that any file with less than 15 lines of actual content is trivial. If a file is auto-generated (eg ldefs-boot.el) from another one in the repository, then it does not really matter about adding a copyright statement to the generated file. Legal advice says that we could, if we wished, put a license notice even in trivial files, because copyright law in general looks at the -overall work as a whole. It is not _necessary_ to do so, and rms -prefers that we do not. This means one needs to take care that trivial +overall work as a whole. It is not _necessary_ to do so, and rms +prefers that we do not. This means one needs to take care that trivial files do not grow and become non-trivial without having a license -added. NB consequently, if you add a lot of text to a small file, +added. NB consequently, if you add a lot of text to a small file, consider whether your changes have made the file worthy of a copyright notice, and if so, please add one. @@ -62,10 +62,10 @@ It can be helpful to put a reminder comment at the start of a trivial file, eg: "add a license notice if this grows to > 10 lines of code". The years in the copyright notice should be updated every year (see -file "years" in this directory). The PDF versions of refcards etc +file "years" in this directory). The PDF versions of refcards etc should display copyright notices (an exception to the rule about -"generated" files), but these can just display the latest year. The -full list of years should be kept in comments in the source file. If +"generated" files), but these can just display the latest year. The +full list of years should be kept in comments in the source file. If these are distributed in the repository, check in a regenerated version when the tex files are updated. @@ -75,28 +75,28 @@ Copyright changes should be propagated to any associated repositories All README (and other such text files) that are non-trivial should contain copyright statements and GPL license notices, exactly as .el -files do (see e.g. README in the top-level directory). Before 2007, +files do (see e.g. README in the top-level directory). Before 2007, we used a simple, short statement permitting copying and modification -provided legal notices were retained. In Feb 2007 we switched to the -standard GPL text, on legal advice. Some older text files in etc/ +provided legal notices were retained. In Feb 2007 we switched to the +standard GPL text, on legal advice. Some older text files in etc/ should, however, keep their current licenses (see below for list). For image files, the copyright and license details should be recorded in a README file in each directory with images. (Legal advice says that we need not add notices to each image file individually, if they -allow for that.). It is recommended to use the word "convert" to +allow for that.). It is recommended to use the word "convert" to describe the automatic process of changing an image from one format to another (https://lists.gnu.org/r/emacs-devel/2007-02/msg00618.html). When installing a file with an "unusual" license (after checking first it is ok), put a copy of the copyright and license in the file (if -possible. It's ok if this makes the file incompatible with its +possible. It's ok if this makes the file incompatible with its original format, if it can still be used by Emacs), or in a README file in the relevant directory. The vast majority of files are copyright FSF and distributed under the -GPL. A few files (mainly related to language and charset support) are +GPL. A few files (mainly related to language and charset support) are copyright AIST alone, or both AIST and FSF. (Contact Kenichi Handa with questions about legal issues in such files.) In all these cases, the copyright years in each file should be updated each year. @@ -106,16 +106,16 @@ these are listed below for reference, together with any files where the copyright needs to be updated in "unusual" ways. If you find any other such cases, please consult to check they are ok, -and note them in this file. This includes missing copyright notices, -and "odd" copyright holders. In most cases, individual authors should -not appear in copyright statements. Either the copyright has been +and note them in this file. This includes missing copyright notices, +and "odd" copyright holders. In most cases, individual authors should +not appear in copyright statements. Either the copyright has been assigned (check copyright.list) to the FSF (in which case the original author should be removed and the year(s) transferred to the FSF); or else it is possible the file should not be in Emacs at all (please report!). Note that it seems painfully clear that one cannot rely on commit logs, -or even change log entries, for older changes. People often installed +or even change log entries, for older changes. People often installed changes from others, without recording the true authorship. [For reference, most of these points were established via email with @@ -146,7 +146,7 @@ lib/Makefile.in - copyright FSF, with MIT-like license build-aux/install-sh - - this file is copyright MIT, which is OK. Leave the copyright alone. + - this file is copyright MIT, which is OK. Leave the copyright alone. etc/refcards/*.tex also update the \def\year macro for the latest year. @@ -162,7 +162,7 @@ etc/letter.pbm,letter.xpm etc/HELLO - standard notices. Just a note that although the file itself is not + standard notices. Just a note that although the file itself is not really copyrightable, in the wider context of it being part of Emacs (and written by those with assignments), a standard notice is fine. @@ -183,20 +183,20 @@ leim/quail/PY.el, ZIRANMA.el) are under GPLv1 or later. leim/SKK-DIC/SKK-JISYO.L ja-dic/ja-dic.el - (the latter is auto-generated from the former). Leave the copyright alone. + (the latter is auto-generated from the former). Leave the copyright alone. lib-src/etags.c - Copyright information is duplicated in etc/ETAGS.README. Update that + Copyright information is duplicated in etc/ETAGS.README. Update that file too. Until 2007 etags.c was described as being copyright FSF and Ken Arnold. After some investigation in Feb 2007, then to the best of our knowledge we believe that the original 1984 Emacs version was based - on the version in BSD4.2. See for example this 1985 post from Ken Arnold: + on the version in BSD4.2. See for example this 1985 post from Ken Arnold: I have received enough requests for the current source to ctags - to post it. Here is the latest version (what will go out with - 4.3, modulo any bugs fixed during the beta period). It is the + to post it. Here is the latest version (what will go out with + 4.3, modulo any bugs fixed during the beta period). It is the 4.2 ctags with recognition of yacc and lex tags added. See also a 1984 version of ctags (no copyright) posted to net.sources: @@ -204,9 +204,9 @@ lib-src/etags.c Version of etags.c in emacs-16.56 duplicates comment typos. Accordingly, in Feb 2007 we added a 1984 copyright for the - University of California and a revised BSD license. The terms of + University of California and a revised BSD license. The terms of this require that the full license details be available in binary - distributions - hence the file etc/ETAGS.README. The fact that the + distributions - hence the file etc/ETAGS.README. The fact that the --version output just says "Copyright FSF" is apparently OK from a legal point of view. @@ -216,7 +216,7 @@ lisp/cedet/semantic/imenu.el from authors other than himself were negligible. lisp/play/tetris.el - - no special rules about the copyright. We note here that we believe + - no special rules about the copyright. We note here that we believe (2007/1) there is no problem with our use of the name "tetris" or the concept. rms: "My understanding is that game rules as such are not copyrightable." @@ -225,7 +225,7 @@ lisp/play/tetris.el lisp/net/tramp.el - - there are also copyrights in the body of the file. Update these too. + - there are also copyrights in the body of the file. Update these too. lwlib/ @@ -237,23 +237,23 @@ below). FSF copyrights should only appear in files which have undergone non-trivial cumulative changes from the original versions in the Lucid -Widget Library. NB this means that if you make non-trivial changes to -a file with no FSF copyright, you should add one. Also, if changes are +Widget Library. NB this means that if you make non-trivial changes to +a file with no FSF copyright, you should add one. Also, if changes are reverted to the extent that a file becomes basically the same as the original version, the FSF copyright should be removed. In my (rgm) opinion, as of Feb 2007, all the non-trivial files differ significantly from the original versions, with the exception of -lwlib-Xm.h. Most of the changes that were made to this file have -subsequently been reverted. Therefore I removed the FSF copyright from -this file (which is arguably too trivial to merit a notice anyway). I +lwlib-Xm.h. Most of the changes that were made to this file have +subsequently been reverted. Therefore I removed the FSF copyright from +this file (which is arguably too trivial to merit a notice anyway). I added FSF copyright to the following files which did not have them already: Makefile.in, lwlib-Xaw.c, lwlib-int.h (borderline), lwlib-utils.c (borderline), lwlib.c, lwlib.h. Copyright years before the advent of public CVS in 2001 were those when I judged (from the CVS logs) that non-trivial amounts of change -had taken place. I also adjusted the existing FSF years in xlwmenu.c, +had taken place. I also adjusted the existing FSF years in xlwmenu.c, xlwmenu.h, and xlwmenuP.h on the same basis. Note that until Feb 2007, the following files in lwlib were lacking @@ -264,17 +264,17 @@ xlwmenuP.h. To the best of our knowledge, all the code files in lwlib were originally part of the Lucid Widget Library, even if they did not say -so explicitly. For example, they were all present in Lucid Emacs 19.1 -in 1992. The exceptions are the two Xaw files, which did not appear -till Lucid Emacs 19.9 in 1994. The file lwlib-Xaw.h is too trivial to +so explicitly. For example, they were all present in Lucid Emacs 19.1 +in 1992. The exceptions are the two Xaw files, which did not appear +till Lucid Emacs 19.9 in 1994. The file lwlib-Xaw.h is too trivial to merit a copyright notice, but would presumably have the same one as -lwlib-Xaw.c. We have been unable to find a true standalone version of +lwlib-Xaw.c. We have been unable to find a true standalone version of LWL, if there was such a thing, to check definitively. To clarify the situation, in Feb 2007 we added Lucid copyrights and GPL notices to those files lacking either that were non-trivial, -namely: lwlib-int.h, lwlib.h, xlwmenu.h, xlwmenuP.h. This represents -our best understanding of the legal status of these files. We also +namely: lwlib-int.h, lwlib.h, xlwmenu.h, xlwmenuP.h. This represents +our best understanding of the legal status of these files. We also clarified the notices in Makefile.in, which was originally the Makefile auto-generated from Lucid's Imakefile. @@ -284,16 +284,16 @@ notices: lwlib-Xaw.h, lwlib-Xlw.h, lwlib-utils.h. The version of lwlib/ first installed in Emacs seems to be the same as that used in Lucid Emacs 19.8 (released 6-sep-93); except the two Xaw files, which did not appear till Athena support was added in Lucid -Emacs 19.9. In Lucid Emacs 19.1, all files were under GPLv1 or later, +Emacs 19.9. In Lucid Emacs 19.1, all files were under GPLv1 or later, but by Lucid Emacs 19.8, lwlib.c and xlwmenu.c had been switched to v2 -or later. These are the versions that were first installed in Emacs. +or later. These are the versions that were first installed in Emacs. So in GNU Emacs, these two files have been under v2 or later since 1994. It seems that it was the intention of Lucid to use v1 or later (excepting the two files mentioned previously); so this is the license we have used when adding notices to code that did not have notices -originally. Although we have the legal right to switch to v2 or later, +originally. Although we have the legal right to switch to v2 or later, rms prefers that we do not do so. @@ -302,7 +302,7 @@ doc/*/doclicense.texi doc/*/*.texi - All manuals should be under GFDL (but see below), and should include a copy of it, so that they can be distributed -separately. faq.texi has a different license, for some reason no-one +separately. efaq.texi has a different license, for some reason no-one can remember. https://lists.gnu.org/r/emacs-devel/2007-04/msg00583.html https://lists.gnu.org/r/emacs-devel/2007-04/msg00618.html @@ -319,23 +319,23 @@ an MIT-like license. oldXMenu/ Keep the "copyright.h" method used by X11, rather than moving the - licenses into the files. Note that the original X10.h did not use + licenses into the files. Note that the original X10.h did not use copyright.h, but had an explicit notice, which we retain. If you make non-trivial changes to a file which does not have an FSF -notice, add one and a GPL notice (as per Activate.c). If changes to a +notice, add one and a GPL notice (as per Activate.c). If changes to a file are reverted such that it becomes essentially the same as the original X11 version, remove the FSF notice and GPL. Only the files which differ significantly from the original X11 -versions should have FSF copyright and GPL notices. At time of writing -(Feb 2007), this is: Activate.c, Create.c, Internal.c. I (rgm) +versions should have FSF copyright and GPL notices. At time of writing +(Feb 2007), this is: Activate.c, Create.c, Internal.c. I (rgm) established this by diff'ing the current files against those in X11R1, and when I found significant differences looking in the ChangeLog for -the years they originated (the CVS logs are truncated before 1999). I +the years they originated (the CVS logs are truncated before 1999). I therefore removed the FSF notices (added in 200x) from the other -files. There are some borderline cases IMO: AddSel.c, InsSel.c, -XMakeAssoc.c, XMenu.h. For these I erred on the side of NOT adding FSF +files. There are some borderline cases IMO: AddSel.c, InsSel.c, +XMakeAssoc.c, XMenu.h. For these I erred on the side of NOT adding FSF notices. With regards to whether the files we have changed should have GPL @@ -347,41 +347,41 @@ added or not, rms says (2007-02-25, "oldXmenu issues"): So, to make things simple, please put our changes under the GPL. -insque.c had no copyright notice until 2005. The version of insque.c +insque.c had no copyright notice until 2005. The version of insque.c added to Emacs 1992-01-27 is essentially the same as insremque.c added to glic three days later by Roland McGrath, with an FSF copyright and GPL, but no ChangeLog entry. To the best of his recollection, McGrath (who has a copyright assignment) was the author of this file (email from roland at frob.com -to rms, 2007-02-23, "Where did insque.c come from?"). The FSF +to rms, 2007-02-23, "Where did insque.c come from?"). The FSF copyright and GPL in this file are therefore correct as far as we understand it. Imakefile had no legal info in Feb 2007, but was obviously based on -the X11 version (which also had no explicit legal info). As it was -unused, I removed it. It would have the same MIT copyright as +the X11 version (which also had no explicit legal info). As it was +unused, I removed it. It would have the same MIT copyright as Makefile.in does now. src/gmalloc.c - - contains numerous copyrights from the GNU C library. Leave them alone. + - contains numerous copyrights from the GNU C library. Leave them alone. nt/inc/dirent.h - - see comments below. This file is OK to be released with Emacs + - see comments below. This file is OK to be released with Emacs 22, but we may want to revisit it afterwards. ** Some notes on resolved issues, for historical information only etc/TERMS -rms: "surely written either by me or by ESR. (If you can figure out -which year, I can probably tell you which.) Either way, we have papers -for it." It was present in Emacs-16.56 (15-jul-85). rms: "Then I +rms: "surely written either by me or by ESR. (If you can figure out +which year, I can probably tell you which.) Either way, we have papers +for it." It was present in Emacs-16.56 (15-jul-85). rms: "Then I conclude it was written by me." lisp/term/README - - had no copyright notice till Feb 2007. ChangeLog.3 suggests it was - written by Eric S. Raymond. When asked by rms on 14 Feb 2007 he said: + - had no copyright notice till Feb 2007. ChangeLog.3 suggests it was + written by Eric S. Raymond. When asked by rms on 14 Feb 2007 he said: I don't remember writing it, but it reads like my prose and I believe I wrote the feature(s) it's describing. So I would have been the @@ -393,10 +393,10 @@ lisp/term/README src/unexhp9k800.c https://lists.gnu.org/r/emacs-devel/2007-02/msg00138.html - - briefly removed due to legal uncertainly Jan-Mar 2007. The - relevant assignment is under "hp9k800" in copyright.list. File was + - briefly removed due to legal uncertainly Jan-Mar 2007. The + relevant assignment is under "hp9k800" in copyright.list. File was written by John V. Morris at HP, and disclaimed by the author and - HP. So this file is public domain. + HP. So this file is public domain. lisp/progmodes/python.el @@ -424,20 +424,20 @@ nt/inc/dirent.h algorithm in this format. With the addition of this notice, these files are OK for the - upcoming Emacs-22 release. Post-release, we can revisit this issue + upcoming Emacs-22 release. Post-release, we can revisit this issue and possibly add a list of all authors who have changed these files. (details in email from Matt Norwood to rms, 2007/02/03). src/s/aix3-2.h, hpux8.h, hpux9.h, irix5-0.h, netbsd.h, usg5-4-2.h [note some of these have since been merged into other files] - all these (not obviously trivial) files were missing copyrights - till Feb 2007, when FSF copyright was added. Matt Norwood advised: + till Feb 2007, when FSF copyright was added. Matt Norwood advised: For now, I think the best policy is to assume that we do have assignments from the authors (I recall many of these header files as having been originally written by rms), and to attach an FSF - copyright with GPL notice. We can amend this if and when we - complete the code audit. Any additions to these files by + copyright with GPL notice. We can amend this if and when we + complete the code audit. Any additions to these files by non-assigned authors are arguably "de minimis" contributions to Emacs: small changes or suggestions to a work that are subsumed in the main authors' copyright in the entire work. @@ -446,18 +446,18 @@ Here is my (rgm) take on the details of the above files: ? irix5-0.h I would say started non-trivial (1993, jimb, heavily based - on irix4-0.h). A few borderline non-tiny changes since. + on irix4-0.h). A few borderline non-tiny changes since. usg5-4-2.h started non-trivial, but was heavily based on usg5-4.h, which was and is - copyright FSF. only tiny changes since installed. + copyright FSF. only tiny changes since installed. aix3-2.h, hpux8.h, hpux9.h, netbsd.h started trivial, grown in tiny changes. netbsd.h: Roland McGrath said to rms (2007/02/17): "I don't really remember -anything about it. If I put it in without other comment, then probably +anything about it. If I put it in without other comment, then probably I wrote it myself." @@ -491,13 +491,13 @@ noted in this file. REMOVED etc/gnu.xpm, nt/icons/emacs21.ico, nt/icons/sink.ico - - Restore if find legal info. emacs21.ico is not due to Davenport. + - Restore if find legal info. emacs21.ico is not due to Davenport. Geoff Voelker checked but could not find a record of where it came from. etc/images - Image files from GTK, Gnome are under GPLv2 (no "or later"?). RMS will + Image files from GTK, Gnome are under GPLv2 (no "or later"?). RMS will contact image authors in regards to future switch to v3. @@ -525,9 +525,9 @@ Some notes: (see https://lists.gnu.org/r/emacs-devel/2007-07/msg01431.html) 1. There are some files in the Emacs tree which are not part of Emacs (eg -those included from Gnulib). These are all copyright FSF and (at time -of writing) GPL >= 2. rms says may as well leave the licenses of these -alone (may import them from Gnulib again). These are: +those included from Gnulib). These are all copyright FSF and (at time +of writing) GPL >= 2. rms says may as well leave the licenses of these +alone (may import them from Gnulib again). These are: Gnulib: build-aux/config.guess @@ -555,7 +555,7 @@ ChangeLog, etc), ie remain under GPL v1 or later, or v2 or later. (rms: "We may as well leave this alone, since we are never going to change it much.") -4. There are some files where the FSF holds no copyright. These were +4. There are some files where the FSF holds no copyright. These were left alone: leim/MISC-DIC/CTLau-b5.html >= v2 @@ -568,7 +568,7 @@ left alone: leim/ja-dic/ja-dic.el >= v2 5. At time of writing, some non-Emacs icons included from Gnome remain -under GPLv2 (no "or later"). See: +under GPLv2 (no "or later"). See: etc/images/gnus/README etc/images/mail/README diff --git a/admin/notes/documentation b/admin/notes/documentation index d894175e212..22bacb48b68 100644 --- a/admin/notes/documentation +++ b/admin/notes/documentation @@ -54,9 +54,9 @@ combine them into a single entry, e.g.: https://lists.gnu.org/r/emacs-devel/2008-10/msg00414.html In Emacs tradition, we treat "point" as a proper name when it refers -to the current editing location. It should not have an article. +to the current editing location. It should not have an article. -Thus, it is incorrect to write, "The point does not move". It should +Thus, it is incorrect to write, "The point does not move". It should be, "Point does not move". If you see "the point" anywhere in Emacs documentation or comments, diff --git a/admin/notes/multi-tty b/admin/notes/multi-tty index f021799b294..508f9abdc17 100644 --- a/admin/notes/multi-tty +++ b/admin/notes/multi-tty @@ -117,7 +117,7 @@ with (Make sure both emacs and emacsclient are multi-tty versions.) You'll hopefully have two fully working, independent frames on -separate terminals. The new frame is closed automatically when you +separate terminals. The new frame is closed automatically when you finish editing the specified files (C-x #), but delete-frame (C-x 5 0) also works. Of course, you can create frames on more than two tty devices. @@ -325,7 +325,7 @@ THINGS TO DO example, custom's buttons are broken on non-initial device types. ** Possibly turn off the double C-g feature when there is an X frame. - C.f. (emacs)Emergency Escape. + Cf. (emacs)Emergency Escape. ** frames-on-display-list should also accept frames. @@ -773,7 +773,7 @@ DIARY OF CHANGES with it. (Done, there was a stupid mistake in - Ftty_supports_face_attributes_p. Colors are broken, though.) + Ftty_supports_face_attributes_p. Colors are broken, though.) -- C-x 5 2, C-x 5 o, C-x 5 0 on an emacsclient frame unexpectedly exits emacsclient. This is a result of trying to be clever with @@ -1080,7 +1080,7 @@ DIARY OF CHANGES fine. Sometimes faces on these screens become garbled. This only seems to affect displays that are of the same terminfo - type as the selected one. Interestingly, in screen Emacs normally + type as the selected one. Interestingly, in screen Emacs normally reports the up arrow key as 'M-o A', but after the above SNAFU, it complains about 'M-[ a'. UNIX ttys are a complete mystery to me, but it seems the reset-reinitialize cycle somehow leaves the @@ -1232,7 +1232,7 @@ DIARY OF CHANGES -- Understand Emacs's low-level input system (it's black magic) :-) What exactly does interrupt_input do? I tried to disable it for raw secondary tty support, but it does not seem to do anything - useful. (Update: Look again. X unconditionally enables this, maybe + useful. (Update: Look again. X unconditionally enables this, maybe that's why raw terminal support is broken again. I really do need to understand input.) (Update: I am starting to understand the read_key_sequence->read-char diff --git a/admin/notes/repo b/admin/notes/repo index 2be707db27f..b4535bcb556 100644 --- a/admin/notes/repo +++ b/admin/notes/repo @@ -113,8 +113,8 @@ pre-commit state. If you have pushed commit, resetting will be ineffective because it will only vanish the commit in your local copy. Instead, use 'git -revert', giving it the commit ID as argument. This will create a -new commit that backs out the change. Then push that. +revert', giving it the commit ID as argument. This will create a +new commit that backs out the change. Then push that. Note that git will generate a log message for the revert that includes a git hash. Please edit this to refer to the commit by the first line diff --git a/admin/notes/tree-sitter/performance b/admin/notes/tree-sitter/performance index 23f84743ced..7af217ffc72 100644 --- a/admin/notes/tree-sitter/performance +++ b/admin/notes/tree-sitter/performance @@ -3,14 +3,14 @@ TREE-SITTER PERFORMANCE NOTES -*- org -*- * Facts Incremental parsing of a few characters worth of edit usually takes -less than 0.1ms. If it takes longer than that, something is wrong. +less than 0.1ms. If it takes longer than that, something is wrong. There’s one time where I found tree-sitter-c takes ~30ms to -incremental parse. Updating to the latest version of tree-sitter-c +incremental parse. Updating to the latest version of tree-sitter-c solves it, so I didn’t investigate further. The ranges set for a parser doesn’t grow when you insert text into a range, so you have to update the ranges every time before -parsing. Fortunately, changing ranges doesn’t invalidate incremental +parsing. Fortunately, changing ranges doesn’t invalidate incremental parsing, so there isn’t any performance lost in update ranges frequently. diff --git a/admin/notes/tree-sitter/starter-guide b/admin/notes/tree-sitter/starter-guide index 846614f1446..b07c80b203c 100644 --- a/admin/notes/tree-sitter/starter-guide +++ b/admin/notes/tree-sitter/starter-guide @@ -35,8 +35,8 @@ merged) and rebuild Emacs. * Install language definitions Tree-sitter by itself doesn’t know how to parse any particular -language. We need to install language definitions (or “grammars”) for -a language to be able to parse it. There are a couple of ways to get +language. We need to install language definitions (or “grammars”) for +a language to be able to parse it. There are a couple of ways to get them. You can use this script that I put together here: @@ -45,7 +45,7 @@ You can use this script that I put together here: This script automatically pulls and builds language definitions for C, C++, Rust, JSON, Go, HTML, JavaScript, CSS, Python, Typescript, -C#, etc. Better yet, I pre-built these language definitions for +C#, etc. Better yet, I pre-built these language definitions for GNU/Linux and macOS, they can be downloaded here: https://github.com/casouri/tree-sitter-module/releases/tag/v2.1 @@ -56,19 +56,19 @@ To build them yourself, run cd tree-sitter-module ./batch.sh -and language definitions will be in the /dist directory. You can +and language definitions will be in the /dist directory. You can either copy them to standard dynamic library locations of your system, -eg, /usr/local/lib, or leave them in /dist and later tell Emacs where +e.g., /usr/local/lib, or leave them in /dist and later tell Emacs where to find language definitions by setting ‘treesit-extra-load-path’. Language definition sources can be found on GitHub under -tree-sitter/xxx, like tree-sitter/tree-sitter-python. The tree-sitter +tree-sitter/xxx, like tree-sitter/tree-sitter-python. The tree-sitter organization has all the "official" language definitions: https://github.com/tree-sitter Alternatively, you can use treesit-install-language-grammar command -and follow its instructions. If everything goes right, it should +and follow its instructions. If everything goes right, it should automatically download and compile the language grammar for you. * Setting up for adding major mode features @@ -91,7 +91,7 @@ Tree-sitter modes should be separate major modes, so other modes inheriting from the original mode don't break if tree-sitter is enabled. For example js2-mode inherits js-mode, we can't enable tree-sitter in js-mode, lest js-mode would not setup things that -js2-mode expects to inherit from. So it's best to use separate major +js2-mode expects to inherit from. So it's best to use separate major modes. If the tree-sitter variant and the "native" variant could share some @@ -115,12 +115,12 @@ symbol (variable, function). Tree-sitter works like this: You provide a query made of patterns and capture names, tree-sitter finds the nodes that match these patterns, tag the corresponding capture names onto the nodes and return them to -you. The query function returns a list of (capture-name . node). For -font-lock, we use face names as capture names. And the captured node +you. The query function returns a list of (capture-name . node). For +font-lock, we use face names as capture names. And the captured node will be fontified in their capture name. The capture name could also be a function, in which case (NODE -OVERRIDE START END) is passed to the function for fontification. START +OVERRIDE START END) is passed to the function for fontification. START and END are the start and end of the region to be fontified. The function should only fontify within that region. The function should also allow more optional arguments with (&rest _), for future @@ -131,11 +131,11 @@ treesit-font-lock-rules. There are two types of nodes, named, like (identifier), (function_definition), and anonymous, like "return", "def", "(", -"}". Parent-child relationship is expressed as +"}". Parent-child relationship is expressed as (parent (child) (child) (child (grand_child))) -Eg, an argument list (1, "3", 1) could be: +For example, an argument list (1, "3", 1) could be: (argument_list "(" (number) (string) (number) ")") @@ -167,7 +167,7 @@ But how do one come up with the queries? Take python for an example, open any python source file, type M-x treesit-explore-mode RET. Now you should see the parse-tree in a separate window, automatically updated as you select text or edit the buffer. Besides this, you can -consult the grammar of the language definition. For example, Python’s +consult the grammar of the language definition. For example, Python’s grammar file is at https://github.com/tree-sitter/tree-sitter-python/blob/master/grammar.js @@ -182,24 +182,24 @@ The manual explains how to read grammar files in the bottom of section ** Debugging queries If your query has problems, use ‘treesit-query-validate’ to debug the -query. It will pop a buffer containing the query (in text format) and +query. It will pop a buffer containing the query (in text format) and mark the offending part in red. ** Code To enable tree-sitter font-lock, set ‘treesit-font-lock-settings’ and ‘treesit-font-lock-feature-list’ buffer-locally and call -‘treesit-major-mode-setup’. For example, see -‘python--treesit-settings’ in python.el. Below is a snippet of it. +‘treesit-major-mode-setup’. For example, see +‘python--treesit-settings’ in python.el. Below is a snippet of it. Just like the current font-lock, if the to-be-fontified region already has a face (ie, an earlier match fontified part/all of the region), -the new face is discarded rather than applied. If you want later +the new face is discarded rather than applied. If you want later matches always override earlier matches, use the :override keyword. Each rule should have a :feature, like function-name, -string-interpolation, builtin, etc. Users can then enable/disable each -feature individually. See Appendix 1 at the bottom for a set of common +string-interpolation, builtin, etc. Users can then enable/disable each +feature individually. See Appendix 1 at the bottom for a set of common features names. #+begin_src elisp @@ -267,17 +267,17 @@ Indent works like this: We have a bunch of rules that look like (MATCHER ANCHOR OFFSET) When the indentation process starts, point is at the BOL of a line, we -want to know which column to indent this line to. Let NODE be the node +want to know which column to indent this line to. Let NODE be the node at point, we pass this node to the MATCHER of each rule, one of them -will match the node (eg, "this node is a closing bracket!"). Then we -pass the node to the ANCHOR, which returns a point, eg, the BOL of the -previous line. We find the column number of that point (eg, 4), add -OFFSET to it (eg, 0), and that is the column we want to indent the +will match the node (e.g., "this node is a closing bracket!"). Then we +pass the node to the ANCHOR, which returns a point, e.g., the BOL of the +previous line. We find the column number of that point (e.g., 4), add +OFFSET to it (e.g., 0), and that is the column we want to indent the current line to (4 + 0 = 4). Matchers and anchors are functions that takes (NODE PARENT BOL &rest -_). Matches return nil/non-nil for no match/match, and anchors return -the anchor point. Below are some convenient builtin matchers and anchors. +_). Matches return nil/non-nil for no match/match, and anchors return +the anchor point. Below are some convenient builtin matchers and anchors. For MATCHER we have @@ -289,8 +289,8 @@ For MATCHER we have (match NODE-TYPE PARENT-TYPE NODE-FIELD NODE-INDEX-MIN NODE-INDEX-MAX) - => checks everything. If an argument is nil, don’t match that. Eg, - (match nil TYPE) is the same as (parent-is TYPE) + => checks everything. If an argument is nil, don’t match that. + E.g., (match nil TYPE) is the same as (parent-is TYPE) For ANCHOR we have @@ -305,8 +305,8 @@ For ANCHOR we have There is also a manual section for indent: "Parser-based Indentation". When writing indent rules, you can use ‘treesit-check-indent’ to -check if your indentation is correct. To debug what went wrong, set -‘treesit--indent-verbose’ to non-nil. Then when you indent, Emacs +check if your indentation is correct. To debug what went wrong, set +‘treesit--indent-verbose’ to non-nil. Then when you indent, Emacs tells you which rule is applied in the echo area. #+begin_src elisp @@ -355,7 +355,7 @@ Set ‘treesit-simple-imenu-settings’ and call * Navigation Set ‘treesit-defun-type-regexp’ and call -‘treesit-major-mode-setup’. You can additionally set +‘treesit-major-mode-setup’. You can additionally set ‘treesit-defun-name-function’. * Which-func @@ -370,7 +370,7 @@ find the current function by ‘treesit-defun-at-point’. Obviously this list is just a starting point, if there are features in the major mode that would benefit from a parse tree, adding tree-sitter -support for that would be great. But in the minimal case, just adding +support for that would be great. But in the minimal case, just adding font-lock is awesome. * Common tasks @@ -403,12 +403,12 @@ BTW ‘treesit-node-string’ does different things. * Manual -I suggest you read the manual section for tree-sitter in Info. The -section is Parsing Program Source. Typing +I suggest you read the manual section for tree-sitter in Info. The +section is Parsing Program Source. Typing C-h i d m elisp RET g Parsing Program Source RET -will bring you to that section. You don’t need to read through every +will bring you to that section. You don’t need to read through every sentence, just read the text paragraphs and glance over function names. @@ -439,13 +439,13 @@ error highlight parse error Abstract features: -assignment: the LHS of an assignment (thing being assigned to), eg: +assignment: the LHS of an assignment (thing being assigned to), e.g.: a = b <--- highlight a a.b = c <--- highlight b a[1] = d <--- highlight a -definition: the thing being defined, eg: +definition: the thing being defined, e.g.: int a(int b) { <--- highlight a return 0 diff --git a/admin/notes/tree-sitter/treesit_record_change b/admin/notes/tree-sitter/treesit_record_change index e80df4adfa7..db79f0d8174 100644 --- a/admin/notes/tree-sitter/treesit_record_change +++ b/admin/notes/tree-sitter/treesit_record_change @@ -47,7 +47,7 @@ EXCEPTIONS There are a couple of functions that replaces characters in-place -rather than insert/delete. They are in casefiddle.c and editfns.c. +rather than insert/delete. They are in casefiddle.c and editfns.c. In casefiddle.c, do_casify_unibyte_region and do_casify_multibyte_region modifies buffer, but they are static @@ -177,7 +177,7 @@ all safe. json.c:790: signal_after_change (PT, 0, inserted); Called in json-insert, calls either decode_coding_gap or -insert_from_gap_1, both are safe. Calls memmove but it’s for +insert_from_gap_1, both are safe. Calls memmove but it’s for decode_coding_gap. keymap.c:2873: /* Insert calls signal_after_change which may GC. */ diff --git a/admin/nt/dist-build/README-scripts b/admin/nt/dist-build/README-scripts index e99fbe07062..da7d03c327b 100644 --- a/admin/nt/dist-build/README-scripts +++ b/admin/nt/dist-build/README-scripts @@ -6,8 +6,8 @@ The scripts are used to build the binary distribution zip files for windows. Environment ----------- -A full installation of msys2 is required along for the build. The -various dependencies of Emacs need to be installed also. These change +A full installation of msys2 is required along for the build. The +various dependencies of Emacs need to be installed also. These change over time, but are listed in build-deps-zips.py. @@ -16,7 +16,7 @@ File System Organization ------------------------ -They are relatively strict about the file system organization. In +They are relatively strict about the file system organization. In general, they should work across several more than just the version of Emacs they come with, as the dependencies of Emacs change relatively slowly. @@ -34,35 +34,36 @@ A checkout out of the master branch of the Emacs git repository. ~/emacs-build/git/emacs-$major-version A worktree of the git repository containing the current release -branch. This has to be created by hand. +branch. This has to be created by hand. ~/emacs-build/git/emacs-$release-version -A branch of the git repository containing the last release. The +A branch of the git repository containing the last release. The build-zips.sh file will create this for you. ~/emacs-build/deps -A location for the dependencies. This needs to contain two zip files -with the dependencies. build-dep-zips.py will create these files for you. +A location for the dependencies. This needs to contain two zip files +with the dependencies. build-dep-zips.py will create these files for +you. ~/emacs-build/deps/libXpm -Contain libXpm-noX4.dll. This file is used to load images for the -splash screen, menu items and so on. Emacs runs without it, but looks -horrible. The files came original from msys2, and contains no -dependencies. It has to be placed manually (but probably never +Contain libXpm-noX4.dll. This file is used to load images for the +splash screen, menu items and so on. Emacs runs without it, but looks +horrible. The files came original from msys2, and contains no +dependencies. It has to be placed manually (but probably never need updating). ~/emacs-build/build/$version -We build Emacs out-of-source here. This directory is created by -build-zips.sh. This directory can be freely deleted after zips have +We build Emacs out-of-source here. This directory is created by +build-zips.sh. This directory can be freely deleted after zips have been created ~/emacs-build/install/$version -We install Emacs here. This directory is created by build-zips.sh. +We install Emacs here. This directory is created by build-zips.sh. This directory can and *should* be deleted after zips have been created. @@ -79,7 +80,7 @@ Build Process ### For each major version -The dependencies files need to be created. This can be around the time +The dependencies files need to be created. This can be around the time of the pre-tests, then used for all releases of that version, to ensure the maximum stability. @@ -87,16 +88,16 @@ To do this: Update msys to the latest version with `pacman -Syu`. -Then run build-dep-zips.py, in the ~/emacs-build/deps directory. Two +Then run build-dep-zips.py, in the ~/emacs-build/deps directory. Two zips will be created, containing the dependencies, as well as the source for these. For emacs release or pre-test version: -Run `build-zips.sh -g` in the release branch. This will create a worktree +Run `build-zips.sh -g` in the release branch. This will create a worktree with the tag of the last version. -Then run `build-zips.sh` in this worktree. Eventually, four new zip +Then run `build-zips.sh` in this worktree. Eventually, four new zip files will be created in ~/emacs-upload from where they can be signed and uploaded with `gnupload`. @@ -104,7 +105,7 @@ and uploaded with `gnupload`. ### For snapshots from Master Snapshots are generally created from master when there is a release -branch on which a release has already been created. At this point, +branch on which a release has already been created. At this point, only pre-tests or full releases need to happen from the release branch. @@ -112,11 +113,11 @@ To do this: Update msys to the latest version with `pacman -Syu`. -Then run build-dep-zips.py, in ~/emacs-build/deps directory. Two zips +Then run build-dep-zips.py, in ~/emacs-build/deps directory. Two zips will be created, containing the dependencies, as well as the source -for these. These deps files contain the date of creation in their -name. The deps file can be reused as desired, or a new version -created. Where multiple deps files exist, the most recent will be +for these. These deps files contain the date of creation in their +name. The deps file can be reused as desired, or a new version +created. Where multiple deps files exist, the most recent will be used. Now, run `build-zips.sh -s` to build a snapshot release. @@ -137,8 +138,8 @@ version (e.g emacs-27.0.50.zip). ### For snapshots from another branch -Snapshots can be build from any other branch. There is rarely a need +Snapshots can be built from any other branch. There is rarely a need to do this, except where some significant, wide-ranging feature is being added on a feature branch. In this case, the branch can be -given using `build-zips.sh -b pdumper -s` for example. Any "/" +given using `build-zips.sh -b pdumper -s` for example. Any "/" characters in the branch title are replaced. diff --git a/admin/nt/dist-build/README-windows-binaries b/admin/nt/dist-build/README-windows-binaries index c51cea73333..3bdb0913869 100644 --- a/admin/nt/dist-build/README-windows-binaries +++ b/admin/nt/dist-build/README-windows-binaries @@ -40,7 +40,7 @@ installer but as a zip file which some users may prefer. emacs-$VERSION-no-deps.zip -Contains Emacs without any dependencies. This may be useful if you +Contains Emacs without any dependencies. This may be useful if you wish to install where the dependencies are already available, or if you want the small possible Emacs. @@ -49,7 +49,7 @@ for most end-users. emacs-$VERSION-deps.zip -The dependencies. Unzipping this file on top of +The dependencies. Unzipping this file on top of emacs-$VERSION-no-deps.zip should result in the same install as emacs-$VERSION.zip. diff --git a/admin/run-codespell b/admin/run-codespell index c61bd47d451..514de157e5c 100755 --- a/admin/run-codespell +++ b/admin/run-codespell @@ -42,6 +42,7 @@ emacs_run_codespell () git ls-files |\ grep -v -E -e '^(lib|m4)/.*' |\ grep -v -E -e '^admin/(charsets|codespell|unidata)/.*' |\ + grep -v -E -e '^doc/lispref/spellfile$' |\ grep -v -E -e '^doc/misc/texinfo.tex$' |\ grep -v -E -e '^doc/translations/.*' |\ grep -v -E -e '^etc/(AUTHORS|HELLO|publicsuffix.txt)$' |\ diff --git a/doc/emacs/ack.texi b/doc/emacs/ack.texi index c3d86bf3426..bb8001c382f 100644 --- a/doc/emacs/ack.texi +++ b/doc/emacs/ack.texi @@ -247,7 +247,7 @@ generating JSON files. @item Andrea Corallo was the Emacs (co-)maintainer from 29.3 onwards. He wrote the native compilation support in @file{comp.c} and -and @file{comp.el}, for compiling Emacs Lisp to native code using +@file{comp.el}, for compiling Emacs Lisp to native code using @samp{libgccjit}. @item diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index edcbb971b98..28ae964a1e4 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -267,7 +267,7 @@ system. @cindex temp~unlinked.NNNN files, Android On Android devices running very old (2.6.29) versions of the Linux kernel, Emacs needs to create files named starting with -@file{temp~unlinked} in the the temporary file directory in order to +@file{temp~unlinked} in the temporary file directory in order to read from asset files. Do not create files with such names yourself, or they may be overwritten or removed. diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index 8776d358373..72e985ec44d 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi @@ -1351,7 +1351,7 @@ when and how to report Emacs bugs (@pxref{Bugs}). To find the documentation of a particular command, look in the index. Keys (character commands) and command names have separate indexes. -There is also a glossary, with a cross reference for each term. +There is also a glossary, with a cross-reference for each term. This manual is available as a printed book and also as an Info file. The Info file is for reading from Emacs itself, or with the Info program. diff --git a/doc/emacs/help.texi b/doc/emacs/help.texi index 6572da9c323..f15b4c5e89d 100644 --- a/doc/emacs/help.texi +++ b/doc/emacs/help.texi @@ -519,7 +519,7 @@ backward. It also provides a few special commands: @table @kbd @item @key{RET} -Follow a cross reference at point (@code{help-follow}). +Follow a cross-reference at point (@code{help-follow}). @item @key{TAB} Move point forward to the next hyperlink (@code{forward-button}). @item S-@key{TAB} diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 8abaeafcf33..9bc2a6407d5 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -1944,7 +1944,7 @@ files needed by @TeX{} for cross-references; these commands are generally not suitable for running the final copy in which all of the cross-references need to be correct. - When you want the auxiliary files for cross references, use @kbd{C-c + When you want the auxiliary files for cross-references, use @kbd{C-c C-f} (@code{tex-file}) which runs @TeX{} on the current buffer's file, in that file's directory. Before running @TeX{}, it offers to save any modified buffers. Generally, you need to use (@code{tex-file}) twice to diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 342f88eb8c0..c56b37ce9b7 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -4678,7 +4678,7 @@ A unibyte string containing data in a certain MIME type. @end table @end defvar - A call to @code{gui-get-selection} generally returns the the data + A call to @code{gui-get-selection} generally returns the data named @var{data-type} within the selection message, albeit with @var{data-type} replaced by an alternative name should it be one of the following X selection targets: diff --git a/doc/lispref/package.texi b/doc/lispref/package.texi index 40c550b56b4..60cff9d1891 100644 --- a/doc/lispref/package.texi +++ b/doc/lispref/package.texi @@ -250,7 +250,7 @@ is the brief description. Each element in this list should have the form @code{(@var{dep-name} @var{dep-version})}, where @var{dep-name} is a symbol whose name is the dependency's package name, and @var{dep-version} is the dependency's -version (a string). The spacial value @samp{emacs} means that the +version (a string). The special value @samp{emacs} means that the package depends on the given version of Emacs. @end defun diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 41ab90a80f3..bb700c279ce 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -6009,7 +6009,7 @@ This API has mandatory and optional parts. To allow its users to initiate JSONRPC contacts (notifications or requests) or reply to endpoint requests, the new transport implementation must equip the @code{jsonrpc-connection-send} generic -function with a specialization for the the new subclass +function with a specialization for the new subclass (@pxref{Generic Functions}). This generic function is called automatically by primitives such as @code{jsonrpc-request} and @code{jsonrpc-notify}. The specialization should ensure that the diff --git a/doc/misc/ChangeLog.1 b/doc/misc/ChangeLog.1 index 03b5037229e..37b304c2dca 100644 --- a/doc/misc/ChangeLog.1 +++ b/doc/misc/ChangeLog.1 @@ -343,9 +343,8 @@ 2014-06-22 Mario Lang - * srecode.texi (Base Arguments): The the -> to the. - - * org.texi (Images in ODT export): The the -> the. + * srecode.texi (Base Arguments): + * org.texi (Images in ODT export): Fix typos. 2014-06-21 Eli Zaretskii diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 2228b2752fd..fa410a89761 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -2815,12 +2815,12 @@ An implementation of @command{expr} using the Calc package. @cmindex ff @item ff @var{directory} @var{pattern} -Shorthand for the the function @code{find-name-dired} (@pxref{Dired +Shorthand for the function @code{find-name-dired} (@pxref{Dired and Find, , , emacs, The Emacs Editor}). @cmindex gf @item gf @var{directory} @var{regexp} -Shorthand for the the function @code{find-grep-dired} (@pxref{Dired +Shorthand for the function @code{find-grep-dired} (@pxref{Dired and Find, , , emacs, The Emacs Editor}). @cmindex intersection diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi index b2dfc46f74c..72a16a179b5 100644 --- a/doc/misc/gnus.texi +++ b/doc/misc/gnus.texi @@ -11513,7 +11513,7 @@ even with @sc{xover} by registering the @code{Xref} lines of all articles you actually read, but if you kill the articles, or just mark them as read without reading them, Gnus will not get a chance to snoop the @code{Xref} lines out of these articles, and will be unable to use -the cross reference mechanism. +the cross-reference mechanism. @cindex LIST overview.fmt @cindex overview.fmt diff --git a/doc/misc/htmlfontify.texi b/doc/misc/htmlfontify.texi index 258c743ac8f..7446f3ee9f4 100644 --- a/doc/misc/htmlfontify.texi +++ b/doc/misc/htmlfontify.texi @@ -751,7 +751,7 @@ should do this. (hfy-face-to-css @var{fn}) @end lisp -Take @var{fn}, a font or @code{defface} specification (c.f. +Take @var{fn}, a font or @code{defface} specification (cf. @code{face-attr-construct}) and return a CSS style specification. See also: @ref{hfy-face-to-style} diff --git a/doc/misc/modus-themes.org b/doc/misc/modus-themes.org index fb1df473f75..1006359c6e1 100644 --- a/doc/misc/modus-themes.org +++ b/doc/misc/modus-themes.org @@ -3638,7 +3638,7 @@ Add this to the `modus-themes-post-load-hook'." The above will work only for themes that belong to the Modus family. For users of Emacs version 29 or higher, there exists a theme-agnostic hook that takes a function with one argument---that of the theme---and -calls in the the "post enable" phase of theme loading. Here is the +calls in the "post enable" phase of theme loading. Here is the above snippet, with the necessary tweaks: #+begin_src emacs-lisp diff --git a/doc/misc/org.org b/doc/misc/org.org index fc2935ebe6d..83a723ea94f 100644 --- a/doc/misc/org.org +++ b/doc/misc/org.org @@ -11766,7 +11766,7 @@ example : ./img/cat.jpg If you wish to define a caption for the image (see [[*Captions]]) and -maybe a label for internal cross references (see [[*Internal Links]]), +maybe a label for internal cross-references (see [[*Internal Links]]), make sure that the link is on a line by itself and precede it with =CAPTION= and =NAME= keywords as follows: diff --git a/doc/misc/reftex.texi b/doc/misc/reftex.texi index 623e10e095f..08ef084ae12 100644 --- a/doc/misc/reftex.texi +++ b/doc/misc/reftex.texi @@ -4823,7 +4823,7 @@ Macros which can be used for the display of cross references. This is used when @code{reftex-view-crossref} is called with point in an argument of a macro. Note that crossref viewing for citations, references (both ways) and index entries is hard-coded. This variable -is only to configure additional structures for which crossreference +is only to configure additional structures for which cross-reference viewing can be useful. Each entry has the structure @example (@var{macro-re} @var{search-re} @var{highlight}). diff --git a/doc/misc/semantic.texi b/doc/misc/semantic.texi index f6cabed6ea6..5cead2f7448 100644 --- a/doc/misc/semantic.texi +++ b/doc/misc/semantic.texi @@ -372,7 +372,7 @@ Infrastructure for searching groups @semantic{} databases, and dealing with the search results format. @item semantic/db-ref.el -Tracks crossreferences. Cross references are needed when buffer is +Tracks cross-references. Cross-references are needed when buffer is reparsed, and must alert other tables that any dependent caches may need to be flushed. References are in the form of include files. diff --git a/etc/ChangeLog.1 b/etc/ChangeLog.1 index 0c7e432bba9..fb9b7fa5447 100644 --- a/etc/ChangeLog.1 +++ b/etc/ChangeLog.1 @@ -1579,7 +1579,7 @@ 2011-05-10 Jim Meyering - * MH-E-NEWS, PROBLEMS: Fix typo "the the -> the". + * MH-E-NEWS, PROBLEMS: Fix typo. 2011-05-03 Leo Liu diff --git a/etc/NEWS b/etc/NEWS index 57b17cc858e..ea0ea978f23 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -436,7 +436,7 @@ the signature) the automatically inferred function type as well. *** 'describe-function' now shows the type of the function object. The text used to say things like "car is a built-in function" whereas it now says "car is a primitive-function" where "primitive-function" is the -the name of the symbol returned by 'cl-type-of'. You can click on those +name of the symbol returned by 'cl-type-of'. You can click on those words to get information about that type. --- diff --git a/etc/NEWS.1-17 b/etc/NEWS.1-17 index 64626060c94..f97f4a8f837 100644 --- a/etc/NEWS.1-17 +++ b/etc/NEWS.1-17 @@ -1355,7 +1355,7 @@ This is because -batch (see above) is now used in building Emacs. There are probably some Mocklisp constructs that are not handled. If you encounter one, feel free to report the failure as a bug. The construct will be handled in a future Emacs release, if that is not - not too hard to do. + too hard to do. Note that lisp code converted from Mocklisp code will not necessarily run as fast as code specifically written for GNU Emacs, nor will it use diff --git a/etc/NEWS.19 b/etc/NEWS.19 index fb43e80feac..0d1211a0e7e 100644 --- a/etc/NEWS.19 +++ b/etc/NEWS.19 @@ -2112,7 +2112,7 @@ deletion) now accept a prefix argument which serves as a repeat count. *** Reference keys can now be entered with TAB completion. All reference keys defined in that buffer and all labels that appear in -crossreference entries are object to completion. +cross-reference entries are object to completion. *** Braces are supported as field delimiters in addition to quotes. BibTeX entries may have brace-delimited and quote-delimited fields diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index b2c591b67d0..41818c76460 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -623,7 +623,7 @@ This new hook runs when a note has been stored. Sorting of agenda items, tables, menus, headlines, etc can now be controlled using a new custom option ~org-sort-function~. -By default, Org mode sorts things according to the operation system +By default, Org mode sorts things according to the operating system language. However, language sorting rules may or may not produce good results depending on the use case. For example, multi-language documents may be sorted weirdly when sorting rules for system language diff --git a/etc/PROBLEMS b/etc/PROBLEMS index eb7239a482a..f8fb9f90c0b 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -757,7 +757,7 @@ window sizes" (Lisp value 'ignore'). This can happen if your Emacs is configured to convert PDF to SVG for display, and the version of the MuPDF package you have installed has a -a known bug, whereby it sometimes produces invalid SVG images. +known bug, whereby it sometimes produces invalid SVG images. Version 1.21 of MuPDF is known to be affected. The solution is either to upgrade or downgrade to a version of MuPDF diff --git a/etc/TODO b/etc/TODO index 52dd26b4e8f..dfadbc8440c 100644 --- a/etc/TODO +++ b/etc/TODO @@ -72,10 +72,10 @@ Convert those to use it. ** Remove unnecessary autoload cookies from defcustoms This needs a bit of care, since often people have become used to -expecting such variables to always be defined, eg when they modify -things in their .emacs. +expecting such variables to always be defined, for example when they +modify things in their .emacs. -** See if other files can use generated-autoload-file (see eg ps-print) +** See if other files can use generated-autoload-file (see e.g. ps-print) ** Do interactive mode tagging for commands Change "(interactive)" to "(interactive nil foo-mode)" for command @@ -482,7 +482,7 @@ LSP), see the thread starting at https://lists.gnu.org/archive/html/emacs-devel/2023-09/msg00609.html ** FFI (foreign function interface) -See eg https://lists.gnu.org/r/emacs-devel/2013-10/msg00246.html +See e.g. https://lists.gnu.org/r/emacs-devel/2013-10/msg00246.html One way of doing this is to start with fx's dynamic loading, and use it to implement things like auto-loaded buffer parsers and database @@ -612,7 +612,7 @@ Ideally from someone familiar with GNUstep and Objective C. ** A more modern printing interface A UI that pops up a dialog that lets you choose printer, page style, etc. Integration with the Gtk print dialog is apparently difficult. -See eg: https://lists.gnu.org/r/emacs-devel/2009-03/msg00501.html +See e.g.: https://lists.gnu.org/r/emacs-devel/2009-03/msg00501.html https://lists.gnu.org/r/emacs-devel/2009-04/msg00034.html ** Allow frames(terminals) created by emacsclient to inherit their environment @@ -752,8 +752,8 @@ them. Zlib is required for PNG, so may be linked anyhow. ** Improve the GC -Introduce generational or incremental GC. We may be able to use the -Boehm collector.) See the Boehm-GC branch in CVS for work on this. +Introduce generational or incremental GC. (We may be able to use the +Boehm collector.) See the Boehm-GC branch in Git for work on this. ** Check what hooks would help Emacspeak See the defadvising in W3. @@ -1061,7 +1061,7 @@ Anders Lindgren has implemented some (very basic) tests for full screen, toolbar, and auto-hiding the menu bar. **** Make sure all build variants work -Emacs can be build in a number of different ways. For each feature, +Emacs can be built in a number of different ways. For each feature, consider if is really is "NS" specific, or if it should be applied to all build versions. diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java index 49d9514c104..5d5f05ba247 100644 --- a/java/org/gnu/emacs/EmacsSdk7FontDriver.java +++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java @@ -354,7 +354,7 @@ protected final class Sdk7FontObject extends FontObject rightwards from the origin to the left most pixel in the glyph raster. rbearing is the distance between the origin and the rightmost pixel in the glyph raster. ascent is the distance - counting upwards between the the topmost pixel in the glyph + counting upwards between the topmost pixel in the glyph raster. descent is the distance (once again counting downwards) between the origin and the bottommost pixel in the glyph raster. diff --git a/lisp/ChangeLog.12 b/lisp/ChangeLog.12 index e042d023292..6e4f9d9281a 100644 --- a/lisp/ChangeLog.12 +++ b/lisp/ChangeLog.12 @@ -15827,7 +15827,7 @@ * progmodes/cc-cmds.el (c-hungry-delete): New function to fix key behavior in XEmacs according to `delete-forward-p'. - C.f. `c-electric-delete'. + Cf. `c-electric-delete'. 2005-12-08 Alan Mackenzie diff --git a/lisp/ChangeLog.17 b/lisp/ChangeLog.17 index 0e69fd5e461..3eec2da2038 100644 --- a/lisp/ChangeLog.17 +++ b/lisp/ChangeLog.17 @@ -8915,7 +8915,7 @@ Return the previous char. (perl-calculate-indent): Use syntax-ppss instead of parse-start and update callers accordingly. For continuation lines, check the - the case of array hashes. + case of array hashes. (perl-backward-to-noncomment): Make it non-interactive. (perl-backward-to-start-of-continued-exp): Rewrite. diff --git a/lisp/ChangeLog.5 b/lisp/ChangeLog.5 index 1cbd1f923d0..df9264d952b 100644 --- a/lisp/ChangeLog.5 +++ b/lisp/ChangeLog.5 @@ -4622,7 +4622,7 @@ (assoc-string-equalp): Renamed to assoc-ignore-case. (bibtex-entry): Reference key can be entered with completion. All reference keys that are defined in buffer and all labels that - appear in crossreference entries are object to completion. + appear in cross-reference entries are object to completion. (Entry types): Changed order of entries in menu "entry types". (bibtex-entry-field-alist): Changed order of entries slightly to be more conform with standard BibTeX style layouts. @@ -4667,7 +4667,7 @@ t) are necessary again. bibtex-clean-entry complains if they are empty but not if they are missing, so you can intentionally omit them, e. g. for a pseudo @Journal entry (needed for - crossreferences) made out of an @article with missing non-optional + cross-references) made out of an @article with missing non-optional fields. Menu bar entries aren't centered anymore. diff --git a/lisp/ChangeLog.6 b/lisp/ChangeLog.6 index 80ca08fae2b..d5975d148e4 100644 --- a/lisp/ChangeLog.6 +++ b/lisp/ChangeLog.6 @@ -1572,7 +1572,7 @@ newlines. (gomoku-init-display): Once again fairly fast due to minimization of characters in buffer and text-property operations. Cursor cannot be - be off a square. + off a square. (gomoku-display-statistics): Simplified equivalently. (gomoku-winning-qtuple-beg, gomoku-winning-qtuple-end) (gomoku-winning-qtuple-dx, gomoku-winning-qtuple-dy): Pseudo variables diff --git a/lisp/calc/calc-funcs.el b/lisp/calc/calc-funcs.el index 62ac27c6dbd..5aafe1a5c82 100644 --- a/lisp/calc/calc-funcs.el +++ b/lisp/calc/calc-funcs.el @@ -897,7 +897,7 @@ ;;; Bn = n! bn ;;; bn = - sum_k=0^n-1 bk / (n-k+1)! -;;; A faster method would be to use "tangent numbers", c.f., Concrete +;;; A faster method would be to use "tangent numbers", cf., Concrete ;;; Mathematics pg. 273. diff --git a/lisp/cedet/srecode/fields.el b/lisp/cedet/srecode/fields.el index 72ee2e91511..f9b15cc4f16 100644 --- a/lisp/cedet/srecode/fields.el +++ b/lisp/cedet/srecode/fields.el @@ -70,7 +70,7 @@ Once an insertion set is done, these fields will be activated.") (defclass srecode-overlaid () ((overlay :documentation "Overlay representing this field. -The overlay will crossreference this object.") +The overlay will cross-reference this object.") ) "An object that gets automatically bound to an overlay. Has virtual :start and :end initializers.") diff --git a/lisp/completion.el b/lisp/completion.el index fff431eaf69..7f8d59263df 100644 --- a/lisp/completion.el +++ b/lisp/completion.el @@ -65,7 +65,7 @@ ;;--------------------- ;; ;; A "word" is any string containing characters with either word or symbol -;; syntax. [E.G. Any alphanumeric string with hyphens, underscores, etc.] +;; syntax. [E.g., any alphanumeric string with hyphens, underscores, etc.] ;; Unless you change the constants, you must type at least three characters ;; for the word to be recognized. Only words longer than 6 characters are ;; saved. diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el index 2fa646f2531..75cfc7b32d3 100644 --- a/lisp/emacs-lisp/byte-run.el +++ b/lisp/emacs-lisp/byte-run.el @@ -334,7 +334,7 @@ This is used by `declare'.") (f (apply (car f) name arglist (cdr x))) ;; Yuck!! ((and (featurep 'cl) - (memq (car x) ;C.f. cl--do-proclaim. + (memq (car x) ;Cf. cl--do-proclaim. '(special inline notinline optimize warn))) (push (list 'declare x) cl-decls) nil) diff --git a/lisp/emulation/cua-base.el b/lisp/emulation/cua-base.el index 8b62b04c99c..c6586197fd4 100644 --- a/lisp/emulation/cua-base.el +++ b/lisp/emulation/cua-base.el @@ -133,7 +133,7 @@ ;; Emacs's normal rectangle support is based on interpreting the region ;; between the mark and point as a "virtual rectangle", and using a ;; completely separate set of "rectangle commands" [C-x r ...] on the -;; region to copy, kill, fill a.s.o. the virtual rectangle. +;; region to copy, kill, fill, and so on the virtual rectangle. ;; ;; cua-mode's superior rectangle support uses a true visual ;; representation of the selected rectangle, i.e. it highlights the diff --git a/lisp/foldout.el b/lisp/foldout.el index 495ce4339f7..5799318fc6f 100644 --- a/lisp/foldout.el +++ b/lisp/foldout.el @@ -44,7 +44,7 @@ ;; ;; When zooming in on a heading you might only want to see the child ;; subheadings. You do this by specifying a numeric argument: C-u C-c C-z. -;; You can specify the number of levels of children too (c.f. show-children): +;; You can specify the number of levels of children too (cf. `show-children'): ;; e.g. M-2 C-c C-z exposes two levels of child subheadings. Alternatively, ;; you might only be interested in the body. You do this by specifying a ;; negative argument: M-- C-c C-z. You can also cause the whole subtree to be @@ -239,7 +239,7 @@ An end marker of nil means the fold ends after (point-max).") Normally the body and the immediate subheadings are exposed, but optional arg EXPOSURE \(interactively with prefix arg) changes this:- - EXPOSURE > 0 exposes n levels of subheadings (c.f. `show-children') + EXPOSURE > 0 exposes n levels of subheadings (cf. `show-children') EXPOSURE < 0 exposes only the body EXPOSURE = 0 exposes the entire subtree" (interactive "P") diff --git a/lisp/international/mule-conf.el b/lisp/international/mule-conf.el index 1a58e9b7068..a448aa494bc 100644 --- a/lisp/international/mule-conf.el +++ b/lisp/international/mule-conf.el @@ -709,7 +709,7 @@ ;; Original name for cp1125, says Serhii Hlodin (define-charset-alias 'cp866u 'cp1125) -;; Fixme: C.f. iconv, https://czyborra.com/charsets/codepages.html +;; FIXME: Cf. iconv, https://czyborra.com/charsets/codepages.html ;; shows this as not ASCII compatible, with various graphics in ;; 0x01-0x1F. (define-charset 'cp437 diff --git a/lisp/language/cyrillic.el b/lisp/language/cyrillic.el index f5eef11cfde..68c42f9cb39 100644 --- a/lisp/language/cyrillic.el +++ b/lisp/language/cyrillic.el @@ -36,8 +36,8 @@ ;; . ;; Note that 8859-5 maps directly onto the Unicode Cyrillic block, -;; apart from codepoints 160 (NBSP, c.f. U+0400), 173 (soft hyphen, -;; c.f. U+04OD) and 253 (section sign, c.f U+045D). The KOI-8 and +;; apart from codepoints 160 (NBSP, cf. U+0400), 173 (soft hyphen, +;; cf. U+04OD) and 253 (section sign, cf. U+045D). The KOI-8 and ;; Alternativnyj coding systems encode both 8859-5 and Unicode. ;;; Code: diff --git a/lisp/org/ChangeLog.1 b/lisp/org/ChangeLog.1 index 1cf159f19a2..73d4a1fd7d8 100644 --- a/lisp/org/ChangeLog.1 +++ b/lisp/org/ChangeLog.1 @@ -654,9 +654,8 @@ 2014-06-22 Mario Lang - * org-list.el (org-list-insert-item): The the -> the. - - * org-bibtex.el (org-bibtex-fields): The the -> the. + * org-list.el (org-list-insert-item): + * org-bibtex.el (org-bibtex-fields): Fix typos. 2013-06-22 Dmitry Antipov diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el index 569da841726..011884d5d5b 100644 --- a/lisp/org/org-agenda.el +++ b/lisp/org/org-agenda.el @@ -2230,7 +2230,7 @@ This is an internal flag indicating either temporary or extended agenda restriction. Specifically, it is set to t if the agenda is restricted to an entire file, and is set to the corresponding buffer if the agenda is restricted to a part of a file, e.g. a -region or a substree. In the latter case, +region or a subtree. In the latter case, `org-agenda-restrict-begin' and `org-agenda-restrict-end' are set to the beginning and the end of the part. diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el index 811d3227653..a3fe427403a 100644 --- a/lisp/org/org-element.el +++ b/lisp/org/org-element.el @@ -7981,7 +7981,7 @@ the cache." (unless (memq granularity '( headline headline+inlinetask greater-element element)) (error "Unsupported granularity: %S" granularity)) - ;; Make TO-POS marker. Otherwise, buffer edits may garble the the + ;; Make TO-POS marker. Otherwise, buffer edits may garble the ;; process. (unless (markerp to-pos) (let ((mk (make-marker))) diff --git a/lisp/org/org-fold-core.el b/lisp/org/org-fold-core.el index 4eb875aff2f..db8e8078b27 100644 --- a/lisp/org/org-fold-core.el +++ b/lisp/org/org-fold-core.el @@ -172,7 +172,7 @@ ;; The isearch behavior is controlled on per-folding-spec basis by ;; setting `isearch-open' and `isearch-ignore' folding spec -;; properties. The the docstring of `org-fold-core--specs' for more details. +;; properties. See the docstring of `org-fold-core--specs' for more details. ;;; Handling edits inside folded text diff --git a/lisp/org/org.el b/lisp/org/org.el index e29a0834999..5fc523a7647 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -3796,7 +3796,7 @@ You need to reload Org or to restart Emacs after setting this.") "Alist of characters and faces to emphasize text. Text starting and ending with a special character will be emphasized, for example *bold*, _underlined_ and /italic/. This variable sets the -the face to be used by font-lock for highlighting in Org buffers. +face to be used by font-lock for highlighting in Org buffers. Marker characters must be one of */_=~+. You need to reload Org or to restart Emacs after customizing this." diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 7dc850cb839..e9e58f45aa8 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -7114,7 +7114,7 @@ comment at the start of cc-engine.el for more info." "\\(?:\\\\\\(?:.\\|\n\\)\\|[^\"\n\\]\\)*[\"\n]" nil 'stay))) ((memq lit-type '(c c++)) ;; To work around a bug in parse-partial-sexp, where effect is given - ;; to the syntax of a backslash, even the the scan starts with point + ;; to the syntax of a backslash, even the scan starts with point ;; just after it. (if (and (eq (char-before pt-search) ?\\) (eq (char-after pt-search) ?\n)) diff --git a/lisp/progmodes/scheme.el b/lisp/progmodes/scheme.el index 3242f1c345c..a0f922f279c 100644 --- a/lisp/progmodes/scheme.el +++ b/lisp/progmodes/scheme.el @@ -545,7 +545,7 @@ that variable's value is a string." '("(\\(element\\)\\>[ \t]*(\\(\\S)+\\))" (1 font-lock-keyword-face) (2 font-lock-type-face)) - '("\\<\\sw+:\\>" . font-lock-constant-face) ; trailing `:' c.f. scheme + '("\\<\\sw+:\\>" . font-lock-constant-face) ; trailing `:' cf. scheme ;; SGML markup (from sgml-mode) : '("<\\([!?][-a-z0-9]+\\)" 1 font-lock-keyword-face) '("<\\(/?[-a-z0-9]+\\)" 1 font-lock-function-name-face))) diff --git a/lisp/textmodes/reftex-dcr.el b/lisp/textmodes/reftex-dcr.el index c8ca054407c..063dd496b4d 100644 --- a/lisp/textmodes/reftex-dcr.el +++ b/lisp/textmodes/reftex-dcr.el @@ -110,7 +110,7 @@ to the functions `reftex-view-cr-cite' and `reftex-view-cr-ref'." (if (and (eq arg 2) (windowp dw)) (select-window dw))))) (defun reftex-view-cr-cite (arg key how) - ;; View crossreference of a ref cite. HOW can have the values + ;; View cross-reference of a ref cite. HOW can have the values ;; nil: Show in another window. ;; echo: Show one-line info in echo area. ;; tmp-window: Show in small window and arrange for window to disappear. @@ -175,7 +175,7 @@ to the functions `reftex-view-cr-cite' and `reftex-view-cr-ref'." (select-window pop-win))))) (defun reftex-view-cr-ref (arg label how) - ;; View crossreference of a ref macro. HOW can have the values + ;; View cross-reference of a ref macro. HOW can have the values ;; nil: Show in another window. ;; echo: Show one-line info in echo area. ;; tmp-window: Show in small window and arrange for window to disappear. diff --git a/lisp/winner.el b/lisp/winner.el index 19641a05bfc..919cd91309e 100644 --- a/lisp/winner.el +++ b/lisp/winner.el @@ -261,7 +261,7 @@ You may want to include buffer names such as *Help*, *Apropos*, ;; Make sure point does not end up in the minibuffer and delete ;; windows displaying dead or boring buffers -;; (c.f. `winner-boring-buffers') and `winner-boring-buffers-regexp'. +;; (cf. `winner-boring-buffers') and `winner-boring-buffers-regexp'. ;; Return nil if all the windows should be deleted. Preserve correct ;; points and marks. (defun winner-set (conf) diff --git a/oldXMenu/Internal.c b/oldXMenu/Internal.c index db13f7ac736..2b49fc9ef5b 100644 --- a/oldXMenu/Internal.c +++ b/oldXMenu/Internal.c @@ -809,7 +809,7 @@ _XMRecomputeSelection(register Display *display, register XMenu *menu, register /* * _XMTransToOrigin - Internal subroutine to translate the point at * the center of the current pane and selection to the - * the menu origin. + * menu origin. * * WARNING! ****** Be certain that all menu dependencies have been * recomputed before calling this routine or diff --git a/src/ChangeLog.12 b/src/ChangeLog.12 index 798e87dd572..9df1933d5b8 100644 --- a/src/ChangeLog.12 +++ b/src/ChangeLog.12 @@ -19776,7 +19776,7 @@ 2011-05-10 Jim Meyering - * xdisp.c (x_intersect_rectangles): Fix typo "the the -> the". + * xdisp.c (x_intersect_rectangles): Fix typo. 2011-05-10 Juanma Barranquero diff --git a/src/ChangeLog.13 b/src/ChangeLog.13 index 312909f462f..ff16ad3b16b 100644 --- a/src/ChangeLog.13 +++ b/src/ChangeLog.13 @@ -6250,7 +6250,7 @@ 2014-06-22 Mario Lang - * w32fns.c (Fw32_shell_execute): The the -> the. + * w32fns.c (Fw32_shell_execute): Fix typo. 2014-06-22 Dmitry Antipov diff --git a/src/ChangeLog.8 b/src/ChangeLog.8 index e91448e32e2..73332715a9a 100644 --- a/src/ChangeLog.8 +++ b/src/ChangeLog.8 @@ -8798,7 +8798,7 @@ * dispextern.h (struct glyph_pos): New member dpvec_index. (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P): Test if row ends in the - the middle of a character. + middle of a character. (MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P): Test if row starts in the middle of a character. diff --git a/src/android.c b/src/android.c index 4b673269407..d7a17c519a1 100644 --- a/src/android.c +++ b/src/android.c @@ -5341,7 +5341,7 @@ android_wc_lookup_string (android_key_pressed_event *event, characters = (*env)->GetStringChars (env, string, NULL); android_exception_check_nonnull ((void *) characters, string); - /* Establish the size of the the string. */ + /* Establish the size of the string. */ size = (*env)->GetStringLength (env, string); /* Copy over the string data. */ diff --git a/src/androidvfs.c b/src/androidvfs.c index 833c6b1b2a7..bb855099c77 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -4356,7 +4356,7 @@ android_saf_stat (const char *uri_name, const char *id_name, return 0; } -/* Detect if Emacs has access to the document designated by the the +/* Detect if Emacs has access to the document designated by the document ID ID_NAME within the tree URI_NAME. If ID_NAME is NULL, use the document ID in URI_NAME itself. diff --git a/src/comp.c b/src/comp.c index 3b372145d07..41aa2c4c9b0 100644 --- a/src/comp.c +++ b/src/comp.c @@ -2821,12 +2821,12 @@ emit_static_object (const char *name, Lisp_Object obj) . Adjust if possible to reduce the number of function calls. */ - size_t chunck_size = NILP (Fcomp_libgccjit_version ()) ? 200 : 1024; - char *buff = xmalloc (chunck_size); + size_t chunk_size = NILP (Fcomp_libgccjit_version ()) ? 200 : 1024; + char *buff = xmalloc (chunk_size); for (ptrdiff_t i = 0; i < len;) { - strncpy (buff, p, chunck_size); - buff[chunck_size - 1] = 0; + strncpy (buff, p, chunk_size); + buff[chunk_size - 1] = 0; uintptr_t l = strlen (buff); if (l != 0) diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 085c41eb759..083e1b1e980 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -1853,7 +1853,7 @@ parse_resource_key (const char *res_key, char *setting_key) *dp++ = c; sp++; } - *dp++ = '/'; /* must ends with '/' */ + *dp++ = '/'; /* must end with '/' */ *dp = '\0'; } diff --git a/src/sfnt.c b/src/sfnt.c index 507f2d40e6f..11670f1dd5c 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -9166,7 +9166,7 @@ sfnt_interpret_alignrp (struct sfnt_interpreter *interpreter) ZP1. Move both points along the freedom vector by half the magnitude of - the the projection of a vector formed by P1.x - P2.x, P1.y - P2.y, + the projection of a vector formed by P1.x - P2.x, P1.y - P2.y, upon the projection vector. */ static void diff --git a/src/sfntfont.c b/src/sfntfont.c index cb94a13642e..d1376939a3c 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -1630,7 +1630,7 @@ sfntfont_registries_compatible_p (Lisp_Object a, Lisp_Object b) Value is 0 if there is no match, -1 if there is a match against DESC itself, and the number of matching instances if the style - matches one or more instances defined in in DESC. Return the index + matches one or more instances defined in DESC. Return the index of each matching instance in INSTANCES; it should be SIZE big. */ static int diff --git a/src/textconv.h b/src/textconv.h index e87ff5cd1f8..f3a4388d1a8 100644 --- a/src/textconv.h +++ b/src/textconv.h @@ -100,7 +100,7 @@ struct textconv_callback_struct the end of the conversion. */ enum textconv_caret_direction direction; - /* The the number of times for which to repeat the scanning in order + /* The number of times for which to repeat the scanning in order to determine the starting position of the text to return. */ unsigned short factor; diff --git a/src/w32fns.c b/src/w32fns.c index e5798fdd84f..f23d3c63b25 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -11614,7 +11614,7 @@ void load_unicows_dll_for_w32fns (HMODULE unicows) { if (!unicows) - /* The functions following are defined by SHELL32.DLL onw Windows + /* The functions following are defined by SHELL32.DLL on Windows NT. */ unicows = GetModuleHandle ("shell32"); diff --git a/test/lisp/progmodes/cperl-mode-tests.el b/test/lisp/progmodes/cperl-mode-tests.el index c91253cbeba..02230049596 100644 --- a/test/lisp/progmodes/cperl-mode-tests.el +++ b/test/lisp/progmodes/cperl-mode-tests.el @@ -1448,7 +1448,7 @@ as a regex." ;; Example 3 and 4 can't be directly tested because jit-lock and ;; batch tests don't play together well. But we can approximate - ;; the behavior by calling the the fontification for the same + ;; the behavior by calling the fontification for the same ;; region which would be used by jit-lock. ;; Example 3 (search-forward "sub do_stuff") commit 41dc28244f238739ce5c8f0c25a3d6d66992dd54 Author: Stefan Kangas Date: Thu Jul 18 10:42:59 2024 +0200 * doc/man/emacs.1.in: Add "No warranty" notice. diff --git a/doc/man/emacs.1.in b/doc/man/emacs.1.in index 04eb0c98d3a..3e5c6de930f 100644 --- a/doc/man/emacs.1.in +++ b/doc/man/emacs.1.in @@ -679,6 +679,8 @@ Permission is granted to copy and distribute translations of this document into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. +.PP +There is NO WARRANTY, to the extent permitted by law. . .\" Local Variables: commit b2ac343586709063edb2a3bdfb2cdc1ac484cda1 Author: Stefan Kangas Date: Thu Jul 18 10:36:01 2024 +0200 ; * doc/man/emacs.1.in: Improve wording. diff --git a/doc/man/emacs.1.in b/doc/man/emacs.1.in index bf3ef9b111d..04eb0c98d3a 100644 --- a/doc/man/emacs.1.in +++ b/doc/man/emacs.1.in @@ -144,7 +144,7 @@ Display version information and exit. .TP .B \-\-help -Display this help and exit. +Display help and exit. .RE .PP The following options are Lisp-oriented commit 110b3d08d73b01c84ee7160c656c66eb206a7d90 Author: Stefan Kangas Date: Thu Jul 18 09:54:44 2024 +0200 Improve emacs man page description of --user flag * doc/man/emacs.1.in: Improve --user flag description. (Bug#72169) diff --git a/doc/man/emacs.1.in b/doc/man/emacs.1.in index b478b5196ee..bf3ef9b111d 100644 --- a/doc/man/emacs.1.in +++ b/doc/man/emacs.1.in @@ -1,5 +1,5 @@ .\" See section COPYING for copyright and redistribution information. -.TH EMACS 1 "2022-06-07" "GNU Emacs @version@" "GNU" +.TH EMACS 1 "2024-07-18" "GNU Emacs @version@" "GNU" . . .SH NAME @@ -115,7 +115,7 @@ This is useful for debugging problems in the init file. .BI \-u " user\fR,\fP " \-\-user= "user" Load .IR user 's -init file. +init file instead of your own. .TP .BI \-\-init\-directory= "directory" Start emacs with user-emacs-directory set to @@ -664,7 +664,7 @@ For detailed credits and acknowledgments, see the GNU Emacs manual. . . .SH COPYING -Copyright 1995, 1999-2024 Free Software Foundation, Inc. +Copyright 1995-2024 Free Software Foundation, Inc. .PP Permission is granted to make and distribute verbatim copies of this document provided the copyright notice and this permission notice are commit 4911f08912a55702db1fc17373e98eec8771c4b7 Author: Stefan Kangas Date: Thu Jul 18 09:48:53 2024 +0200 Checkdoc fixes in allout-widgets.el * lisp/allout-widgets.el (allout-widgets-setup) (allout-widgets-tally-string, allout-widgets-mode-inhibit): (allout-widgets-hook-error-handler): Checkdoc fixes. diff --git a/lisp/allout-widgets.el b/lisp/allout-widgets.el index 7f5831d4124..6808a68681a 100644 --- a/lisp/allout-widgets.el +++ b/lisp/allout-widgets.el @@ -115,7 +115,7 @@ inhibition of `allout-widgets-mode'." ;;;_ > allout-widgets-setup (varname value) ;;;###autoload (defun allout-widgets-setup (varname value) - "Commission or decommission allout-widgets-mode along with allout-mode. + "Commission or decommission `allout-widgets-mode' along with `allout-mode'. Meant to be used by customization of `allout-widgets-auto-activation'." (set-default varname value) @@ -254,7 +254,8 @@ or deleted while this variable is nil.") (defun allout-widgets-tally-string () "Return a string with number of tracked widgets, or empty string if not tracking. -The string is formed for appending to the allout-mode mode-line lighter. +The string is formed for appending to the `allout-mode' mode-line +lighter. An empty string is also returned if tracking is inhibited or widgets are locally inhibited. @@ -303,9 +304,9 @@ You can use this as a file local variable setting to disable allout widgets enhancements in selected buffers while generally enabling widgets by customizing `allout-widgets-auto-activation'. -In addition, you can invoked `allout-widgets-mode' allout-mode -buffers where this is set to enable and disable widget -enhancements, directly.") +In addition, you can invoke `allout-widgets-mode' in `allout-mode' +buffers where this is set to enable and disable widget enhancements, +directly.") ;;;###autoload (put 'allout-widgets-mode-inhibit 'safe-local-variable #'booleanp) ;;;_ = allout-inhibit-body-modification-hook @@ -862,7 +863,7 @@ Optional RECURSING is for internal use, to limit recursion." We store a backtrace of the error information in the variable, `allout-widgets-last-hook-error', unset the error handlers, and reraise the error, so that processing continues to the -encompassing condition-case." +encompassing `condition-case'." ;; first deconstruct special error environment so errors here propagate ;; to encompassing condition-case: (setq debugger 'debug commit 109b592d77b41b474a6d61e5a73de66b99d54ce6 Author: Stefan Kangas Date: Thu Jul 18 09:47:19 2024 +0200 Checkdoc fixes in subr.el * lisp/subr.el (ctl-x-4-map, ctl-x-map) (touch-screen-events-received): Checkdoc fixes. diff --git a/lisp/subr.el b/lisp/subr.el index ab388630a91..5a4ef38c3fe 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -1507,7 +1507,7 @@ The normal global definition of the character ESC indirects to this keymap.") (make-obsolete 'ESC-prefix 'esc-map "28.1") (defvar ctl-x-4-map (make-sparse-keymap) - "Keymap for subcommands of C-x 4.") + "Keymap for subcommands of \\`C-x 4'.") (defalias 'ctl-x-4-prefix ctl-x-4-map) (defvar ctl-x-5-map (make-sparse-keymap) @@ -1530,8 +1530,9 @@ The normal global definition of the character ESC indirects to this keymap.") (define-key map "<" #'scroll-left) (define-key map ">" #'scroll-right) map) - "Default keymap for C-x commands. -The normal global definition of the character C-x indirects to this keymap.") + "Default keymap for \\`C-x' commands. +The normal global definition of the character \\`C-x' indirects to this +keymap.") (fset 'Control-X-prefix ctl-x-map) (make-obsolete 'Control-X-prefix 'ctl-x-map "28.1") @@ -3372,8 +3373,8 @@ only unbound fallback disabled is downcasing of the last event." (defvar touch-screen-events-received nil "Whether a touch screen event has ever been translated. -The value of this variable governs whether -`read--potential-mouse-event' calls read-key or read-event.") +The value of this variable governs whether `read--potential-mouse-event' +calls `read-key' or `read-event'.") ;; FIXME: Once there's a safe way to transition away from read-event, ;; callers to this function should be updated to that way and this commit 46436720787821d55589188290442fd5ef559705 Author: Stefan Kangas Date: Thu Jul 18 09:44:28 2024 +0200 Checkdoc fixes in touch-screen.el * lisp/touch-screen.el (touch-screen-handle-touch): Checkdoc fixes. diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index c5918efb800..e7d33845f09 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el @@ -1490,9 +1490,9 @@ If INTERACTIVE, execute the command associated with any event generated instead of throwing `input-event'. Otherwise, throw `input-event' with a single input event if that event should take the place of EVENT within the key sequence being translated, or -`nil' if all tools have been released. +nil if all tools have been released. -Set `touch-screen-events-received' to `t' to indicate that touch +Set `touch-screen-events-received' to t to indicate that touch screen events have been received, and thus by extension require functions undertaking event management themselves to call `read-key' rather than `read-event'." @@ -2077,4 +2077,4 @@ Must be called from a command bound to a `touchscreen-hold' or (provide 'touch-screen) -;;; touch-screen ends here +;;; touch-screen.el ends here commit 9889774c62e7430bce7f9a241ebe529ea00f2362 Author: Stefan Kangas Date: Thu Jul 18 09:43:55 2024 +0200 Checkdoc fixes in treesit.el * lisp/treesit.el (treesit-add-font-lock-rules) (treesit--font-lock-mark-ranges-to-fontify): Checkdoc fixes. diff --git a/lisp/treesit.el b/lisp/treesit.el index b9661f53601..42215333699 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1122,7 +1122,7 @@ and leave settings for other languages unchanged." (t current-value)))))) (defun treesit-add-font-lock-rules (rules &optional how feature) - "Add font-lock RULES to the current buffer + "Add font-lock RULES to the current buffer. RULES should be the return value of `treesit-font-lock-rules'. RULES will be enabled and added to `treesit-font-lock-settings'. @@ -1413,7 +1413,8 @@ For RANGES and PARSER see `treesit-parser-add-notifier'. After the parser reparses, we get the changed ranges, and 1) update non-primary parsers' ranges in the changed ranges 2) mark these ranges as to-be-fontified, -3) tell syntax-ppss to start reparsing from the min point of the ranges. +3) tell `syntax-ppss' to start reparsing from the min point of the + ranges. We need to mark to-be-fontified ranges before redisplay starts working, because sometimes the range edited by the user is not the only range commit c9d28a05d98a2c3c0fe89ac37bc143a41b60ea96 Author: Stefan Kangas Date: Thu Jul 18 09:34:22 2024 +0200 Avoid overflow in pgtk_is_numeric_char * src/pgtkfns.c (parse_resource_key): Avoid overflow by making array larger, if a key is RESOURCE_KEY_MAX_LEN long. Do not merge to master, since it's fixed in a different way there. diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 49467988cae..085c41eb759 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -1803,7 +1803,7 @@ pgtk_is_numeric_char (int c) static GSettings * parse_resource_key (const char *res_key, char *setting_key) { - char path[32 + RESOURCE_KEY_MAX_LEN]; + char path[33 + RESOURCE_KEY_MAX_LEN]; const char *sp = res_key; char *dp; commit da97096fdbb50bf69348813c960eb8d10b2bdc44 Author: Robert Pluim Date: Thu Jul 18 09:05:53 2024 +0200 ; fix previous find-function change diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el index a320a00608d..c1835feff18 100644 --- a/lisp/emacs-lisp/find-func.el +++ b/lisp/emacs-lisp/find-func.el @@ -354,13 +354,13 @@ if non-nil)." (setq def nil)) (completing-read (format-prompt "Library name" def) table nil nil nil - find-function--read-history-library def)) + 'find-function--read-history-library def)) (let ((files (read-library-name--find-files dirs suffixes))) (when (and def (not (member def files))) (setq def nil)) (completing-read (format-prompt "Library name" def) files nil t nil - find-function--read-history-library def))))) + 'find-function--read-history-library def))))) (defun read-library-name--find-files (dirs suffixes) "Return a list of all files in DIRS that match SUFFIXES." commit d31b202377ed844c1ecc405ffb879c03d5552d6b Merge: 3a790abd869 4c35382e983 Author: Po Lu Date: Thu Jul 18 13:36:46 2024 +0800 Merge from savannah/emacs-30 4c35382e983 ; * src/emacs.c (syms_of_emacs) : Fix doc s... 34882d52432 Port better to Android 3.0 765cfaed775 ; * doc/emacs/anti.texi (Antinews): Fix typos (bug#72167). 7093504da2d ; Fix typos (bug#72167) 8c7c4f4baaa New Tramp tests 85d2d7982d4 Update Tramp manual 504bdd560af ; Fix last change 3ccebbe17b7 Fix 'toggle-window-dedicated' documentation 719d5753ca6 ; * doc/lispref/help.texi (Keys in Documentation): Add cr... e3bba63ecb9 Checkdoc fixes in transient.el commit 4c35382e98308843dce79438844fb5a796b7032b Author: Po Lu Date: Thu Jul 18 13:35:47 2024 +0800 ; * src/emacs.c (syms_of_emacs) : Fix doc string indentation. diff --git a/src/emacs.c b/src/emacs.c index 7b315310873..3017063bec4 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -3603,7 +3603,7 @@ Special values: `windows-nt' compiled as a native W32 application. `cygwin' compiled using the Cygwin library. `haiku' compiled for a Haiku system. - `android' compiled for Android. + `android' compiled for Android. Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, hpux, usg-unix-v) indicates some sort of Unix system. */); Vsystem_type = intern_c_string (SYSTEM_TYPE); commit 34882d524328638e2198952578638e0ffe0697c5 Author: Po Lu Date: Tue Jul 16 10:14:30 2024 +0800 Port better to Android 3.0 * java/org/gnu/emacs/EmacsNoninteractive.java (main): Use the old getPackageInfo calling convention if it exists rather than on Android 2.3.3 and earlier. diff --git a/java/org/gnu/emacs/EmacsNoninteractive.java b/java/org/gnu/emacs/EmacsNoninteractive.java index 9f2b9fa8b56..8a1ad98d8f9 100644 --- a/java/org/gnu/emacs/EmacsNoninteractive.java +++ b/java/org/gnu/emacs/EmacsNoninteractive.java @@ -120,11 +120,11 @@ public final class EmacsNoninteractive } /* Get a LoadedApk or ActivityThread.PackageInfo. How to do - this varies by Android version. On Android 2.3.3 and - earlier, there is no ``compatibilityInfo'' argument to + this varies by Android version. On Android 3.0 and earlier, + there is no ``compatibilityInfo'' argument to getPackageInfo. */ - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) + try { method = activityThreadClass.getMethod ("getPackageInfo", @@ -134,7 +134,7 @@ public final class EmacsNoninteractive (Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY)); } - else + catch (NoSuchMethodException exception) { compatibilityInfoClass = Class.forName ("android.content.res.CompatibilityInfo"); commit 765cfaed775567afde3607b87f2657f0c0179f28 Author: john muhl Date: Wed Jul 17 15:48:37 2024 -0500 ; * doc/emacs/anti.texi (Antinews): Fix typos (bug#72167). diff --git a/doc/emacs/anti.texi b/doc/emacs/anti.texi index 42c656ac852..bf355ff1fea 100644 --- a/doc/emacs/anti.texi +++ b/doc/emacs/anti.texi @@ -42,9 +42,9 @@ explicitly at configure time. This makes the default Emacs build process much faster. @item -JSON interfaces are slowly move into oblivion as past years come closer, -so we have removed our internal implementation of JSON; you will now -need to build Emacs with the libjansson library, if you need JSON. +JSON interfaces slowly move into oblivion as past years come closer, so +we have removed our internal implementation of JSON; you will now need +to build Emacs with the libjansson library, if you need JSON. Eventually, we plan on removing JSON support from Emacs altogether; this move will make the removal much simpler. @@ -52,7 +52,7 @@ move will make the removal much simpler. Tree-sitter based modes are now completely independent of their non-Tree-Sitter counterparts. We decided that keeping the settings separate and independent goes a long way toward simplicity, which is one -of our main motivation for removing stuff from Emacs. +of our main motivations for removing stuff from Emacs. @item Various Help commands no longer turn on Outline minor mode. With less commit 7093504da2d7267cec1f6530b3cb234a5301012d Author: john muhl Date: Mon Jul 15 15:08:41 2024 -0500 ; Fix typos (bug#72167) * lisp/minibuffer.el (completion-auto-deselect): Correct spelling of "minibuffer". * lisp/progmodes/peg.el (peg--actions): Correct spelling of "post-processing". * lisp/progmodes/php-ts-mode.el: Correct spelling of "taken". diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 0a0b17b3850..0f6e3518758 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2529,7 +2529,7 @@ any completion candidate highlighted in *Completions* window (to indicate that it is the selected candidate) will be un-highlighted, and point in the *Completions* window will be moved off such a candidate. This means that `RET' (`minibuffer-choose-completion-or-exit') will exit -the minubuffer with the minibuffer's current contents, instead of the +the minibuffer with the minibuffer's current contents, instead of the selected completion candidate." :type '(choice (const :tag "Candidates in *Completions* stay selected as you type" nil) (const :tag "Typing deselects any completion candidate in *Completions*" t)) diff --git a/lisp/progmodes/peg.el b/lisp/progmodes/peg.el index 6dedb6e4895..d19a48c3294 100644 --- a/lisp/progmodes/peg.el +++ b/lisp/progmodes/peg.el @@ -274,7 +274,7 @@ "Actions collected along the current parse. Used at runtime for backtracking. It's a list ((POS . THUNK)...). Each THUNK is executed at the corresponding POS. Thunks are -executed in a postprocessing step, not during parsing.") +executed in a post-processing step, not during parsing.") (defvar peg--errors nil "Data keeping track of the rightmost parse failure location. diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el index 1298b39311b..89444f0208e 100644 --- a/lisp/progmodes/php-ts-mode.el +++ b/lisp/progmodes/php-ts-mode.el @@ -209,7 +209,7 @@ symbol." (when (derived-mode-p 'php-ts-mode) (php-ts-mode-set-style val))))) -;; teken from c-ts-mode +;; taken from c-ts-mode (defun php-ts-indent-style-safep (style) "Non-nil if STYLE's value is safe for file-local variables." (and (symbolp style) (not (functionp style)))) commit 8c7c4f4baaa1cb9f6d5d355c03dddc3dd1e0a747 Author: Michael Albinus Date: Wed Jul 17 18:05:02 2024 +0200 New Tramp tests * test/lisp/net/tramp-tests.el (tramp-test41-special-characters-direct-async) (tramp-test42-utf8-direct-async): New tests. diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 8074bed7a47..786700c727e 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -7623,6 +7623,8 @@ This requires restrictions of file name syntax." (tramp--test-deftest-without-file-attributes tramp-test41-special-characters) +(tramp--test-deftest-direct-async-process tramp-test41-special-characters) + (ert-deftest tramp-test42-utf8 () "Check UTF8 encoding in file names and file contents." (skip-unless (tramp--test-enabled)) @@ -7691,6 +7693,8 @@ This requires restrictions of file name syntax." (tramp--test-deftest-without-file-attributes tramp-test42-utf8) +(tramp--test-deftest-direct-async-process tramp-test42-utf8) + (ert-deftest tramp-test43-file-system-info () "Check that `file-system-info' returns proper values." (skip-unless (tramp--test-enabled)) commit 85d2d7982d41d7c8ea31dd7150c78428a968944a Author: Michael Albinus Date: Wed Jul 17 17:57:20 2024 +0200 Update Tramp manual * doc/misc/tramp.texi (Remote processes): Add another reason why a direct asynchronous process could fail. diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index e1130917f0c..69572a139ff 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -4580,6 +4580,11 @@ It does not report the remote terminal name via @code{process-tty-name}. @item It does not set process property @code{remote-pid}. + +@item +It fails, when the command is too long. This can happen on +directories with a long directory name, or when the remote @env{PATH} +and/or other environment variables, which must be set, are too long. @end itemize In order to gain even more performance, it is recommended to bind commit 3a790abd869ddadc343710deb0c4368227ba6611 Author: Paul Eggert Date: Wed Jul 17 08:13:31 2024 -0700 Go back to preferring -isystem to -I * configure.ac: Go back to preferring -isystem to -I, as headers like still need it. This reverts almost all of 2024-07-16T02:25:44!eggert@cs.ucla.edu, except that the ‘nw="$nw -Wsystem-headers"’ line continues to be removed as it is no longer needed due to recent Gnulib changes. Problem reported by Eli Zaretskii in: https://lists.gnu.org/r/emacs-devel/2024-07/msg00756.html diff --git a/configure.ac b/configure.ac index e2b6dc2fc4d..b6acdf2e456 100644 --- a/configure.ac +++ b/configure.ac @@ -1759,8 +1759,11 @@ if test "$enable_check_lisp_object_type" = yes; then fi WERROR_CFLAGS= +# When compiling with GCC, prefer -isystem to -I when including system +# include files, to avoid generating useless diagnostics for the files. AS_IF([test $gl_gcc_warnings = no], [ + isystem='-I' AS_IF([test "$emacs_cv_clang" = yes], [ # Turn off some warnings if supported. @@ -1770,6 +1773,8 @@ AS_IF([test $gl_gcc_warnings = no], gl_WARN_ADD([-Wno-unknown-pragmas]) ]) ],[ + isystem='-isystem ' + # This, $nw, is the list of warnings we disable. nw= @@ -1909,6 +1914,9 @@ AC_SUBST([GNULIB_WARN_CFLAGS]) edit_cflags=" s,///*,/,g + s/^/ / + s/ -I/ $isystem/g + s/^ // " AC_ARG_ENABLE([link-time-optimization], @@ -2816,7 +2824,7 @@ fi AC_SUBST([LD_SWITCH_X_SITE_RPATH]) if test "${x_includes}" != NONE && test -n "${x_includes}"; then - C_SWITCH_X_SITE=-I`AS_ECHO(["$x_includes"]) | sed -e "s/:/ -I/g"` + C_SWITCH_X_SITE=$isystem`AS_ECHO(["$x_includes"]) | sed -e "s/:/ $isystem/g"` fi if test x"${x_includes}" = x; then @@ -2882,8 +2890,8 @@ if test "${with_ns}" != no; then GNUSTEP_LOCAL_HEADERS="-I${GNUSTEP_LOCAL_HEADERS}" test "x${GNUSTEP_LOCAL_LIBRARIES}" != "x" && \ GNUSTEP_LOCAL_LIBRARIES="-L${GNUSTEP_LOCAL_LIBRARIES}" - CPPFLAGS="$CPPFLAGS -I ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" - CFLAGS="$CFLAGS -I ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" + CPPFLAGS="$CPPFLAGS -isystem ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" + CFLAGS="$CFLAGS -isystem ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" LDFLAGS="$LDFLAGS -L${GNUSTEP_SYSTEM_LIBRARIES} ${GNUSTEP_LOCAL_LIBRARIES}" LIBS_GNUSTEP="-lgnustep-gui -lgnustep-base -lobjc -lpthread" dnl GNUstep defines BASE_NATIVE_OBJC_EXCEPTIONS to 0 or 1. @@ -5787,13 +5795,13 @@ if test "${with_xml2}" != "no"; then xcsdkdir="" ;; esac fi - CPPFLAGS="$CPPFLAGS -I${xcsdkdir}/usr/include/libxml2" + CPPFLAGS="$CPPFLAGS -isystem${xcsdkdir}/usr/include/libxml2" AC_CHECK_HEADER([libxml/HTMLparser.h], [AC_CHECK_DECL([HTML_PARSE_RECOVER], [HAVE_LIBXML2=yes], [], [#include ])]) CPPFLAGS="$SAVE_CPPFLAGS" if test "${HAVE_LIBXML2}" = "yes"; then - LIBXML2_CFLAGS="-I${xcsdkdir}/usr/include/libxml2" + LIBXML2_CFLAGS="-isystem${xcsdkdir}/usr/include/libxml2" LIBXML2_LIBS="-lxml2" fi fi commit 504bdd560affd9173f0b406bcc830afca8648e20 Author: Eli Zaretskii Date: Wed Jul 17 14:10:50 2024 +0300 ; Fix last change * doc/lispref/windows.texi (Dedicated Windows): * doc/emacs/windows.texi (Displaying Buffers): Mention keybinding. diff --git a/doc/emacs/windows.texi b/doc/emacs/windows.texi index 7b9c4146700..69f24ec192f 100644 --- a/doc/emacs/windows.texi +++ b/doc/emacs/windows.texi @@ -434,9 +434,9 @@ you dedicate a window to that buffer, the command (through @kindex C-x w d @findex toggle-window-dedicated - You can use the command @code{toggle-window-dedicated} to toggle -whether the selected window is dedicated to the current buffer. With a -prefix argument, make the window strongly dedicated instead. + You can use the command @kbd{C-x w d} (@code{toggle-window-dedicated}) +to toggle whether the selected window is dedicated to the current +buffer. With a prefix argument, it makes the window strongly dedicated. @menu * Window Choice:: How @code{display-buffer} works. diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 9e47d12c42b..2b1b0d704a0 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -4447,10 +4447,12 @@ the value assigned by the last call of @code{set-window-dedicated-p} for selected window. @end defun +@findex toggle-window-dedicated @defun set-window-dedicated-p window flag This function marks @var{window} as dedicated to its buffer if @var{flag} is non-@code{nil}, and non-dedicated otherwise. -Interactively you can use the @code{toggle-window-dedicated} command. +Interactively you can use the @kbd{C-x w d} +(@code{toggle-window-dedicated}) command to do the same. As a special case, if @var{flag} is @code{t}, @var{window} becomes @dfn{strongly} dedicated to its buffer. @code{set-window-buffer} commit a1f29998bf49c85c2eddc1201657639fdd494ef2 Author: Robert Pluim Date: Tue Jul 16 16:05:40 2024 +0200 Add history variables for find-func entry points * lisp/emacs-lisp/find-func.el (find-function--read-history-library): New defvar. (read-library-name): Use it in 'completing-read' calls. (find-function--read-history-function, find-function--read-history-variable, find-function--read-history-face): New defvars. (find-function-read): Use them in 'completing-read' calls. diff --git a/etc/NEWS b/etc/NEWS index f10f9ae4d65..60bde2abb40 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -30,6 +30,12 @@ applies, and please also update docstrings as needed. * Changes in Emacs 31.1 +--- +** "find-func.el" commands now have history enabled. +The 'find-function', 'find-library', 'find-face-definition', and +'find-variable' commands now allow retrieving previous input using the +usual minibuffer history commands. Each command has a separate history. + * Editing Changes in Emacs 31.1 diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el index ce783983b77..a320a00608d 100644 --- a/lisp/emacs-lisp/find-func.el +++ b/lisp/emacs-lisp/find-func.el @@ -323,6 +323,8 @@ customizing the candidate completions." (switch-to-buffer (find-file-noselect (find-library-name library))) (run-hooks 'find-function-after-hook))) +(defvar find-function--read-history-library nil) + ;;;###autoload (defun read-library-name () "Read and return a library name, defaulting to the one near point. @@ -351,12 +353,14 @@ if non-nil)." (when (and def (not (test-completion def table))) (setq def nil)) (completing-read (format-prompt "Library name" def) - table nil nil nil nil def)) + table nil nil nil + find-function--read-history-library def)) (let ((files (read-library-name--find-files dirs suffixes))) (when (and def (not (member def files))) (setq def nil)) (completing-read (format-prompt "Library name" def) - files nil t nil nil def))))) + files nil t nil + find-function--read-history-library def))))) (defun read-library-name--find-files (dirs suffixes) "Return a list of all files in DIRS that match SUFFIXES." @@ -575,6 +579,10 @@ is non-nil, signal an error instead." (let ((func-lib (find-function-library function lisp-only t))) (find-function-search-for-symbol (car func-lib) nil (cdr func-lib)))) +(defvar find-function--read-history-function nil) +(defvar find-function--read-history-variable nil) +(defvar find-function--read-history-face nil) + (defun find-function-read (&optional type) "Read and return an interned symbol, defaulting to the one near point. @@ -597,7 +605,9 @@ otherwise uses `variable-at-point'." (list (intern (completing-read (format-prompt "Find %s" symb prompt-type) obarray predicate - 'lambda nil nil (and symb (symbol-name symb))))))) + 'lambda nil + (intern (format "find-function--read-history-%s" prompt-type)) + (and symb (symbol-name symb))))))) (defun find-function-do-it (symbol type switch-fn) "Find Emacs Lisp SYMBOL in a buffer and display it. commit 3ccebbe17b73488d2d0ba73fda3b70cb6034cc7d Author: Robert Pluim Date: Wed Jul 17 09:38:43 2024 +0200 Fix 'toggle-window-dedicated' documentation * doc/emacs/windows.texi (Displaying Buffers): Fix the cross reference to the elisp manual. Add missing 'toggle-window-dedicated'. * doc/lispref/windows.texi (Dedicated Windows): Mention 'toggle-window-dedicated'. diff --git a/doc/emacs/windows.texi b/doc/emacs/windows.texi index 60599d42020..7b9c4146700 100644 --- a/doc/emacs/windows.texi +++ b/doc/emacs/windows.texi @@ -418,7 +418,7 @@ these commands are bound in the @kbd{C-x 5} prefix key. @cindex dedicated window Sometimes, a window is ``dedicated'' to its current buffer. -@xref{Dedicated Windows,, elisp, The Emacs Lisp Reference Manual}. +@xref{Dedicated Windows,,, elisp, The Emacs Lisp Reference Manual}. @code{display-buffer} will avoid reusing dedicated windows most of the time. This is indicated by a @samp{d} in the mode line (@pxref{Mode Line}). A window can also be strongly dedicated, which prevents any @@ -434,9 +434,9 @@ you dedicate a window to that buffer, the command (through @kindex C-x w d @findex toggle-window-dedicated - Toggle whether the selected window is dedicated to the current -buffer. With a prefix argument, make the window strongly dedicated -instead. + You can use the command @code{toggle-window-dedicated} to toggle +whether the selected window is dedicated to the current buffer. With a +prefix argument, make the window strongly dedicated instead. @menu * Window Choice:: How @code{display-buffer} works. diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 01ec2a6ecd5..9e47d12c42b 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -4450,6 +4450,7 @@ selected window. @defun set-window-dedicated-p window flag This function marks @var{window} as dedicated to its buffer if @var{flag} is non-@code{nil}, and non-dedicated otherwise. +Interactively you can use the @code{toggle-window-dedicated} command. As a special case, if @var{flag} is @code{t}, @var{window} becomes @dfn{strongly} dedicated to its buffer. @code{set-window-buffer} commit 5684fc5207e15adc2647a08bb9e6205fde112fa6 Author: Yuan Fu Date: Tue Jul 16 21:07:00 2024 -0700 Handle an edge case in c-ts-mode filling (bug#72116) * lisp/progmodes/c-ts-common.el: (c-ts-common-comment-setup): Add a new regexp branch. diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el index a1f257ee09a..6c0b1c9100d 100644 --- a/lisp/progmodes/c-ts-common.el +++ b/lisp/progmodes/c-ts-common.el @@ -251,19 +251,31 @@ Set up: (concat (rx (* (syntax whitespace)) (group (or (seq "/" (+ "/")) (* "*")))) adaptive-fill-regexp)) - ;; Note the missing * comparing to `adaptive-fill-regexp'. The - ;; reason for its absence is a bit convoluted to explain. Suffice - ;; to say that without it, filling a single line paragraph that - ;; starts with /* doesn't insert * at the beginning of each - ;; following line, and filling a multi-line paragraph whose first - ;; two lines start with * does insert * at the beginning of each - ;; following line. If you know how does adaptive filling works, you - ;; know what I mean. + ;; For (1): Note the missing * comparing to `adaptive-fill-regexp'. + ;; The reason for its absence is a bit convoluted to explain. Suffice + ;; to say that without it, filling a single line paragraph that starts + ;; with /* doesn't insert * at the beginning of each following line, + ;; and filling a multi-line paragraph whose first two lines start with + ;; * does insert * at the beginning of each following line. If you + ;; know how does adaptive filling work, you know what I mean. + ;; + ;; For (2): If we only have (1), filling a single line that starts + ;; with a single * (and not /*) in a block comment doesn't work as + ;; expected: the following lines won't be prefixed with *. So we add + ;; another rule to cover this case too. (See bug#72116.) I + ;; intentionally made the matching strict (it only matches if there + ;; are only a single * at the BOL) because I want to minimize the + ;; possibility of this new rule matching in unintended situations. (setq-local adaptive-fill-first-line-regexp (rx bos - (seq (* (syntax whitespace)) - (group (seq "/" (+ "/"))) - (* (syntax whitespace))) + ;; (1) + (or (seq (* (syntax whitespace)) + (group (seq "/" (+ "/"))) + (* (syntax whitespace))) + ;; (2) + (seq (* (syntax whitespace)) + (group "*") + (* (syntax whitespace)))) eos)) ;; Same as `adaptive-fill-regexp'. (setq-local paragraph-start commit d7b93f63f6923f13fe999d12c4f0ba1dbf7160a8 Author: João Távora Date: Mon Jul 15 19:13:12 2024 +0100 Eglot: supported nested {} patterns in globs The tailwindcss-language server issues patterns like this: **/{tailwind,tailwind.config,tailwind.*.config,\ tailwind.config.*}.{js,cjs,ts,mjs} Notive the nested "*" blob inside the the {} group. Eglot used to reject them in 'workspace/didChangeWatchedFiles' requests, responding with "Internal Error". This could confuse some servers. Now I've done some changes to the state machine generation and it supports them. * lisp/progmodes/eglot.el (eglot--glob-parse): Relax parser. (eglot--glob-fsm): New helper. (eglot--glob-compile, eglot--glob-emit-{}): Use it. * test/lisp/progmodes/eglot-tests.el (eglot-test-glob-test): Uncomment some test cases. Github-reference: https://github.com/joaotavora/eglot/issues/1403 diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 5845aff39b7..31948a12d69 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -3879,7 +3879,7 @@ at point. With prefix argument, prompt for ACTION-KIND." with grammar = '((:** "\\*\\*/?" eglot--glob-emit-**) (:* "\\*" eglot--glob-emit-*) (:? "\\?" eglot--glob-emit-?) - (:{} "{[^][*{}]+}" eglot--glob-emit-{}) + (:{} "{[^{}]+}" eglot--glob-emit-{}) (:range "\\[\\^?[^][/,*{}]+\\]" eglot--glob-emit-range) (:literal "[^][,*?{}]+" eglot--glob-emit-self)) until (eobp) @@ -3889,20 +3889,25 @@ at point. With prefix argument, prompt for ACTION-KIND." (list (cl-gensym "state-") emitter (match-string 0))) finally (error "Glob '%s' invalid at %s" (buffer-string) (point)))))) +(cl-defun eglot--glob-fsm (states &key (exit 'eobp) noerror) + `(cl-labels ,(cl-loop for (this that) on states + for (self emit text) = this + for next = (or (car that) exit) + collect (funcall emit text self next)) + ,(if noerror + `(,(caar states)) + `(or (,(caar states)) + (error "Glob done but more unmatched text: '%s'" + (buffer-substring (point) (point-max))))))) + (defun eglot--glob-compile (glob &optional byte-compile noerror) "Convert GLOB into Elisp function. Maybe BYTE-COMPILE it. If NOERROR, return predicate, else erroring function." - (let* ((states (eglot--glob-parse glob)) + (let* ((states (eglot--glob-parse glob)) (body `(with-current-buffer (get-buffer-create " *eglot-glob-matcher*") (erase-buffer) (save-excursion (insert string)) - (cl-labels ,(cl-loop for (this that) on states - for (self emit text) = this - for next = (or (car that) 'eobp) - collect (funcall emit text self next)) - (or (,(caar states)) - (error "Glob done but more unmatched text: '%s'" - (buffer-substring (point) (point-max))))))) + ,(eglot--glob-fsm states))) (form `(lambda (string) ,(if noerror `(ignore-errors ,body) body)))) (if byte-compile (byte-compile form) form))) @@ -3922,10 +3927,20 @@ If NOERROR, return predicate, else erroring function." (defun eglot--glob-emit-{} (arg self next) (let ((alternatives (split-string (substring arg 1 (1- (length arg))) ","))) - `(,self () - (or (re-search-forward ,(concat "\\=" (regexp-opt alternatives)) nil t) - (error "Failed matching any of %s" ',alternatives)) - (,next)))) + (if (cl-notany (lambda (a) (string-match "\\*" a)) alternatives) + `(,self () + (or (re-search-forward ,(concat "\\=" (regexp-opt alternatives)) nil t) + (error "No alternatives match: %s" ',alternatives)) + (,next)) + (let ((fsms (mapcar (lambda (a) + `(save-excursion + (ignore-errors + ,(eglot--glob-fsm (eglot--glob-parse a) + :exit next :noerror t)))) + alternatives))) + `(,self () + (or ,@fsms + (error "Glob match fail after alternatives %s" ',alternatives))))))) (defun eglot--glob-emit-range (arg self next) (when (eq ?! (aref arg 1)) (aset arg 1 ?^)) diff --git a/test/lisp/progmodes/eglot-tests.el b/test/lisp/progmodes/eglot-tests.el index af1ee998919..1e653716a2c 100644 --- a/test/lisp/progmodes/eglot-tests.el +++ b/test/lisp/progmodes/eglot-tests.el @@ -1284,13 +1284,19 @@ GUESSED-MAJOR-MODES-SYM are bound to the useful return values of ;; (should (eglot--glob-match "{foo,bar}/**" "foo")) ;; (should (eglot--glob-match "{foo,bar}/**" "bar")) - ;; VSCode also supports nested blobs. Do we care? + ;; VSCode also supports nested blobs. Do we care? Apparently yes: + ;; github#1403 ;; - ;; (should (eglot--glob-match "{**/*.d.ts,**/*.js}" "/testing/foo.js")) - ;; (should (eglot--glob-match "{**/*.d.ts,**/*.js}" "testing/foo.d.ts")) - ;; (should (eglot--glob-match "{**/*.d.ts,**/*.js,foo.[0-9]}" "foo.5")) - ;; (should (eglot--glob-match "prefix/{**/*.d.ts,**/*.js,foo.[0-9]}" "prefix/foo.8")) - ) + (should (eglot--glob-match "{**/*.d.ts,**/*.js}" "/testing/foo.js")) + (should (eglot--glob-match "{**/*.d.ts,**/*.js}" "testing/foo.d.ts")) + (should (eglot--glob-match "{**/*.d.ts,**/*.js,foo.[0-9]}" "foo.5")) + (should-not (eglot--glob-match "{**/*.d.ts,**/*.js,foo.[0-4]}" "foo.5")) + (should (eglot--glob-match "prefix/{**/*.d.ts,**/*.js,foo.[0-9]}" + "prefix/foo.8")) + (should (eglot--glob-match "prefix/{**/*.js,**/foo.[0-9]}.suffix" + "prefix/a/b/c/d/foo.5.suffix")) + (should (eglot--glob-match "prefix/{**/*.js,**/foo.[0-9]}.suffix" + "prefix/a/b/c/d/foo.js.suffix"))) (defvar tramp-histfile-override) (defun eglot--call-with-tramp-test (fn) commit 7cda30602fcaeecd0072d980a99156812fc7f086 Author: Paul Eggert Date: Tue Jul 16 09:19:31 2024 -0700 Check for more ‘find’ failures and port ‘find’ * Makefile.in (install-eln), configure.ac (emacs_cv_find_delete): * make-dist: Use ‘find ... -exec CMD {} +’ rather than ‘find ... -exec CMD {} \;’ so that if CMD fails, ‘find’ fails too. * Makefile.in (install-eln): Port to ‘find’ implementations that behave differently from GNU ‘find’ when given an argument that contains ‘{}’ within a longer string. POSIX allows this behavior. diff --git a/Makefile.in b/Makefile.in index 2ab8cf0ecc5..ade7d258a4c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -915,8 +915,14 @@ install-etc: install-eln: lisp ifeq ($(HAVE_NATIVE_COMP),yes) umask 022 ; \ - find native-lisp -type d -exec $(MKDIR_P) '$(ELN_DESTDIR){}' \; ; \ - find native-lisp -type f -exec ${INSTALL_ELN} '{}' '$(ELN_DESTDIR){}' \; + find native-lisp -exec sh -c \ + 'for f in "$$@"; do \ + if test -d "$$f"; then \ + $(MKDIR_P) '\''$(ELN_DESTDIR)'\''"$$f" || exit; \ + else \ + $(INSTALL_ELN) "$$f" '\''$(ELN_DESTDIR)'\''"$$f"; \ + fi || exit; \ + done' - {} + endif ### Build Emacs and install it, stripping binaries while installing them. diff --git a/configure.ac b/configure.ac index 144f0bd9fc4..e2b6dc2fc4d 100644 --- a/configure.ac +++ b/configure.ac @@ -2060,7 +2060,7 @@ AC_CACHE_CHECK([for 'find' args to delete a file], [if touch conftest.tmp && find conftest.tmp -delete 2>/dev/null && test ! -f conftest.tmp then emacs_cv_find_delete="-delete" - else emacs_cv_find_delete="-exec rm -f {} ';'" + else emacs_cv_find_delete="-exec rm -f {} +" fi]) FIND_DELETE=$emacs_cv_find_delete AC_SUBST([FIND_DELETE]) diff --git a/make-dist b/make-dist index c8b0fcf4f24..fcf9b28e722 100755 --- a/make-dist +++ b/make-dist @@ -464,7 +464,7 @@ if [ "${newer}" ]; then ## up an incremental distribution already has a running Emacs to byte-compile ## them with. find ${tempdir} \( -name '*.elc' -o ! -newer "${newer}" \) \ - -exec rm -f {} \; || exit + -exec rm -f {} + || exit fi if [ "${make_tar}" = yes ]; then commit a826296cff6ac1c636db83ff66199c60b69cdeb3 Author: Paul Eggert Date: Mon Jul 15 19:41:35 2024 -0700 Quote BIN_DESTDIR better * Makefile.in (BIN_DESTDIR, install-eln, uninstall): * src/Makefile.in ($(pdmp)): Be more consistent about quoting BIN_DESTDIR and ELN_DESTDIR, avoiding double-quoting ''like this'' which does not work as expected. diff --git a/Makefile.in b/Makefile.in index 20394cb333d..2ab8cf0ecc5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -361,10 +361,10 @@ COPYDIR = ${srcdir}/etc ${srcdir}/lisp COPYDESTS = "$(DESTDIR)${etcdir}" "$(DESTDIR)${lispdir}" ifeq (${ns_self_contained},no) -BIN_DESTDIR='$(DESTDIR)${bindir}/' +BIN_DESTDIR = $(DESTDIR)${bindir}/ ELN_DESTDIR = $(DESTDIR)${libdir}/emacs/${version}/ else -BIN_DESTDIR='${ns_appbindir}/' +BIN_DESTDIR = ${ns_appbindir}/ ELN_DESTDIR = ${ns_applibdir}/ endif @@ -915,8 +915,8 @@ install-etc: install-eln: lisp ifeq ($(HAVE_NATIVE_COMP),yes) umask 022 ; \ - find native-lisp -type d -exec $(MKDIR_P) "$(ELN_DESTDIR){}" \; ; \ - find native-lisp -type f -exec ${INSTALL_ELN} "{}" "$(ELN_DESTDIR){}" \; + find native-lisp -type d -exec $(MKDIR_P) '$(ELN_DESTDIR){}' \; ; \ + find native-lisp -type f -exec ${INSTALL_ELN} '{}' '$(ELN_DESTDIR){}' \; endif ### Build Emacs and install it, stripping binaries while installing them. @@ -931,7 +931,7 @@ uninstall: uninstall-$(NTDIR) uninstall-doc uninstall-gsettings-schemas rm -f "$(DESTDIR)$(includedir)/emacs-module.h" $(MAKE) -C lib-src uninstall -unset CDPATH; \ - for dir in "$(DESTDIR)${lispdir}" "$(DESTDIR)${etcdir}" "$(ELN_DESTDIR)" ; do \ + for dir in "$(DESTDIR)${lispdir}" "$(DESTDIR)${etcdir}" '$(ELN_DESTDIR)' ; do \ if [ -d "$${dir}" ]; then \ case `cd "$${dir}" ; pwd -P` in \ "`cd ${srcdir} ; pwd -P`"* ) ;; \ diff --git a/src/Makefile.in b/src/Makefile.in index 7575ecbd07a..c278924ef94 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -682,7 +682,7 @@ endif ifeq ($(DUMPING),pdumper) $(pdmp): emacs$(EXEEXT) $(lispsource)/loaddefs.el $(lispsource)/loaddefs.elc LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \ - --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR) + --bin-dest '$(BIN_DESTDIR)' --eln-dest '$(ELN_DESTDIR)' cp -f $@ $(bootstrap_pdmp) endif @@ -975,7 +975,7 @@ NATIVE_COMPILATION_AOT = @NATIVE_COMPILATION_AOT@ find $@ -name '*.eln' | rebase -v -O -T -; \ fi; \ LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \ - --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR) \ + --bin-dest '$(BIN_DESTDIR)' --eln-dest '$(ELN_DESTDIR)' \ && cp -f emacs$(EXEEXT) bootstrap-emacs$(EXEEXT) \ && cp -f $(pdmp) $(bootstrap_pdmp); \ if test $(NATIVE_COMPILATION_AOT) = yes; then \ @@ -1014,7 +1014,7 @@ ifeq ($(DUMPING),pdumper) $(bootstrap_pdmp): bootstrap-emacs$(EXEEXT) rm -f $@ $(RUN_TEMACS) --batch $(BUILD_DETAILS) -l loadup --temacs=pbootstrap \ - --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR) + --bin-dest '$(BIN_DESTDIR)' --eln-dest '$(ELN_DESTDIR)' @: Compile some files earlier to speed up further compilation. @: First, byte compile these files, .... ANCIENT=yes $(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)" commit a86c25c91f39a25a93d18c9267e024822c1bc43e Author: Paul Eggert Date: Mon Jul 15 19:25:44 2024 -0700 Prefer -I to -isystem * configure.ac: Simplify configuration by using -I instead of -isystem, as -isystem is no longer helpful for suppressing diagnostics (and likely has not been helpful for years). Do not suppress -Wsystem-headers, as Gnulib no longer enables it. diff --git a/configure.ac b/configure.ac index 3198ecd629b..144f0bd9fc4 100644 --- a/configure.ac +++ b/configure.ac @@ -1759,11 +1759,8 @@ if test "$enable_check_lisp_object_type" = yes; then fi WERROR_CFLAGS= -# When compiling with GCC, prefer -isystem to -I when including system -# include files, to avoid generating useless diagnostics for the files. AS_IF([test $gl_gcc_warnings = no], [ - isystem='-I' AS_IF([test "$emacs_cv_clang" = yes], [ # Turn off some warnings if supported. @@ -1773,8 +1770,6 @@ AS_IF([test $gl_gcc_warnings = no], gl_WARN_ADD([-Wno-unknown-pragmas]) ]) ],[ - isystem='-isystem ' - # This, $nw, is the list of warnings we disable. nw= @@ -1797,7 +1792,6 @@ AS_IF([test $gl_gcc_warnings = no], nw="$nw -Wcast-align=strict" # Emacs is tricky with pointers. nw="$nw -Wduplicated-branches" # Too many false alarms nw="$nw -Wformat-overflow=2" # False alarms due to GCC bug 110333 - nw="$nw -Wsystem-headers" # Don't let system headers trigger warnings nw="$nw -Woverlength-strings" # Not a problem these days nw="$nw -Wvla" # Emacs uses . nw="$nw -Wunused-const-variable=2" # lisp.h declares const objects. @@ -1915,9 +1909,6 @@ AC_SUBST([GNULIB_WARN_CFLAGS]) edit_cflags=" s,///*,/,g - s/^/ / - s/ -I/ $isystem/g - s/^ // " AC_ARG_ENABLE([link-time-optimization], @@ -2825,7 +2816,7 @@ fi AC_SUBST([LD_SWITCH_X_SITE_RPATH]) if test "${x_includes}" != NONE && test -n "${x_includes}"; then - C_SWITCH_X_SITE=$isystem`AS_ECHO(["$x_includes"]) | sed -e "s/:/ $isystem/g"` + C_SWITCH_X_SITE=-I`AS_ECHO(["$x_includes"]) | sed -e "s/:/ -I/g"` fi if test x"${x_includes}" = x; then @@ -2891,8 +2882,8 @@ if test "${with_ns}" != no; then GNUSTEP_LOCAL_HEADERS="-I${GNUSTEP_LOCAL_HEADERS}" test "x${GNUSTEP_LOCAL_LIBRARIES}" != "x" && \ GNUSTEP_LOCAL_LIBRARIES="-L${GNUSTEP_LOCAL_LIBRARIES}" - CPPFLAGS="$CPPFLAGS -isystem ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" - CFLAGS="$CFLAGS -isystem ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" + CPPFLAGS="$CPPFLAGS -I ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" + CFLAGS="$CFLAGS -I ${GNUSTEP_SYSTEM_HEADERS} ${GNUSTEP_LOCAL_HEADERS}" LDFLAGS="$LDFLAGS -L${GNUSTEP_SYSTEM_LIBRARIES} ${GNUSTEP_LOCAL_LIBRARIES}" LIBS_GNUSTEP="-lgnustep-gui -lgnustep-base -lobjc -lpthread" dnl GNUstep defines BASE_NATIVE_OBJC_EXCEPTIONS to 0 or 1. @@ -5796,13 +5787,13 @@ if test "${with_xml2}" != "no"; then xcsdkdir="" ;; esac fi - CPPFLAGS="$CPPFLAGS -isystem${xcsdkdir}/usr/include/libxml2" + CPPFLAGS="$CPPFLAGS -I${xcsdkdir}/usr/include/libxml2" AC_CHECK_HEADER([libxml/HTMLparser.h], [AC_CHECK_DECL([HTML_PARSE_RECOVER], [HAVE_LIBXML2=yes], [], [#include ])]) CPPFLAGS="$SAVE_CPPFLAGS" if test "${HAVE_LIBXML2}" = "yes"; then - LIBXML2_CFLAGS="-isystem${xcsdkdir}/usr/include/libxml2" + LIBXML2_CFLAGS="-I${xcsdkdir}/usr/include/libxml2" LIBXML2_LIBS="-lxml2" fi fi commit e1089cc9b6d7abfe468175eb92b146c884e00374 Author: Paul Eggert Date: Mon Jul 15 01:00:56 2024 +0100 Simplify time form analysis This does not change behavior; it merely refactors the code for simplicity. * src/timefns.c (enum timeform, struct form_time): Remove. All uses removed. (decode_time_components): Accept HZ instead of FORM. This saves a switch. All uses changed. (decode_lisp_time): Return union c_time instead of struct form_time. All uses changed. (lisp_time_cform): Remove. All uses changed to just use decode_lisp_time. (time_arith, Ftime_convert): Check (TICKS . HZ) form directly using CONSP, instead of using the old struct form_time. That's fast enough here. diff --git a/src/timefns.c b/src/timefns.c index 333ff3730fd..7d8ecd36407 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -851,39 +851,16 @@ struct err_time union c_time time; }; -/* Lisp timestamp classification. */ -enum timeform - { - TIMEFORM_HI_LO, /* seconds in the form (HI << LO_TIME_BITS) + LO. */ - TIMEFORM_HI_LO_US, /* seconds plus microseconds (HI LO US) */ - TIMEFORM_HI_LO_US_PS, /* seconds plus micro and picoseconds (HI LO US PS) */ - TIMEFORM_FLOAT, /* time as a float */ - TIMEFORM_TICKS_HZ, /* fractional time: HI is ticks, LO is ticks per second */ - TIMEFORM_NIL, /* current time in nanoseconds */ - }; - -/* Assuming the input form was FORM (which should be one of - TIMEFORM_HI_LO, TIMEFORM_HI_LO_US, TIMEFORM_HI_LO_US_PS), - and from the time components HIGH, LOW, USEC and PSEC, - generate the corresponding time value in CFORM form. - +/* From the time components HIGH, LOW, USEC and PSEC and the timestamp + resolution HZ, generate the corresponding time value in CFORM form. + HZ should be either 1, 1000000, or 1000000000000. Return a (0, valid timestamp) pair if successful, an (error number, unspecified timestamp) pair otherwise. */ static struct err_time -decode_time_components (enum timeform form, - Lisp_Object high, Lisp_Object low, +decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, Lisp_Object psec, - enum cform cform) + Lisp_Object hz, enum cform cform) { - Lisp_Object hz; - switch (form) - { - case TIMEFORM_HI_LO: hz = make_fixnum (1); break; - case TIMEFORM_HI_LO_US: hz = make_fixnum (1000000); break; - case TIMEFORM_HI_LO_US_PS: hz = trillion; break; - default: eassume (false); - } - if (!(FIXNUMP (usec) && FIXNUMP (psec))) return (struct err_time) { .err = EINVAL }; @@ -913,26 +890,16 @@ decode_time_components (enum timeform form, } }; - switch (form) + if (BASE_EQ (hz, trillion)) + { + int_fast64_t million = 1000000; + v |= ckd_mul (&iticks, iticks, TRILLION); + v |= ckd_add (&iticks, iticks, us * million + ps); + } + else if (BASE_EQ (hz, make_fixnum (1000000))) { - case TIMEFORM_HI_LO: - break; - - case TIMEFORM_HI_LO_US: v |= ckd_mul (&iticks, iticks, 1000000); v |= ckd_add (&iticks, iticks, us); - break; - - case TIMEFORM_HI_LO_US_PS: - { - int_fast64_t million = 1000000; - v |= ckd_mul (&iticks, iticks, TRILLION); - v |= ckd_add (&iticks, iticks, us * million + ps); - } - break; - - default: - eassume (false); } if (!v) @@ -950,45 +917,30 @@ decode_time_components (enum timeform form, mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); - switch (form) + if (BASE_EQ (hz, trillion)) + { + #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX + unsigned long i = us; + mpz_set_ui (mpz[0], i * 1000000 + ps); + mpz_addmul_ui (mpz[0], *s, TRILLION); + #else + intmax_t i = us; + mpz_set_intmax (mpz[0], i * 1000000 + ps); + mpz_addmul (mpz[0], *s, ztrillion); + #endif + } + else if (BASE_EQ (hz, make_fixnum (1000000))) { - case TIMEFORM_HI_LO: - mpz_swap (mpz[0], *s); - break; - - case TIMEFORM_HI_LO_US: mpz_set_ui (mpz[0], us); mpz_addmul_ui (mpz[0], *s, 1000000); - break; - - case TIMEFORM_HI_LO_US_PS: - { - #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX - unsigned long i = us; - mpz_set_ui (mpz[0], i * 1000000 + ps); - mpz_addmul_ui (mpz[0], *s, TRILLION); - #else - intmax_t i = us; - mpz_set_intmax (mpz[0], i * 1000000 + ps); - mpz_addmul (mpz[0], *s, ztrillion); - #endif - } - break; - - default: - eassume (false); } + else + mpz_swap (mpz[0], *s); + Lisp_Object ticks = make_integer_mpz (); return (struct err_time) { .time = decode_ticks_hz (ticks, hz, cform) }; } -/* A (Lisp timeform, C timestamp) pair. */ -struct form_time -{ - enum timeform form; - union c_time time; -}; - /* Current time (seconds since epoch) in form CFORM. */ static union c_time current_time_in_cform (enum cform cform) @@ -1008,7 +960,7 @@ current_time_in_cform (enum cform cform) components of an old-format SPECIFIED_TIME. Signal an error if unsuccessful. */ -static struct form_time +static union c_time decode_lisp_time (Lisp_Object specified_time, enum cform cform) { /* specified_time is one of: @@ -1034,8 +986,7 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) */ if (NILP (specified_time)) - return (struct form_time) {.form = TIMEFORM_NIL, - .time = current_time_in_cform (cform) }; + return current_time_in_cform (cform); else if (CONSP (specified_time)) { Lisp_Object high = XCAR (specified_time); @@ -1044,7 +995,7 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) Lisp_Object psec = make_fixnum (0); if (CONSP (low)) { - enum timeform form = TIMEFORM_HI_LO; + Lisp_Object hz = make_fixnum (1); Lisp_Object low_tail = XCDR (low); low = XCAR (low); if (cform != CFORM_SECS_ONLY) @@ -1056,23 +1007,23 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) if (CONSP (low_tail)) { psec = XCAR (low_tail); - form = TIMEFORM_HI_LO_US_PS; + hz = trillion; } else - form = TIMEFORM_HI_LO_US; + hz = make_fixnum (1000000); } else if (!NILP (low_tail)) { usec = low_tail; - form = TIMEFORM_HI_LO_US; + hz = make_fixnum (1000000); } } struct err_time err_time - = decode_time_components (form, high, low, usec, psec, cform); + = decode_time_components (high, low, usec, psec, hz, cform); if (err_time.err) time_error (err_time.err); - return (struct form_time) { .form = form, .time = err_time.time }; + return err_time.time; } else { @@ -1080,27 +1031,17 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) if (!(INTEGERP (high) && (FIXNUMP (low) ? XFIXNUM (low) > 0 : !NILP (Fnatnump (low))))) time_spec_invalid (); - return (struct form_time) { .form = TIMEFORM_TICKS_HZ, - .time = decode_ticks_hz (high, low, - cform) }; + return decode_ticks_hz (high, low, cform); } } else if (INTEGERP (specified_time)) - return (struct form_time) - { - .form = TIMEFORM_HI_LO, - .time = decode_ticks_hz (specified_time, make_fixnum (1), cform) - }; + return decode_ticks_hz (specified_time, make_fixnum (1), cform); else if (FLOATP (specified_time)) { double d = XFLOAT_DATA (specified_time); if (!isfinite (d)) time_error (isnan (d) ? EDOM : EOVERFLOW); - return (struct form_time) - { - .form = TIMEFORM_FLOAT, - .time = decode_float_time (d, cform) - }; + return decode_float_time (d, cform); } else time_spec_invalid (); @@ -1111,7 +1052,7 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) double float_time (Lisp_Object specified_time) { - return decode_lisp_time (specified_time, CFORM_DOUBLE).time.d; + return decode_lisp_time (specified_time, CFORM_DOUBLE).d; } /* Convert (HIGH LOW USEC PSEC) to struct timespec. @@ -1121,21 +1062,10 @@ list4_to_timespec (Lisp_Object high, Lisp_Object low, Lisp_Object usec, Lisp_Object psec) { struct err_time err_time - = decode_time_components (TIMEFORM_HI_LO_US_PS, high, low, usec, psec, - CFORM_TIMESPEC); + = decode_time_components (high, low, usec, psec, trillion, CFORM_TIMESPEC); return err_time.err ? invalid_timespec () : err_time.time.ts; } -/* Decode a Lisp time value SPECIFIED_TIME that represents a time. - If SPECIFIED_TIME is nil, use the current time. - Decode to CFORM form. - Signal an error if SPECIFIED_TIME does not represent a time. */ -static union c_time -lisp_time_cform (Lisp_Object specified_time, enum cform cform) -{ - return decode_lisp_time (specified_time, cform).time; -} - /* Decode a Lisp time value SPECIFIED_TIME that represents a time. Discard any low-order (sub-ns) resolution. If SPECIFIED_TIME is nil, use the current time. @@ -1143,7 +1073,7 @@ lisp_time_cform (Lisp_Object specified_time, enum cform cform) struct timespec lisp_time_argument (Lisp_Object specified_time) { - struct timespec t = lisp_time_cform (specified_time, CFORM_TIMESPEC).ts; + struct timespec t = decode_lisp_time (specified_time, CFORM_TIMESPEC).ts; if (! timespec_valid_p (t)) time_overflow (); return t; @@ -1154,8 +1084,7 @@ lisp_time_argument (Lisp_Object specified_time) static time_t lisp_seconds_argument (Lisp_Object specified_time) { - struct timespec t - = decode_lisp_time (specified_time, CFORM_SECS_ONLY).time.ts; + struct timespec t = decode_lisp_time (specified_time, CFORM_SECS_ONLY).ts; if (! timespec_valid_p (t)) time_overflow (); return t.tv_sec; @@ -1202,11 +1131,9 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) static Lisp_Object time_arith (Lisp_Object a, Lisp_Object b, bool subtract) { - struct form_time - fta = decode_lisp_time (a, CFORM_TICKS_HZ), - ftb = decode_lisp_time (b, CFORM_TICKS_HZ); - enum timeform aform = fta.form, bform = ftb.form; - struct ticks_hz ta = fta.time.th, tb = ftb.time.th; + struct ticks_hz + ta = decode_lisp_time (a, CFORM_TICKS_HZ).th, + tb = decode_lisp_time (b, CFORM_TICKS_HZ).th; Lisp_Object ticks, hz; if (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz)) @@ -1290,8 +1217,8 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) return (BASE_EQ (hz, make_fixnum (1)) ? ticks : (!current_time_list - || aform == TIMEFORM_TICKS_HZ - || bform == TIMEFORM_TICKS_HZ + || (CONSP (a) && !CONSP (XCDR (a))) + || (CONSP (b) && !CONSP (XCDR (b))) || !trillion_factor (hz)) ? Fcons (ticks, hz) : ticks_hz_list4 (ticks, hz)); @@ -1347,8 +1274,8 @@ time_cmp (Lisp_Object a, Lisp_Object b) /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing ATICKS * BHZ to BTICKS * AHZ. */ - struct ticks_hz ta = lisp_time_cform (a, CFORM_TICKS_HZ).th; - struct ticks_hz tb = lisp_time_cform (b, CFORM_TICKS_HZ).th; + struct ticks_hz ta = decode_lisp_time (a, CFORM_TICKS_HZ).th; + struct ticks_hz tb = decode_lisp_time (b, CFORM_TICKS_HZ).th; mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); if (! (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz))) @@ -1631,7 +1558,7 @@ usage: (decode-time &optional TIME ZONE FORM) */) struct ticks_hz th; if (EQ (form, Qt)) { - th = lisp_time_cform (specified_time, CFORM_TICKS_HZ).th; + th = decode_lisp_time (specified_time, CFORM_TICKS_HZ).th; struct timespec ts = ticks_hz_to_timespec (th.ticks, th.hz); if (! timespec_valid_p (ts)) time_overflow (); @@ -1817,7 +1744,7 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) } /* Let SEC = floor (TH.ticks / HZ), with SUBSECTICKS the remainder. */ - struct ticks_hz th = decode_lisp_time (secarg, CFORM_TICKS_HZ).time.th; + struct ticks_hz th = decode_lisp_time (secarg, CFORM_TICKS_HZ).th; Lisp_Object hz = th.hz, sec, subsecticks; if (FASTER_TIMEFNS && BASE_EQ (hz, make_fixnum (1))) { @@ -1886,8 +1813,7 @@ but new code should not rely on it. */) { /* FIXME: Any reason why we don't offer a `float` output format option as well, since we accept it as input? */ - struct form_time form_time = decode_lisp_time (time, CFORM_TICKS_HZ); - struct ticks_hz t = form_time.time.th; + struct ticks_hz t = decode_lisp_time (time, CFORM_TICKS_HZ).th; form = (!NILP (form) ? maybe_remove_pos_from_symbol (form) : current_time_list ? Qlist : Qt); if (BASE_EQ (form, Qlist)) @@ -1896,8 +1822,7 @@ but new code should not rely on it. */) return FASTER_TIMEFNS && INTEGERP (time) ? time : ticks_hz_seconds (t); if (BASE_EQ (form, Qt)) form = t.hz; - if (FASTER_TIMEFNS - && form_time.form == TIMEFORM_TICKS_HZ && BASE_EQ (form, XCDR (time))) + if (FASTER_TIMEFNS && CONSP (time) && BASE_EQ (form, XCDR (time))) return time; return Fcons (ticks_hz_hz_ticks (t, form), form); } commit d10c1796c99637d847fa78e3fcb438d03774a00b Author: Paul Eggert Date: Sun Jul 14 17:36:01 2024 +0100 Test !FASTER_TIMEFNS with builtin resolutions * src/timefns.c (timespec_hz, trillion, ztrillion): If !FASTER_TIMEFNS, do not optimize the calculations of these variables. This gives better test coverage of the slow-path code, when compiling with -DFASTER_TIMEFNS=0. (NEED_ZTRILLION_INIT): Move up, to simplify #ifdefery. Now defined or not defined, instead of being 1 or not defined, since it is used only via #ifdef. diff --git a/src/timefns.c b/src/timefns.c index 4ed5f50be96..333ff3730fd 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -73,20 +73,24 @@ enum { TM_YEAR_BASE = 1900 }; enum { CURRENT_TIME_LIST = true }; #endif -#if FIXNUM_OVERFLOW_P (1000000000) -static Lisp_Object timespec_hz; -#else +#if FASTER_TIMEFNS && !FIXNUM_OVERFLOW_P (1000000000) # define timespec_hz make_fixnum (TIMESPEC_HZ) +#else +static Lisp_Object timespec_hz; #endif #define TRILLION 1000000000000 -#if FIXNUM_OVERFLOW_P (TRILLION) -static Lisp_Object trillion; -# define ztrillion (*xbignum_val (trillion)) -#else +#if FASTER_TIMEFNS && !FIXNUM_OVERFLOW_P (TRILLION) # define trillion make_fixnum (TRILLION) -# if ULONG_MAX < TRILLION || !FASTER_TIMEFNS +#else +static Lisp_Object trillion; +#endif +#if ! (FASTER_TIMEFNS && TRILLION <= ULONG_MAX) +# if FIXNUM_OVERFLOW_P (TRILLION) +# define ztrillion (*xbignum_val (trillion)) +# else static mpz_t ztrillion; +# define NEED_ZTRILLION_INIT # endif #endif @@ -2137,10 +2141,6 @@ emacs_setenv_TZ (const char *tzstring) return 0; } -#if (ULONG_MAX < TRILLION || !FASTER_TIMEFNS) && !defined ztrillion -# define NEED_ZTRILLION_INIT 1 -#endif - #ifdef NEED_ZTRILLION_INIT static void syms_of_timefns_for_pdumper (void) commit 51d096ec07dc3bc053965096cd768847020c240d Author: Paul Eggert Date: Sun Jul 14 15:59:20 2024 +0100 Make ztrillion static * src/timefns.c (ztrillion): Now static, when it is a variable, since no other module uses it. diff --git a/src/timefns.c b/src/timefns.c index 331c11e0f34..4ed5f50be96 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -86,7 +86,7 @@ static Lisp_Object trillion; #else # define trillion make_fixnum (TRILLION) # if ULONG_MAX < TRILLION || !FASTER_TIMEFNS -mpz_t ztrillion; +static mpz_t ztrillion; # endif #endif commit a53fd69fe21ea057cd257e663219a33399545949 Author: Paul Eggert Date: Sun Jul 14 23:45:31 2024 +0100 Fix buffer size problem in print_bool_vector * src/print.c (print_bool_vector): Don’t assume SIZE fits into ptrdiff_t, since it is an EMACS_INT. This pacifies gcc -Wformat-overflow on i686 --with-wide-int. diff --git a/src/print.c b/src/print.c index bd1d76b3b1b..8f28b14e8b6 100644 --- a/src/print.c +++ b/src/print.c @@ -1617,7 +1617,7 @@ print_bool_vector (Lisp_Object obj, Lisp_Object printcharfun) ptrdiff_t real_size_in_bytes = size_in_bytes; unsigned char *data = bool_vector_uchar_data (obj); - char buf[sizeof "#&\"" + INT_STRLEN_BOUND (ptrdiff_t)]; + char buf[sizeof "#&\"" + INT_STRLEN_BOUND (EMACS_INT)]; int len = sprintf (buf, "#&%"pI"d\"", size); strout (buf, len, len, printcharfun); commit b77abd2bfeb13ae046b1f8c6157bd5a497665657 Author: Paul Eggert Date: Sun Jul 14 23:37:50 2024 +0100 alloc.c: ckd_add, not by-hand checks * src/alloc.c (lmalloc, lrealloc): Prefer ckd_add to by-hand checks for integer addition overflow. diff --git a/src/alloc.c b/src/alloc.c index 37069ee4c9e..52f8a65d59d 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1404,8 +1404,8 @@ lmalloc (size_t size, bool clearit) if (laligned (p, size) && (MALLOC_0_IS_NONNULL || size || p)) return p; free (p); - size_t bigger = size + LISP_ALIGNMENT; - if (size < bigger) + size_t bigger; + if (!ckd_add (&bigger, size, LISP_ALIGNMENT)) size = bigger; } } @@ -1418,8 +1418,8 @@ lrealloc (void *p, size_t size) p = realloc (p, size); if (laligned (p, size) && (size || p)) return p; - size_t bigger = size + LISP_ALIGNMENT; - if (size < bigger) + size_t bigger; + if (!ckd_add (&bigger, size, LISP_ALIGNMENT)) size = bigger; } } commit b4050ab75e896dd0df51624c956e0dd412dde2cc Author: Paul Eggert Date: Sun Jul 14 23:24:21 2024 +0100 Fix get_conversion_field --with-wide-wint overflow * src/textconv.c (get_conversion_field): Set max value to PTRDIFF_MAX, not MOST_POSITIVE_FIXNUM, since the variable is ptrdiff_t, not EMACS_INT. Problem caught by gcc -Woverflow on a 32-bit platform with --with-wide-int. diff --git a/src/textconv.c b/src/textconv.c index e3f928cd789..948f4c14725 100644 --- a/src/textconv.c +++ b/src/textconv.c @@ -1741,7 +1741,7 @@ handle_pending_conversion_events (void) /* Return the confines of the field to which editing operations on frame F should be constrained in *BEG and *END. Should no field be active, - set *END to MOST_POSITIVE_FIXNUM. */ + set *END to PTRDIFF_MAX. */ void get_conversion_field (struct frame *f, ptrdiff_t *beg, ptrdiff_t *end) @@ -1769,7 +1769,7 @@ get_conversion_field (struct frame *f, ptrdiff_t *beg, ptrdiff_t *end) } *beg = 1; - *end = MOST_POSITIVE_FIXNUM; + *end = PTRDIFF_MAX; } /* Start a ``batch edit'' in frame F. During a batch edit, commit a4bafce01e605ddcfff7a4de018b50ad96ea6f8a Author: Paul Eggert Date: Sun Jul 14 23:03:05 2024 +0100 Pacify -Wmissing-variable-declarations for lisp_malloc_user * src/alloc.c (lisp_malloc_user) [!USE_LSB_TAG]: Provide extern decl. diff --git a/src/alloc.c b/src/alloc.c index 666f77bfce1..37069ee4c9e 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -998,6 +998,7 @@ record_xmalloc (size_t size) allocated memory block (for strings, for conses, ...). */ #if ! USE_LSB_TAG +extern void *lisp_malloc_loser; void *lisp_malloc_loser EXTERNALLY_VISIBLE; #endif commit 31517e81d0d8562e222d4b0de399915df956099f Author: Paul Eggert Date: Sun Jul 14 20:53:28 2024 +0100 Pacify 32-bit GCC 14.1.1 in timer_check_2 * src/keyboard.c (timer_check_2): Refactor to make flow control more obvious, to pacify -Wanalyzer-use-of-uninitialized-value with gcc 14.1.1 20240607 (Red Hat 14.1.1-5) on i686. diff --git a/src/keyboard.c b/src/keyboard.c index 6c33d08c265..b312d529e59 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4679,15 +4679,6 @@ decode_timer (Lisp_Object timer) static struct timespec timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) { - struct timespec nexttime; - struct timespec now; - struct timespec idleness_now; - Lisp_Object chosen_timer; - - nexttime = invalid_timespec (); - - chosen_timer = Qnil; - /* First run the code that was delayed. */ while (CONSP (pending_funcalls)) { @@ -4696,17 +4687,18 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) safe_calln (Qapply, XCAR (funcall), XCDR (funcall)); } - if (CONSP (timers) || CONSP (idle_timers)) - { - now = current_timespec (); - idleness_now = (timespec_valid_p (timer_idleness_start_time) - ? timespec_sub (now, timer_idleness_start_time) - : make_timespec (0, 0)); - } + if (! (CONSP (timers) || CONSP (idle_timers))) + return invalid_timespec (); + + struct timespec + now = current_timespec (), + idleness_now = (timespec_valid_p (timer_idleness_start_time) + ? timespec_sub (now, timer_idleness_start_time) + : make_timespec (0, 0)); - while (CONSP (timers) || CONSP (idle_timers)) + do { - Lisp_Object timer = Qnil, idle_timer = Qnil; + Lisp_Object chosen_timer, timer = Qnil, idle_timer = Qnil; struct timespec difference; struct timespec timer_difference = invalid_timespec (); struct timespec idle_timer_difference = invalid_timespec (); @@ -4810,8 +4802,7 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) return 0 to indicate that. */ } - nexttime = make_timespec (0, 0); - break; + return make_timespec (0, 0); } else /* When we encounter a timer that is still waiting, @@ -4820,10 +4811,10 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) return difference; } } + while (CONSP (timers) || CONSP (idle_timers)); /* No timers are pending in the future. */ - /* Return 0 if we generated an event, and -1 if not. */ - return nexttime; + return invalid_timespec (); } commit 2067c255e677f77eaf27dc992400111d8ac59bfd Author: Paul Eggert Date: Fri Jul 12 17:23:30 2024 +0100 Use Gnulib workaround for Android strnlen bug The workaround for the Android 5.0 (API 21) strnlen bug is now done in m4/strnlen.m4, taken from Gnulib, so there is no need for Emacs to have its own workaround. * configure.ac (ORIGINAL_AC_FUNC_STRNLEN, AC_FUNC_STRNLEN): Remove. diff --git a/configure.ac b/configure.ac index 48120e60f37..3198ecd629b 100644 --- a/configure.ac +++ b/configure.ac @@ -1611,30 +1611,6 @@ AC_DEFUN([gl_TYPE_OFF64_T], [HAVE_OFF64_T=1 AC_SUBST([HAVE_OFF64_T])]) -# `strnlen' cannot accept nlen greater than the size of the object S -# on Android 5.0 and earlier. -m4_define([ORIGINAL_AC_FUNC_STRNLEN], m4_defn([AC_FUNC_STRNLEN])) -AC_DEFUN([AC_FUNC_STRNLEN], [ -AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_CACHE_CHECK([for strnlen capable of accepting large limits], - [emacs_cv_func_strnlen_working], - [AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], [[ - volatile size_t (*strnlen_pointer) (const char *s, size_t) = &strnlen; - if ((*strnlen_pointer) ("", -1) != 0) - return 1; - return 0; -]])],[emacs_cv_func_strnlen_working=yes], - [emacs_cv_func_strnlen_working=no], - [# Guess no on Android 21 and earlier, yes elsewhere. - AS_IF([test -n "$ANDROID_SDK" && test "$ANDROID_SDK" -lt 22], - [emacs_cv_func_strnlen_working=no], - [emacs_cv_func_strnlen_working='guessing yes'])])]) -AS_IF([test "$emacs_cv_func_strnlen_working" != "no"], - [ORIGINAL_AC_FUNC_STRNLEN], - [ac_cv_func_strnlen_working=no - AC_LIBOBJ([strnlen])])]) - # Initialize gnulib right after choosing the compiler. dnl Amongst other things, this sets AR and ARFLAGS. gl_EARLY commit f5dbdedcc53d2c57b9ddecbe9248c90ef0fa08d6 Author: Paul Eggert Date: Mon Jul 15 19:03:17 2024 -0700 Update from Gnulib by running admin/merge-gnulib diff --git a/build-aux/gitlog-to-changelog b/build-aux/gitlog-to-changelog index 49e7ef95cef..a2c348e2cf0 100755 --- a/build-aux/gitlog-to-changelog +++ b/build-aux/gitlog-to-changelog @@ -35,7 +35,7 @@ eval 'exec perl -wSx "$0" "$@"' if 0; -my $VERSION = '2023-06-24 21:59'; # UTC +my $VERSION = '2024-07-04 10:56'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook @@ -97,6 +97,7 @@ OPTIONS: --strip-cherry-pick remove data inserted by "git cherry-pick"; this includes the "cherry picked from commit ..." line, and the possible final "Conflicts:" paragraph. + --commit-timezone use dates respecting the timezone commits were made in. --help display this help and exit --version output version information and exit @@ -247,6 +248,7 @@ sub git_dir_option($) my $ignore_line; my $strip_tab = 0; my $strip_cherry_pick = 0; + my $commit_timezone = 0; my $srcdir; GetOptions ( @@ -262,6 +264,7 @@ sub git_dir_option($) 'ignore-line=s' => \$ignore_line, 'strip-tab' => \$strip_tab, 'strip-cherry-pick' => \$strip_cherry_pick, + 'commit-timezone' => \$commit_timezone, 'srcdir=s' => \$srcdir, ) or usage 1; @@ -274,10 +277,12 @@ sub git_dir_option($) # that makes a correction in the log or attribution of that commit. my $amend_code = defined $amend_file ? parse_amend_file $amend_file : {}; + my $commit_time_format = $commit_timezone ? '%cI' : '%ct'; my @cmd = ('git', git_dir_option $srcdir, qw(log --log-size), - '--pretty=format:%H:%ct %an <%ae>%n%n'.$format_string, @ARGV); + ("--pretty=format:%H:$commit_time_format" + . ' %an <%ae>%n%n'.$format_string, @ARGV)); open PIPE, '-|', @cmd or die ("$ME: failed to run '". quoted_cmd (@cmd) ."': $!\n" . "(Is your Git too old? Version 1.5.1 or later is required.)\n"); @@ -350,17 +355,31 @@ sub git_dir_option($) my $author_line = shift @line; defined $author_line or die "$ME:$.: unexpected EOF\n"; - $author_line =~ /^(\d+) (.*>)$/ + $author_line =~ /^(\S+) (.*>)$/ or die "$ME:$.: Invalid line " . "(expected date/author/email):\n$author_line\n"; + # Author + my $author = $2; + + my $commit_date = $1; + if (! $commit_timezone) + { + # Seconds since the Epoch. + $commit_date = strftime "%Y-%m-%d", localtime ($commit_date); + } + else + { + # ISO 8601 date. + $commit_date =~ s/T.*$//; + } + # Format 'Copyright-paperwork-exempt: Yes' as a standard ChangeLog # '(tiny change)' annotation. my $tiny = (grep (/^(?:Copyright-paperwork-exempt|Tiny-change):\s+[Yy]es$/, @line) ? ' (tiny change)' : ''); - my $date_line = sprintf "%s %s$tiny\n", - strftime ("%Y-%m-%d", localtime ($1)), $2; + my $date_line = "$commit_date $author$tiny\n"; my @coauthors = grep /^Co-authored-by:.*$/, @line; # Omit meta-data lines we've already interpreted. @@ -507,7 +526,7 @@ sub git_dir_option($) # Local Variables: # mode: perl # indent-tabs-mode: nil -# eval: (add-hook 'before-save-hook 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp nil t) # time-stamp-line-limit: 50 # time-stamp-start: "my $VERSION = '" # time-stamp-format: "%:y-%02m-%02d %02H:%02M" diff --git a/build-aux/move-if-change b/build-aux/move-if-change index 18a720735cd..a73bd2403cf 100755 --- a/build-aux/move-if-change +++ b/build-aux/move-if-change @@ -2,7 +2,7 @@ # Like mv $1 $2, but if the files are the same, just delete $1. # Status is zero if successful, nonzero otherwise. -VERSION='2018-03-07 03:47'; # UTC +VERSION='2024-07-04 10:56'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook @@ -76,7 +76,7 @@ else fi ## Local Variables: -## eval: (add-hook 'before-save-hook 'time-stamp) +## eval: (add-hook 'before-save-hook 'time-stamp nil t) ## time-stamp-start: "VERSION='" ## time-stamp-format: "%:y-%02m-%02d %02H:%02M" ## time-stamp-time-zone: "UTC0" diff --git a/build-aux/update-copyright b/build-aux/update-copyright index ea3e46fe60f..42f26933835 100755 --- a/build-aux/update-copyright +++ b/build-aux/update-copyright @@ -138,7 +138,7 @@ eval 'exec perl -wSx -0777 -pi "$0" "$@"' if 0; -my $VERSION = '2024-01-15.18:30'; # UTC +my $VERSION = '2024-07-04.10:56'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook @@ -298,7 +298,7 @@ if (!$found) # coding: utf-8 # mode: perl # indent-tabs-mode: nil -# eval: (add-hook 'before-save-hook 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp nil t) # time-stamp-line-limit: 200 # time-stamp-start: "my $VERSION = '" # time-stamp-format: "%:y-%02m-%02d.%02H:%02M" diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 948269e744d..cebde64d117 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -386,6 +386,7 @@ GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@ GL_GNULIB_DUP = @GL_GNULIB_DUP@ GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@ GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@ +GL_GNULIB_DZPRINTF = @GL_GNULIB_DZPRINTF@ GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@ GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@ GL_GNULIB_EXECL = @GL_GNULIB_EXECL@ @@ -431,6 +432,7 @@ GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@ GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@ GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@ GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@ +GL_GNULIB_FZPRINTF = @GL_GNULIB_FZPRINTF@ GL_GNULIB_GETC = @GL_GNULIB_GETC@ GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@ GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@ @@ -602,6 +604,7 @@ GL_GNULIB_SIGNAL_H_SIGPIPE = @GL_GNULIB_SIGNAL_H_SIGPIPE@ GL_GNULIB_SIGPROCMASK = @GL_GNULIB_SIGPROCMASK@ GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@ GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@ +GL_GNULIB_SNZPRINTF = @GL_GNULIB_SNZPRINTF@ GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@ GL_GNULIB_STAT = @GL_GNULIB_STAT@ GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@ @@ -637,6 +640,7 @@ GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@ GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@ GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@ GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@ +GL_GNULIB_SZPRINTF = @GL_GNULIB_SZPRINTF@ GL_GNULIB_TIME = @GL_GNULIB_TIME@ GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@ GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@ @@ -658,22 +662,24 @@ GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@ GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@ GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@ GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@ -GL_GNULIB_VAZSPRINTF = @GL_GNULIB_VAZSPRINTF@ +GL_GNULIB_VASZPRINTF = @GL_GNULIB_VASZPRINTF@ GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@ +GL_GNULIB_VDZPRINTF = @GL_GNULIB_VDZPRINTF@ GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@ GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@ GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@ +GL_GNULIB_VFZPRINTF = @GL_GNULIB_VFZPRINTF@ GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@ GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@ GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@ GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@ +GL_GNULIB_VSNZPRINTF = @GL_GNULIB_VSNZPRINTF@ GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@ -GL_GNULIB_VZSNPRINTF = @GL_GNULIB_VZSNPRINTF@ -GL_GNULIB_VZSPRINTF = @GL_GNULIB_VZSPRINTF@ +GL_GNULIB_VSZPRINTF = @GL_GNULIB_VSZPRINTF@ +GL_GNULIB_VZPRINTF = @GL_GNULIB_VZPRINTF@ GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@ GL_GNULIB_WRITE = @GL_GNULIB_WRITE@ -GL_GNULIB_ZSNPRINTF = @GL_GNULIB_ZSNPRINTF@ -GL_GNULIB_ZSPRINTF = @GL_GNULIB_ZSPRINTF@ +GL_GNULIB_ZPRINTF = @GL_GNULIB_ZPRINTF@ GL_GNULIB__EXIT = @GL_GNULIB__EXIT@ GL_STDC_BIT_CEIL = @GL_STDC_BIT_CEIL@ GL_STDC_BIT_FLOOR = @GL_STDC_BIT_FLOOR@ @@ -3285,6 +3291,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ -e 's|@''NEXT_STDIO_H''@|$(NEXT_STDIO_H)|g' \ -e 's/@''GNULIB_DPRINTF''@/$(GL_GNULIB_DPRINTF)/g' \ + -e 's/@''GNULIB_DZPRINTF''@/$(GL_GNULIB_DZPRINTF)/g' \ -e 's/@''GNULIB_FCLOSE''@/$(GL_GNULIB_FCLOSE)/g' \ -e 's/@''GNULIB_FDOPEN''@/$(GL_GNULIB_FDOPEN)/g' \ -e 's/@''GNULIB_FFLUSH''@/$(GL_GNULIB_FFLUSH)/g' \ @@ -3305,6 +3312,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's/@''GNULIB_FTELL''@/$(GL_GNULIB_FTELL)/g' \ -e 's/@''GNULIB_FTELLO''@/$(GL_GNULIB_FTELLO)/g' \ -e 's/@''GNULIB_FWRITE''@/$(GL_GNULIB_FWRITE)/g' \ + -e 's/@''GNULIB_FZPRINTF''@/$(GL_GNULIB_FZPRINTF)/g' \ -e 's/@''GNULIB_GETC''@/$(GL_GNULIB_GETC)/g' \ -e 's/@''GNULIB_GETCHAR''@/$(GL_GNULIB_GETCHAR)/g' \ -e 's/@''GNULIB_GETDELIM''@/$(GL_GNULIB_GETDELIM)/g' \ @@ -3325,25 +3333,29 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's/@''GNULIB_RENAMEAT''@/$(GL_GNULIB_RENAMEAT)/g' \ -e 's/@''GNULIB_SCANF''@/$(GL_GNULIB_SCANF)/g' \ -e 's/@''GNULIB_SNPRINTF''@/$(GL_GNULIB_SNPRINTF)/g' \ + -e 's/@''GNULIB_SNZPRINTF''@/$(GL_GNULIB_SNZPRINTF)/g' \ -e 's/@''GNULIB_SPRINTF_POSIX''@/$(GL_GNULIB_SPRINTF_POSIX)/g' \ -e 's/@''GNULIB_STDIO_H_NONBLOCKING''@/$(GL_GNULIB_STDIO_H_NONBLOCKING)/g' \ -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GL_GNULIB_STDIO_H_SIGPIPE)/g' \ + -e 's/@''GNULIB_SZPRINTF''@/$(GL_GNULIB_SZPRINTF)/g' \ -e 's/@''GNULIB_TMPFILE''@/$(GL_GNULIB_TMPFILE)/g' \ -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \ - -e 's/@''GNULIB_VAZSPRINTF''@/$(GL_GNULIB_VAZSPRINTF)/g' \ + -e 's/@''GNULIB_VASZPRINTF''@/$(GL_GNULIB_VASZPRINTF)/g' \ -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \ + -e 's/@''GNULIB_VDZPRINTF''@/$(GL_GNULIB_VDZPRINTF)/g' \ -e 's/@''GNULIB_VFPRINTF''@/$(GL_GNULIB_VFPRINTF)/g' \ -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GL_GNULIB_VFPRINTF_POSIX)/g' \ + -e 's/@''GNULIB_VFZPRINTF''@/$(GL_GNULIB_VFZPRINTF)/g' \ -e 's/@''GNULIB_VFSCANF''@/$(GL_GNULIB_VFSCANF)/g' \ -e 's/@''GNULIB_VSCANF''@/$(GL_GNULIB_VSCANF)/g' \ -e 's/@''GNULIB_VPRINTF''@/$(GL_GNULIB_VPRINTF)/g' \ -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GL_GNULIB_VPRINTF_POSIX)/g' \ -e 's/@''GNULIB_VSNPRINTF''@/$(GL_GNULIB_VSNPRINTF)/g' \ + -e 's/@''GNULIB_VSNZPRINTF''@/$(GL_GNULIB_VSNZPRINTF)/g' \ -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GL_GNULIB_VSPRINTF_POSIX)/g' \ - -e 's/@''GNULIB_VZSNPRINTF''@/$(GL_GNULIB_VZSNPRINTF)/g' \ - -e 's/@''GNULIB_VZSPRINTF''@/$(GL_GNULIB_VZSPRINTF)/g' \ - -e 's/@''GNULIB_ZSNPRINTF''@/$(GL_GNULIB_ZSNPRINTF)/g' \ - -e 's/@''GNULIB_ZSPRINTF''@/$(GL_GNULIB_ZSPRINTF)/g' \ + -e 's/@''GNULIB_VSZPRINTF''@/$(GL_GNULIB_VSZPRINTF)/g' \ + -e 's/@''GNULIB_VZPRINTF''@/$(GL_GNULIB_VZPRINTF)/g' \ + -e 's/@''GNULIB_ZPRINTF''@/$(GL_GNULIB_ZPRINTF)/g' \ -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GL_GNULIB_MDA_FCLOSEALL)/g' \ -e 's/@''GNULIB_MDA_FDOPEN''@/$(GL_GNULIB_MDA_FDOPEN)/g' \ -e 's/@''GNULIB_MDA_FILENO''@/$(GL_GNULIB_MDA_FILENO)/g' \ diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c index dfc39cead05..877f42588b7 100644 --- a/lib/qcopy-acl.c +++ b/lib/qcopy-acl.c @@ -26,6 +26,20 @@ #if USE_XATTR # include +# include + +# if HAVE_LINUX_XATTR_H +# include +# endif +# ifndef XATTR_NAME_NFSV4_ACL +# define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" +# endif +# ifndef XATTR_NAME_POSIX_ACL_ACCESS +# define XATTR_NAME_POSIX_ACL_ACCESS "system.posix_acl_access" +# endif +# ifndef XATTR_NAME_POSIX_ACL_DEFAULT +# define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default" +# endif /* Returns 1 if NAME is the name of an extended attribute that is related to permissions, i.e. ACLs. Returns 0 otherwise. */ @@ -33,7 +47,12 @@ static int is_attr_permissions (const char *name, struct error_context *ctx) { - return attr_copy_action (name, ctx) == ATTR_ACTION_PERMISSIONS; + /* We need to explicitly test for the known extended attribute names, + because at least on CentOS 7, attr_copy_action does not do it. */ + return strcmp (name, XATTR_NAME_POSIX_ACL_ACCESS) == 0 + || strcmp (name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0 + || strcmp (name, XATTR_NAME_NFSV4_ACL) == 0 + || attr_copy_action (name, ctx) == ATTR_ACTION_PERMISSIONS; } #endif /* USE_XATTR */ diff --git a/lib/stdio.in.h b/lib/stdio.in.h index cf2d8c999bc..38572382d46 100644 --- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -280,7 +280,26 @@ #endif +#if @GNULIB_DZPRINTF@ +/* Prints formatted output to file descriptor FD. + Returns the number of bytes written to the file descriptor. Upon + failure, returns -1 with errno set. + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure codes are ENOMEM + and the possible failure codes from write(), excluding EINTR. */ +_GL_FUNCDECL_SYS (dzprintf, off64_t, + (int fd, const char *restrict format, ...) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_SYS (dzprintf, off64_t, + (int fd, const char *restrict format, ...)); +#endif + #if @GNULIB_DPRINTF@ +/* Prints formatted output to file descriptor FD. + Returns the number of bytes written to the file descriptor. Upon + failure, returns a negative value. */ # if @REPLACE_DPRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define dprintf rpl_dprintf @@ -547,7 +566,26 @@ _GL_WARN_ON_USE (fopen, "fopen on native Windows platforms is not POSIX complian # endif #endif +#if @GNULIB_FZPRINTF@ +/* Prints formatted output to stream FP. + Returns the number of bytes written to the stream. Upon failure, + returns -1 with the stream's error indicator set. + Failure cause EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure causes are ENOMEM + and the possible failure causes from fwrite(). */ +_GL_FUNCDECL_SYS (fzprintf, off64_t, + (FILE *restrict fp, const char *restrict format, ...) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (fzprintf, off64_t, + (FILE *restrict fp, const char *restrict format, ...)); +#endif + #if @GNULIB_FPRINTF_POSIX@ || @GNULIB_FPRINTF@ +/* Prints formatted output to stream FP. + Returns the number of bytes written to the stream. Upon failure, + returns a negative value with the stream's error indicator set. */ # if (@GNULIB_FPRINTF_POSIX@ && @REPLACE_FPRINTF@) \ || (@GNULIB_FPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) @@ -1227,7 +1265,24 @@ _GL_WARN_ON_USE (popen, "popen is buggy on some platforms - " # endif #endif +#if @GNULIB_ZPRINTF@ +/* Prints formatted output to standard output. + Returns the number of bytes written to standard output. Upon failure, + returns -1 with stdout's error indicator set. + Failure cause EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure causes are ENOMEM + and the possible failure causes from fwrite(). */ +_GL_FUNCDECL_SYS (zprintf, off64_t, (const char *restrict format, ...) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_SYS (zprintf, off64_t, (const char *restrict format, ...)); +#endif + #if @GNULIB_PRINTF_POSIX@ || @GNULIB_PRINTF@ +/* Prints formatted output to standard output. + Returns the number of bytes written to standard output. Upon failure, + returns a negative value with stdout's error indicator set. */ # if (@GNULIB_PRINTF_POSIX@ && @REPLACE_PRINTF@) \ || (@GNULIB_PRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if defined __GNUC__ || defined __clang__ @@ -1459,7 +1514,7 @@ _GL_CXXALIASWARN (scanf); # endif #endif -#if @GNULIB_ZSNPRINTF@ +#if @GNULIB_SNZPRINTF@ /* Prints formatted output to string STR. Similar to sprintf, but the additional parameter SIZE limits how much is written into STR. STR may be NULL, in which case nothing will be written. @@ -1468,12 +1523,12 @@ _GL_CXXALIASWARN (scanf); Failure code EOVERFLOW can only occur when a width > INT_MAX is used. Therefore, if the format string is valid and does not use %ls/%lc directives nor widths, the only possible failure code is ENOMEM. */ -_GL_FUNCDECL_SYS (zsnprintf, ptrdiff_t, +_GL_FUNCDECL_SYS (snzprintf, ptrdiff_t, (char *restrict str, size_t size, const char *restrict format, ...) _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4) _GL_ARG_NONNULL ((3))); -_GL_CXXALIAS_SYS (zsnprintf, ptrdiff_t, +_GL_CXXALIAS_SYS (snzprintf, ptrdiff_t, (char *restrict str, size_t size, const char *restrict format, ...)); #endif @@ -1520,19 +1575,19 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - " # endif #endif -#if @GNULIB_ZSPRINTF@ +#if @GNULIB_SZPRINTF@ /* Prints formatted output to string STR. Returns the string length of the formatted string. Upon failure, returns -1 with errno set. Failure code EOVERFLOW can only occur when a width > INT_MAX is used. Therefore, if the format string is valid and does not use %ls/%lc directives nor widths, the only possible failure code is ENOMEM. */ -_GL_FUNCDECL_SYS (zsprintf, ptrdiff_t, +_GL_FUNCDECL_SYS (szprintf, ptrdiff_t, (char *restrict str, const char *restrict format, ...) _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_SYS (zsprintf, ptrdiff_t, +_GL_CXXALIAS_SYS (szprintf, ptrdiff_t, (char *restrict str, const char *restrict format, ...)); #endif @@ -1629,7 +1684,7 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - " # endif #endif -#if @GNULIB_VAZSPRINTF@ +#if @GNULIB_VASZPRINTF@ /* Prints formatted output to a string dynamically allocated with malloc(). If the memory allocation succeeds, it stores the address of the string in *RESULT and returns the number of resulting bytes, excluding the trailing @@ -1638,17 +1693,17 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - " Failure code EOVERFLOW can only occur when a width > INT_MAX is used. Therefore, if the format string is valid and does not use %ls/%lc directives nor widths, the only possible failure code is ENOMEM. */ -_GL_FUNCDECL_SYS (azsprintf, ptrdiff_t, +_GL_FUNCDECL_SYS (aszprintf, ptrdiff_t, (char **result, const char *format, ...) _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_SYS (azsprintf, ptrdiff_t, +_GL_CXXALIAS_SYS (aszprintf, ptrdiff_t, (char **result, const char *format, ...)); -_GL_FUNCDECL_SYS (vazsprintf, ptrdiff_t, +_GL_FUNCDECL_SYS (vaszprintf, ptrdiff_t, (char **result, const char *format, va_list args) _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_SYS (vazsprintf, ptrdiff_t, +_GL_CXXALIAS_SYS (vaszprintf, ptrdiff_t, (char **result, const char *format, va_list args)); #endif @@ -1703,7 +1758,26 @@ _GL_CXXALIAS_SYS (vasprintf, int, _GL_CXXALIASWARN (vasprintf); #endif +#if @GNULIB_VDZPRINTF@ +/* Prints formatted output to file descriptor FD. + Returns the number of bytes written to the file descriptor. Upon + failure, returns -1 with errno set. + Failure code EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure codes are ENOMEM + and the possible failure codes from write(), excluding EINTR. */ +_GL_FUNCDECL_SYS (vdzprintf, off64_t, + (int fd, const char *restrict format, va_list args) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_SYS (vdzprintf, off64_t, + (int fd, const char *restrict format, va_list args)); +#endif + #if @GNULIB_VDPRINTF@ +/* Prints formatted output to file descriptor FD. + Returns the number of bytes written to the file descriptor. Upon + failure, returns a negative value. */ # if @REPLACE_VDPRINTF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define vdprintf rpl_vdprintf @@ -1737,7 +1811,28 @@ _GL_WARN_ON_USE (vdprintf, "vdprintf is unportable - " # endif #endif +#if @GNULIB_VFZPRINTF@ +/* Prints formatted output to stream FP. + Returns the number of bytes written to the stream. Upon failure, + returns -1 with the stream's error indicator set. + Failure cause EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure causes are ENOMEM + and the possible failure causes from fwrite(). */ +_GL_FUNCDECL_SYS (vfzprintf, off64_t, + (FILE *restrict fp, + const char *restrict format, va_list args) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) + _GL_ARG_NONNULL ((1, 2))); +_GL_CXXALIAS_SYS (vfzprintf, off64_t, + (FILE *restrict fp, + const char *restrict format, va_list args)); +#endif + #if @GNULIB_VFPRINTF_POSIX@ || @GNULIB_VFPRINTF@ +/* Prints formatted output to stream FP. + Returns the number of bytes written to the stream. Upon failure, + returns a negative value with the stream's error indicator set. */ # if (@GNULIB_VFPRINTF_POSIX@ && @REPLACE_VFPRINTF@) \ || (@GNULIB_VFPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) @@ -1806,7 +1901,25 @@ _GL_CXXALIASWARN (vfscanf); # endif #endif +#if @GNULIB_VZPRINTF@ +/* Prints formatted output to standard output. + Returns the number of bytes written to standard output. Upon failure, + returns -1 with stdout's error indicator set. + Failure cause EOVERFLOW can only occur when a width > INT_MAX is used. + Therefore, if the format string is valid and does not use %ls/%lc + directives nor widths, the only possible failure causes are ENOMEM + and the possible failure causes from fwrite(). */ +_GL_FUNCDECL_SYS (vzprintf, off64_t, (const char *restrict format, va_list args) + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_SYS (vzprintf, off64_t, + (const char *restrict format, va_list args)); +#endif + #if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VPRINTF@ +/* Prints formatted output to standard output. + Returns the number of bytes written to standard output. Upon failure, + returns a negative value with stdout's error indicator set. */ # if (@GNULIB_VPRINTF_POSIX@ && @REPLACE_VPRINTF@) \ || (@GNULIB_VPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) @@ -1862,7 +1975,7 @@ _GL_CXXALIASWARN (vscanf); # endif #endif -#if @GNULIB_VZSNPRINTF@ +#if @GNULIB_VSNZPRINTF@ /* Prints formatted output to string STR. Similar to sprintf, but the additional parameter SIZE limits how much is written into STR. STR may be NULL, in which case nothing will be written. @@ -1871,12 +1984,12 @@ _GL_CXXALIASWARN (vscanf); Failure code EOVERFLOW can only occur when a width > INT_MAX is used. Therefore, if the format string is valid and does not use %ls/%lc directives nor widths, the only possible failure code is ENOMEM. */ -_GL_FUNCDECL_SYS (vzsnprintf, ptrdiff_t, +_GL_FUNCDECL_SYS (vsnzprintf, ptrdiff_t, (char *restrict str, size_t size, const char *restrict format, va_list args) _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0) _GL_ARG_NONNULL ((3))); -_GL_CXXALIAS_SYS (vzsnprintf, ptrdiff_t, +_GL_CXXALIAS_SYS (vsnzprintf, ptrdiff_t, (char *restrict str, size_t size, const char *restrict format, va_list args)); #endif @@ -1923,19 +2036,19 @@ _GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - " # endif #endif -#if @GNULIB_VZSPRINTF@ +#if @GNULIB_VSZPRINTF@ /* Prints formatted output to string STR. Returns the string length of the formatted string. Upon failure, returns -1 with errno set. Failure code EOVERFLOW can only occur when a width > INT_MAX is used. Therefore, if the format string is valid and does not use %ls/%lc directives nor widths, the only possible failure code is ENOMEM. */ -_GL_FUNCDECL_SYS (vzsprintf, ptrdiff_t, +_GL_FUNCDECL_SYS (vszprintf, ptrdiff_t, (char *restrict str, const char *restrict format, va_list args) _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) _GL_ARG_NONNULL ((1, 2))); -_GL_CXXALIAS_SYS (vzsprintf, ptrdiff_t, +_GL_CXXALIAS_SYS (vszprintf, ptrdiff_t, (char *restrict str, const char *restrict format, va_list args)); #endif diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index cfc69d0a506..e42368eef27 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -20,9 +20,18 @@ #endif @PRAGMA_COLUMNS@ -#if defined __need_system_stdlib_h || defined __need_malloc_and_calloc +#if (defined __need_system_stdlib_h && !defined _GLIBCXX_STDLIB_H) || defined __need_malloc_and_calloc /* Special invocation conventions inside some gnulib header files, - and inside some glibc header files, respectively. */ + and inside some glibc header files, respectively. + Do not recognize this special invocation convention when GCC's + c++/11/stdlib.h is being included or has been included. This is needed + to support the use of clang+llvm binaries on Ubuntu 22.04 with + CXX="$clangdir/bin/clang++ -I/usr/include/c++/11 \ + -I/usr/include/x86_64-linux-gnu/c++/11 + -L/usr/lib/gcc/x86_64-linux-gnu/11 + -Wl,-rpath,$clangdir/lib" + because in this case /usr/include/c++/11/stdlib.h (which does not support + the convention) is seen before the gnulib-generated stdlib.h. */ #@INCLUDE_NEXT@ @NEXT_STDLIB_H@ @@ -108,6 +117,17 @@ struct random_data # include #endif +#if ((@GNULIB_STRTOL@ && @REPLACE_STRTOL@) || (@GNULIB_STRTOLL@ && @REPLACE_STRTOLL@) || (@GNULIB_STRTOUL@ && @REPLACE_STRTOUL@) || (@GNULIB_STRTOULL@ && @REPLACE_STRTOULL@)) && defined __cplusplus && !defined GNULIB_NAMESPACE && defined __GNUG__ && !defined __clang__ && defined __sun +/* When strtol, strtoll, strtoul, or strtoull is going to be defined as a macro + below, this may cause compilation errors later in the libstdc++ header files + (that are part of GCC), such as: + error: 'rpl_strtol' is not a member of 'std' + To avoid this, include the relevant header files here, before these symbols + get defined as macros. But do so only on Solaris 11 (where it is needed), + not on mingw (where it would cause other compilation errors). */ +# include +#endif + /* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers that can be freed by passing them as the Ith argument to the function F. */ diff --git a/m4/acl.m4 b/m4/acl.m4 index c7b6ec2b14e..be88f1b8313 100644 --- a/m4/acl.m4 +++ b/m4/acl.m4 @@ -1,5 +1,5 @@ # acl.m4 -# serial 30 +# serial 31 dnl Copyright (C) 2002, 2004-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -178,13 +178,14 @@ AC_DEFUN([gl_ACL_GET_FILE], AS_IF([test "$gl_cv_func_working_acl_get_file" != no], [$1], [$2]) ]) -# On GNU/Linux, testing if a file has an acl can be done with the -# listxattr and getxattr syscalls, which don't require linking -# against additional libraries. Assume this works if linux/attr.h -# and listxattr are present. +# Prerequisites of module file-has-acl. AC_DEFUN([gl_FILE_HAS_ACL], [ AC_REQUIRE([gl_FUNC_ACL_ARG]) + # On GNU/Linux, testing if a file has an acl can be done with the + # listxattr and getxattr syscalls, which don't require linking + # against additional libraries. Assume this works if linux/attr.h + # and listxattr are present. AC_CHECK_HEADERS_ONCE([linux/xattr.h]) AC_CHECK_FUNCS_ONCE([listxattr]) FILE_HAS_ACL_LIB= @@ -198,3 +199,17 @@ AC_DEFUN([gl_FILE_HAS_ACL], FILE_HAS_ACL_LIB=$LIB_ACL]) AC_SUBST([FILE_HAS_ACL_LIB]) ]) + +# Prerequisites of module qcopy-acl. +AC_DEFUN([gl_QCOPY_ACL], +[ + AC_REQUIRE([gl_FUNC_ACL]) + AC_CHECK_HEADERS_ONCE([linux/xattr.h]) + gl_FUNC_XATTR + if test "$use_xattr" = yes; then + QCOPY_ACL_LIB="$LIB_XATTR" + else + QCOPY_ACL_LIB="$LIB_ACL" + fi + AC_SUBST([QCOPY_ACL_LIB]) +]) diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 6c49edac932..79a0f27382a 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -478,14 +478,7 @@ AC_DEFUN([gl_INIT], gl_PREREQ_PTHREAD_SIGMASK ]) gl_SIGNAL_MODULE_INDICATOR([pthread_sigmask]) - gl_FUNC_XATTR - AC_REQUIRE([gl_FUNC_ACL]) - if test "$use_xattr" = yes; then - QCOPY_ACL_LIB="$LIB_XATTR" - else - QCOPY_ACL_LIB="$LIB_ACL" - fi - AC_SUBST([QCOPY_ACL_LIB]) + gl_QCOPY_ACL gl_FUNC_READLINK gl_CONDITIONAL([GL_COND_OBJ_READLINK], [test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1]) diff --git a/m4/manywarnings.m4 b/m4/manywarnings.m4 index 14bc5041eaa..5b0baee2057 100644 --- a/m4/manywarnings.m4 +++ b/m4/manywarnings.m4 @@ -1,5 +1,5 @@ # manywarnings.m4 -# serial 26 +# serial 27 dnl Copyright (C) 2008-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -141,7 +141,6 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC(C)], -Wsuggest-final-methods \ -Wsuggest-final-types \ -Wsync-nand \ - -Wsystem-headers \ -Wtrampolines \ -Wuninitialized \ -Wunknown-pragmas \ diff --git a/m4/memmem.m4 b/m4/memmem.m4 index a9bc277813b..e6b1d91cbb1 100644 --- a/m4/memmem.m4 +++ b/m4/memmem.m4 @@ -1,5 +1,5 @@ # memmem.m4 -# serial 29 +# serial 30 dnl Copyright (C) 2002-2004, 2007-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -102,7 +102,7 @@ static void quit (int sig) { _exit (sig + 128); } 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. */ + since all such platforms (mingw, MSVC) also lack memmem. */ signal (SIGALRM, quit); alarm (5); /* Check for quadratic performance. */ diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4 index 10e1fbb8aa9..ec52ae92ff4 100644 --- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,5 +1,5 @@ # stdio_h.m4 -# serial 69 +# serial 75 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -133,6 +133,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], [ m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS], [ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCLOSE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDOPEN]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFLUSH]) @@ -153,6 +154,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELLO]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FWRITE]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETC]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETCHAR]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDELIM]) @@ -173,25 +175,29 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RENAMEAT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SCANF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SNPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SNZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SPRINTF_POSIX]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_NONBLOCKING]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF]) - gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VAZSPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF_POSIX]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX]) - gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF]) - gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSPRINTF]) - gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF]) - gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSZPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZPRINTF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZPRINTF]) dnl Support Microsoft deprecated alias function names by default. gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1]) diff --git a/m4/strnlen.m4 b/m4/strnlen.m4 index b4d2778524e..83a75c0c327 100644 --- a/m4/strnlen.m4 +++ b/m4/strnlen.m4 @@ -1,11 +1,60 @@ # strnlen.m4 -# serial 14 +# serial 15 dnl Copyright (C) 2002-2003, 2005-2007, 2009-2024 Free Software Foundation, dnl 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. +m4_version_prereq([2.73], [], [ +# Replace AC_FUNC_STRNLEN from Autoconf 2.72 and earlier, +# which does not check for Android strnlen bugs. + +AC_DEFUN([AC_FUNC_STRNLEN], +[AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])dnl +AC_CACHE_CHECK([for working strnlen], [ac_cv_func_strnlen_working], +[AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [AC_INCLUDES_DEFAULT + [/* Use pstrnlen to test; 'volatile' prevents the compiler + from optimizing the strnlen calls away. */ + size_t (*volatile pstrnlen) (char const *, size_t) = strnlen; + char const s[] = "foobar"; + int s_len = sizeof s - 1; + ]], + [[ + /* AIX 4.3 is buggy: strnlen (S, 1) == 3. */ + int i; + for (i = 0; i < s_len + 1; ++i) + { + int expected = i <= s_len ? i : s_len; + if (pstrnlen (s, i) != expected) + return 1; + } + + /* Android 5.0 (API 21) strnlen ("", SIZE_MAX) incorrectly crashes. */ + if (pstrnlen ("", -1) != 0) + return 1;]])], + [ac_cv_func_strnlen_working=yes], + [ac_cv_func_strnlen_working=no], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], + [[#if defined _AIX && !defined _AIX51 + #error "AIX pre 5.1 is buggy" + #endif + #ifdef __ANDROID__ + #include + #if __ANDROID_API__ < 22 + #error "Android API < 22 is buggy" + #endif + #endif + ]])], + [ac_cv_func_strnlen_working=yes], + [ac_cv_func_strnlen_working=no])])]) +test $ac_cv_func_strnlen_working = no && AC_LIBOBJ([strnlen]) +])# AC_FUNC_STRNLEN +]) + AC_DEFUN([gl_FUNC_STRNLEN], [ AC_REQUIRE([gl_STRING_H_DEFAULTS]) commit 719d5753ca661d5ab264383a2a3ca5932c595b41 Author: Eli Zaretskii Date: Tue Jul 16 17:35:42 2024 +0300 ; * doc/lispref/help.texi (Keys in Documentation): Add cross-reference. diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi index f3d12feefc6..268ae08bc46 100644 --- a/doc/lispref/help.texi +++ b/doc/lispref/help.texi @@ -375,7 +375,7 @@ as a link in the @file{*Help*} buffer. @end table @strong{Please note:} Each @samp{\} must be doubled when written in a -string in Emacs Lisp. +string in Emacs Lisp (@pxref{Syntax for Strings}). @defun substitute-command-keys string &optional no-face include-menus @vindex help-key-binding@r{ (face)} commit fd8bdedde9655f04c03eb04af09f73ee77600f53 Merge: 7d8ff5a56c5 970409916e0 Author: Michael Albinus Date: Tue Jul 16 10:11:45 2024 +0200 Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs commit 7d8ff5a56c52ed8917d9f45f2b113cfd3de7d497 Author: Michael Albinus Date: Mon Jul 15 19:24:56 2024 +0200 Adapt tressitter tests on EMBA * test/infra/Makefile.in (TREE-SITTER-FILES): Simplify. * test/infra/test-jobs.yml: Regenerate. diff --git a/test/infra/Makefile.in b/test/infra/Makefile.in index 0144ad1cbd9..3e462add494 100644 --- a/test/infra/Makefile.in +++ b/test/infra/Makefile.in @@ -117,12 +117,8 @@ endef $(foreach subdir, $(SUBDIRS), $(eval $(call subdir_template,$(subdir)))) -# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow -# test file name convention. TREE-SITTER-FILES ?= $(shell cd .. ; \ - find lisp src \( -name "*-ts-mode-tests.el" -o -name "treesit-tests.el" \ - -o -name "csharp-mode-tests.el" -o -name "js-tests.el" \ - -o -name "python-tests.el" \) | \ + find lisp src -name "*-tests.el" | xargs grep -El "treesit.*-p" | \ sort | sed s/\\.el/.log/) all: generate-test-jobs @@ -133,8 +129,6 @@ generate-test-jobs: $(FILE) $(SUBDIR_TARGETS) tree-sitter-files tree-sitter-files: @echo >>$(FILE) - @echo "# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow" >>$(FILE) - @echo "# test file name convention." >>$(FILE) @echo '.tree-sitter-files:' >>$(FILE) @echo ' variables:' >>$(FILE) @echo ' tree_sitter_files: >-' >>$(FILE) diff --git a/test/infra/test-jobs.yml b/test/infra/test-jobs.yml index 13b184b1277..180f29947ca 100644 --- a/test/infra/test-jobs.yml +++ b/test/infra/test-jobs.yml @@ -577,11 +577,10 @@ test-src-inotify: target: emacs-inotify make_params: -C test check-src -# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow -# test file name convention. .tree-sitter-files: variables: tree_sitter_files: >- + lisp/align-tests.log lisp/progmodes/csharp-mode-tests.log lisp/progmodes/c-ts-mode-tests.log lisp/progmodes/elixir-ts-mode-tests.log commit 970409916e0dff9cd4d542f16f7d570149bdeeb1 Author: Stefan Kangas Date: Tue Jul 16 04:53:38 2024 +0200 Make error messages adhere to our standards * src/cygw32.c (chdir_to_default_directory): * src/fns.c (secure_hash): * src/keyboard.c (Finternal_handle_focus_in): * src/keymap.c (store_in_keymap): * src/pgtkfns.c (pgtk_set_scroll_bar_foreground) (pgtk_set_scroll_bar_background, Fx_export_frames) (Fpgtk_set_monitor_scale_factor, pgtk_get_defaults_value) (pgtk_set_defaults_value, Fpgtk_print_frames_dialog) (pgtk_get_monitor_scale_factor): * src/pgtkterm.c (pgtk_set_parent_frame): * src/process.c (network_interface_info, send_process): * src/w32.c (w32_read_registry): * src/w32fns.c (Fw32_read_registry): * src/window.c (Frecenter): * src/xfns.c (Fx_export_frames, Fx_print_frames_dialog) (x_set_mouse_color): Make 'error' message strings follow our guidelines. More specifically, they should not end in a period, and normally also be capitalized. See '(elisp) Programming Tips'. diff --git a/src/cygw32.c b/src/cygw32.c index 7658e9a24a0..8415e0eab8e 100644 --- a/src/cygw32.c +++ b/src/cygw32.c @@ -37,7 +37,7 @@ chdir_to_default_directory (void) int old_cwd_fd = emacs_open (".", O_RDONLY | O_DIRECTORY, 0); if (old_cwd_fd == -1) - error ("could not open current directory: %s", strerror (errno)); + error ("Could not open current directory: %s", strerror (errno)); record_unwind_protect_int (fchdir_unwind, old_cwd_fd); @@ -47,7 +47,7 @@ chdir_to_default_directory (void) new_cwd = build_string ("/"); if (chdir (SSDATA (ENCODE_FILE (new_cwd)))) - error ("could not chdir: %s", strerror (errno)); + error ("Could not chdir: %s", strerror (errno)); } static Lisp_Object diff --git a/src/fns.c b/src/fns.c index 6ccdfbcd070..f623ff96c25 100644 --- a/src/fns.c +++ b/src/fns.c @@ -6320,7 +6320,7 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, const char *input = extract_data_from_object (spec, &start_byte, &end_byte); if (input == NULL) - error ("secure_hash: failed to extract data from object, aborting!"); + error ("secure_hash: Failed to extract data from object, aborting!"); if (EQ (algorithm, Qmd5)) { diff --git a/src/keyboard.c b/src/keyboard.c index 40276b4157c..6c33d08c265 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7714,7 +7714,7 @@ This function potentially generates an artificial switch-frame event. */) if (!EQ (CAR_SAFE (event), Qfocus_in) || !CONSP (XCDR (event)) || !FRAMEP ((frame = XCAR (XCDR (event))))) - error ("invalid focus-in event"); + error ("Invalid focus-in event"); /* Conceptually, the concept of window manager focus on a particular frame and the Emacs selected frame shouldn't be related, but for diff --git a/src/keymap.c b/src/keymap.c index 0f50d804dff..f2a7e4006c3 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -749,7 +749,7 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, def = Fcons (XCAR (def), XCDR (def)); if (!CONSP (keymap) || !EQ (XCAR (keymap), Qkeymap)) - error ("attempt to define a key in a non-keymap"); + error ("Attempt to define a key in a non-keymap"); /* If idx is a cons, and the car part is a character, idx must be of the form (FROM-CHAR . TO-CHAR). */ diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 49467988cae..b8e65f4c052 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -71,7 +71,7 @@ pgtk_get_monitor_scale_factor (const char *model) else if (FLOATP (cdr)) return XFLOAT_DATA (cdr); else - error ("unknown type of scale-factor"); + error ("Unknown type of scale-factor"); } struct pgtk_display_info * @@ -826,7 +826,7 @@ pgtk_set_scroll_bar_foreground (struct frame *f, Lisp_Object new_value, Emacs_Color rgb; if (!pgtk_parse_color (f, SSDATA (new_value), &rgb)) - error ("Unknown color."); + error ("Unknown color"); char css[64]; sprintf (css, "scrollbar slider { background-color: #%06x; }", @@ -836,7 +836,7 @@ pgtk_set_scroll_bar_foreground (struct frame *f, Lisp_Object new_value, } else - error ("Invalid scroll-bar-foreground."); + error ("Invalid scroll-bar-foreground"); } static void @@ -856,7 +856,7 @@ pgtk_set_scroll_bar_background (struct frame *f, Lisp_Object new_value, Emacs_Color rgb; if (!pgtk_parse_color (f, SSDATA (new_value), &rgb)) - error ("Unknown color."); + error ("Unknown color"); /* On pgtk, this frame parameter should be ignored, and honor gtk theme. (It honors the GTK theme if not explicitly set, so @@ -869,7 +869,7 @@ pgtk_set_scroll_bar_background (struct frame *f, Lisp_Object new_value, } else - error ("Invalid scroll-bar-background."); + error ("Invalid scroll-bar-background"); } @@ -904,7 +904,7 @@ unless TYPE is `png'. */) XSETFRAME (frame, f); if (!FRAME_VISIBLE_P (f)) - error ("Frames to be exported must be visible."); + error ("Frames to be exported must be visible"); tmp = Fcons (frame, tmp); } frames = Fnreverse (tmp); @@ -918,7 +918,7 @@ unless TYPE is `png'. */) if (EQ (type, Qpng)) { if (!NILP (XCDR (frames))) - error ("PNG export cannot handle multiple frames."); + error ("PNG export cannot handle multiple frames"); surface_type = CAIRO_SURFACE_TYPE_IMAGE; } else @@ -933,7 +933,7 @@ unless TYPE is `png'. */) { /* For now, we stick to SVG 1.1. */ if (!NILP (XCDR (frames))) - error ("SVG export cannot handle multiple frames."); + error ("SVG export cannot handle multiple frames"); surface_type = CAIRO_SURFACE_TYPE_SVG; } else @@ -1153,15 +1153,15 @@ scale factor. */) if (FIXNUMP (scale_factor)) { if (XFIXNUM (scale_factor) <= 0) - error ("scale factor must be > 0."); + error ("Scale factor must be > 0"); } else if (FLOATP (scale_factor)) { if (XFLOAT_DATA (scale_factor) <= 0.0) - error ("scale factor must be > 0."); + error ("Scale factor must be > 0"); } else - error ("unknown type of scale-factor"); + error ("Unknown type of scale-factor"); } Lisp_Object tem = Fassoc (monitor_model, monitor_scale_factor_alist, Qnil); @@ -1907,7 +1907,7 @@ pgtk_get_defaults_value (const char *key) char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; if (strlen (key) >= RESOURCE_KEY_MAX_LEN) - error ("resource key too long."); + error ("Resource key too long"); GSettings *gs = parse_resource_key (key, skey); if (gs == NULL) @@ -1937,11 +1937,11 @@ pgtk_set_defaults_value (const char *key, const char *value) char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; if (strlen (key) >= RESOURCE_KEY_MAX_LEN) - error ("resource key too long."); + error ("Resource key too long"); GSettings *gs = parse_resource_key (key, skey); if (gs == NULL) - error ("unknown resource key."); + error ("Unknown resource key"); if (value != NULL) { @@ -1971,7 +1971,7 @@ pgtk_get_defaults_value (const char *key) static void pgtk_set_defaults_value (const char *key, const char *value) { - error ("gsettings not supported."); + error ("gsettings not supported"); } #endif @@ -3659,7 +3659,7 @@ visible. */) XSETFRAME (frame, f); if (!FRAME_VISIBLE_P (f)) - error ("Frames to be printed must be visible."); + error ("Frames to be printed must be visible"); tmp = Fcons (frame, tmp); } frames = Fnreverse (tmp); diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 839bfdce988..079945126e0 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -928,7 +928,7 @@ pgtk_set_parent_frame (struct frame *f, Lisp_Object new_value, if (p != NULL) { if (FRAME_DISPLAY_INFO (f) != FRAME_DISPLAY_INFO (p)) - error ("Cross display reparent."); + error ("Cross display reparent"); } GtkWidget *fixed = FRAME_GTK_WIDGET (f); diff --git a/src/process.c b/src/process.c index 0167ceff7e0..93178eb241f 100644 --- a/src/process.c +++ b/src/process.c @@ -4471,7 +4471,7 @@ network_interface_info (Lisp_Object ifname) CHECK_STRING (ifname); if (sizeof rq.ifr_name <= SBYTES (ifname)) - error ("interface name too long"); + error ("Interface name too long"); lispstpcpy (rq.ifr_name, ifname); s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); @@ -6853,7 +6853,7 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len, pset_status (p, list2 (Qexit, make_fixnum (256))); p->tick = ++process_tick; deactivate_process (proc); - error ("process %s no longer connected to pipe; closed it", + error ("Process %s no longer connected to pipe; closed it", SDATA (p->name)); } else diff --git a/src/w32.c b/src/w32.c index 6dcbbbcc61b..31ffa301c2f 100644 --- a/src/w32.c +++ b/src/w32.c @@ -10221,7 +10221,7 @@ w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname) retval = Fnreverse (val); break; default: - error ("unsupported registry data type: %d", (int)vtype); + error ("Unsupported registry data type: %d", (int)vtype); } xfree (pvalue); diff --git a/src/w32fns.c b/src/w32fns.c index e5798fdd84f..cd89745e9fa 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -10583,7 +10583,7 @@ to be converted to forward slashes by the caller. */) else if (EQ (root, QHKCC)) rootkey = HKEY_CURRENT_CONFIG; else if (!NILP (root)) - error ("unknown root key: %s", SDATA (SYMBOL_NAME (root))); + error ("Unknown root key: %s", SDATA (SYMBOL_NAME (root))); Lisp_Object val = w32_read_registry (rootkey, key, name); if (NILP (val) && NILP (root)) diff --git a/src/window.c b/src/window.c index ff28bac5306..4bb36b6733a 100644 --- a/src/window.c +++ b/src/window.c @@ -6711,7 +6711,7 @@ and redisplay normally--don't erase and redraw the frame. */) https://lists.gnu.org/r/emacs-devel/2014-06/msg00053.html, https://lists.gnu.org/r/emacs-devel/2014-06/msg00094.html. */ if (buf != current_buffer) - error ("`recenter'ing a window that does not display current-buffer."); + error ("`recenter'ing a window that does not display current-buffer"); /* If redisplay is suppressed due to an error, try again. */ buf->display_error_modiff = 0; diff --git a/src/xfns.c b/src/xfns.c index 9bc2f794849..917b82ff8da 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1406,9 +1406,9 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) if (cursor_data.error_cursor >= 0) bad_cursor_name = mouse_cursor_types[cursor_data.error_cursor].name; if (bad_cursor_name) - error ("bad %s pointer cursor: %s", bad_cursor_name, xmessage); + error ("Bad %s pointer cursor: %s", bad_cursor_name, xmessage); else - error ("can't set cursor shape: %s", xmessage); + error ("Can't set cursor shape: %s", xmessage); } x_uncatch_errors_after_check (); @@ -9854,7 +9854,7 @@ unless TYPE is `png'. */) XSETFRAME (frame, f); if (!FRAME_VISIBLE_P (f)) - error ("Frames to be exported must be visible."); + error ("Frames to be exported must be visible"); tmp = Fcons (frame, tmp); } frames = Fnreverse (tmp); @@ -9868,7 +9868,7 @@ unless TYPE is `png'. */) if (EQ (type, Qpng)) { if (!NILP (XCDR (frames))) - error ("PNG export cannot handle multiple frames."); + error ("PNG export cannot handle multiple frames"); surface_type = CAIRO_SURFACE_TYPE_IMAGE; } else @@ -9883,7 +9883,7 @@ unless TYPE is `png'. */) { /* For now, we stick to SVG 1.1. */ if (!NILP (XCDR (frames))) - error ("SVG export cannot handle multiple frames."); + error ("SVG export cannot handle multiple frames"); surface_type = CAIRO_SURFACE_TYPE_SVG; } else @@ -9957,7 +9957,7 @@ Note: Text drawn with the `x' font backend is shown with hollow boxes. */) XSETFRAME (frame, f); if (!FRAME_VISIBLE_P (f)) - error ("Frames to be printed must be visible."); + error ("Frames to be printed must be visible"); tmp = Fcons (frame, tmp); } frames = Fnreverse (tmp); commit 06ce99b76a8e5823f003f4e0dee945d97d0271ea Merge: 0fc8d883670 72c8e0df87b Author: Po Lu Date: Tue Jul 16 10:15:59 2024 +0800 Merge remote-tracking branch 'savannah/master' into master-android-1 commit 0fc8d8836701f928a124ac13c32e6dae7f55ee37 Merge: 35606d575b8 a7b68c25640 Author: Po Lu Date: Tue Jul 16 10:15:27 2024 +0800 Merge from savannah/emacs-30 a7b68c25640 Fix intermittent failure of dired-test-bug27243-02 fc25b4d8370 * etc/TODO: Refer to Bug#72127 for Magit assignments. 17c62c1242f Rename treesitter test commit 35606d575b8830174874b9ddcc24ed8243071f53 Merge: f54ad127eec 684e96a30d9 Author: Po Lu Date: Tue Jul 16 10:15:27 2024 +0800 ; Merge from savannah/emacs-30 The following commit was skipped: 684e96a30d9 Adapt tressitter tests on EMBA commit f54ad127eec285bffa8c6f2bcb884ec848a73cb1 Merge: 46f2c94949c 68b7806c319 Author: Po Lu Date: Tue Jul 16 10:15:26 2024 +0800 Merge from savannah/emacs-30 68b7806c319 Support passing signals like 'SIGCODE' to 'tramp-signal-p... 510ca5e84b5 Merge branch 'emacs-30' of git.sv.gnu.org:/srv/git/emacs ... fe28ba5d55b ; Replace quotes with @code{...} in texinfo files ecc8516d9ca ; Replace (non-)nil with (non-)@code{nil} in texinfo files 3407e274999 Don't save to history from 'eshell-command' when aborting commit 72c8e0df87b0776451f9065f3432a8ebecee974d Author: Stefan Kangas Date: Tue Jul 16 02:00:52 2024 +0200 Delete commented out code from `signal_or_quit` * src/eval.c (signal_or_quit): Delete code commented out since 2001. diff --git a/src/eval.c b/src/eval.c index 1e0628b4aa3..2161ab1e1ea 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1857,14 +1857,6 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool continuable) if (gc_in_progress || waiting_for_input) emacs_abort (); -#if 0 /* rms: I don't know why this was here, - but it is surely wrong for an error that is handled. */ -#ifdef HAVE_WINDOW_SYSTEM - if (display_hourglass_p) - cancel_hourglass (); -#endif -#endif - /* This hook is used by edebug. */ if (! NILP (Vsignal_hook_function) && !oom) commit fcb4d89aaa7bf3ed77aaa4d6d5047a0ec2ed9225 Author: Stefan Kangas Date: Mon Jul 15 15:17:16 2024 +0200 Prefer `memcpy` to `strcpy` in image.c * src/image.c (lookup_image, xpm_cache_color) (imagemagick_create_cache): Prefer 'memcpy' to 'strcpy'. diff --git a/src/image.c b/src/image.c index b77c12b4cbc..90e6312e128 100644 --- a/src/image.c +++ b/src/image.c @@ -3525,8 +3525,9 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id) img->face_font_size = font_size; img->face_font_height = face->font->height; img->face_font_width = face->font->average_width; - img->face_font_family = xmalloc (strlen (font_family) + 1); - strcpy (img->face_font_family, font_family); + size_t len = strlen (font_family) + 1; + img->face_font_family = xmalloc (len); + memcpy (img->face_font_family, font_family, len); img->load_failed_p = ! img->type->load_img (f, img); /* If we can't load the image, and we don't have a width and @@ -5544,15 +5545,13 @@ xpm_color_bucket (char *color_name) static struct xpm_cached_color * xpm_cache_color (struct frame *f, char *color_name, XColor *color, int bucket) { - size_t nbytes; - struct xpm_cached_color *p; - if (bucket < 0) bucket = xpm_color_bucket (color_name); - nbytes = FLEXSIZEOF (struct xpm_cached_color, name, strlen (color_name) + 1); - p = xmalloc (nbytes); - strcpy (p->name, color_name); + size_t len = strlen (color_name) + 1; + size_t nbytes = FLEXSIZEOF (struct xpm_cached_color, name, len); + struct xpm_cached_color *p = xmalloc (nbytes); + memcpy (p->name, color_name, len); p->color = *color; p->next = xpm_color_cache[bucket]; xpm_color_cache[bucket] = p; @@ -10867,13 +10866,13 @@ static struct animation_cache *animation_cache = NULL; static struct animation_cache * imagemagick_create_cache (char *signature) { + size_t len = strlen (signature) + 1; struct animation_cache *cache - = xmalloc (FLEXSIZEOF (struct animation_cache, signature, - strlen (signature) + 1)); + = xmalloc (FLEXSIZEOF (struct animation_cache, signature, len)); cache->wand = 0; cache->index = 0; cache->next = 0; - strcpy (cache->signature, signature); + memcpy (cache->signature, signature, len); return cache; } commit 72ba45e2749df8561fe93bafdefbdc8eca56571f Author: Stefan Kangas Date: Fri Jul 12 02:16:47 2024 +0200 Restrict loop variable scope in `xpm_str_to_color_key` * src/image.c (xpm_str_to_color_key): Restrict scope of loop variable. diff --git a/src/image.c b/src/image.c index 3d761bd48be..b77c12b4cbc 100644 --- a/src/image.c +++ b/src/image.c @@ -6249,9 +6249,7 @@ static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"}; static int xpm_str_to_color_key (const char *s) { - int i; - - for (i = 0; i < ARRAYELTS (xpm_color_key_strings); i++) + for (int i = 0; i < ARRAYELTS (xpm_color_key_strings); i++) if (strcmp (xpm_color_key_strings[i], s) == 0) return i; return -1; commit 6b2f51633e0f508d393516d6624e1a4ddaca31d1 Author: Spencer Baugh Date: Tue Jul 9 14:30:27 2024 -0400 Add project argument to project-kill-buffers Previously, project-kill-buffers always called (project-current t). A Lisp program could change what project project-kill-buffers operated on by binding project-current-directory-override. However, in some edge cases (for example, if the project was deleted between looking it up and calling project-kill-buffers) this might fail to detect a project, and so (project-current t) would prompt the user. To avoid this, accept the project to kill buffers for as an argument. * lisp/progmodes/project.el (project-kill-buffers): Take project as an optional argument (bug#72019). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index b7c1698f50b..3d0f742c51d 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1715,7 +1715,7 @@ in `project-kill-buffer-conditions'." bufs)) ;;;###autoload -(defun project-kill-buffers (&optional no-confirm) +(defun project-kill-buffers (&optional no-confirm project) "Kill the buffers belonging to the current project. Two buffers belong to the same project if their project instances, as reported by `project-current' in each buffer, are @@ -1725,9 +1725,11 @@ is non-nil, the command will not ask the user for confirmation. NO-CONFIRM is always nil when the command is invoked interactively. +If PROJECT is non-nil, kill buffers for that project instead. + Also see the `project-kill-buffers-display-buffer-list' variable." (interactive) - (let* ((pr (project-current t)) + (let* ((pr (or project (project-current t))) (bufs (project--buffers-to-kill pr)) (query-user (lambda () (yes-or-no-p commit e3bba63ecb9302d5a30c7ec55fa564aa9aba2b11 Author: Stefan Kangas Date: Tue Jul 16 03:35:59 2024 +0200 Checkdoc fixes in transient.el * lisp/transient.el (transient-format-description): Checkdoc fixes. diff --git a/lisp/transient.el b/lisp/transient.el index 05ad0ed8a0b..8788fbc834f 100644 --- a/lisp/transient.el +++ b/lisp/transient.el @@ -4001,9 +4001,9 @@ and its value is returned to the caller." set " "))))) (cl-defmethod transient-format-description ((obj transient-group)) - "Format the description by calling the next method. If the result -doesn't use the `face' property at all, then apply the face -`transient-heading' to the complete string." + "Format the description by calling the next method. +If the result doesn't use the `face' property at all, then apply the +face `transient-heading' to the complete string." (and-let* ((desc (transient--get-description obj))) (cond ((oref obj inapt) (propertize desc 'face 'transient-inapt-suffix)) @@ -4012,8 +4012,9 @@ doesn't use the `face' property at all, then apply the face ((propertize desc 'face 'transient-heading))))) (cl-defmethod transient-format-description :around ((obj transient-suffix)) - "Format the description by calling the next method. If the result -is nil, then use \"(BUG: no description)\" as the description. + "Format the description by calling the next method. +If the result is nil, then use \"(BUG: no description)\" as the +description. If the OBJ's `key' is currently unreachable, then apply the face `transient-unreachable' to the complete string." (let ((desc (or (cl-call-next-method obj) commit a7b68c25640de8214bc759d20180373c2dbcfa16 Author: Peter Oliver Date: Mon Jul 15 12:03:47 2024 +0100 Fix intermittent failure of dired-test-bug27243-02 * test/lisp/dired-tests.el (dired-test-bug27243-02): Exclude free disk space from dired listing in this test, in case it changes while it's running and confuses the result. (Bug#72120) diff --git a/test/lisp/dired-tests.el b/test/lisp/dired-tests.el index 651b77500a1..3b1f80d3d3d 100644 --- a/test/lisp/dired-tests.el +++ b/test/lisp/dired-tests.el @@ -189,7 +189,9 @@ (ert-deftest dired-test-bug27243-02 () "Test for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27243#28 ." (ert-with-temp-directory test-dir - (let ((dired-auto-revert-buffer t) buffers) + (let ((dired-auto-revert-buffer t) + (dired-free-space nil) + buffers) ;; On MS-Windows, get rid of 8+3 short names in test-dir, if the ;; corresponding long file names exist, otherwise such names trip ;; string comparisons below. commit fc25b4d8370a7c3d24b4c1335babfa1a66fe45dd Author: Stefan Kangas Date: Mon Jul 15 22:59:50 2024 +0200 * etc/TODO: Refer to Bug#72127 for Magit assignments. diff --git a/etc/TODO b/etc/TODO index 53b456c733a..52dd26b4e8f 100644 --- a/etc/TODO +++ b/etc/TODO @@ -730,8 +730,7 @@ bar. In the mean time, it should process other messages. *** Magit This needs work on getting the relevant copyright assignments. This task should be highly doable for anyone, but will likely require some -patience. For inspiration, see how this was done for 'use-package': -https://github.com/jwiegley/use-package/issues/282 +patience. See . *** PSGML, _possibly_ ECB https://lists.gnu.org/r/emacs-devel/2007-05/msg01493.html Check the commit 17c62c1242faeab030d4b0d05dc00cc8c3d8ae5f Author: Michael Albinus Date: Mon Jul 15 19:25:42 2024 +0200 Rename treesitter test * test/lisp/align-tests.el (align-ts-lua): Rename test in order to fit to treesitter tests on EMBA. diff --git a/test/lisp/align-tests.el b/test/lisp/align-tests.el index eaebaf8360c..486658a9523 100644 --- a/test/lisp/align-tests.el +++ b/test/lisp/align-tests.el @@ -51,7 +51,7 @@ (autoload 'treesit-ready-p "treesit") -(ert-deftest align-lua () +(ert-deftest align-ts-lua () (skip-unless (treesit-ready-p 'lua t)) (let ((comment-column 20) (indent-tabs-mode nil)) commit 684e96a30d95b2ed5f2be6b85cfba3f8481707d1 Author: Michael Albinus Date: Mon Jul 15 19:24:56 2024 +0200 Adapt tressitter tests on EMBA * test/infra/Makefile.in (TREE-SITTER-FILES): Simplify. * test/infra/test-jobs.yml: Regenerate. diff --git a/test/infra/Makefile.in b/test/infra/Makefile.in index 0144ad1cbd9..3e462add494 100644 --- a/test/infra/Makefile.in +++ b/test/infra/Makefile.in @@ -117,12 +117,8 @@ endef $(foreach subdir, $(SUBDIRS), $(eval $(call subdir_template,$(subdir)))) -# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow -# test file name convention. TREE-SITTER-FILES ?= $(shell cd .. ; \ - find lisp src \( -name "*-ts-mode-tests.el" -o -name "treesit-tests.el" \ - -o -name "csharp-mode-tests.el" -o -name "js-tests.el" \ - -o -name "python-tests.el" \) | \ + find lisp src -name "*-tests.el" | xargs grep -El "treesit.*-p" | \ sort | sed s/\\.el/.log/) all: generate-test-jobs @@ -133,8 +129,6 @@ generate-test-jobs: $(FILE) $(SUBDIR_TARGETS) tree-sitter-files tree-sitter-files: @echo >>$(FILE) - @echo "# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow" >>$(FILE) - @echo "# test file name convention." >>$(FILE) @echo '.tree-sitter-files:' >>$(FILE) @echo ' variables:' >>$(FILE) @echo ' tree_sitter_files: >-' >>$(FILE) diff --git a/test/infra/test-jobs.yml b/test/infra/test-jobs.yml index 13b184b1277..180f29947ca 100644 --- a/test/infra/test-jobs.yml +++ b/test/infra/test-jobs.yml @@ -577,11 +577,10 @@ test-src-inotify: target: emacs-inotify make_params: -C test check-src -# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow -# test file name convention. .tree-sitter-files: variables: tree_sitter_files: >- + lisp/align-tests.log lisp/progmodes/csharp-mode-tests.log lisp/progmodes/c-ts-mode-tests.log lisp/progmodes/elixir-ts-mode-tests.log commit 68b7806c319f282c0882fa9167752d1ac385163d Author: Jim Porter Date: Sun Jul 14 15:07:28 2024 -0700 Support passing signals like 'SIGCODE' to 'tramp-signal-process' POSIX specifies that "kill" should take signal names without the "SIG" prefix. * lisp/net/tramp.el (tramp-signal-process): Strip the "SIG" prefix when present. diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index e8329c82743..5c7236011b8 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -6986,8 +6986,13 @@ SIGCODE may be an integer, or a symbol whose name is a signal name." (setq pid process vec (and (stringp remote) (tramp-dissect-file-name remote)))) (t (signal 'wrong-type-argument (list #'processp process)))) - (unless (or (numberp sigcode) (symbolp sigcode)) - (signal 'wrong-type-argument (list #'numberp sigcode))) + (cond + ((symbolp sigcode) + (setq sigcode (upcase (symbol-name sigcode))) + (when (string-prefix-p "SIG" sigcode) + (setq sigcode (substring sigcode 3)))) + ((not (numberp sigcode)) + (signal 'wrong-type-argument (list #'numberp sigcode)))) ;; If it's a Tramp process, send SIGCODE remotely. (when (and pid vec) (tramp-message commit 510ca5e84b5b33a9bcfbd26801179767d97144e3 Merge: fe28ba5d55b 3407e274999 Author: Michael Albinus Date: Mon Jul 15 18:20:59 2024 +0200 Merge branch 'emacs-30' of git.sv.gnu.org:/srv/git/emacs into emacs-30 commit fe28ba5d55b5a2f8b2d1cfb9109a68c1df2b88ed Author: Steven Allen Date: Mon Jul 15 18:20:24 2024 +0200 ; Replace quotes with @code{...} in texinfo files * doc/misc/cc-mode.texi: * doc/misc/cl.texi: Replace quotes with @code{...} diff --git a/doc/misc/cc-mode.texi b/doc/misc/cc-mode.texi index bcbd9faf0c9..ced59c0eee6 100644 --- a/doc/misc/cc-mode.texi +++ b/doc/misc/cc-mode.texi @@ -6283,8 +6283,8 @@ returned if there's no template argument on the first line. @defun c-lineup-template-args-indented-from-margin @findex lineup-template-args-indented-from-margin (c-) -Indent a template argument line `c-basic-offset' from the left-hand -margin of the line with the containing <. +Indent a template argument line @code{c-basic-offset} from the +left-hand margin of the line with the containing <. @workswith @code{template-args-cont}. @end defun diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index e893205b40e..c3a91f7dab1 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi @@ -391,7 +391,8 @@ property will contain state (including @var{start}) in order to print the elided part of @var{object} later. @var{start} should be @code{nil} if the whole @var{object} is being elided, otherwise it should be an index or other pointer into the internals of @var{object} -which can be passed to `cl-print-object-contents' at a later time. +which can be passed to @code{cl-print-object-contents} at a later +time. @end defun @defvar cl-print-expand-ellipsis-function commit ecc8516d9ca17c70b4407296fa1140bb5e2b822c Author: Steven Allen Date: Mon Jul 15 18:16:41 2024 +0200 ; Replace (non-)nil with (non-)@code{nil} in texinfo files * doc/lispref/functions.texi: * doc/lispref/keymaps.texi: * doc/lispref/strings.texi: * doc/misc/cl.texi: * doc/misc/dbus.texi: * doc/misc/eshell.texi: * doc/misc/message.texi: * doc/misc/ses.texi: * doc/misc/vtable.texi: Replace (non-)nil with (non-)@code{nil}. diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index 695e1c3efb5..0cf41072ec3 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -2089,7 +2089,7 @@ code) obey the advice and other calls (from C code) do not. @defmac define-advice symbol (where lambda-list &optional name depth) &rest body This macro defines a piece of advice and adds it to the function named -@var{symbol}. If @var{name} is non-nil, the advice is named +@var{symbol}. If @var{name} is non-@code{nil}, the advice is named @code{@var{symbol}@@@var{name}} and installed with the name @var{name}; otherwise, the advice is anonymous. See @code{advice-add} for explanation of other arguments. diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index 32aa98d31cb..a67d8da244e 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi @@ -2603,10 +2603,10 @@ operates on menu data structures, so you should write it so it can safely be called at any time. @item :wrap @var{wrap-p} -If @var{wrap-p} is non-nil inside a tool bar, the menu item is not -displayed, but instead causes subsequent items to be displayed on a -new line. This is not supported when Emacs uses the GTK+ or Nextstep -toolkits. +If @var{wrap-p} is non-@code{nil} inside a tool bar, the menu item is +not displayed, but instead causes subsequent items to be displayed on +a new line. This is not supported when Emacs uses the GTK+ or +Nextstep toolkits. @end table @node Menu Separators diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index e290e2e7a6b..d29665ac19b 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -1499,7 +1499,7 @@ case. The definition of a word is any sequence of consecutive characters that are assigned to the word constituent syntax class in the current syntax table (@pxref{Syntax Class Table}); if @code{case-symbols-as-words} -is non-nil, characters assigned to the symbol constituent syntax +is non-@code{nil}, characters assigned to the symbol constituent syntax class are also considered as word constituent. When @var{string-or-char} is a character, this function does the same diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index a4a34ae07d6..e893205b40e 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi @@ -388,10 +388,10 @@ This function prints an ellipsis (``@dots{}'') to @var{stream} (see above). When @var{stream} is a buffer, the ellipsis will be given the @code{cl-print-ellipsis} text property. The value of the text property will contain state (including @var{start}) in order to print -the elided part of @var{object} later. @var{start} should be nil if -the whole @var{object} is being elided, otherwise it should be an -index or other pointer into the internals of @var{object} which can be -passed to `cl-print-object-contents' at a later time. +the elided part of @var{object} later. @var{start} should be +@code{nil} if the whole @var{object} is being elided, otherwise it +should be an index or other pointer into the internals of @var{object} +which can be passed to `cl-print-object-contents' at a later time. @end defun @defvar cl-print-expand-ellipsis-function diff --git a/doc/misc/dbus.texi b/doc/misc/dbus.texi index e5d867acd40..a98b738e73e 100644 --- a/doc/misc/dbus.texi +++ b/doc/misc/dbus.texi @@ -1420,7 +1420,7 @@ We are not an owner of the name @var{service}. @end table When @var{service} is not a known name but a unique name, the function -returns nil. +returns @code{nil}. @end defun When a name has been chosen, Emacs can offer its own methods, which diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 45bb1f806ee..2228b2752fd 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -1758,8 +1758,8 @@ shells, there are also many differences. Don't let these similarities lull you into a false sense of familiarity. When using command form (@pxref{Invocation}), Eshell will ignore any -leading nil values, so if @var{foo} is @code{nil}, @samp{$@var{foo} -echo hello} is equivalent to @samp{echo hello}. +leading @code{nil} values, so if @var{foo} is @code{nil}, +@samp{$@var{foo} echo hello} is equivalent to @samp{echo hello}. @table @code @@ -2419,8 +2419,9 @@ an @code{eshell-generic-target} as described above). @defun eshell-function-target-create output-function &optional close-function Create a new virtual target for Eshell that repeatedly calls @var{output-function} with the redirected output, as described above. -If @var{close-function} is non-nil, Eshell will call it when closing the -target, passing non-@code{nil} if the redirected command succeeded. +If @var{close-function} is non-@code{nil}, Eshell will call it when +closing the target, passing non-@code{nil} if the redirected command +succeeded. @end defun @node Pipelines diff --git a/doc/misc/message.texi b/doc/misc/message.texi index d881244c735..6e0e4be7bf5 100644 --- a/doc/misc/message.texi +++ b/doc/misc/message.texi @@ -2565,8 +2565,8 @@ into the message headers as the SMTP Method. If @var{cond} is a function, it will be called in the message buffer without any arguments, and the corresponding @var{method} will be inserted into the message headers as the SMTP Method if the function returns a -non-@code{nil} value; if @var{method} is nil, the value returned by -the function @code{cond} is used instead. +non-@code{nil} value; if @var{method} is @code{nil}, the value +returned by the function @code{cond} is used instead. @end table diff --git a/doc/misc/ses.texi b/doc/misc/ses.texi index 8500a0f08c4..80c7b93aa28 100644 --- a/doc/misc/ses.texi +++ b/doc/misc/ses.texi @@ -1060,9 +1060,10 @@ as a single argument, since you'll probably use it with @code{ses-range}. Special cell values: @itemize -@item nil prints typically the same as "", but allows previous cell to spill over. -@item '*skip* replaces nil when the previous cell actually does spill over; -nothing is printed for it. +@item @code{nil} prints typically the same as "", but allows previous +cell to spill over. +@item '*skip* replaces @code{nil} when the previous cell actually does +spill over; nothing is printed for it. @item '*error* indicates that the formula signaled an error instead of producing a value: the print cell is filled with hash marks (#). @end itemize diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi index 6003435385f..2e0adfb235a 100644 --- a/doc/misc/vtable.texi +++ b/doc/misc/vtable.texi @@ -559,9 +559,9 @@ table. @defun vtable-insert-object table object &optional location before Insert @var{object} into @var{table}. @var{location} should be an object in the table, the new object is inserted after this object, or -before it if @var{before} is non-nil. If @var{location} is @code{nil}, -@var{object} is appended to @var{table}, or prepended if @var{before} is -non-@code{nil}. +before it if @var{before} is non-@code{nil}. If @var{location} is +@code{nil}, @var{object} is appended to @var{table}, or prepended if +@var{before} is non-@code{nil}. @var{location} can also be an integer, a zero-based index into the table. In this case, @var{object} is inserted at that index. If the commit 3407e274999ce80582932332b108d84fba69d107 Author: Jim Porter Date: Sat Jul 13 11:43:42 2024 -0700 Don't save to history from 'eshell-command' when aborting * lisp/eshell/eshell.el (eshell-add-input-to-history) (eshell--save-history): Declare. (eshell-command-mode-exit): New function... (eshell-command-mode): ... use it. * lisp/eshell/em-hist.el (eshell-hist-initialize): Don't handle minibuffer logic here. Always read history file (this ensures that 'eshell-command' can see the history, too). (eshell-add-command-to-history): Remove. diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el index 9ffddfb611f..fffd611c06f 100644 --- a/lisp/eshell/em-hist.el +++ b/lisp/eshell/em-hist.el @@ -295,12 +295,8 @@ Returns nil if INPUT is prepended by blank space, otherwise non-nil." (setq-local eshell-hist--new-items 0) (setq-local eshell-history-ring nil) - (if (minibuffer-window-active-p (selected-window)) - (progn - (setq-local eshell-history-append t) - (add-hook 'minibuffer-exit-hook #'eshell-add-command-to-history nil t)) - (if eshell-history-file-name - (eshell-read-history nil t))) + (when eshell-history-file-name + (eshell-read-history nil t)) (unless eshell-history-ring (setq eshell-history-ring (make-ring eshell-history-size))) @@ -411,18 +407,6 @@ input." (setq eshell-save-history-index eshell-history-index) (setq eshell-history-index nil)) -(defun eshell-add-command-to-history () - "Add the command entered at `eshell-command's prompt to the history ring. -The command is added to the input history ring, if the value of -variable `eshell-input-filter' returns non-nil when called on the -command. - -This function is supposed to be called from the minibuffer, presumably -as a `minibuffer-exit-hook'." - (eshell-add-input-to-history - (buffer-substring (minibuffer-prompt-end) (point-max))) - (eshell--save-history)) - (defun eshell-add-to-history () "Add last Eshell command to the history ring. The command is entered into the input history ring, if the value of diff --git a/lisp/eshell/eshell.el b/lisp/eshell/eshell.el index 18e05a371a4..43f6930c80b 100644 --- a/lisp/eshell/eshell.el +++ b/lisp/eshell/eshell.el @@ -256,14 +256,26 @@ information on Eshell, see Info node `(eshell)Top'." (eshell-mode)) buf)) +(declare-function eshell-add-input-to-history "em-hist" (input)) +(declare-function eshell--save-history "em-hist" ()) + +(defun eshell-command-mode-exit () + "Exit the `eshell-commad-mode' minibuffer and save Eshell history." + (interactive) + (when (eshell-using-module 'eshell-hist) + (eshell-add-input-to-history + (buffer-substring (minibuffer-prompt-end) (point-max))) + (eshell--save-history)) + (exit-minibuffer)) + (define-minor-mode eshell-command-mode "Minor mode for `eshell-command' input. \\{eshell-command-mode-map}" :keymap (let ((map (make-sparse-keymap))) - (define-key map [(control ?g)] 'abort-recursive-edit) - (define-key map [(control ?m)] 'exit-minibuffer) - (define-key map [(control ?j)] 'exit-minibuffer) - (define-key map [(meta control ?m)] 'exit-minibuffer) + (define-key map [(control ?g)] #'abort-recursive-edit) + (define-key map [(control ?m)] #'eshell-command-mode-exit) + (define-key map [(control ?j)] #'eshell-command-mode-exit) + (define-key map [(meta control ?m)] #'eshell-command-mode-exit) map)) (define-obsolete-function-alias 'eshell-return-exits-minibuffer commit 46f2c94949c97c95e3c0f7fede4937326ef3e234 Merge: eae1104f97e 5ec73eca57c Author: Po Lu Date: Mon Jul 15 21:12:01 2024 +0800 Merge from savannah/emacs-30 5ec73eca57c Update to Org 9.7.7-2-gf308d3 33ba72f52fd Fix decoding 'display' properties with SVG images in Enri... 174a0b7642b * configure.ac (D8): Fix typo. c56e837a10e ; * src/android.c (setEmacsParams): Delete unused variable. commit eae1104f97ef944127eb5c977129b55f137e0830 Author: Michael Albinus Date: Mon Jun 24 20:02:07 2024 +0200 Extend treesitter tests on emba * test/infra/Dockerfile.emba (emacs-tree-sitter): Install c-ashrp grammar. * test/infra/Makefile.in (TREE-SITTER-FILES): Add csharp-mode-tests.el. (tree-sitter-files): Rename from tree-sitter-files-template. Generate .tree-sitter-files. * test/infra/gitlab-ci.yml (test-tree-sitter): Extend .tree-sitter-files. * test/infra/test-jobs.yml: Regenerate. diff --git a/test/infra/Dockerfile.emba b/test/infra/Dockerfile.emba index 088df86ad70..de32906212b 100644 --- a/test/infra/Dockerfile.emba +++ b/test/infra/Dockerfile.emba @@ -145,6 +145,7 @@ RUN src/emacs -Q --batch \ treesit-language-source-alist \ (quote ((bash "https://github.com/tree-sitter/tree-sitter-bash") \ (c "https://github.com/tree-sitter/tree-sitter-c") \ + (c-sharp "https://github.com/tree-sitter/tree-sitter-c-sharp") \ (cpp "https://github.com/tree-sitter/tree-sitter-cpp") \ (css "https://github.com/tree-sitter/tree-sitter-css") \ (elixir "https://github.com/elixir-lang/tree-sitter-elixir") \ diff --git a/test/infra/Makefile.in b/test/infra/Makefile.in index 9c32fd6a192..0144ad1cbd9 100644 --- a/test/infra/Makefile.in +++ b/test/infra/Makefile.in @@ -117,22 +117,25 @@ endef $(foreach subdir, $(SUBDIRS), $(eval $(call subdir_template,$(subdir)))) -# js-tests.el and python-tests.el don't follow test file name convention. +# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow +# test file name convention. TREE-SITTER-FILES ?= $(shell cd .. ; \ find lisp src \( -name "*-ts-mode-tests.el" -o -name "treesit-tests.el" \ - -o -name "js-tests.el" -o -name "python-tests.el" \) | \ + -o -name "csharp-mode-tests.el" -o -name "js-tests.el" \ + -o -name "python-tests.el" \) | \ sort | sed s/\\.el/.log/) all: generate-test-jobs -.PHONY: generate-test-jobs $(FILE) $(SUBDIR_TARGETS) tree-sitter-files-template +.PHONY: generate-test-jobs $(FILE) $(SUBDIR_TARGETS) tree-sitter-files -generate-test-jobs: $(FILE) $(SUBDIR_TARGETS) tree-sitter-files-template +generate-test-jobs: $(FILE) $(SUBDIR_TARGETS) tree-sitter-files -tree-sitter-files-template: +tree-sitter-files: @echo >>$(FILE) - @echo "# js-tests.el and python-tests.el don't follow test file name convention." >>$(FILE) - @echo '.tree-sitter-files-template:' >>$(FILE) + @echo "# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow" >>$(FILE) + @echo "# test file name convention." >>$(FILE) + @echo '.tree-sitter-files:' >>$(FILE) @echo ' variables:' >>$(FILE) @echo ' tree_sitter_files: >-' >>$(FILE) @for name in $(TREE-SITTER-FILES) ; do echo " $${name}" >>$(FILE) ; done diff --git a/test/infra/gitlab-ci.yml b/test/infra/gitlab-ci.yml index 11ff0d1c738..e5e48b76ec2 100644 --- a/test/infra/gitlab-ci.yml +++ b/test/infra/gitlab-ci.yml @@ -294,7 +294,7 @@ build-image-tree-sitter: test-tree-sitter: stage: platforms - extends: [.job-template, .test-template, .tree-sitter-template, .tree-sitter-files-template] + extends: [.job-template, .test-template, .tree-sitter-template, .tree-sitter-files] needs: - job: build-image-tree-sitter optional: true diff --git a/test/infra/test-jobs.yml b/test/infra/test-jobs.yml index 0d9cbb029e5..13b184b1277 100644 --- a/test/infra/test-jobs.yml +++ b/test/infra/test-jobs.yml @@ -577,10 +577,12 @@ test-src-inotify: target: emacs-inotify make_params: -C test check-src -# js-tests.el and python-tests.el don't follow test file name convention. -.tree-sitter-files-template: +# csharp-mode-tests.el, js-tests.el and python-tests.el don't follow +# test file name convention. +.tree-sitter-files: variables: tree_sitter_files: >- + lisp/progmodes/csharp-mode-tests.log lisp/progmodes/c-ts-mode-tests.log lisp/progmodes/elixir-ts-mode-tests.log lisp/progmodes/go-ts-mode-tests.log commit 1fea9adf52019cb3f5ba89a402cf791164a94cbb Author: Eli Zaretskii Date: Sun Jul 14 21:20:42 2024 +0300 Improve support for Tifinagh * lisp/international/fontset.el (script-representative-chars) (setup-default-fontset): Add support for Tifinagh. diff --git a/lisp/international/fontset.el b/lisp/international/fontset.el index 33e444507c4..a6129cbc8f0 100644 --- a/lisp/international/fontset.el +++ b/lisp/international/fontset.el @@ -199,6 +199,7 @@ (tai-tham #x1A20 #x1A55 #x1A61 #x1A80) (symbol . [#x201C #x2200 #x2500]) (braille #x2800) + (tifinagh #x2D30 #x2D60) (ideographic-description #x2FF0) ;; Noto Sans Phags Pa is broken and reuses the CJK misc code ;; points for some of its own characters. Add one actual CJK @@ -860,6 +861,7 @@ nag-mundari mende-kikakui adlam + tifinagh tai-tham indic-siyaq-number ottoman-siyaq-number commit 5ec73eca57c09ad1a33c56dc4cd5b965cfaef063 Author: Kyle Meyer Date: Sun Jul 14 12:30:50 2024 -0400 Update to Org 9.7.7-2-gf308d3 diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index bbf26d9515d..b2c591b67d0 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -271,6 +271,10 @@ Image filename chosen can be customized by setting ~org-yank-image-file-name-function~ which by default autogenerates a filename based on the current time. +Note that ~yank-media~, as of Emacs 30, does not yet support Windows +(Emacs bug#71909) and may not be always reliable on Mac (Emacs +bug#71731). + *** Files and images can be attached by dropping onto Emacs By default, Org asks the user what to do with the dropped file like diff --git a/etc/refcards/orgcard.tex b/etc/refcards/orgcard.tex index 1860e269706..112832e0074 100644 --- a/etc/refcards/orgcard.tex +++ b/etc/refcards/orgcard.tex @@ -1,5 +1,5 @@ % Reference Card for Org Mode -\def\orgversionnumber{9.7.5} +\def\orgversionnumber{9.7.7} \def\versionyear{2024} % latest update \input emacsver.tex diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el index 60f213fe751..7b4ca9b5ea3 100644 --- a/lisp/org/ob-core.el +++ b/lisp/org/ob-core.el @@ -2455,8 +2455,8 @@ the inline source block. The macro is stripped upon export. Multiline and non-scalar RESULTS from inline source blocks are not allowed. When EXEC-TIME is provided it may be included in a generated message. With optional argument RESULT-PARAMS controls -insertion of results in the Org mode file. RESULT-PARAMS can -take the following values: +insertion of results in the Org mode file. RESULT-PARAMS is a list +that can contain the following values: replace - (default option) insert results after the source block or inline source block replacing any previously @@ -2515,15 +2515,17 @@ list ---- the results are rendered as a list. This option not table --- the results are rendered as a table. This option not allowed for inline source blocks. -INFO may provide the values of these header arguments (in the -`header-arguments-alist' see the docstring for -`org-babel-get-src-block-info'): +INFO is the src block info, as returned by +`org-babel-get-src-block-info' (which see). Some values from its +PARAMETERS part (header argument alist) can affect the inserted +result: -:file --- the name of the file to which output should be written. +:file-desc - when RESULT-PARAMS contains \"file\", use it as + description of the inserted link. -:wrap --- the effect is similar to `latex' in RESULT-PARAMS but - using the argument supplied to specify the export block - or snippet type." +:wrap the effect is similar to `latex' in RESULT-PARAMS but + using the argument supplied to specify the export block + or snippet type." (cond ((stringp result) (setq result (substring-no-properties result)) (when (member "file" result-params) diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el index b2a5ff92734..569da841726 100644 --- a/lisp/org/org-agenda.el +++ b/lisp/org/org-agenda.el @@ -2048,6 +2048,9 @@ the normal rules apply." (defcustom org-agenda-category-icon-alist nil "Alist of category icon to be displayed in agenda views. +The icons are displayed in place of the %i placeholders in +`org-agenda-prefix-format', which see. + Each entry should have the following format: (CATEGORY-REGEXP FILE-OR-DATA TYPE DATA-P PROPS) diff --git a/lisp/org/org-persist.el b/lisp/org/org-persist.el index b93e32274e9..5cc572a78cc 100644 --- a/lisp/org/org-persist.el +++ b/lisp/org/org-persist.el @@ -670,8 +670,8 @@ When INNER is non-nil, do not try to match as list of containers." ;; `secure-hash' may trigger interactive dialog when it ;; cannot determine the coding system automatically. ;; Force coding system that works reliably for any text - ;; to avoid it. The has will be consistent anyway, as - ;; long as we use the same coding system. + ;; to avoid it. The hash will be consistent, as long + ;; as we use the same coding system. (let ((coding-system-for-write 'emacs-internal)) (secure-hash 'md5 associated))) (puthash associated diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el index c02aff62ec4..75e792b74be 100644 --- a/lisp/org/org-version.el +++ b/lisp/org/org-version.el @@ -5,13 +5,13 @@ (defun org-release () "The release version of Org. Inserted by installing Org mode or when a release is made." - (let ((org-release "9.7.5")) + (let ((org-release "9.7.7")) org-release)) ;;;###autoload (defun org-git-version () "The Git version of Org mode. Inserted by installing Org or when a release is made." - (let ((org-git-version "release_9.7.5-9-ga091ca")) + (let ((org-git-version "release_9.7.7-2-gf308d3")) org-git-version)) (provide 'org-version) diff --git a/lisp/org/org.el b/lisp/org/org.el index 96b0e0b0ce1..e29a0834999 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -9,7 +9,7 @@ ;; URL: https://orgmode.org ;; Package-Requires: ((emacs "26.1")) -;; Version: 9.7.5 +;; Version: 9.7.7 ;; This file is part of GNU Emacs. ;; @@ -6698,7 +6698,7 @@ The prefix argument ARG is passed to `org-insert-heading'. Unlike `org-insert-heading', when point is at the beginning of a heading, still insert the new sub-heading below." (interactive "P") - (when (bolp) (forward-char)) + (when (and (bolp) (not (eobp)) (not (eolp))) (forward-char)) (org-insert-heading arg) (cond ((org-at-heading-p) (org-do-demote)) @@ -19809,7 +19809,11 @@ Also align node properties according to `org-property-format'." (+ (org-current-text-indentation) org-edit-src-content-indentation))))) (ignore-errors ; do not err when there is no proper major mode - (org-babel-do-in-edit-buffer (funcall indent-line-function))) + ;; It is important to call `indent-according-to-mode' + ;; rather than `indent-line-function' here or we may + ;; sometimes break `electric-indent-mode' + ;; https://orgmode.org/list/5O9VMGb6WRaqeHR5_NXTb832Z2Lek_5L40YPDA52-S3kPwGYJspI8kLWaGtuq3DXyhtHpj1J7jTIXb39RX9BtCa2ecrWHjijZqI8QAD742U=@proton.me + (org-babel-do-in-edit-buffer (indent-according-to-mode))) (when (and block-content-ind (looking-at-p "^$")) (indent-line-to block-content-ind)))) (t commit a44376432de78374017c2009163a9242acbf6355 Author: Mattias Engdegård Date: Sun Jul 14 13:01:57 2024 +0200 Further time decoding tidying * src/timefns.c (enum timeform): Reorder. (decode_time_components, decode_lisp_time): Simplify and clean up. diff --git a/src/timefns.c b/src/timefns.c index dc77051071d..331c11e0f34 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -852,10 +852,10 @@ enum timeform { TIMEFORM_HI_LO, /* seconds in the form (HI << LO_TIME_BITS) + LO. */ TIMEFORM_HI_LO_US, /* seconds plus microseconds (HI LO US) */ - TIMEFORM_NIL, /* current time in nanoseconds */ TIMEFORM_HI_LO_US_PS, /* seconds plus micro and picoseconds (HI LO US PS) */ TIMEFORM_FLOAT, /* time as a float */ - TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */ + TIMEFORM_TICKS_HZ, /* fractional time: HI is ticks, LO is ticks per second */ + TIMEFORM_NIL, /* current time in nanoseconds */ }; /* Assuming the input form was FORM (which should be one of @@ -871,132 +871,110 @@ decode_time_components (enum timeform form, Lisp_Object usec, Lisp_Object psec, enum cform cform) { - Lisp_Object ticks, hz; - + Lisp_Object hz; switch (form) { - case TIMEFORM_TICKS_HZ: - case TIMEFORM_FLOAT: - case TIMEFORM_NIL: - eassume (false); - - case TIMEFORM_HI_LO: - hz = make_fixnum (1); - goto check_high_low; + case TIMEFORM_HI_LO: hz = make_fixnum (1); break; + case TIMEFORM_HI_LO_US: hz = make_fixnum (1000000); break; + case TIMEFORM_HI_LO_US_PS: hz = trillion; break; + default: eassume (false); + } - case TIMEFORM_HI_LO_US: - hz = make_fixnum (1000000); - goto check_high_low_usec; + if (!(FIXNUMP (usec) && FIXNUMP (psec))) + return (struct err_time) { .err = EINVAL }; - case TIMEFORM_HI_LO_US_PS: - hz = trillion; - if (!FIXNUMP (psec)) - return (struct err_time) { .err = EINVAL }; - check_high_low_usec: - if (!FIXNUMP (usec)) - return (struct err_time) { .err = EINVAL }; - check_high_low: - { - EMACS_INT us = XFIXNUM (usec); - EMACS_INT ps = XFIXNUM (psec); - - /* Normalize out-of-range lower-order components by carrying - each overflow into the next higher-order component. */ - us += ps / 1000000 - (ps % 1000000 < 0); - EMACS_INT s_from_us_ps = us / 1000000 - (us % 1000000 < 0); - ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); - us = us % 1000000 + 1000000 * (us % 1000000 < 0); - - if (FASTER_TIMEFNS && FIXNUMP (high) && FIXNUMP (low)) - { - /* Use intmax_t arithmetic if the tick count fits. */ - intmax_t iticks; - bool v = false; - v |= ckd_mul (&iticks, XFIXNUM (high), 1 << LO_TIME_BITS); - v |= ckd_add (&iticks, iticks, XFIXNUM (low) + s_from_us_ps); - if (!v) - { - if (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY) - return (struct err_time) { - .time = { - .ts = s_ns_to_timespec (iticks, us * 1000 + ps / 1000) - } - }; + EMACS_INT us = XFIXNUM (usec); + EMACS_INT ps = XFIXNUM (psec); - switch (form) - { - case TIMEFORM_HI_LO: - break; + /* Normalize out-of-range lower-order components by carrying + each overflow into the next higher-order component. */ + us += ps / 1000000 - (ps % 1000000 < 0); + EMACS_INT s_from_us_ps = us / 1000000 - (us % 1000000 < 0); + ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); + us = us % 1000000 + 1000000 * (us % 1000000 < 0); - case TIMEFORM_HI_LO_US: - v |= ckd_mul (&iticks, iticks, 1000000); - v |= ckd_add (&iticks, iticks, us); - break; + if (FASTER_TIMEFNS && FIXNUMP (high) && FIXNUMP (low)) + { + /* Use intmax_t arithmetic if the tick count fits. */ + intmax_t iticks; + bool v = false; + v |= ckd_mul (&iticks, XFIXNUM (high), 1 << LO_TIME_BITS); + v |= ckd_add (&iticks, iticks, XFIXNUM (low) + s_from_us_ps); + if (!v) + { + if (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY) + return (struct err_time) { + .time = { + .ts = s_ns_to_timespec (iticks, us * 1000 + ps / 1000) + } + }; - case TIMEFORM_HI_LO_US_PS: - { - int_fast64_t million = 1000000; - v |= ckd_mul (&iticks, iticks, TRILLION); - v |= ckd_add (&iticks, iticks, us * million + ps); - } - break; + switch (form) + { + case TIMEFORM_HI_LO: + break; - default: - eassume (false); - } + case TIMEFORM_HI_LO_US: + v |= ckd_mul (&iticks, iticks, 1000000); + v |= ckd_add (&iticks, iticks, us); + break; - if (!v) - return (struct err_time) { - .time = decode_ticks_hz (make_int (iticks), hz, cform) - }; + case TIMEFORM_HI_LO_US_PS: + { + int_fast64_t million = 1000000; + v |= ckd_mul (&iticks, iticks, TRILLION); + v |= ckd_add (&iticks, iticks, us * million + ps); } - } + break; - if (! (INTEGERP (high) && INTEGERP (low))) - return (struct err_time) { .err = EINVAL }; + default: + eassume (false); + } - mpz_t *s = &mpz[1]; - mpz_set_intmax (*s, s_from_us_ps); - mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); - mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); + if (!v) + return (struct err_time) { + .time = decode_ticks_hz (make_int (iticks), hz, cform) + }; + } + } - switch (form) - { - case TIMEFORM_HI_LO: - /* Floats and nil were handled above, so it was an integer. */ - mpz_swap (mpz[0], *s); - break; + if (! (INTEGERP (high) && INTEGERP (low))) + return (struct err_time) { .err = EINVAL }; - case TIMEFORM_HI_LO_US: - mpz_set_ui (mpz[0], us); - mpz_addmul_ui (mpz[0], *s, 1000000); - break; + mpz_t *s = &mpz[1]; + mpz_set_intmax (*s, s_from_us_ps); + mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); + mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); - case TIMEFORM_HI_LO_US_PS: - { - #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX - unsigned long i = us; - mpz_set_ui (mpz[0], i * 1000000 + ps); - mpz_addmul_ui (mpz[0], *s, TRILLION); - #else - intmax_t i = us; - mpz_set_intmax (mpz[0], i * 1000000 + ps); - mpz_addmul (mpz[0], *s, ztrillion); - #endif - } - break; + switch (form) + { + case TIMEFORM_HI_LO: + mpz_swap (mpz[0], *s); + break; - default: - eassume (false); - } - ticks = make_integer_mpz (); + case TIMEFORM_HI_LO_US: + mpz_set_ui (mpz[0], us); + mpz_addmul_ui (mpz[0], *s, 1000000); + break; + + case TIMEFORM_HI_LO_US_PS: + { + #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX + unsigned long i = us; + mpz_set_ui (mpz[0], i * 1000000 + ps); + mpz_addmul_ui (mpz[0], *s, TRILLION); + #else + intmax_t i = us; + mpz_set_intmax (mpz[0], i * 1000000 + ps); + mpz_addmul (mpz[0], *s, ztrillion); + #endif } break; default: eassume (false); } - + Lisp_Object ticks = make_integer_mpz (); return (struct err_time) { .time = decode_ticks_hz (ticks, hz, cform) }; } @@ -1054,19 +1032,15 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) if (NILP (specified_time)) return (struct form_time) {.form = TIMEFORM_NIL, .time = current_time_in_cform (cform) }; - - Lisp_Object high = make_fixnum (0); - Lisp_Object low = specified_time; - Lisp_Object usec = make_fixnum (0); - Lisp_Object psec = make_fixnum (0); - enum timeform form = TIMEFORM_HI_LO; - - if (CONSP (specified_time)) + else if (CONSP (specified_time)) { - high = XCAR (specified_time); - low = XCDR (specified_time); + Lisp_Object high = XCAR (specified_time); + Lisp_Object low = XCDR (specified_time); + Lisp_Object usec = make_fixnum (0); + Lisp_Object psec = make_fixnum (0); if (CONSP (low)) { + enum timeform form = TIMEFORM_HI_LO; Lisp_Object low_tail = XCDR (low); low = XCAR (low); if (cform != CFORM_SECS_ONLY) @@ -1089,6 +1063,12 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) form = TIMEFORM_HI_LO_US; } } + + struct err_time err_time + = decode_time_components (form, high, low, usec, psec, cform); + if (err_time.err) + time_error (err_time.err); + return (struct form_time) { .form = form, .time = err_time.time }; } else { @@ -1101,10 +1081,10 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) cform) }; } } - else if (FASTER_TIMEFNS && INTEGERP (specified_time)) + else if (INTEGERP (specified_time)) return (struct form_time) { - .form = form, + .form = TIMEFORM_HI_LO, .time = decode_ticks_hz (specified_time, make_fixnum (1), cform) }; else if (FLOATP (specified_time)) @@ -1118,12 +1098,8 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) .time = decode_float_time (d, cform) }; } - - struct err_time err_time - = decode_time_components (form, high, low, usec, psec, cform); - if (err_time.err) - time_error (err_time.err); - return (struct form_time) { .form = form, .time = err_time.time }; + else + time_spec_invalid (); } /* Convert a non-float Lisp timestamp SPECIFIED_TIME to double. commit 159f3f59b1d6ca57cff6f0628458908b62639e30 Author: Eli Zaretskii Date: Sun Jul 14 11:41:30 2024 +0300 Minor improvement in 'rmail-redecode-body' * lisp/mail/rmail.el (rmail-redecode-body): Signal user-error if 'rmail-enable-mime' is non-nil; doc fix. diff --git a/lisp/mail/rmail.el b/lisp/mail/rmail.el index 5e3633d221c..e38ab12fae6 100644 --- a/lisp/mail/rmail.el +++ b/lisp/mail/rmail.el @@ -2955,51 +2955,56 @@ charset= headers. This function assumes that the current message is already decoded and displayed in the RMAIL buffer, but the coding system used to decode it was incorrect. It then decodes the message again, -using the coding system CODING." +using the coding system CODING. + +This function does nothing (except reporting a user-error) +if `rmail-enable-mime' is non-nil." (interactive "zCoding system for re-decoding this message: ") - (when (not rmail-enable-mime) - (with-current-buffer rmail-buffer - (rmail-swap-buffers-maybe) - (save-restriction - (widen) - (let ((msgbeg (rmail-msgbeg rmail-current-message)) - (msgend (rmail-msgend rmail-current-message)) - (buffer-read-only nil) - body-start x-coding-header old-coding) - (narrow-to-region msgbeg msgend) - (goto-char (point-min)) - (unless (setq body-start (search-forward "\n\n" (point-max) 1)) - (error "No message body")) - - (save-restriction - ;; Narrow to headers - (narrow-to-region (point-min) body-start) - (setq x-coding-header (goto-char (point-min))) - (if (not (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)) - (setq old-coding (rmail-get-coding-system)) - (setq old-coding (intern (match-string 1))) - (setq x-coding-header (point))) - (check-coding-system old-coding) - ;; Make sure the new coding system uses the same EOL - ;; conversion, to prevent ^M characters from popping up - ;; all over the place. - (let ((eol-type (coding-system-eol-type old-coding))) - (if (numberp eol-type) - (setq coding - (coding-system-change-eol-conversion coding eol-type)))) - (when (not (coding-system-equal - (coding-system-base old-coding) - (coding-system-base coding))) - ;; Rewrite the coding-system header. - (goto-char x-coding-header) - (if (> (point) (point-min)) - (delete-region (line-beginning-position) (point)) - (forward-line) - (insert "\n") - (forward-line -1)) - (insert "X-Coding-System: " - (symbol-name coding)))) - (rmail-show-message)))))) + (if (not rmail-enable-mime) + (with-current-buffer rmail-buffer + (rmail-swap-buffers-maybe) + (save-restriction + (widen) + (let ((msgbeg (rmail-msgbeg rmail-current-message)) + (msgend (rmail-msgend rmail-current-message)) + (buffer-read-only nil) + body-start x-coding-header old-coding) + (narrow-to-region msgbeg msgend) + (goto-char (point-min)) + (unless (setq body-start (search-forward "\n\n" (point-max) 1)) + (error "No message body")) + + (save-restriction + ;; Narrow to headers + (narrow-to-region (point-min) body-start) + (setq x-coding-header (goto-char (point-min))) + (if (not (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)) + (setq old-coding (rmail-get-coding-system)) + (setq old-coding (intern (match-string 1))) + (setq x-coding-header (point))) + (check-coding-system old-coding) + ;; Make sure the new coding system uses the same EOL + ;; conversion, to prevent ^M characters from popping up + ;; all over the place. + (let ((eol-type (coding-system-eol-type old-coding))) + (if (numberp eol-type) + (setq coding + (coding-system-change-eol-conversion coding eol-type)))) + (when (not (coding-system-equal + (coding-system-base old-coding) + (coding-system-base coding))) + ;; Rewrite the coding-system header. + (goto-char x-coding-header) + (if (> (point) (point-min)) + (delete-region (line-beginning-position) (point)) + (forward-line) + (insert "\n") + (forward-line -1)) + (insert "X-Coding-System: " + (symbol-name coding)))) + (rmail-show-message)))) + (user-error + (substitute-quotes "`rmail-enable-mime' is non-nil; disable it first")))) (defun rmail-highlight-headers () "Highlight the headers specified by `rmail-highlighted-headers'. commit 33ba72f52fd2138a7c2d6c065236fd459b8c659d Author: Eli Zaretskii Date: Sun Jul 14 09:06:55 2024 +0300 Fix decoding 'display' properties with SVG images in Enriched mode * lisp/textmodes/enriched.el (enriched-next-annotation): Reject matches of 'enriched-annotation-regexp' inside strings. Reported by Christopher Howard in https://lists.gnu.org/archive/html/help-gnu-emacs/2024-06/msg00178.html. diff --git a/lisp/textmodes/enriched.el b/lisp/textmodes/enriched.el index 385674f5b1a..bd4ced78efd 100644 --- a/lisp/textmodes/enriched.el +++ b/lisp/textmodes/enriched.el @@ -453,7 +453,12 @@ Any \"<<\" strings encountered are converted to \"<\". Return value is \(begin end name positive-p), or nil if none was found." (while (and (search-forward "<" nil 1) (progn (goto-char (match-beginning 0)) - (not (looking-at enriched-annotation-regexp)))) + ;; Make sure we are not inside a string, where any + ;; matches for 'enriched-annotation-regexp' are + ;; false positives. This happens, for example, in + ;; display properties that specify SVG images. + (or (nth 3 (syntax-ppss)) + (not (looking-at enriched-annotation-regexp))))) (forward-char 1) (if (eq ?< (char-after (point))) (delete-char 1) commit 174a0b7642bd2d8bc397a73afc647a799e873e20 Author: Pip Cet Date: Sun Jul 14 05:41:17 2024 +0000 * configure.ac (D8): Fix typo. diff --git a/configure.ac b/configure.ac index 3ee332521f6..d054104dd17 100644 --- a/configure.ac +++ b/configure.ac @@ -1026,7 +1026,7 @@ Please verify that the path to the SDK build tools you specified is correct]) fi AC_PATH_PROGS([D8], [d8], [], "${SDK_BUILD_TOOLS}:$PATH") - if test "D8" = ""; then + if test "$D8" = ""; then AC_MSG_ERROR([The Android dexer was not found. Please verify that the path to the SDK build tools you specified is correct]) fi commit 62fdcfd4842693f436acd5b729d20934d12ca708 Author: Paul Eggert Date: Sat Jul 13 22:16:26 2024 -0700 Minor renaming in timefns.c * src/timefns.c (current_time_in_cform): Rename this static function from current_time_in_form, since this is about enum cform not enum timeform. Use changed. diff --git a/src/timefns.c b/src/timefns.c index 7b8107ee12e..dc77051071d 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -858,7 +858,9 @@ enum timeform TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */ }; -/* From the time components HIGH, LOW, USEC and PSEC, +/* Assuming the input form was FORM (which should be one of + TIMEFORM_HI_LO, TIMEFORM_HI_LO_US, TIMEFORM_HI_LO_US_PS), + and from the time components HIGH, LOW, USEC and PSEC, generate the corresponding time value in CFORM form. Return a (0, valid timestamp) pair if successful, an (error number, @@ -1007,7 +1009,7 @@ struct form_time /* Current time (seconds since epoch) in form CFORM. */ static union c_time -current_time_in_form (enum cform cform) +current_time_in_cform (enum cform cform) { struct timespec now = current_timespec (); return ((FASTER_TIMEFNS @@ -1037,11 +1039,21 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) A/B s (A B C D) ; A, B : integer, C, D : fixnum (A * 2**16 + B + C / 10**6 + D / 10**12) s + + The following specified_time forms are also supported, + for compatibility with older Emacs versions: + + (A B) + like (A B 0 0) + (A B . C) ; C : fixnum + like (A B C 0) + (A B C) + like (A B C 0) */ if (NILP (specified_time)) return (struct form_time) {.form = TIMEFORM_NIL, - .time = current_time_in_form (cform) }; + .time = current_time_in_cform (cform) }; Lisp_Object high = make_fixnum (0); Lisp_Object low = specified_time; commit c56e837a10eb34cbe04da8f2c16ebcae7f70704b Author: Po Lu Date: Sun Jul 14 12:51:48 2024 +0800 ; * src/android.c (setEmacsParams): Delete unused variable. diff --git a/src/android.c b/src/android.c index 3c96867a6b5..4b673269407 100644 --- a/src/android.c +++ b/src/android.c @@ -1338,7 +1338,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, int pipefd[2]; pthread_t thread; - const char *java_string, *tem; + const char *java_string; struct stat statb; #ifdef THREADS_ENABLED commit f9dae55ccca065a6b27d00959db711faf59b9fa3 Merge: f38c42d1c7a b00fc31dd1d Author: Po Lu Date: Sun Jul 14 12:47:51 2024 +0800 Merge from savannah/emacs-30 b00fc31dd1d Do not set LD_LIBRARY_PATH during Android initialization 04bf3172f03 ; Set Transient's version e6f78485aa6 ; Fix typos in 'which-key-mode' (bug#72093) commit b00fc31dd1d4543f8b017e8d7fef7686cd430bcc Author: Po Lu Date: Sun Jul 14 12:46:23 2024 +0800 Do not set LD_LIBRARY_PATH during Android initialization * doc/emacs/android.texi (Android Environment): Adjust documentation to match. * java/org/gnu/emacs/EmacsNoninteractive.java (main1): New function. Remove initialization of EmacsNative hither. (main): Acquire an ApplicationInfo or LoadedApk, as the case may be on the host system, derive a ClassLoader from the result, and load and call `main1' from within this class loader. * src/android-emacs.c (main): * src/android.c (setEmacsParams): Do not override LD_LIBRARY_PATH or set EMACS_LD_LIBRARY_PATH. This enables Emacs to execute subprocesses in certain "fortified" Android systems, amongst other things. diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 2d95f5c8fef..edcbb971b98 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -378,20 +378,18 @@ definition documents, so your mileage may vary. @cindex EMACS_CLASS_PATH environment variable, Android Even when the location of the @command{libandroid-emacs.so} command is -known in advance, special configuration is required to run Emacs from +known in advance, special preparation is required to run Emacs from elsewhere than a subprocess of an existing Emacs session, as it must be made to understand the location of resources and shared libraries in or extracted from the installed application package. The OS command @command{pm path org.gnu.emacs} will print the location of the -application package, and the adjacent @file{lib} directory will hold -shared libraries extracted from the same, though the said command must -be invoked in a peculiar manner to satisfy system restrictions on -communication between pseudoterminal devices created by user -applications and system services such as the package manager, which is -to say, with the standard IO streams redirected to a real file or a -pipe. Such values, once established, must be specified in the -environment variables @code{EMACS_CLASS_PATH} and -@code{EMACS_LD_LIBRARY_PATH}, so that this sample shell script may be +application package, though the said command must be invoked in a +peculiar manner to satisfy system restrictions on communication between +pseudoterminal devices created by user applications and system services +such as the package manager, which is to say, with the standard IO +streams redirected to a real file or a pipe. This value, once +established, must be specified in the environment variables +@code{EMACS_CLASS_PATH}, so that this sample shell script may be installed as @code{emacs} in any location that is accessible: @example @@ -400,7 +398,6 @@ installed as @code{emacs} in any location that is accessible: package_name=`pm path org.gnu.emacs 2>/dev/null Date: Sat Jul 13 21:59:20 2024 +0200 ; Set Transient's version diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi index 22db4e82143..9245a76e66b 100644 --- a/doc/misc/transient.texi +++ b/doc/misc/transient.texi @@ -31,7 +31,7 @@ General Public License for more details. @finalout @titlepage @title Transient User and Developer Manual -@subtitle for version 0.7.2 +@subtitle for version 0.7.2.1 @author Jonas Bernoulli @page @vskip 0pt plus 1filll @@ -53,7 +53,7 @@ resource to get over that hurdle is Psionic K's interactive tutorial, available at @uref{https://github.com/positron-solutions/transient-showcase}. @noindent -This manual is for Transient version 0.7.2. +This manual is for Transient version 0.7.2.1. @insertcopying @end ifnottex diff --git a/lisp/transient.el b/lisp/transient.el index 312ed540f73..05ad0ed8a0b 100644 --- a/lisp/transient.el +++ b/lisp/transient.el @@ -5,7 +5,7 @@ ;; Author: Jonas Bernoulli ;; URL: https://github.com/magit/transient ;; Keywords: extensions -;; Version: 0.7.2 +;; Version: 0.7.2.1 ;; SPDX-License-Identifier: GPL-3.0-or-later commit f38c42d1c7a8413f63b1e56261850d3dbe8abef8 Author: Jim Porter Date: Thu Jul 11 16:29:37 2024 -0700 Treat SVG images like other image types in 'shr-put-image' For both SVG and no-SVG builds, this works as expected (in the no-SVG case, it would raise an error which subsequently gets ignored). However, compared to the previous implementation, this lets users resize SVG images just like every other image type (bug#71913). * lisp/net/shr.el (shr-put-image): Don't special-case SVGs. diff --git a/lisp/net/shr.el b/lisp/net/shr.el index 39271cc5296..d3c48b34428 100644 --- a/lisp/net/shr.el +++ b/lisp/net/shr.el @@ -1193,23 +1193,18 @@ You can specify the following optional properties: (if (display-graphic-p) (let* ((zoom (or (plist-get flags :zoom) (car shr-image-zoom-levels))) - (zoom-function (nth 2 (assq zoom shr-image-zoom-level-alist))) + (zoom-function (or (nth 2 (assq zoom shr-image-zoom-level-alist)) + (error "Unrecognized zoom level %s" zoom))) (data (if (consp spec) (car spec) spec)) (content-type (and (consp spec) (cadr spec))) (start (point)) - (image (cond - ((eq content-type 'image/svg+xml) - (when (image-type-available-p 'svg) - (create-image data 'svg t :ascent shr-image-ascent))) - (zoom-function - (ignore-errors - (funcall zoom-function data content-type - (plist-get flags :width) - (plist-get flags :height)))) - (t (error "Unrecognized zoom level %s" zoom))))) + (image (ignore-errors + (funcall zoom-function data content-type + (plist-get flags :width) + (plist-get flags :height))))) (when image ;; The trailing space can confuse shr-insert into not ;; putting any space after inline images. commit e6f78485aa66ff762376702fc97a14a4dfe9b258 Author: john muhl Date: Wed Jul 10 17:13:58 2024 -0500 ; Fix typos in 'which-key-mode' (bug#72093) * lisp/which-key.el (which-key-preserve-window-configuration): Correct spelling of "taken". (which-key--create-pages): Correct spelling of "widths". (which-key--start-paging-timer): Correct spelling of "secondary". diff --git a/lisp/which-key.el b/lisp/which-key.el index 677a84b328d..37b42a009f7 100644 --- a/lisp/which-key.el +++ b/lisp/which-key.el @@ -444,7 +444,7 @@ Note that `which-key-idle-delay' should be set before turning on If non-nil, save window configuration before which-key buffer is shown and restore it after which-key buffer is hidden. It prevents which-key from changing window position of visible -buffers. Only takken into account when popup type is +buffers. Only taken into account when popup type is side-window." :type 'boolean :package-version "1.0" :version "30.1") @@ -2113,7 +2113,7 @@ should be minimized." (defun which-key--create-pages (keys &optional prefix-keys prefix-title) "Create page strings using `which-key--list-to-pages'. Will try to find the best number of rows and columns using the -given dimensions and the length and wdiths of KEYS. SEL-WIN-WIDTH +given dimensions and the length and widths of KEYS. SEL-WIN-WIDTH is the width of the live window." (let* ((max-dims (which-key--popup-max-dimensions)) (max-lines (car max-dims)) @@ -2825,7 +2825,7 @@ Finally, show the buffer." (funcall which-key-this-command-keys-function))))) (cancel-timer which-key--paging-timer) (if which-key-idle-secondary-delay - ;; we haven't executed a command yet so the secandary + ;; we haven't executed a command yet so the secondary ;; timer is more relevant here (which-key--start-timer which-key-idle-secondary-delay t) (which-key--start-timer))))))) commit 5389b6a856b39427846e38b06fa398bafc04836a Author: Eli Zaretskii Date: Sat Jul 13 15:52:38 2024 +0300 Fix renaming symlinks on MS-Windows * src/w32.c (sys_rename_replace): Handle renames of a symlink. This makes 'wdired-tests' succeed on MS-Windows. diff --git a/src/w32.c b/src/w32.c index ab45ae8ec6b..6dcbbbcc61b 100644 --- a/src/w32.c +++ b/src/w32.c @@ -4761,6 +4761,15 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force) strcpy (temp, map_w32_filename (oldname, NULL)); + /* 'rename' (which calls MoveFileW) renames the _target_ of the + symlink, which is different from Posix behavior and not what we + want here. So in that case we pretend this is a cross-device move, + for which Frename_file already has a workaround. */ + if (is_symlink (temp)) + { + errno = EXDEV; + return -1; + } /* volume_info is set indirectly by map_w32_filename. */ oldname_dev = volume_info.serialnum; commit 44ae4868d38acf7d8173be39c052b7fc9a7aaefa Merge: 3a26a51c69b a6c78ccf5f2 Author: Eli Zaretskii Date: Sat Jul 13 08:44:49 2024 -0400 Merge from origin/emacs-30 a6c78ccf5f2 ; * src/w32fns.c (Fw32_notification_close): Fix typo (bug... febafe37884 * test/lisp/wdired-tests.el (wdired-test-bug34915): Fix f... 846b79b6d02 Fix 'wdired-test-unfinished-edit-01' bc154cba130 ; * src/search.c (Fre_search_forward): Clarify doc string... 53291e3d46e Fontify destructor in c++-ts-mode d77f8a34750 Fix invalid defcustom type for erc-buffers option d68a4ea3ec6 ; Fix 'ibuffer-do-isearch{-regexp}' 8b1a0f8695a Fix infloop in 'shell-resync-dirs' ce13eee5ab7 ; * src/image.c (free_image_cache): Add assertion. (Bug#... commit a6c78ccf5f297e612ff0f2159a7bed3a70637168 Author: Raffael Stocker Date: Sat Jul 13 13:26:23 2024 +0200 ; * src/w32fns.c (Fw32_notification_close): Fix typo (bug#72091). diff --git a/src/w32fns.c b/src/w32fns.c index 7fc2f598b3e..e5798fdd84f 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -10472,7 +10472,7 @@ DEFUN ("w32-notification-close", { struct frame *f = SELECTED_FRAME (); - if (FIXNUMP (id) && !pfnShell_NotifyIconW) + if (FIXNUMP (id) && pfnShell_NotifyIconW) delete_tray_notification (f, XFIXNUM (id)); return Qnil; commit febafe37884823d5ac6a63a57c7500f4a0a8a792 Author: Eli Zaretskii Date: Sat Jul 13 15:06:43 2024 +0300 * test/lisp/wdired-tests.el (wdired-test-bug34915): Fix for MS-Windows. diff --git a/test/lisp/wdired-tests.el b/test/lisp/wdired-tests.el index f6d2194e998..7c7026354b8 100644 --- a/test/lisp/wdired-tests.el +++ b/test/lisp/wdired-tests.el @@ -141,21 +141,27 @@ wdired-get-filename before and after editing." ;; FIXME: Add a test for a door (indicator ">") only under Solaris? (ert-with-temp-directory test-dir (let* ((dired-listing-switches "-Fl") - (dired-ls-F-marks-symlinks (eq system-type 'darwin)) + (dired-ls-F-marks-symlinks + (or (eq system-type 'darwin) + (featurep 'ls-lisp))) (buf (find-file-noselect test-dir)) proc) (unwind-protect (progn (with-current-buffer buf - (dired-create-empty-file "foo") - (set-file-modes "foo" (file-modes-symbolic-to-number "+x")) + ;; Create a .bat file so that MS-Windows, where the 'x' + ;; bit is not recorded in the filesystem, considers it an + ;; executable. + (dired-create-empty-file "foo.bat") + (set-file-modes "foo.bat" (file-modes-symbolic-to-number "+x")) (skip-unless ;; This check is for wdired, not symbolic links, so skip ;; it when make-symbolic-link fails for any reason (like ;; insufficient privileges). - (ignore-errors (make-symbolic-link "foo" "bar") t)) + (ignore-errors (make-symbolic-link "foo.bat" "bar") t)) (make-directory "foodir") - (dired-smart-shell-command "mkfifo foopipe") + (unless (memq system-type '(windows-nt ms-dos)) + (dired-smart-shell-command "mkfifo foopipe")) (when (featurep 'make-network-process '(:family local)) (setq proc (make-network-process :name "foo" commit 846b79b6d02faf188f0131c57a49a60bb8f71d64 Author: Peter Oliver Date: Fri Jul 12 10:52:23 2024 +0100 Fix 'wdired-test-unfinished-edit-01' * test/lisp/wdired-tests.el (wdired-test-unfinished-edit-01): Don't modify the random directory name if, by chance, it happens to contain the substring "foo" anywhere but immediately after the slash. (Bug#72073) diff --git a/test/lisp/wdired-tests.el b/test/lisp/wdired-tests.el index f7bff743058..f6d2194e998 100644 --- a/test/lisp/wdired-tests.el +++ b/test/lisp/wdired-tests.el @@ -114,7 +114,7 @@ wdired-mode." (setq test-dir (file-truename test-dir)) (let* ((test-file (concat (file-name-as-directory test-dir) "foo.c")) (replace "bar") - (new-file (string-replace "foo" replace test-file))) + (new-file (string-replace "/foo" (concat "/" replace) test-file))) (write-region "" nil test-file nil 'silent) (let ((buf (find-file-noselect test-dir))) (unwind-protect commit bc154cba13024d2c159f6cadd324a8ef3f6dddcc Author: Eli Zaretskii Date: Sat Jul 13 13:22:01 2024 +0300 ; * src/search.c (Fre_search_forward): Clarify doc string (bug#71879). diff --git a/src/search.c b/src/search.c index dd813eda913..2ff8b0599c4 100644 --- a/src/search.c +++ b/src/search.c @@ -2279,7 +2279,7 @@ The optional second argument BOUND is a buffer position that bounds value of nil means search to the end of the accessible portion of the buffer. The optional third argument NOERROR indicates how errors are handled - when the search fails. If it is nil or omitted, emit an error; if + when the search fails: if it is nil or omitted, emit an error; if it is t, simply return nil and do nothing; if it is neither nil nor t, move to the limit of search and return nil. The optional fourth argument COUNT is a number that indicates the commit 3a26a51c69b064546fd4647a94cdfc2656b201ec Author: Eli Zaretskii Date: Sat Jul 13 13:16:42 2024 +0300 ; Fix last change * lisp/progmodes/java-ts-mode.el (java-ts-mode): * lisp/progmodes/c-ts-mode.el (c-ts-mode, c++-ts-mode): Load the Doxygen grammar quietly, so that if it isn't available, the user is not annoyed. (Bug#71874) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index a0f2bc33963..31dd49dd00c 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -1351,7 +1351,7 @@ in your init files." (treesit-font-lock-recompute-features '(emacs-devel))) ;; Inject doxygen parser for comment. - (when (treesit-ready-p 'doxygen) + (when (treesit-ready-p 'doxygen t) (setq-local treesit-primary-parser primary-parser) (setq-local treesit-font-lock-settings (append @@ -1412,7 +1412,7 @@ recommended to enable `electric-pair-mode' with this mode." #'c-ts-mode--emacs-current-defun-name)) ;; Inject doxygen parser for comment. - (when (treesit-ready-p 'doxygen) + (when (treesit-ready-p 'doxygen t) (setq-local treesit-primary-parser primary-parser) (setq-local treesit-font-lock-settings (append diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 68ead567632..ac104534734 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -401,7 +401,7 @@ Return nil if there is no name or if NODE is not a defun node." java-ts-mode--font-lock-settings) ;; Inject doxygen parser for comment. - (when (treesit-ready-p 'doxygen) + (when (treesit-ready-p 'doxygen t) (setq-local treesit-primary-parser primary-parser) (setq-local treesit-font-lock-settings (append treesit-font-lock-settings commit c77a9b934bc1120c7726d271bbd4ada178cf8c2d Author: Vincenzo Pupillo Date: Mon Jul 1 12:34:01 2024 +0200 Fontify doxygen support to 'c-ts-mode', 'c++-ts-mode' and 'java-ts-mode' Add doxygen support to 'c-ts-mode', 'c++-ts-mode' and 'java-ts-mode' using tree-sitter-doxygen from github.com/tree-sitter-grammars. * lisp/progmodes/c-ts-common.el (c-ts-mode-doxygen-comment-font-lock-settings): Add font locking rules for doxygen comment. * lisp/progmodes/c-ts-mode.el (c-ts-mode--feature-list): Add 'document' feature. (c-ts-mode--doxygen-comment-regex): New regular expression for doxygen comments. (c-ts-mode, c++-ts-mode): Add support for doxygen parser. * lisp/progmodes/java-ts-mode.el (java-ts-mode): Add support for doxygen parser. (Bug#71874) diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el index 3882a697c48..a1f257ee09a 100644 --- a/lisp/progmodes/c-ts-common.el +++ b/lisp/progmodes/c-ts-common.el @@ -348,6 +348,28 @@ and /* */ comments. SOFT works the same as in (delete-region (line-beginning-position) (point)) (insert whitespaces))))) +;; Font locking using doxygen parser +(defvar c-ts-mode-doxygen-comment-font-lock-settings + (treesit-font-lock-rules + :language 'doxygen + :feature 'document + :override t + '((document) @font-lock-doc-face) + + :language 'doxygen + :override t + :feature 'keyword + '((tag_name) @font-lock-constant-face + (storageclass) @font-lock-constant-face) + + :language 'doxygen + :override t + :feature 'definition + '((tag (identifier) @font-lock-variable-name-face) + (function (identifier) @font-lock-function-name-face) + (function_link) @font-lock-function-name-face)) + "Tree-sitter font lock rules for doxygen like comment styles.") + ;;; Statement indent (defvar c-ts-common-indent-offset nil diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index e7f74fc53f2..a0f2bc33963 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -63,6 +63,9 @@ ;; will set up Emacs to use the C/C++ modes defined here for other ;; files, provided that you have the corresponding parser grammar ;; libraries installed. +;; +;; If the tree-sitter doxygen grammar is available, then the comment +;; blocks will be highlighted according to this grammar. ;;; Code: @@ -539,7 +542,7 @@ NODE should be a labeled_statement. PARENT is its parent." ;;; Font-lock (defvar c-ts-mode--feature-list - '(( comment definition) + '(( comment document definition) ( keyword preprocessor string type) ( assignment constant escape-sequence label literal) ( bracket delimiter error function operator property variable)) @@ -591,6 +594,10 @@ MODE is either `c' or `cpp'." "LIVE_BUFFER" "FRAME")) "A regexp matching all the variants of the FOR_EACH_* macro.") +(defvar c-ts-mode--doxygen-comment-regex + (rx (| "/**" "/*!" "//!" "///")) + "A regexp that matches all doxygen comment styles.") + (defun c-ts-mode--font-lock-settings (mode) "Tree-sitter font-lock settings. MODE is either `c' or `cpp'." @@ -1317,30 +1324,47 @@ in your init files." (when c-ts-mode-emacs-sources-support (treesit-parser-create 'c nil nil 'for-each)) - (treesit-parser-create 'c) - ;; Comments. - (setq-local comment-start "/* ") - (setq-local comment-end " */") - ;; Indent. - (setq-local treesit-simple-indent-rules - (c-ts-mode--get-indent-style 'c)) - ;; Font-lock. - (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c)) - ;; Navigation. - (setq-local treesit-defun-tactic 'top-level) - (treesit-major-mode-setup) - - ;; Emacs source support: handle DEFUN and FOR_EACH_* gracefully. - (when c-ts-mode-emacs-sources-support - (setq-local add-log-current-defun-function - #'c-ts-mode--emacs-current-defun-name) - - (setq-local treesit-range-settings - (treesit-range-rules 'c-ts-mode--emacs-set-ranges)) - - (setq-local treesit-language-at-point-function - (lambda (_pos) 'c)) - (treesit-font-lock-recompute-features '(emacs-devel))))) + (let ((primary-parser (treesit-parser-create 'c))) + ;; Comments. + (setq-local comment-start "/* ") + (setq-local comment-end " */") + ;; Indent. + (setq-local treesit-simple-indent-rules + (c-ts-mode--get-indent-style 'c)) + ;; Font-lock. + (setq-local treesit-font-lock-settings + (c-ts-mode--font-lock-settings 'c)) + ;; Navigation. + (setq-local treesit-defun-tactic 'top-level) + (treesit-major-mode-setup) + + ;; Emacs source support: handle DEFUN and FOR_EACH_* gracefully. + (when c-ts-mode-emacs-sources-support + (setq-local add-log-current-defun-function + #'c-ts-mode--emacs-current-defun-name) + + (setq-local treesit-range-settings + (treesit-range-rules 'c-ts-mode--emacs-set-ranges)) + + (setq-local treesit-language-at-point-function + (lambda (_pos) 'c)) + (treesit-font-lock-recompute-features '(emacs-devel))) + + ;; Inject doxygen parser for comment. + (when (treesit-ready-p 'doxygen) + (setq-local treesit-primary-parser primary-parser) + (setq-local treesit-font-lock-settings + (append + treesit-font-lock-settings + c-ts-mode-doxygen-comment-font-lock-settings)) + (setq-local treesit-range-settings + (treesit-range-rules + :embed 'doxygen + :host 'c + :local t + `(((comment) @cap + (:match + ,c-ts-mode--doxygen-comment-regex @cap))))))))) (derived-mode-add-parents 'c-ts-mode '(c-mode)) @@ -1368,24 +1392,40 @@ recommended to enable `electric-pair-mode' with this mode." :after-hook (c-ts-mode-set-modeline) (when (treesit-ready-p 'cpp) - - (treesit-parser-create 'cpp) - - ;; Syntax. - (setq-local syntax-propertize-function - #'c-ts-mode--syntax-propertize) - - ;; Indent. - (setq-local treesit-simple-indent-rules - (c-ts-mode--get-indent-style 'cpp)) - - ;; Font-lock. - (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp)) - (treesit-major-mode-setup) - - (when c-ts-mode-emacs-sources-support - (setq-local add-log-current-defun-function - #'c-ts-mode--emacs-current-defun-name)))) + (let ((primary-parser (treesit-parser-create 'cpp))) + + ;; Syntax. + (setq-local syntax-propertize-function + #'c-ts-mode--syntax-propertize) + + ;; Indent. + (setq-local treesit-simple-indent-rules + (c-ts-mode--get-indent-style 'cpp)) + + ;; Font-lock. + (setq-local treesit-font-lock-settings + (c-ts-mode--font-lock-settings 'cpp)) + (treesit-major-mode-setup) + + (when c-ts-mode-emacs-sources-support + (setq-local add-log-current-defun-function + #'c-ts-mode--emacs-current-defun-name)) + + ;; Inject doxygen parser for comment. + (when (treesit-ready-p 'doxygen) + (setq-local treesit-primary-parser primary-parser) + (setq-local treesit-font-lock-settings + (append + treesit-font-lock-settings + c-ts-mode-doxygen-comment-font-lock-settings)) + (setq-local treesit-range-settings + (treesit-range-rules + :embed 'doxygen + :host 'cpp + :local t + `(((comment) @cap + (:match + ,c-ts-mode--doxygen-comment-regex @cap))))))))) (derived-mode-add-parents 'c++-ts-mode '(c++-mode)) diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 4ceb211ade1..68ead567632 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -24,6 +24,8 @@ ;;; Commentary: ;; +;; If the tree-sitter doxygen grammar is available, then the comment +;; blocks will be highlighted according to this grammar. ;;; Code: @@ -312,7 +314,7 @@ Return nil if there is no name or if NODE is not a defun node." (defvar java-ts-mode--feature-list - '(( comment definition ) + '(( comment document definition ) ( constant keyword string type) ( annotation expression literal) ( bracket delimiter operator))) @@ -326,76 +328,91 @@ Return nil if there is no name or if NODE is not a defun node." (unless (treesit-ready-p 'java) (error "Tree-sitter for Java isn't available")) - (treesit-parser-create 'java) - - ;; Comments. - (c-ts-common-comment-setup) - - ;; Indent. - (setq-local c-ts-common-indent-type-regexp-alist - `((block . ,(rx (or "class_body" - "array_initializer" - "constructor_body" - "annotation_type_body" - "interface_body" - "lambda_expression" - "enum_body" - "switch_block" - "record_declaration_body" - "block"))) - (close-bracket . "}") - (if . "if_statement") - (else . ("if_statement" . "alternative")) - (for . "for_statement") - (while . "while_statement") - (do . "do_statement"))) - (setq-local c-ts-common-indent-offset 'java-ts-mode-indent-offset) - (setq-local treesit-simple-indent-rules java-ts-mode--indent-rules) - - ;; Electric - (setq-local electric-indent-chars - (append "{}():;," electric-indent-chars)) - - ;; Navigation. - (setq-local treesit-defun-type-regexp - (regexp-opt '("method_declaration" - "class_declaration" - "record_declaration" - "interface_declaration" - "enum_declaration" - "import_declaration" - "package_declaration" - "module_declaration" - "constructor_declaration"))) - (setq-local treesit-defun-name-function #'java-ts-mode--defun-name) - - (setq-local treesit-thing-settings - `((java - (sexp ,(rx (or "annotation" - "parenthesized_expression" - "argument_list" - "identifier" - "modifiers" - "block" - "body" - "literal" - "access" - "reference" - "_type" - "true" - "false"))) - (sentence ,(rx (or "statement" - "local_variable_declaration" - "field_declaration" - "module_declaration" - "package_declaration" - "import_declaration"))) - (text ,(regexp-opt '("line_comment" - "block_comment" - "text_block")))))) - - ;; Font-lock. - (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings) + (let ((primary-parser (treesit-parser-create 'java))) + + ;; Comments. + (c-ts-common-comment-setup) + + ;; Indent. + (setq-local c-ts-common-indent-type-regexp-alist + `((block . ,(rx (or "class_body" + "array_initializer" + "constructor_body" + "annotation_type_body" + "interface_body" + "lambda_expression" + "enum_body" + "switch_block" + "record_declaration_body" + "block"))) + (close-bracket . "}") + (if . "if_statement") + (else . ("if_statement" . "alternative")) + (for . "for_statement") + (while . "while_statement") + (do . "do_statement"))) + (setq-local c-ts-common-indent-offset 'java-ts-mode-indent-offset) + (setq-local treesit-simple-indent-rules java-ts-mode--indent-rules) + + ;; Electric + (setq-local electric-indent-chars + (append "{}():;," electric-indent-chars)) + + ;; Navigation. + (setq-local treesit-defun-type-regexp + (regexp-opt '("method_declaration" + "class_declaration" + "record_declaration" + "interface_declaration" + "enum_declaration" + "import_declaration" + "package_declaration" + "module_declaration" + "constructor_declaration"))) + (setq-local treesit-defun-name-function #'java-ts-mode--defun-name) + + (setq-local treesit-thing-settings + `((java + (sexp ,(rx (or "annotation" + "parenthesized_expression" + "argument_list" + "identifier" + "modifiers" + "block" + "body" + "literal" + "access" + "reference" + "_type" + "true" + "false"))) + (sentence ,(rx (or "statement" + "local_variable_declaration" + "field_declaration" + "module_declaration" + "package_declaration" + "import_declaration"))) + (text ,(regexp-opt '("line_comment" + "block_comment" + "text_block")))))) + + ;; Font-lock. + (setq-local treesit-font-lock-settings + java-ts-mode--font-lock-settings) + + ;; Inject doxygen parser for comment. + (when (treesit-ready-p 'doxygen) + (setq-local treesit-primary-parser primary-parser) + (setq-local treesit-font-lock-settings + (append treesit-font-lock-settings + c-ts-mode-doxygen-comment-font-lock-settings)) + (setq-local treesit-range-settings + (treesit-range-rules + :embed 'doxygen + :host 'java + :local t + `(((block_comment) @cap (:match "/\\*\\*" @cap))))))) + (setq-local treesit-font-lock-feature-list java-ts-mode--feature-list) ;; Imenu. commit 53291e3d46ee81b2b0fb7594496d938eab61bc0f Author: Vincenzo Pupillo Date: Mon Jul 1 11:52:18 2024 +0200 Fontify destructor in c++-ts-mode * lisp/progmodes/c-ts-mode.el (c-ts-mode--font-lock-settings): Add a rule for destructors. (Bug#71872) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index e7f74fc53f2..2ac163d7a7e 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -674,7 +674,9 @@ MODE is either `c' or `cpp'." :language mode :feature 'definition ;; Highlights identifiers in declarations. - `((declaration + `(,@(when (eq mode 'cpp) + '((destructor_name (identifier) @font-lock-function-name-face))) + (declaration declarator: (_) @c-ts-mode--fontify-declarator) (field_declaration commit b23ab371756b5f77f62020cdfda5fe7b6fb04470 Author: Mattias Engdegård Date: Fri Jul 12 12:16:22 2024 +0200 Simplify timestamp decoding * src/timefns.c (current_time_in_form, time_spec_invalid): New. (enum timeform): Remove TIMEFORM_INVALID. (decode_time_components): Move handling of TIMEFORM_INVALID, TIMEFORM_TICKS_HZ and TIMEFORM_NIL... (decode_lisp_time): ...here, avoiding the detour. diff --git a/src/timefns.c b/src/timefns.c index 1e551009df8..7b8107ee12e 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -357,6 +357,12 @@ time_overflow (void) error ("Specified time is not representable"); } +static AVOID +time_spec_invalid (void) +{ + error ("Invalid time specification"); +} + static AVOID time_error (int err) { @@ -364,7 +370,7 @@ time_error (int err) { case ENOMEM: memory_full (SIZE_MAX); case EOVERFLOW: time_overflow (); - default: error ("Invalid time specification"); + default: time_spec_invalid (); } } @@ -844,7 +850,6 @@ struct err_time /* Lisp timestamp classification. */ enum timeform { - TIMEFORM_INVALID = 0, TIMEFORM_HI_LO, /* seconds in the form (HI << LO_TIME_BITS) + LO. */ TIMEFORM_HI_LO_US, /* seconds plus microseconds (HI LO US) */ TIMEFORM_NIL, /* current time in nanoseconds */ @@ -853,10 +858,8 @@ enum timeform TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */ }; -/* From the non-float form FORM and the time components HIGH, LOW, USEC - and PSEC, generate the corresponding time value in CFORM form. If LOW is - floating point, the other components should be zero and FORM should - not be TIMEFORM_TICKS_HZ. +/* From the time components HIGH, LOW, USEC and PSEC, + generate the corresponding time value in CFORM form. Return a (0, valid timestamp) pair if successful, an (error number, unspecified timestamp) pair otherwise. */ @@ -870,30 +873,10 @@ decode_time_components (enum timeform form, switch (form) { - case TIMEFORM_INVALID: - return (struct err_time) { .err = EINVAL }; - case TIMEFORM_TICKS_HZ: - if (! (INTEGERP (high) - && (FIXNUMP (low) ? 0 < XFIXNUM (low) : !NILP (Fnatnump (low))))) - return (struct err_time) { .err = EINVAL }; - ticks = high; - hz = low; - break; - case TIMEFORM_FLOAT: - eassume (false); - case TIMEFORM_NIL: - { - struct timespec now = current_timespec (); - if (FASTER_TIMEFNS - && (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY)) - return (struct err_time) { .time = { .ts = now } }; - ticks = timespec_ticks (now); - hz = timespec_hz; - } - break; + eassume (false); case TIMEFORM_HI_LO: hz = make_fixnum (1); @@ -1022,6 +1005,17 @@ struct form_time union c_time time; }; +/* Current time (seconds since epoch) in form CFORM. */ +static union c_time +current_time_in_form (enum cform cform) +{ + struct timespec now = current_timespec (); + return ((FASTER_TIMEFNS + && (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY)) + ? (union c_time) {.ts = now} + : decode_ticks_hz (timespec_ticks (now), timespec_hz, cform)); +} + /* Decode a Lisp timestamp SPECIFIED_TIME that represents a time. Return a (form, time) pair that is the form of SPECIFIED-TIME @@ -1033,15 +1027,29 @@ struct form_time static struct form_time decode_lisp_time (Lisp_Object specified_time, enum cform cform) { + /* specified_time is one of: + + nil + current time + NUMBER + that number of seconds + (A . B) ; A, B : integer, B>0 + A/B s + (A B C D) ; A, B : integer, C, D : fixnum + (A * 2**16 + B + C / 10**6 + D / 10**12) s + */ + + if (NILP (specified_time)) + return (struct form_time) {.form = TIMEFORM_NIL, + .time = current_time_in_form (cform) }; + Lisp_Object high = make_fixnum (0); Lisp_Object low = specified_time; Lisp_Object usec = make_fixnum (0); Lisp_Object psec = make_fixnum (0); enum timeform form = TIMEFORM_HI_LO; - if (NILP (specified_time)) - form = TIMEFORM_NIL; - else if (CONSP (specified_time)) + if (CONSP (specified_time)) { high = XCAR (specified_time); low = XCDR (specified_time); @@ -1072,13 +1080,14 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) } else { - form = TIMEFORM_TICKS_HZ; + /* (TICKS . HZ) */ + if (!(INTEGERP (high) && (FIXNUMP (low) ? XFIXNUM (low) > 0 + : !NILP (Fnatnump (low))))) + time_spec_invalid (); + return (struct form_time) { .form = TIMEFORM_TICKS_HZ, + .time = decode_ticks_hz (high, low, + cform) }; } - - /* Require LOW to be an integer, as otherwise the computation - would be considerably trickier. */ - if (! INTEGERP (low)) - form = TIMEFORM_INVALID; } else if (FASTER_TIMEFNS && INTEGERP (specified_time)) return (struct form_time) commit d77f8a347500da4c1ce7553332a481c5507412fc Author: F. Jason Park Date: Fri Jul 12 14:41:54 2024 -0700 Fix invalid defcustom type for erc-buffers option * lisp/erc/erc.el (erc-ensure-target-buffer-on-privmsg): Change invalid inner `choice' to a `const' for the third-state `status' variant, which is new in ERC 5.6 and Emacs 30. Thanks to Mattias Engdegård for catching this. diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 7cc7bf56252..fd2a49c2504 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -6033,8 +6033,7 @@ manner implied above, which was lost sometime before ERC 5.4." :group 'erc-buffers :group 'erc-query :type '(choice boolean - (choice :tag "Create pseudo queries for STATUSMSGs" - status))) + (const :tag "Create pseudo queries for STATUSMSGs" status))) (defcustom erc-format-query-as-channel-p t "If non-nil, format text from others in a query buffer like in a channel. commit 900f135b68b4e9830eac5d7500b3175f160f6c34 Author: Juri Linkov Date: Fri Jul 12 20:54:53 2024 +0300 * lisp/gnus/mm-uu.el (mm-uu-type-alist): Fix end-regexp of git-format-patch. Replace git-format-patch end-regexp "^-- " with "^$". The regexp "^-- " was intended to mark the end of the git-formatted patch. However, git-format-patch can produce patches without a signature. Also often patches are just copy-pasted from the output of 'C-x v d'. Therefore, now an empty line marks the end of the patch since properly formatted patches don't contain an empty line and properly configured MUAs don't strip whitespace from patches. Suggested by Luis Henriques and Kévin Le Gouguec in bug#72059. diff --git a/lisp/gnus/mm-uu.el b/lisp/gnus/mm-uu.el index 3c7e3cbdf1a..26b2c03a3dc 100644 --- a/lisp/gnus/mm-uu.el +++ b/lisp/gnus/mm-uu.el @@ -173,7 +173,7 @@ This can be either \"inline\" or \"attachment\".") ,#'mm-uu-diff-test) (git-format-patch "^diff --git " - "^-- " + "^$" ,#'mm-uu-diff-extract nil ,#'mm-uu-diff-test) commit d68a4ea3ec69da0755d0a8ba70afe4b4ce379687 Author: Eshel Yaron Date: Sat Jul 6 20:53:06 2024 +0200 ; Fix 'ibuffer-do-isearch{-regexp}' * lisp/ibuf-ext.el (ibuffer-do-isearch) (ibuffer-do-isearch-regexp): Use 'defun' instead of 'define-ibuffer-op'. (Bug#71927) diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el index 95ff014aa5b..33b68b96ff2 100644 --- a/lisp/ibuf-ext.el +++ b/lisp/ibuf-ext.el @@ -594,22 +594,16 @@ To evaluate a form without viewing the buffer, see `ibuffer-do-eval'." :modifier-p :maybe) (revert-buffer t t)) -;;;###autoload (autoload 'ibuffer-do-isearch "ibuf-ext") -(define-ibuffer-op ibuffer-do-isearch () +;;;###autoload +(defun ibuffer-do-isearch () "Perform a `isearch-forward' in marked buffers." - (:interactive () - :opstring "searched in" - :complex t - :modifier-p :maybe) + (interactive "" ibuffer-mode) (multi-isearch-buffers (ibuffer-get-marked-buffers))) -;;;###autoload (autoload 'ibuffer-do-isearch-regexp "ibuf-ext") -(define-ibuffer-op ibuffer-do-isearch-regexp () +;;;###autoload +(defun ibuffer-do-isearch-regexp () "Perform a `isearch-forward-regexp' in marked buffers." - (:interactive () - :opstring "searched regexp in" - :complex t - :modifier-p :maybe) + (interactive "" ibuffer-mode) (multi-isearch-buffers-regexp (ibuffer-get-marked-buffers))) ;;;###autoload (autoload 'ibuffer-do-replace-regexp "ibuf-ext") commit 8b1a0f8695a43e74daa5275559267e96c14aba03 Author: Eli Zaretskii Date: Fri Jul 12 09:58:53 2024 +0300 Fix infloop in 'shell-resync-dirs' * lisp/shell.el (shell-eval-command): Fix detection of newline after last output line. (Bug#71896) (shell-resync-dirs): Make sure the inner loop never infloops. Suggested by Troy Hinckley . diff --git a/lisp/shell.el b/lisp/shell.el index e1936ff1119..4d92fe71df4 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -1255,7 +1255,7 @@ line output and parses it to form the new directory stack." (while dlsl (let ((newelt "") tem1 tem2) - (while newelt + (while (and dlsl newelt) ;; We need tem1 because we don't want to prepend ;; `comint-file-name-prefix' repeatedly into newelt via tem2. (setq tem1 (pop dlsl) @@ -1629,10 +1629,14 @@ Returns t if successful." ;; a newline). This is far from fool-proof -- if something ;; outputs incomplete data and then sleeps, we'll think ;; we've received the prompt. - (while (not (let* ((lines (string-lines result)) - (last (car (last lines)))) + (while (not (let* ((lines (string-lines result nil t)) + (last (car (last lines))) + (last-end (if (equal last "") + last + (substring last -1)))) (and (length> lines 0) - (not (equal last "")) + (not (member last '("" "\n"))) + (not (equal last-end "\n")) (or (not prev) (not (equal last prev))) (setq prev last)))) commit ce13eee5ab73e73ffd5d8e67a1dd21fc667ab7e1 Author: Eli Zaretskii Date: Fri Jul 12 09:39:39 2024 +0300 ; * src/image.c (free_image_cache): Add assertion. (Bug#71929) diff --git a/src/image.c b/src/image.c index 2ee2f3245be..3d761bd48be 100644 --- a/src/image.c +++ b/src/image.c @@ -2306,6 +2306,9 @@ free_image_cache (struct frame *f) struct image_cache *c = FRAME_IMAGE_CACHE (f); ptrdiff_t i; + /* This function assumes the caller already verified that the frame's + image cache is non-NULL. */ + eassert (c); /* Cache should not be referenced by any frame when freed. */ eassert (c->refcount == 0); commit e64a34e62be7185779904517cbdb73bf9408f414 Merge: 38fa3e93501 b22ab99f0a8 Author: Po Lu Date: Fri Jul 12 14:32:49 2024 +0800 Merge from savannah/emacs-30 b22ab99f0a8 Render more Android functions safe to execute in a batch ... commit b22ab99f0a85f73a1aec582f7aba0e6b5101b953 Author: Po Lu Date: Fri Jul 12 14:31:33 2024 +0800 Render more Android functions safe to execute in a batch session * src/androidfns.c (Fx_display_mm_width, Fx_display_mm_height) (Fandroid_display_monitor_attributes_list) (Fandroid_external_storage_available_p) (Fandroid_request_storage_access): Verify that a display connection or service object is available. * src/androidselect.c (Fandroid_get_clipboard) (Fandroid_browse_url_internal, Fandroid_get_clipboard_targets) (Fandroid_get_clipboard_data, Fandroid_notifications_notify): Moderate tone of error messages. diff --git a/src/androidfns.c b/src/androidfns.c index 7595e176618..af2247ad962 100644 --- a/src/androidfns.c +++ b/src/androidfns.c @@ -1374,6 +1374,7 @@ DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, error ("Android cross-compilation stub called!"); return Qnil; #else + check_android_display_info (terminal); return make_fixnum (android_get_mm_width ()); #endif } @@ -1386,6 +1387,7 @@ DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, error ("Android cross-compilation stub called!"); return Qnil; #else + check_android_display_info (terminal); return make_fixnum (android_get_mm_height ()); #endif } @@ -1469,6 +1471,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) #else struct MonitorInfo monitor; + check_android_display_info (terminal); memset (&monitor, 0, sizeof monitor); monitor.geom.width = android_get_screen_width (); monitor.geom.height = android_get_screen_height (); @@ -3270,6 +3273,11 @@ External storage on Android encompasses the `/sdcard' and absent these permissions. */) (void) { + /* Implement a rather undependable fallback when no GUI is + available. */ + if (!android_init_gui) + return Ffile_accessible_directory_p (build_string ("/sdcard")); + return android_external_storage_available_p () ? Qt : Qnil; } @@ -3284,6 +3292,9 @@ Use `android-external-storage-available-p' (which see) to verify whether Emacs has actually received such access permissions. */) (void) { + if (!android_init_gui) + return Qnil; + android_request_storage_access (); return Qnil; } diff --git a/src/androidselect.c b/src/androidselect.c index d5783b75417..cbd163c6c9f 100644 --- a/src/androidselect.c +++ b/src/androidselect.c @@ -189,7 +189,7 @@ Alternatively, return nil if the clipboard is empty. */) const char *data; if (!android_init_gui) - error ("No Android display connection!"); + error ("No Android display connection"); method = clipboard_class.get_clipboard; text @@ -258,7 +258,7 @@ for. Use `android-browse-url' instead. */) Lisp_Object value; if (!android_init_gui) - error ("No Android display connection!"); + error ("No Android display connection"); CHECK_STRING (url); value = android_browse_url (url, send); @@ -290,7 +290,7 @@ data type available from the clipboard. */) Lisp_Object targets, tem; if (!android_init_gui) - error ("No Android display connection!"); + error ("No Android display connection"); targets = Qnil; block_input (); @@ -544,7 +544,7 @@ does not have any corresponding data. In that case, use char *buffer, *start; if (!android_init_gui) - error ("No Android display connection!"); + error ("No Android display connection"); CHECK_STRING (type); @@ -1003,7 +1003,7 @@ usage: (android-notifications-notify &rest ARGS) */) AUTO_STRING (default_icon, "ic_dialog_alert"); if (!android_init_gui) - error ("No Android display connection!"); + error ("No Android display connection"); /* Clear each variable above. */ title = body = replaces_id = group = icon = urgency = actions = Qnil; commit 38fa3e9350134fb69655e1e9b8e6d95a2dbcf3db Merge: dc8cde2b6f3 a5ef9e25680 Author: Po Lu Date: Fri Jul 12 12:15:50 2024 +0800 Merge from savannah/emacs-30 a5ef9e25680 Document means of executing Emacs from unrelated Android ... 0de0056fd6b Don't emit a prompt in Eshell when a background command i... ec1e300a215 Fix reference from buffer-stale-function docstring commit a5ef9e25680d490e2a453e5ed518aba8f4560b2d Author: Po Lu Date: Fri Jul 12 11:59:09 2024 +0800 Document means of executing Emacs from unrelated Android applications * doc/emacs/android.texi (Android Environment): Document significance, effect and purpose of EMACS_CLASS_PATH and EMACS_LD_LIBRARY_PATH, and the utility of `pm path org.gnu.emacs'. diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 606c5e719cb..2d95f5c8fef 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -364,17 +364,58 @@ consult the values of the variables @code{ctags-program-name}, @code{ebrowse-program-name}, and @code{rcs2log-program-name}. @xref{Subprocess Creation,,, elisp, the Emacs Lisp Reference Manual}. - The @file{/assets} directory containing Emacs start-up files is -meant to be inaccessible to processes not directly created by -@code{zygote}, the system service responsible for starting -applications. Since required Lisp is found in the @file{/assets} -directory, it would thus follow that it is not possible for Emacs to -start itself as a subprocess. A special binary named -@command{libandroid-emacs.so} is provided with Emacs, which tries its -best to start Emacs for the purpose of running Lisp in batch mode. -However, the approach it takes was devised by reading Android source -code, and is not sanctioned by the Android compatibility definition -documents, so your mileage may vary. + The @file{/assets} directory containing Emacs start-up files is meant +to be inaccessible to processes not directly created by @code{zygote}, +the system service responsible for starting applications. Since +required Lisp is found in the @file{/assets} directory, it would thus +follow that it is not possible for Emacs to start itself as a +subprocess. A special binary named @command{libandroid-emacs.so} is +provided with Emacs, which is installed into the library directory, and +which tries its best to start Emacs for the purpose of running Lisp in +batch mode. The approach it takes was devised by reference to Android +source code, and is not sanctioned by the Android compatibility +definition documents, so your mileage may vary. + +@cindex EMACS_CLASS_PATH environment variable, Android + Even when the location of the @command{libandroid-emacs.so} command is +known in advance, special configuration is required to run Emacs from +elsewhere than a subprocess of an existing Emacs session, as it must be +made to understand the location of resources and shared libraries in or +extracted from the installed application package. The OS command +@command{pm path org.gnu.emacs} will print the location of the +application package, and the adjacent @file{lib} directory will hold +shared libraries extracted from the same, though the said command must +be invoked in a peculiar manner to satisfy system restrictions on +communication between pseudoterminal devices created by user +applications and system services such as the package manager, which is +to say, with the standard IO streams redirected to a real file or a +pipe. Such values, once established, must be specified in the +environment variables @code{EMACS_CLASS_PATH} and +@code{EMACS_LD_LIBRARY_PATH}, so that this sample shell script may be +installed as @code{emacs} in any location that is accessible: + +@example +#!/system/bin/sh + +package_name=`pm path org.gnu.emacs 2>/dev/null Date: Tue Jul 9 10:45:35 2024 -0700 Don't emit a prompt in Eshell when a background command is killed * lisp/eshell/esh-cmd.el (eshell-resume-command): Check for background-ness before resetting the prompt. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/background/simple-command): Make the regexp a bit stricter. (esh-cmd-test/background/kill): New test. diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 0b3137127d2..e97e4f6d067 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -1030,6 +1030,9 @@ process(es) in a cons cell like: PROC is the process that invoked this from its sentinel, and STATUS is its status." (when proc + ;; Iterate over all the commands associated with this process. Each + ;; element is a list of the form (BACKGROUND FORM PROCESSES) (see + ;; `eshell-add-command'). (dolist (command (eshell-commands-for-process proc)) (unless (seq-some #'eshell-process-active-p (nth 2 command)) (setf (nth 2 command) nil) ; Clear processes from command. @@ -1040,8 +1043,12 @@ STATUS is its status." (not (string-match eshell-reset-signals status))) (eshell-resume-eval command) (eshell-remove-command command) - (declare-function eshell-reset "esh-mode" (&optional no-hooks)) - (eshell-reset)))))) + ;; Check if the command we just aborted is marked as a + ;; background command. If not, we need to reset the prompt so + ;; the user can enter another command. + (unless (car command) + (declare-function eshell-reset "esh-mode" (&optional no-hooks)) + (eshell-reset))))))) (defun eshell-resume-eval (command) "Destructively evaluate a COMMAND which may need to be deferred. diff --git a/test/lisp/eshell/esh-cmd-tests.el b/test/lisp/eshell/esh-cmd-tests.el index 70e1901c169..d8124a19af6 100644 --- a/test/lisp/eshell/esh-cmd-tests.el +++ b/test/lisp/eshell/esh-cmd-tests.el @@ -113,7 +113,7 @@ bug#59469." (with-temp-eshell (eshell-match-command-output (format "*echo hi > #<%s> &" bufname) - (rx "[echo" (? ".exe") "] " (+ digit) "\n")) + (rx bos "[echo" (? ".exe") "] " (+ digit) "\n")) (eshell-wait-for-subprocess t)) (should (equal (buffer-string) "hi\n")))) @@ -129,6 +129,18 @@ bug#59469." (eshell-wait-for-subprocess t)) (should (equal (buffer-string) "olleh\n")))) +(ert-deftest esh-cmd-test/background/kill () + "Make sure that a background command that gets killed doesn't emit a prompt." + (skip-unless (executable-find "sleep")) + (let ((background-message (rx bos "[sleep" (? ".exe") "] " (+ digit) "\n"))) + (with-temp-eshell + (eshell-match-command-output "*sleep 10 &" background-message) + (kill-process (caar eshell-process-list)) + (eshell-wait-for-subprocess t) + ;; Ensure we didn't emit another prompt after killing the + ;; background process. + (should (eshell-match-output background-message))))) + ;; Lisp forms commit dc8cde2b6f3e7c55a85439c771284df2b4fa0e37 Author: Andrea Corallo Date: Wed Jul 10 23:50:18 2024 +0200 Add a type-check--optim test * test/src/comp-tests.el (comp-tests-type-branch-optim-checker): New function. (comp-tests-type-branch-optim): Add new test. diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el index bab5a358290..dfeeaff05d8 100644 --- a/test/src/comp-tests.el +++ b/test/src/comp-tests.el @@ -1570,4 +1570,28 @@ folded." (comp-deftest comp-tests-result-lambda () (native-compile 'comp-tests-result-lambda) (should (eq (funcall (comp-tests-result-lambda) '(a . b)) 'a))) + +(defun comp-tests-type-branch-optim-checker (_) + "Check there's only a single call to `type-of'." + (should (= (cl-count t (comp-tests-map-checker + #'comp-tests-type-branch-optim-1-f + (lambda (insn) + (pcase insn + (`(set ,_mvar-1 (call type-of ,_mvar-2)) + t))))) + 1))) + +(declare-function comp-tests-type-branch-optim-1-f nil) + +(comp-deftest comp-tests-type-branch-optim () + (let ((native-comp-speed 2) + (comp-post-pass-hooks '((comp--final comp-tests-type-branch-optim-checker)))) + (eval '(progn + (cl-defstruct type-branch-optim-struct a b c) + (defun comp-tests-type-branch-optim-1-f (x) + (setf (type-branch-optim-struct-a x) 3) + (+ (type-branch-optim-struct-b x) (type-branch-optim-struct-c x)))) + t) + (native-compile #'comp-tests-type-branch-optim-1-f))) + ;;; comp-tests.el ends here commit ffaf1cb235c8b399cd9fb704f9b5879db2f5d6a6 Author: Andrea Corallo Date: Wed Jul 10 23:48:19 2024 +0200 Some clean-up in comp-tests.el * test/src/comp-tests.el (comp-tests-cond-rw-checked-function) (comp-tests-cond-rw-checker-val) (comp-tests-cond-rw-expected-type) (comp-tests-cond-rw-checker-type): Remove. diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el index 33b127d5d26..bab5a358290 100644 --- a/test/src/comp-tests.el +++ b/test/src/comp-tests.el @@ -1567,36 +1567,6 @@ folded." (should (native-comp-function-p (symbol-function 'comp-tests-pure-fibn-entry-f))) (should (= (comp-tests-pure-fibn-entry-f) 6765)))) -(defvar comp-tests-cond-rw-checked-function nil - "Function to be checked.") -(defun comp-tests-cond-rw-checker-val (_) - "Check we manage to propagate the correct return value." - (should - (cl-some - #'identity - (comp-tests-map-checker - comp-tests-cond-rw-checked-function - (lambda (insn) - (pcase insn - (`(return ,mvar) - (and (comp-cstr-imm-vld-p mvar) - (eql (comp-cstr-imm mvar) 123))))))))) - -(defvar comp-tests-cond-rw-expected-type nil - "Type to expect in `comp-tests-cond-rw-checker-type'.") -(defun comp-tests-cond-rw-checker-type (_) - "Check we manage to propagate the correct return type." - (should - (cl-some - #'identity - (comp-tests-map-checker - comp-tests-cond-rw-checked-function - (lambda (insn) - (pcase insn - (`(return ,mvar) - (equal (comp-mvar-typeset mvar) - comp-tests-cond-rw-expected-type)))))))) - (comp-deftest comp-tests-result-lambda () (native-compile 'comp-tests-result-lambda) (should (eq (funcall (comp-tests-result-lambda) '(a . b)) 'a))) commit baf74968f9704b6354fff7a254172f72f0ebb747 Author: Andrea Corallo Date: Fri May 31 10:24:11 2024 +0200 Fix 'comp--type-check-optim-block' it using 'comp-cstr-type-p' * lisp/emacs-lisp/comp.el (comp--type-check-optim-block): Better condition. diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index f5b35ec07b5..9447f68c362 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -2849,10 +2849,7 @@ Return t if something was changed." (call memq ,(and (pred comp-mvar-p) mvar-1) ,(and (pred comp-mvar-p) mvar-2))) (cond-jump ,(and (pred comp-mvar-p) mvar-3) ,(pred comp-mvar-p) ,_bb1 ,bb2)) (cl-assert (comp-cstr-imm-vld-p mvar-tag)) - (when (and (length= (comp-mvar-typeset mvar-tested) 1) - (member - (car (comp-mvar-typeset mvar-tested)) - (symbol-value (comp-cstr-imm mvar-tag)))) + (when (comp-cstr-type-p mvar-tested (comp-cstr-cl-tag mvar-tag)) (comp-log (format "Optimizing conditional branch in function: %s" (comp-func-name comp-func)) 3) commit 0d6f3f134e4e9e41df86e015ea5cfc0a990b62e5 Author: Andrea Corallo Date: Fri May 31 10:08:18 2024 +0200 Generalize 'comp-cstr-symbol-p' * lisp/emacs-lisp/comp-cstr.el (comp-cstr-symbol-p): Make use of 'comp-cstr-type-p'. diff --git a/lisp/emacs-lisp/comp-cstr.el b/lisp/emacs-lisp/comp-cstr.el index 058fc522858..66c44f16835 100644 --- a/lisp/emacs-lisp/comp-cstr.el +++ b/lisp/emacs-lisp/comp-cstr.el @@ -926,15 +926,6 @@ Non memoized version of `comp-cstr-intersection-no-mem'." (> high most-positive-fixnum)) t)))))) -(defun comp-cstr-symbol-p (cstr) - "Return t if CSTR is certainly a symbol." - (with-comp-cstr-accessors - (and (null (range cstr)) - (null (neg cstr)) - (and (or (null (typeset cstr)) - (equal (typeset cstr) '(symbol))) - (cl-every #'symbolp (valset cstr)))))) - (defsubst comp-cstr-cons-p (cstr) "Return t if CSTR is certainly a cons." (with-comp-cstr-accessors @@ -965,6 +956,10 @@ Non memoized version of `comp-cstr-intersection-no-mem'." (error "Unknown predicate for type %s" type))))) t)) +(defun comp-cstr-symbol-p (cstr) + "Return t if CSTR is certainly a symbol." + (comp-cstr-type-p cstr 'symbol)) + ;; Move to comp.el? (defsubst comp-cstr-cl-tag-p (cstr) "Return non-nil if CSTR is a CL tag." commit a1775552cef5a8bc0ba13e802ecf343423a53364 Author: Andrea Corallo Date: Tue May 23 11:18:07 2023 +0200 Add 'comp-type-check-optim' pass * lisp/emacs-lisp/comp.el (comp-passes): Add 'comp--type-check-optim'. (comp--type-check-optim-block, comp--type-check-optim): New functions. diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index 06261e30402..f5b35ec07b5 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -164,6 +164,7 @@ Can be one of: `d-default', `d-impure' or `d-ephemeral'. See `comp-ctxt'.") comp--ipa-pure comp--add-cstrs comp--fwprop + comp--type-check-optim comp--tco comp--fwprop comp--remove-type-hints @@ -2812,6 +2813,71 @@ Return t if something was changed." (comp--log-func comp-func 3)))) (comp-ctxt-funcs-h comp-ctxt))) + +;;; Type check optimizer pass specific code. + +;; This pass optimize-out unnecessary type checks, that is calls to +;; `type-of' and corresponding conditional branches. +;; +;; This is often advantageous in cases where a function manipulates an +;; object with several slot accesses like: +;; +;; (cl-defstruct foo a b c) +;; (defun bar (x) +;; (setf (foo-a x) 3) +;; (+ (foo-b x) (foo-c x))) +;; +;; After x is accessed and type checked once, it's proved to be of type +;; foo, and no other type checks are required. + +;; At present running this pass over the whole Emacs codebase triggers +;; the optimization of 1972 type checks. + +(defun comp--type-check-optim-block (block) + "Optimize conditional branches in BLOCK when possible." + (cl-loop + named in-the-basic-block + for insns-seq on (comp-block-insns block) + do (pcase insns-seq + (`((set ,(and (pred comp-mvar-p) mvar-tested-copy) + ,(and (pred comp-mvar-p) mvar-tested)) + (set ,(and (pred comp-mvar-p) mvar-1) + (call type-of ,(and (pred comp-mvar-p) mvar-tested-copy))) + (set ,(and (pred comp-mvar-p) mvar-2) + (call symbol-value ,(and (pred comp-cstr-cl-tag-p) mvar-tag))) + (set ,(and (pred comp-mvar-p) mvar-3) + (call memq ,(and (pred comp-mvar-p) mvar-1) ,(and (pred comp-mvar-p) mvar-2))) + (cond-jump ,(and (pred comp-mvar-p) mvar-3) ,(pred comp-mvar-p) ,_bb1 ,bb2)) + (cl-assert (comp-cstr-imm-vld-p mvar-tag)) + (when (and (length= (comp-mvar-typeset mvar-tested) 1) + (member + (car (comp-mvar-typeset mvar-tested)) + (symbol-value (comp-cstr-imm mvar-tag)))) + (comp-log (format "Optimizing conditional branch in function: %s" + (comp-func-name comp-func)) + 3) + (setf (car insns-seq) '(comment "optimized by comp--type-check-optim") + (cdr insns-seq) `((jump ,bb2)) + ;; Set the SSA status as dirty so + ;; `comp--ssa-function' will remove the unreachable + ;; branches later. + (comp-func-ssa-status comp-func) 'dirty)))))) + +(defun comp--type-check-optim (_) + "Optimize conditional branches when possible." + (cl-loop + for f being each hash-value of (comp-ctxt-funcs-h comp-ctxt) + for comp-func = f + when (>= (comp-func-speed f) 2) + do (cl-loop + for b being each hash-value of (comp-func-blocks f) + do (comp--type-check-optim-block b) + finally + (progn + (when (eq (comp-func-ssa-status f) 'dirty) + (comp--ssa-function f)) + (comp--log-func comp-func 3))))) + ;;; Call optimizer pass specific code. ;; This pass is responsible for the following optimizations: commit 8538a281f53107b69ed4a4b0d21f237cd79de400 Author: Andrea Corallo Date: Sun Apr 7 14:35:53 2024 +0200 Split 'comp--ssa' code * lisp/emacs-lisp/comp.el (comp--ssa-function): New function. (comp--ssa): Update. diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index 0a2c520c5d5..06261e30402 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -2548,26 +2548,29 @@ Return t when one or more block was removed, nil otherwise." ret t) finally return ret)) +(defun comp--ssa-function (function) + "Port into minimal SSA FUNCTION." + (let* ((comp-func function) + (ssa-status (comp-func-ssa-status function))) + (unless (eq ssa-status t) + (cl-loop + when (eq ssa-status 'dirty) + do (comp--clean-ssa function) + do (comp--compute-edges) + (comp--compute-dominator-tree) + until (null (comp--remove-unreachable-blocks))) + (comp--compute-dominator-frontiers) + (comp--log-block-info) + (comp--place-phis) + (comp--ssa-rename) + (comp--finalize-phis) + (comp--log-func comp-func 3) + (setf (comp-func-ssa-status function) t)))) + (defun comp--ssa () - "Port all functions into minimal SSA form." - (maphash (lambda (_ f) - (let* ((comp-func f) - (ssa-status (comp-func-ssa-status f))) - (unless (eq ssa-status t) - (cl-loop - when (eq ssa-status 'dirty) - do (comp--clean-ssa f) - do (comp--compute-edges) - (comp--compute-dominator-tree) - until (null (comp--remove-unreachable-blocks))) - (comp--compute-dominator-frontiers) - (comp--log-block-info) - (comp--place-phis) - (comp--ssa-rename) - (comp--finalize-phis) - (comp--log-func comp-func 3) - (setf (comp-func-ssa-status f) t)))) - (comp-ctxt-funcs-h comp-ctxt))) + "Port all functions into minimal SSA all functions." + (cl-loop for f being the hash-value in (comp-ctxt-funcs-h comp-ctxt) + do (comp--ssa-function f))) ;;; propagate pass specific code. commit c3e6923b0043711a688a677edb52b31fa1640f0e Author: Paul Eggert Date: Thu Jul 11 15:40:47 2024 +0200 Rename timefns static function lisp_time_struct * src/timefns.c (lisp_time_cform): Rename from lisp_time_struct, since it no longer returns a struct, and now accepts CFORM. All uses changed. diff --git a/src/timefns.c b/src/timefns.c index 8c30016360d..1e551009df8 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -1125,24 +1125,24 @@ list4_to_timespec (Lisp_Object high, Lisp_Object low, return err_time.err ? invalid_timespec () : err_time.time.ts; } -/* Decode a Lisp list SPECIFIED_TIME that represents a time. +/* Decode a Lisp time value SPECIFIED_TIME that represents a time. If SPECIFIED_TIME is nil, use the current time. Decode to CFORM form. Signal an error if SPECIFIED_TIME does not represent a time. */ static union c_time -lisp_time_struct (Lisp_Object specified_time, enum cform cform) +lisp_time_cform (Lisp_Object specified_time, enum cform cform) { return decode_lisp_time (specified_time, cform).time; } -/* Decode a Lisp list SPECIFIED_TIME that represents a time. +/* Decode a Lisp time value SPECIFIED_TIME that represents a time. Discard any low-order (sub-ns) resolution. If SPECIFIED_TIME is nil, use the current time. Signal an error if SPECIFIED_TIME does not represent a timespec. */ struct timespec lisp_time_argument (Lisp_Object specified_time) { - struct timespec t = lisp_time_struct (specified_time, CFORM_TIMESPEC).ts; + struct timespec t = lisp_time_cform (specified_time, CFORM_TIMESPEC).ts; if (! timespec_valid_p (t)) time_overflow (); return t; @@ -1346,8 +1346,8 @@ time_cmp (Lisp_Object a, Lisp_Object b) /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing ATICKS * BHZ to BTICKS * AHZ. */ - struct ticks_hz ta = lisp_time_struct (a, CFORM_TICKS_HZ).th; - struct ticks_hz tb = lisp_time_struct (b, CFORM_TICKS_HZ).th; + struct ticks_hz ta = lisp_time_cform (a, CFORM_TICKS_HZ).th; + struct ticks_hz tb = lisp_time_cform (b, CFORM_TICKS_HZ).th; mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); if (! (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz))) @@ -1630,7 +1630,7 @@ usage: (decode-time &optional TIME ZONE FORM) */) struct ticks_hz th; if (EQ (form, Qt)) { - th = lisp_time_struct (specified_time, CFORM_TICKS_HZ).th; + th = lisp_time_cform (specified_time, CFORM_TICKS_HZ).th; struct timespec ts = ticks_hz_to_timespec (th.ticks, th.hz); if (! timespec_valid_p (ts)) time_overflow (); commit e30706fd12bce459b56123ad36a4e8c1c9d374e1 Author: Paul Eggert Date: Thu Jul 11 15:28:58 2024 +0200 Avoid mpz for some common timestamp cases Performance problem reported by Gerd Möllmann and Mattias Engdegård in: https://lists.gnu.org/r/emacs-devel/2024-06/msg00530.html https://lists.gnu.org/r/emacs-devel/2024-06/msg00539.html * src/timefns.c (CFORM_SECS_ONLY): The exact tv_nsec value is now ignored if nonnegative (i.e., the only thing that matters is that it’s nonnegative). (decode_time_components): Use intmax_t instead of mpz arithmetic if the tick count fits. Add another ‘default: eassume (false);’ so that the revised code pacifies --enable-gcc-warnings with GCC 11.4.0 on x86-64. diff --git a/src/timefns.c b/src/timefns.c index ad39d1307cd..8c30016360d 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -570,7 +570,8 @@ enum cform { CFORM_TICKS_HZ, /* struct ticks_hz */ CFORM_TIMESPEC, /* struct timespec */ - CFORM_SECS_ONLY, /* struct timespec but tv_nsec == 0 if timespec valid */ + CFORM_SECS_ONLY, /* struct timespec but tv_nsec irrelevant + if timespec valid */ CFORM_DOUBLE /* double */ }; @@ -894,11 +895,22 @@ decode_time_components (enum timeform form, } break; - default: - if (! (INTEGERP (high) && INTEGERP (low) - && FIXNUMP (usec) && FIXNUMP (psec))) - return (struct err_time) { .err = EINVAL }; + case TIMEFORM_HI_LO: + hz = make_fixnum (1); + goto check_high_low; + + case TIMEFORM_HI_LO_US: + hz = make_fixnum (1000000); + goto check_high_low_usec; + case TIMEFORM_HI_LO_US_PS: + hz = trillion; + if (!FIXNUMP (psec)) + return (struct err_time) { .err = EINVAL }; + check_high_low_usec: + if (!FIXNUMP (usec)) + return (struct err_time) { .err = EINVAL }; + check_high_low: { EMACS_INT us = XFIXNUM (usec); EMACS_INT ps = XFIXNUM (psec); @@ -906,25 +918,73 @@ decode_time_components (enum timeform form, /* Normalize out-of-range lower-order components by carrying each overflow into the next higher-order component. */ us += ps / 1000000 - (ps % 1000000 < 0); + EMACS_INT s_from_us_ps = us / 1000000 - (us % 1000000 < 0); + ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); + us = us % 1000000 + 1000000 * (us % 1000000 < 0); + + if (FASTER_TIMEFNS && FIXNUMP (high) && FIXNUMP (low)) + { + /* Use intmax_t arithmetic if the tick count fits. */ + intmax_t iticks; + bool v = false; + v |= ckd_mul (&iticks, XFIXNUM (high), 1 << LO_TIME_BITS); + v |= ckd_add (&iticks, iticks, XFIXNUM (low) + s_from_us_ps); + if (!v) + { + if (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY) + return (struct err_time) { + .time = { + .ts = s_ns_to_timespec (iticks, us * 1000 + ps / 1000) + } + }; + + switch (form) + { + case TIMEFORM_HI_LO: + break; + + case TIMEFORM_HI_LO_US: + v |= ckd_mul (&iticks, iticks, 1000000); + v |= ckd_add (&iticks, iticks, us); + break; + + case TIMEFORM_HI_LO_US_PS: + { + int_fast64_t million = 1000000; + v |= ckd_mul (&iticks, iticks, TRILLION); + v |= ckd_add (&iticks, iticks, us * million + ps); + } + break; + + default: + eassume (false); + } + + if (!v) + return (struct err_time) { + .time = decode_ticks_hz (make_int (iticks), hz, cform) + }; + } + } + + if (! (INTEGERP (high) && INTEGERP (low))) + return (struct err_time) { .err = EINVAL }; + mpz_t *s = &mpz[1]; - mpz_set_intmax (*s, us / 1000000 - (us % 1000000 < 0)); + mpz_set_intmax (*s, s_from_us_ps); mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); - ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); - us = us % 1000000 + 1000000 * (us % 1000000 < 0); switch (form) { case TIMEFORM_HI_LO: /* Floats and nil were handled above, so it was an integer. */ mpz_swap (mpz[0], *s); - hz = make_fixnum (1); break; case TIMEFORM_HI_LO_US: mpz_set_ui (mpz[0], us); mpz_addmul_ui (mpz[0], *s, 1000000); - hz = make_fixnum (1000000); break; case TIMEFORM_HI_LO_US_PS: @@ -938,7 +998,6 @@ decode_time_components (enum timeform form, mpz_set_intmax (mpz[0], i * 1000000 + ps); mpz_addmul (mpz[0], *s, ztrillion); #endif - hz = trillion; } break; @@ -948,6 +1007,9 @@ decode_time_components (enum timeform form, ticks = make_integer_mpz (); } break; + + default: + eassume (false); } return (struct err_time) { .time = decode_ticks_hz (ticks, hz, cform) }; commit e8b3c4cb58ce6e78b9bcfb9146f0ac6ece0d3055 Author: Paul Eggert Date: Thu Jul 11 15:03:50 2024 +0200 Decode current time directly to timespec * src/timefns.c (decode_time_components): If FASTER_TIMEFNS, when returning the current time and the desired form is struct timespec or time_t, return it directly rather than converting it to struct ticks_hz and then to struct timespec. This can avoid some mpz calculations and/or bignums. diff --git a/src/timefns.c b/src/timefns.c index 6949c83dbcb..ad39d1307cd 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -884,8 +884,14 @@ decode_time_components (enum timeform form, eassume (false); case TIMEFORM_NIL: - ticks = timespec_ticks (current_timespec ()); - hz = timespec_hz; + { + struct timespec now = current_timespec (); + if (FASTER_TIMEFNS + && (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY)) + return (struct err_time) { .time = { .ts = now } }; + ticks = timespec_ticks (now); + hz = timespec_hz; + } break; default: commit 75f53d7c2c1f6706d1d4c1f3eed3aa675464c62f Author: Paul Eggert Date: Thu Jul 11 12:57:01 2024 +0200 In timefns.c avoid by-hand overflow checking Prefer functions like ckd_add to do overflow checking, instead of doing it by hand, to simplify and I hope to make things a bit less error prone. * src/timefns.c (TIME_T_MIN, TIME_T_MAX): Remove. All by-hand overflow checking replaced with calls to ckd_add or ckd_mul. (s_ns_to_timespec): New static function, that uses ckd_add instead of by-hand overflow checking. (ticks_hz_to_timespec): Use it. (check_tm_member): Use mpz_fits_sint_p and mpz_get_si rather than mpz_to_intmax and by-hand overflow checking. diff --git a/src/timefns.c b/src/timefns.c index 45a0930f8a8..6949c83dbcb 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -60,13 +60,6 @@ enum { TM_YEAR_BASE = 1900 }; # define HAVE_TM_GMTOFF false #endif -#ifndef TIME_T_MIN -# define TIME_T_MIN TYPE_MINIMUM (time_t) -#endif -#ifndef TIME_T_MAX -# define TIME_T_MAX TYPE_MAXIMUM (time_t) -#endif - /* Compile with -DFASTER_TIMEFNS=0 to disable common optimizations and allow easier testing of some slow-path code. */ #ifndef FASTER_TIMEFNS @@ -127,10 +120,14 @@ make_timeval (struct timespec t) { if (tv.tv_usec < 999999) tv.tv_usec++; - else if (tv.tv_sec < TIME_T_MAX) + else { - tv.tv_sec++; - tv.tv_usec = 0; + time_t s1; + if (!ckd_add (&s1, tv.tv_sec, 1)) + { + tv.tv_sec = s1; + tv.tv_usec = 0; + } } } @@ -492,18 +489,23 @@ mpz_time (mpz_t const z, time_t *t) if (TYPE_SIGNED (time_t)) { intmax_t i; - if (! (mpz_to_intmax (z, &i) && TIME_T_MIN <= i && i <= TIME_T_MAX)) - return false; - *t = i; + return mpz_to_intmax (z, &i) && !ckd_add (t, i, 0); } else { uintmax_t i; - if (! (mpz_to_uintmax (z, &i) && i <= TIME_T_MAX)) - return false; - *t = i; + return mpz_to_uintmax (z, &i) && !ckd_add (t, i, 0); } - return true; +} + +/* Return a valid timespec (S, N) if S is in time_t range, + an invalid timespec otherwise. */ +static struct timespec +s_ns_to_timespec (intmax_t s, long int ns) +{ + time_t sec; + long int nsec = ckd_add (&sec, s, 0) ? -1 : ns; + return make_timespec (sec, nsec); } /* Components of a Lisp timestamp (TICKS . HZ). Using this C struct can @@ -522,7 +524,6 @@ struct ticks_hz static struct timespec ticks_hz_to_timespec (Lisp_Object ticks, Lisp_Object hz) { - struct timespec result = invalid_timespec (); int ns; mpz_t *q = &mpz[0]; mpz_t const *qt = q; @@ -539,33 +540,16 @@ ticks_hz_to_timespec (Lisp_Object ticks, Lisp_Object hz) ns = XFIXNUM (ticks) % TIMESPEC_HZ; if (ns < 0) s--, ns += TIMESPEC_HZ; - if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) - && s <= TIME_T_MAX) - { - result.tv_sec = s; - result.tv_nsec = ns; - } - return result; + return s_ns_to_timespec (s, ns); } - else - ns = mpz_fdiv_q_ui (*q, *xbignum_val (ticks), TIMESPEC_HZ); + ns = mpz_fdiv_q_ui (*q, *xbignum_val (ticks), TIMESPEC_HZ); } else if (FASTER_TIMEFNS && BASE_EQ (hz, make_fixnum (1))) { ns = 0; if (FIXNUMP (ticks)) - { - EMACS_INT s = XFIXNUM (ticks); - if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) - && s <= TIME_T_MAX) - { - result.tv_sec = s; - result.tv_nsec = ns; - } - return result; - } - else - qt = xbignum_val (ticks); + return s_ns_to_timespec (XFIXNUM (ticks), ns); + qt = xbignum_val (ticks); } else { @@ -577,12 +561,7 @@ ticks_hz_to_timespec (Lisp_Object ticks, Lisp_Object hz) /* Check that Q fits in time_t, not merely in RESULT.tv_sec. With some MinGW versions, tv_sec is a 64-bit type, whereas time_t is a 32-bit type. */ time_t sec; - if (mpz_time (*qt, &sec)) - { - result.tv_sec = sec; - result.tv_nsec = ns; - } - return result; + return mpz_time (*qt, &sec) ? make_timespec (sec, ns) : invalid_timespec (); } /* C timestamp forms. This enum is passed to conversion functions to @@ -700,7 +679,7 @@ ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) int us = mpz_get_ui (mpz[1]); #endif - /* mpz[0] = floor (mpz[0] / 1 << LO_TIME_BITS), with lo = remainder. */ + /* mpz[0] = floor (mpz[0] / (1 << LO_TIME_BITS)), with LO = remainder. */ unsigned long ulo = mpz_get_ui (mpz[0]); if (mpz_sgn (mpz[0]) < 0) ulo = -ulo; @@ -1686,10 +1665,9 @@ check_tm_member (Lisp_Object obj, int offset) { CHECK_INTEGER (obj); mpz_sub_ui (mpz[0], *bignum_integer (&mpz[0], obj), offset); - intmax_t i; - if (! (mpz_to_intmax (mpz[0], &i) && INT_MIN <= i && i <= INT_MAX)) + if (!mpz_fits_sint_p (mpz[0])) time_overflow (); - return i; + return mpz_get_si (mpz[0]); } } commit 0c850df888ebb68096a82ab32089e809de591620 Author: Paul Eggert Date: Thu Jul 11 12:42:57 2024 +0200 Optimize smallish mpz to native int conversion * src/bignum.c (make_integer_mpz, mpz_to_intmax): If FASTER_BIGNUM, optimize the common case where the value fits in long int. In this case we can use mpz_fits_slong_p and mpz_get_si instead of looping with mpz_getlimbn. (mpz_to_uintmax): Likewise for unsigned long int and mpz_get_ui. diff --git a/src/bignum.c b/src/bignum.c index 1fe195d78ea..7589691dd0c 100644 --- a/src/bignum.c +++ b/src/bignum.c @@ -145,9 +145,19 @@ make_neg_biguint (uintmax_t n) Lisp_Object make_integer_mpz (void) { + if (FASTER_BIGNUM && mpz_fits_slong_p (mpz[0])) + { + long int v = mpz_get_si (mpz[0]); + if (!FIXNUM_OVERFLOW_P (v)) + return make_fixnum (v); + } + size_t bits = mpz_sizeinbase (mpz[0], 2); - if (bits <= FIXNUM_BITS) + if (! (FASTER_BIGNUM + && FIXNUM_OVERFLOW_P (LONG_MIN) + && FIXNUM_OVERFLOW_P (LONG_MAX)) + && bits <= FIXNUM_BITS) { EMACS_INT v = 0; int i = 0, shift = 0; @@ -216,6 +226,17 @@ mpz_set_uintmax_slow (mpz_t result, uintmax_t v) bool mpz_to_intmax (mpz_t const z, intmax_t *pi) { + if (FASTER_BIGNUM) + { + if (mpz_fits_slong_p (z)) + { + *pi = mpz_get_si (z); + return true; + } + if (LONG_MIN <= INTMAX_MIN && INTMAX_MAX <= LONG_MAX) + return false; + } + ptrdiff_t bits = mpz_sizeinbase (z, 2); bool negative = mpz_sgn (z) < 0; @@ -246,6 +267,17 @@ mpz_to_intmax (mpz_t const z, intmax_t *pi) bool mpz_to_uintmax (mpz_t const z, uintmax_t *pi) { + if (FASTER_BIGNUM) + { + if (mpz_fits_ulong_p (z)) + { + *pi = mpz_get_ui (z); + return true; + } + if (UINTMAX_MAX <= ULONG_MAX) + return false; + } + if (mpz_sgn (z) < 0) return false; ptrdiff_t bits = mpz_sizeinbase (z, 2); commit 1c8e64a9536ed092af27279fa3f044cf031a4324 Author: Paul Eggert Date: Thu Jul 11 12:27:36 2024 +0200 New FASTER_BIGNUM macro to test slow-path code * src/bignum.h (FASTER_BIGNUM): New macro. (mpz_set_intmax, mpz_set_uintmax): Optimize only if FASTER_BIGNUM. Also, use ckd_add to test for overflow instead of doing it by hand. diff --git a/src/bignum.h b/src/bignum.h index 2749f8370d0..54ba0cde410 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -25,6 +25,12 @@ along with GNU Emacs. If not, see . */ #include #include "lisp.h" +/* Compile with -DFASTER_BIGNUM=0 to disable common optimizations and + allow easier testing of some slow-path code. */ +#ifndef FASTER_BIGNUM +# define FASTER_BIGNUM 1 +#endif + /* Number of data bits in a limb. */ #ifndef GMP_NUMB_BITS enum { GMP_NUMB_BITS = TYPE_WIDTH (mp_limb_t) }; @@ -68,16 +74,18 @@ mpz_set_intmax (mpz_t result, intmax_t v) /* mpz_set_si works in terms of long, but Emacs may use a wider integer type, and so sometimes will have to construct the mpz_t by hand. */ - if (LONG_MIN <= v && v <= LONG_MAX) - mpz_set_si (result, v); + long int i; + if (FASTER_BIGNUM && !ckd_add (&i, v, 0)) + mpz_set_si (result, i); else mpz_set_intmax_slow (result, v); } INLINE void ARG_NONNULL ((1)) mpz_set_uintmax (mpz_t result, uintmax_t v) { - if (v <= ULONG_MAX) - mpz_set_ui (result, v); + unsigned long int i; + if (FASTER_BIGNUM && !ckd_add (&i, v, 0)) + mpz_set_ui (result, i); else mpz_set_uintmax_slow (result, v); } commit 2fb7bb41bee5e39391c9abc8013bcef39782e88d Author: Paul Eggert Date: Wed Jul 10 11:04:18 2024 +0200 In timefns, call natnump only for non-fixnums * src/timefns.c (decode_time_components): Call Fnatnump only for non-fixnums, as we need to special-case 0 anyway. diff --git a/src/timefns.c b/src/timefns.c index ba1ba10a809..45a0930f8a8 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -895,7 +895,7 @@ decode_time_components (enum timeform form, case TIMEFORM_TICKS_HZ: if (! (INTEGERP (high) - && !NILP (Fnatnump (low)) && !BASE_EQ (low, make_fixnum (0)))) + && (FIXNUMP (low) ? 0 < XFIXNUM (low) : !NILP (Fnatnump (low))))) return (struct err_time) { .err = EINVAL }; ticks = high; hz = low; commit b6cbf0cbb66fa4c1a7f351350d5f9aed9c93cd26 Author: Paul Eggert Date: Wed Jul 10 10:36:35 2024 +0200 In timefns, do gcd reduction more often * src/timefns.c (ticks_hz_hz_ticks): Reduce by gcd even if t.ticks is not a fixnum, since that’s easy. diff --git a/src/timefns.c b/src/timefns.c index 0df7d1f4363..ba1ba10a809 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -774,8 +774,8 @@ ticks_hz_hz_ticks (struct ticks_hz t, Lisp_Object hz) if (XFIXNUM (hz) <= 0) invalid_hz (hz); - /* For speed, use intmax_t arithmetic if it will do. */ - if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz)) + /* Prefer non-bignum arithmetic to speed up common cases. */ + if (FASTER_TIMEFNS && FIXNUMP (t.hz)) { /* Reduce T.hz and HZ by their GCD, to avoid some intmax_t overflows that would occur in T.ticks * HZ. */ @@ -784,9 +784,12 @@ ticks_hz_hz_ticks (struct ticks_hz t, Lisp_Object hz) ithz /= d; ihz /= d; - intmax_t ticks; - if (!ckd_mul (&ticks, XFIXNUM (t.ticks), ihz)) - return make_int (ticks / ithz - (ticks % ithz < 0)); + if (FIXNUMP (t.ticks)) + { + intmax_t ticks; + if (!ckd_mul (&ticks, XFIXNUM (t.ticks), ihz)) + return make_int (ticks / ithz - (ticks % ithz < 0)); + } t.hz = make_fixnum (ithz); hz = make_fixnum (ihz); commit abafc6ca01444de7aad9856b4901aa82a68dff32 Author: Paul Eggert Date: Wed Jul 10 10:23:31 2024 +0200 In timefns, prefer ui mul and div * src/timefns.c (ticks_hz_hz_ticks): If the multiplier is a fixnum that fits in unsigned long, use mpz_mul_ui instead of the more-expensive mpz_mul. Similarly, if the divisor is a fixnum that fits in unsigned long, use mpz_fdiv_q_ui instead of mpz_fdiv_q. diff --git a/src/timefns.c b/src/timefns.c index 0a34bda28c7..0df7d1f4363 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -796,10 +796,15 @@ ticks_hz_hz_ticks (struct ticks_hz t, Lisp_Object hz) invalid_hz (hz); /* Fall back on bignum arithmetic. */ - mpz_mul (mpz[0], - *bignum_integer (&mpz[0], t.ticks), - *bignum_integer (&mpz[1], hz)); - mpz_fdiv_q (mpz[0], mpz[0], *bignum_integer (&mpz[1], t.hz)); + mpz_t const *zticks = bignum_integer (&mpz[0], t.ticks); + if (FASTER_TIMEFNS && FIXNUMP (hz) && XFIXNUM (hz) <= ULONG_MAX) + mpz_mul_ui (mpz[0], *zticks, XFIXNUM (hz)); + else + mpz_mul (mpz[0], *zticks, *bignum_integer (&mpz[1], hz)); + if (FASTER_TIMEFNS && FIXNUMP (t.hz) && XFIXNUM (t.hz) <= ULONG_MAX) + mpz_fdiv_q_ui (mpz[0], mpz[0], XFIXNUM (t.hz)); + else + mpz_fdiv_q (mpz[0], mpz[0], *bignum_integer (&mpz[1], t.hz)); return make_integer_mpz (); } commit 6ef052d9b23aef3f34d19e5d93d97884215d1465 Author: Paul Eggert Date: Wed Jul 10 02:37:55 2024 +0200 Reduce size of integer product in timefns * src/timefns.c (emacs_gcd): New static function. (ticks_hz_hz_ticks): Use it to reduce the size of the integer product in the common case when converting from ns to ps. For that, we need to multiply t.ticks only by 10³, not multiply by 10¹² and then divide by 10⁹. This avoids the need to use bignums in a significant number of cases. diff --git a/src/timefns.c b/src/timefns.c index 0c5f3bf3ff1..0a34bda28c7 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -748,6 +748,15 @@ timespec_ticks (struct timespec t) return make_integer_mpz (); } +/* Return greatest common divisor of positive A and B. */ +static EMACS_INT +emacs_gcd (EMACS_INT a, EMACS_INT b) +{ + for (EMACS_INT r; (r = a % b) != 0; a = b, b = r) + continue; + return b; +} + /* Convert T to a Lisp integer counting HZ ticks, taking the floor. Assume T is valid, but check HZ. */ static Lisp_Object @@ -766,11 +775,22 @@ ticks_hz_hz_ticks (struct ticks_hz t, Lisp_Object hz) invalid_hz (hz); /* For speed, use intmax_t arithmetic if it will do. */ - intmax_t ticks; - if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz) - && !ckd_mul (&ticks, XFIXNUM (t.ticks), XFIXNUM (hz))) - return make_int (ticks / XFIXNUM (t.hz) - - (ticks % XFIXNUM (t.hz) < 0)); + if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz)) + { + /* Reduce T.hz and HZ by their GCD, to avoid some intmax_t + overflows that would occur in T.ticks * HZ. */ + EMACS_INT ithz = XFIXNUM (t.hz), ihz = XFIXNUM (hz); + EMACS_INT d = emacs_gcd (ithz, ihz); + ithz /= d; + ihz /= d; + + intmax_t ticks; + if (!ckd_mul (&ticks, XFIXNUM (t.ticks), ihz)) + return make_int (ticks / ithz - (ticks % ithz < 0)); + + t.hz = make_fixnum (ithz); + hz = make_fixnum (ihz); + } } else if (! (BIGNUMP (hz) && 0 < mpz_sgn (*xbignum_val (hz)))) invalid_hz (hz); commit 5e8a38ecb2a78c0e318892683dc0195084197c57 Author: Paul Eggert Date: Mon Jul 8 09:26:14 2024 +0200 Rename timefns internals The old names didn’t fit in the conventions used for newer names. * src/timefns.c (struct ticks_hz): Rename from struct lisp_time. (union c_time): Rename lt to th. (ticks_hz_hz_ticks): Rename from lisp_time_hz_ticks. (ticks_hz_seconds): Rename from lisp_time_seconds. All uses changed. diff --git a/src/timefns.c b/src/timefns.c index ded31997620..0c5f3bf3ff1 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -508,7 +508,7 @@ mpz_time (mpz_t const z, time_t *t) /* Components of a Lisp timestamp (TICKS . HZ). Using this C struct can avoid the consing overhead of creating (TICKS . HZ). */ -struct lisp_time +struct ticks_hz { /* Clock count as a Lisp integer. */ Lisp_Object ticks; @@ -589,7 +589,7 @@ ticks_hz_to_timespec (Lisp_Object ticks, Lisp_Object hz) specify the desired C timestamp form. */ enum cform { - CFORM_TICKS_HZ, /* struct lisp_time */ + CFORM_TICKS_HZ, /* struct ticks_hz */ CFORM_TIMESPEC, /* struct timespec */ CFORM_SECS_ONLY, /* struct timespec but tv_nsec == 0 if timespec valid */ CFORM_DOUBLE /* double */ @@ -598,7 +598,7 @@ enum cform /* A C timestamp in one of the forms specified by enum cform. */ union c_time { - struct lisp_time lt; + struct ticks_hz th; struct timespec ts; double d; }; @@ -614,7 +614,7 @@ decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, enum cform cform) return (union c_time) { .d = frac_to_double (ticks, hz) }; case CFORM_TICKS_HZ: - return (union c_time) { .lt = { .ticks = ticks, .hz = hz } }; + return (union c_time) { .th = { .ticks = ticks, .hz = hz } }; default: return (union c_time) { .ts = ticks_hz_to_timespec (ticks, hz) }; @@ -751,7 +751,7 @@ timespec_ticks (struct timespec t) /* Convert T to a Lisp integer counting HZ ticks, taking the floor. Assume T is valid, but check HZ. */ static Lisp_Object -lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) +ticks_hz_hz_ticks (struct ticks_hz t, Lisp_Object hz) { /* The idea is to return the floor of ((T.ticks * HZ) / T.hz). */ @@ -785,19 +785,19 @@ lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) /* Convert T to a Lisp integer counting seconds, taking the floor. */ static Lisp_Object -lisp_time_seconds (struct lisp_time t) +ticks_hz_seconds (struct ticks_hz t) { /* The idea is to return the floor of T.ticks / T.hz. */ if (!FASTER_TIMEFNS) - return lisp_time_hz_ticks (t, make_fixnum (1)); + return ticks_hz_hz_ticks (t, make_fixnum (1)); /* For speed, use EMACS_INT arithmetic if it will do. */ if (FIXNUMP (t.ticks) && FIXNUMP (t.hz)) return make_fixnum (XFIXNUM (t.ticks) / XFIXNUM (t.hz) - (XFIXNUM (t.ticks) % XFIXNUM (t.hz) < 0)); - /* For speed, inline what lisp_time_hz_ticks would do. */ + /* For speed, inline what ticks_hz_hz_ticks would do. */ mpz_fdiv_q (mpz[0], *bignum_integer (&mpz[0], t.ticks), *bignum_integer (&mpz[1], t.hz)); @@ -1130,7 +1130,7 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) fta = decode_lisp_time (a, CFORM_TICKS_HZ), ftb = decode_lisp_time (b, CFORM_TICKS_HZ); enum timeform aform = fta.form, bform = ftb.form; - struct lisp_time ta = fta.time.lt, tb = ftb.time.lt; + struct ticks_hz ta = fta.time.th, tb = ftb.time.th; Lisp_Object ticks, hz; if (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz)) @@ -1271,8 +1271,8 @@ time_cmp (Lisp_Object a, Lisp_Object b) /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing ATICKS * BHZ to BTICKS * AHZ. */ - struct lisp_time ta = lisp_time_struct (a, CFORM_TICKS_HZ).lt; - struct lisp_time tb = lisp_time_struct (b, CFORM_TICKS_HZ).lt; + struct ticks_hz ta = lisp_time_struct (a, CFORM_TICKS_HZ).th; + struct ticks_hz tb = lisp_time_struct (b, CFORM_TICKS_HZ).th; mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); if (! (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz))) @@ -1549,18 +1549,18 @@ usage: (decode-time &optional TIME ZONE FORM) */) (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) { /* Convert SPECIFIED_TIME to TIME_SPEC and HZ; - if HZ != 1 also set LT.ticks. */ + if HZ != 1 also set TH.ticks. */ time_t time_spec; Lisp_Object hz; - struct lisp_time lt; + struct ticks_hz th; if (EQ (form, Qt)) { - lt = lisp_time_struct (specified_time, CFORM_TICKS_HZ).lt; - struct timespec ts = ticks_hz_to_timespec (lt.ticks, lt.hz); + th = lisp_time_struct (specified_time, CFORM_TICKS_HZ).th; + struct timespec ts = ticks_hz_to_timespec (th.ticks, th.hz); if (! timespec_valid_p (ts)) time_overflow (); time_spec = ts.tv_sec; - hz = lt.hz; + hz = th.hz; } else { @@ -1601,20 +1601,20 @@ usage: (decode-time &optional TIME ZONE FORM) */) sec = make_fixnum (local_tm.tm_sec); else { - /* Let TICKS = HZ * LOCAL_TM.tm_sec + mod (LT.ticks, HZ) + /* Let TICKS = HZ * LOCAL_TM.tm_sec + mod (TH.ticks, HZ) and SEC = (TICKS . HZ). */ Lisp_Object ticks; intmax_t n; - if (FASTER_TIMEFNS && FIXNUMP (lt.ticks) && FIXNUMP (hz) + if (FASTER_TIMEFNS && FIXNUMP (th.ticks) && FIXNUMP (hz) && !ckd_mul (&n, XFIXNUM (hz), local_tm.tm_sec) - && !ckd_add (&n, n, (XFIXNUM (lt.ticks) % XFIXNUM (hz) - + (XFIXNUM (lt.ticks) % XFIXNUM (hz) < 0 + && !ckd_add (&n, n, (XFIXNUM (th.ticks) % XFIXNUM (hz) + + (XFIXNUM (th.ticks) % XFIXNUM (hz) < 0 ? XFIXNUM (hz) : 0)))) ticks = make_int (n); else { mpz_fdiv_r (mpz[0], - *bignum_integer (&mpz[0], lt.ticks), + *bignum_integer (&mpz[0], th.ticks), *bignum_integer (&mpz[1], hz)); mpz_addmul_ui (mpz[0], *bignum_integer (&mpz[1], hz), local_tm.tm_sec); @@ -1741,18 +1741,18 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) yeararg = args[5]; } - /* Let SEC = floor (LT.ticks / HZ), with SUBSECTICKS the remainder. */ - struct lisp_time lt = decode_lisp_time (secarg, CFORM_TICKS_HZ).time.lt; - Lisp_Object hz = lt.hz, sec, subsecticks; + /* Let SEC = floor (TH.ticks / HZ), with SUBSECTICKS the remainder. */ + struct ticks_hz th = decode_lisp_time (secarg, CFORM_TICKS_HZ).time.th; + Lisp_Object hz = th.hz, sec, subsecticks; if (FASTER_TIMEFNS && BASE_EQ (hz, make_fixnum (1))) { - sec = lt.ticks; + sec = th.ticks; subsecticks = make_fixnum (0); } else { mpz_fdiv_qr (mpz[0], mpz[1], - *bignum_integer (&mpz[0], lt.ticks), + *bignum_integer (&mpz[0], th.ticks), *bignum_integer (&mpz[1], hz)); sec = make_integer_mpz (); mpz_swap (mpz[0], mpz[1]); @@ -1780,8 +1780,8 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) : INT_TO_INTEGER (value)); else { - struct lisp_time val1 = { INT_TO_INTEGER (value), make_fixnum (1) }; - Lisp_Object secticks = lisp_time_hz_ticks (val1, hz); + struct ticks_hz val1 = { INT_TO_INTEGER (value), make_fixnum (1) }; + Lisp_Object secticks = ticks_hz_hz_ticks (val1, hz); Lisp_Object ticks = lispint_arith (secticks, subsecticks, false); return Fcons (ticks, hz); } @@ -1812,19 +1812,19 @@ but new code should not rely on it. */) /* FIXME: Any reason why we don't offer a `float` output format option as well, since we accept it as input? */ struct form_time form_time = decode_lisp_time (time, CFORM_TICKS_HZ); - struct lisp_time t = form_time.time.lt; + struct ticks_hz t = form_time.time.th; form = (!NILP (form) ? maybe_remove_pos_from_symbol (form) : current_time_list ? Qlist : Qt); if (BASE_EQ (form, Qlist)) return ticks_hz_list4 (t.ticks, t.hz); if (BASE_EQ (form, Qinteger)) - return FASTER_TIMEFNS && INTEGERP (time) ? time : lisp_time_seconds (t); + return FASTER_TIMEFNS && INTEGERP (time) ? time : ticks_hz_seconds (t); if (BASE_EQ (form, Qt)) form = t.hz; if (FASTER_TIMEFNS && form_time.form == TIMEFORM_TICKS_HZ && BASE_EQ (form, XCDR (time))) return time; - return Fcons (lisp_time_hz_ticks (t, form), form); + return Fcons (ticks_hz_hz_ticks (t, form), form); } DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, commit a6a3f322453d35074a4866f2fda08781722cbc72 Author: Paul Eggert Date: Sun Jul 7 21:34:23 2024 +0200 Speed up decode-time when not doing subseconds * src/timefns.c (Fdecode_time): Avoid some unnecessary conversions in the common case where subsecond resolution is not required. diff --git a/src/timefns.c b/src/timefns.c index cc148fa9752..ded31997620 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -1548,12 +1548,27 @@ SEC is always an integer between 0 and 59.) usage: (decode-time &optional TIME ZONE FORM) */) (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) { - /* Compute broken-down local time LOCAL_TM from SPECIFIED_TIME and ZONE. */ - struct lisp_time lt = lisp_time_struct (specified_time, CFORM_TICKS_HZ).lt; - struct timespec ts = ticks_hz_to_timespec (lt.ticks, lt.hz); - if (! timespec_valid_p (ts)) - time_overflow (); - time_t time_spec = ts.tv_sec; + /* Convert SPECIFIED_TIME to TIME_SPEC and HZ; + if HZ != 1 also set LT.ticks. */ + time_t time_spec; + Lisp_Object hz; + struct lisp_time lt; + if (EQ (form, Qt)) + { + lt = lisp_time_struct (specified_time, CFORM_TICKS_HZ).lt; + struct timespec ts = ticks_hz_to_timespec (lt.ticks, lt.hz); + if (! timespec_valid_p (ts)) + time_overflow (); + time_spec = ts.tv_sec; + hz = lt.hz; + } + else + { + time_spec = lisp_seconds_argument (specified_time); + hz = make_fixnum (1); + } + + /* Compute broken-down local time LOCAL_TM from TIME_SPEC and ZONE. */ struct tm local_tm, gmt_tm; timezone_t tz = tzlookup (zone, false); struct tm *tm = emacs_localtime_rz (tz, &time_spec, &local_tm); @@ -1581,8 +1596,8 @@ usage: (decode-time &optional TIME ZONE FORM) */) } /* Compute SEC from LOCAL_TM.tm_sec and HZ. */ - Lisp_Object hz = lt.hz, sec; - if (BASE_EQ (hz, make_fixnum (1)) || !EQ (form, Qt)) + Lisp_Object sec; + if (BASE_EQ (hz, make_fixnum (1))) sec = make_fixnum (local_tm.tm_sec); else { commit 34bde2f790decfff61f03c5ab92ad0436958bacf Author: Paul Eggert Date: Sun Jul 7 20:50:47 2024 +0200 Push some time conversions down * src/timefns.c: Push some time conversions down to lower level fns. This is a win in its own right and should allow for further speedups. (lisp_to_timespec): Remove; this convenience function is no longer needed now that there would be only one caller. Remaining caller changed to use definiens. (enum cform): New constant CFORM_TIMESPEC. Also, CFORM_SECS_ONLY now generates a struct timespec instead of a struct lisp_time. (union c_time.ts): New member. (decode_ticks_hz): Handle new struct timespec cases. (decode_float_time, lisp_time_struct): New arg cform, and return union c_time rather than struct lisp_time. All callers changed. (list4_to_timespec, lisp_time_argument, lisp_seconds_argument): Let lower-level function do the conversion, to allow for better optimization. diff --git a/src/timefns.c b/src/timefns.c index c748867b54d..cc148fa9752 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -585,20 +585,13 @@ ticks_hz_to_timespec (Lisp_Object ticks, Lisp_Object hz) return result; } -/* Convert T to struct timespec, returning an invalid timespec - if T does not fit. */ -static struct timespec -lisp_to_timespec (struct lisp_time t) -{ - return ticks_hz_to_timespec (t.ticks, t.hz); -} - /* C timestamp forms. This enum is passed to conversion functions to specify the desired C timestamp form. */ enum cform { CFORM_TICKS_HZ, /* struct lisp_time */ - CFORM_SECS_ONLY, /* struct lisp_time but HZ is 1 */ + CFORM_TIMESPEC, /* struct timespec */ + CFORM_SECS_ONLY, /* struct timespec but tv_nsec == 0 if timespec valid */ CFORM_DOUBLE /* double */ }; @@ -606,6 +599,7 @@ enum cform union c_time { struct lisp_time lt; + struct timespec ts; double d; }; @@ -619,16 +613,22 @@ decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, enum cform cform) case CFORM_DOUBLE: return (union c_time) { .d = frac_to_double (ticks, hz) }; - default: + case CFORM_TICKS_HZ: return (union c_time) { .lt = { .ticks = ticks, .hz = hz } }; + + default: + return (union c_time) { .ts = ticks_hz_to_timespec (ticks, hz) }; } } -/* Convert the finite number T into an Emacs time, truncating +/* Convert the finite number T into a C time of form CFORM, truncating toward minus infinity. Signal an error if unsuccessful. */ -static struct lisp_time -decode_float_time (double t) +static union c_time +decode_float_time (double t, enum cform cform) { + if (FASTER_TIMEFNS && cform == CFORM_DOUBLE) + return (union c_time) { .d = t }; + Lisp_Object ticks, hz; if (t == 0) { @@ -671,7 +671,7 @@ decode_float_time (double t) ASET (flt_radix_power, scale, hz); } } - return (struct lisp_time) { .ticks = ticks, .hz = hz }; + return decode_ticks_hz (ticks, hz, cform); } /* Make a 4-element timestamp (HI LO US PS) from TICKS and HZ. @@ -1019,10 +1019,7 @@ decode_lisp_time (Lisp_Object specified_time, enum cform cform) return (struct form_time) { .form = TIMEFORM_FLOAT, - .time - = (cform == CFORM_DOUBLE - ? (union c_time) { .d = d } - : (union c_time) { .lt = decode_float_time (d) }) + .time = decode_float_time (d, cform) }; } @@ -1049,19 +1046,18 @@ list4_to_timespec (Lisp_Object high, Lisp_Object low, { struct err_time err_time = decode_time_components (TIMEFORM_HI_LO_US_PS, high, low, usec, psec, - CFORM_TICKS_HZ); - return (err_time.err - ? invalid_timespec () - : lisp_to_timespec (err_time.time.lt)); + CFORM_TIMESPEC); + return err_time.err ? invalid_timespec () : err_time.time.ts; } /* Decode a Lisp list SPECIFIED_TIME that represents a time. If SPECIFIED_TIME is nil, use the current time. + Decode to CFORM form. Signal an error if SPECIFIED_TIME does not represent a time. */ -static struct lisp_time -lisp_time_struct (Lisp_Object specified_time) +static union c_time +lisp_time_struct (Lisp_Object specified_time, enum cform cform) { - return decode_lisp_time (specified_time, CFORM_TICKS_HZ).time.lt; + return decode_lisp_time (specified_time, cform).time; } /* Decode a Lisp list SPECIFIED_TIME that represents a time. @@ -1071,8 +1067,7 @@ lisp_time_struct (Lisp_Object specified_time) struct timespec lisp_time_argument (Lisp_Object specified_time) { - struct lisp_time lt = lisp_time_struct (specified_time); - struct timespec t = lisp_to_timespec (lt); + struct timespec t = lisp_time_struct (specified_time, CFORM_TIMESPEC).ts; if (! timespec_valid_p (t)) time_overflow (); return t; @@ -1083,8 +1078,8 @@ lisp_time_argument (Lisp_Object specified_time) static time_t lisp_seconds_argument (Lisp_Object specified_time) { - struct form_time ft = decode_lisp_time (specified_time, CFORM_SECS_ONLY); - struct timespec t = lisp_to_timespec (ft.time.lt); + struct timespec t + = decode_lisp_time (specified_time, CFORM_SECS_ONLY).time.ts; if (! timespec_valid_p (t)) time_overflow (); return t.tv_sec; @@ -1276,8 +1271,8 @@ time_cmp (Lisp_Object a, Lisp_Object b) /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing ATICKS * BHZ to BTICKS * AHZ. */ - struct lisp_time ta = lisp_time_struct (a); - struct lisp_time tb = lisp_time_struct (b); + struct lisp_time ta = lisp_time_struct (a, CFORM_TICKS_HZ).lt; + struct lisp_time tb = lisp_time_struct (b, CFORM_TICKS_HZ).lt; mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); if (! (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz))) @@ -1554,8 +1549,8 @@ usage: (decode-time &optional TIME ZONE FORM) */) (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) { /* Compute broken-down local time LOCAL_TM from SPECIFIED_TIME and ZONE. */ - struct lisp_time lt = lisp_time_struct (specified_time); - struct timespec ts = lisp_to_timespec (lt); + struct lisp_time lt = lisp_time_struct (specified_time, CFORM_TICKS_HZ).lt; + struct timespec ts = ticks_hz_to_timespec (lt.ticks, lt.hz); if (! timespec_valid_p (ts)) time_overflow (); time_t time_spec = ts.tv_sec; commit 22a3a90f7636a9cb55a463a8149d6e3ec12d1b81 Author: Paul Eggert Date: Sun Jul 7 16:18:18 2024 +0200 Split lisp_to_timespec in two * src/timefns.c (ticks_hz_to_timespec): New function, which is almost all the old lisp_to_timespec but with a 2-arg API. This should help further changes. (lisp_to_timespec): Use it. diff --git a/src/timefns.c b/src/timefns.c index ac41a3d6958..c748867b54d 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -517,26 +517,26 @@ struct lisp_time Lisp_Object hz; }; -/* Convert T to struct timespec, returning an invalid timespec - if T does not fit. */ +/* Convert (TICKS . HZ) to struct timespec, returning an invalid + timespec if the result would not fit. */ static struct timespec -lisp_to_timespec (struct lisp_time t) +ticks_hz_to_timespec (Lisp_Object ticks, Lisp_Object hz) { struct timespec result = invalid_timespec (); int ns; mpz_t *q = &mpz[0]; mpz_t const *qt = q; - /* Floor-divide (T.ticks * TIMESPEC_HZ) by T.hz, + /* Floor-divide (TICKS * TIMESPEC_HZ) by HZ, yielding quotient Q (tv_sec) and remainder NS (tv_nsec). Return an invalid timespec if Q does not fit in time_t. For speed, prefer fixnum arithmetic if it works. */ - if (FASTER_TIMEFNS && BASE_EQ (t.hz, timespec_hz)) + if (FASTER_TIMEFNS && BASE_EQ (hz, timespec_hz)) { - if (FIXNUMP (t.ticks)) + if (FIXNUMP (ticks)) { - EMACS_INT s = XFIXNUM (t.ticks) / TIMESPEC_HZ; - ns = XFIXNUM (t.ticks) % TIMESPEC_HZ; + EMACS_INT s = XFIXNUM (ticks) / TIMESPEC_HZ; + ns = XFIXNUM (ticks) % TIMESPEC_HZ; if (ns < 0) s--, ns += TIMESPEC_HZ; if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) @@ -548,14 +548,14 @@ lisp_to_timespec (struct lisp_time t) return result; } else - ns = mpz_fdiv_q_ui (*q, *xbignum_val (t.ticks), TIMESPEC_HZ); + ns = mpz_fdiv_q_ui (*q, *xbignum_val (ticks), TIMESPEC_HZ); } - else if (FASTER_TIMEFNS && BASE_EQ (t.hz, make_fixnum (1))) + else if (FASTER_TIMEFNS && BASE_EQ (hz, make_fixnum (1))) { ns = 0; - if (FIXNUMP (t.ticks)) + if (FIXNUMP (ticks)) { - EMACS_INT s = XFIXNUM (t.ticks); + EMACS_INT s = XFIXNUM (ticks); if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) && s <= TIME_T_MAX) { @@ -565,17 +565,17 @@ lisp_to_timespec (struct lisp_time t) return result; } else - qt = xbignum_val (t.ticks); + qt = xbignum_val (ticks); } else { - mpz_mul_ui (*q, *bignum_integer (q, t.ticks), TIMESPEC_HZ); - mpz_fdiv_q (*q, *q, *bignum_integer (&mpz[1], t.hz)); + mpz_mul_ui (*q, *bignum_integer (q, ticks), TIMESPEC_HZ); + mpz_fdiv_q (*q, *q, *bignum_integer (&mpz[1], hz)); ns = mpz_fdiv_q_ui (*q, *q, TIMESPEC_HZ); } - /* Check that Q fits in time_t, not merely in T.tv_sec. With some versions - of MinGW, tv_sec is a 64-bit type, whereas time_t is a 32-bit type. */ + /* Check that Q fits in time_t, not merely in RESULT.tv_sec. With some MinGW + versions, tv_sec is a 64-bit type, whereas time_t is a 32-bit type. */ time_t sec; if (mpz_time (*qt, &sec)) { @@ -585,6 +585,14 @@ lisp_to_timespec (struct lisp_time t) return result; } +/* Convert T to struct timespec, returning an invalid timespec + if T does not fit. */ +static struct timespec +lisp_to_timespec (struct lisp_time t) +{ + return ticks_hz_to_timespec (t.ticks, t.hz); +} + /* C timestamp forms. This enum is passed to conversion functions to specify the desired C timestamp form. */ enum cform commit c45ae286b540f1fc4e424a04eb1d423037cab19c Author: Paul Eggert Date: Sun Jul 7 16:05:52 2024 +0200 Refactor decode_ticks_hz via switch * src/timefns.c (decode_ticks_hz): Change ?: to ‘switch’, for benefit of future changes. diff --git a/src/timefns.c b/src/timefns.c index a7a7d552506..ac41a3d6958 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -606,9 +606,14 @@ union c_time static union c_time decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, enum cform cform) { - return (cform == CFORM_DOUBLE - ? (union c_time) { .d = frac_to_double (ticks, hz) } - : (union c_time) { .lt = { .ticks = ticks, .hz = hz } }); + switch (cform) + { + case CFORM_DOUBLE: + return (union c_time) { .d = frac_to_double (ticks, hz) }; + + default: + return (union c_time) { .lt = { .ticks = ticks, .hz = hz } }; + } } /* Convert the finite number T into an Emacs time, truncating commit 0e221d3789a40d22bd4a9489985aebeb86f43e01 Author: Paul Eggert Date: Sun Jul 7 15:42:10 2024 +0200 Refactor timefns order Move definitions around in timefns.c. This does not affect the implementation; it merely makes future changes easier to follow. * src/timefns.c (frac_to_double, mpz_time, lisp_to_timespec) (enum cform, union c_time, decode_ticks_hz): Move earlier. diff --git a/src/timefns.c b/src/timefns.c index 70961c1a560..a7a7d552506 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -400,6 +400,112 @@ enum { flt_radix_power_size = DBL_MANT_DIG - DBL_MIN_EXP + 1 }; equals FLT_RADIX**P. */ static Lisp_Object flt_radix_power; +/* Return NUMERATOR / DENOMINATOR, rounded to the nearest double. + Arguments must be Lisp integers, and DENOMINATOR must be positive. */ +static double +frac_to_double (Lisp_Object numerator, Lisp_Object denominator) +{ + intmax_t intmax_numerator, intmax_denominator; + if (FASTER_TIMEFNS + && integer_to_intmax (numerator, &intmax_numerator) + && integer_to_intmax (denominator, &intmax_denominator) + && intmax_numerator % intmax_denominator == 0) + return intmax_numerator / intmax_denominator; + + /* Compute number of base-FLT_RADIX digits in numerator and denominator. */ + mpz_t const *n = bignum_integer (&mpz[0], numerator); + mpz_t const *d = bignum_integer (&mpz[1], denominator); + ptrdiff_t ndig = mpz_sizeinbase (*n, FLT_RADIX); + ptrdiff_t ddig = mpz_sizeinbase (*d, FLT_RADIX); + + /* Scale with SCALE when doing integer division. That is, compute + (N * FLT_RADIX**SCALE) / D [or, if SCALE is negative, N / (D * + FLT_RADIX**-SCALE)] as a bignum, convert the bignum to double, + then divide the double by FLT_RADIX**SCALE. First scale N + (or scale D, if SCALE is negative) ... */ + ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG; + if (scale < 0) + { + mpz_mul_2exp (mpz[1], *d, - (scale * LOG2_FLT_RADIX)); + d = &mpz[1]; + } + else + { + /* min so we don't scale tiny numbers as if they were normalized. */ + scale = min (scale, flt_radix_power_size - 1); + + mpz_mul_2exp (mpz[0], *n, scale * LOG2_FLT_RADIX); + n = &mpz[0]; + } + /* ... and then divide, with quotient Q and remainder R. */ + mpz_t *q = &mpz[2]; + mpz_t *r = &mpz[3]; + mpz_tdiv_qr (*q, *r, *n, *d); + + /* The amount to add to the absolute value of Q so that truncating + it to double will round correctly. */ + int incr; + + /* Round the quotient before converting it to double. + If the quotient is less than FLT_RADIX ** DBL_MANT_DIG, + round to the nearest integer; otherwise, it is less than + FLT_RADIX ** (DBL_MANT_DIG + 1) and round it to the nearest + multiple of FLT_RADIX. Break ties to even. */ + if (mpz_sizeinbase (*q, FLT_RADIX) <= DBL_MANT_DIG) + { + /* Converting to double will use the whole quotient so add 1 to + its absolute value as per round-to-even; i.e., if the doubled + remainder exceeds the denominator, or exactly equals the + denominator and adding 1 would make the quotient even. */ + mpz_mul_2exp (*r, *r, 1); + int cmp = mpz_cmpabs (*r, *d); + incr = cmp > 0 || (cmp == 0 && (FASTER_TIMEFNS && FLT_RADIX == 2 + ? mpz_odd_p (*q) + : mpz_tdiv_ui (*q, FLT_RADIX) & 1)); + } + else + { + /* Converting to double will discard the quotient's low-order digit, + so add FLT_RADIX to its absolute value as per round-to-even. */ + int lo_2digits = mpz_tdiv_ui (*q, FLT_RADIX * FLT_RADIX); + eassume (0 <= lo_2digits && lo_2digits < FLT_RADIX * FLT_RADIX); + int lo_digit = lo_2digits % FLT_RADIX; + incr = ((lo_digit > FLT_RADIX / 2 + || (lo_digit == FLT_RADIX / 2 && FLT_RADIX % 2 == 0 + && ((lo_2digits / FLT_RADIX) & 1 + || mpz_sgn (*r) != 0))) + ? FLT_RADIX : 0); + } + + /* Increment the absolute value of the quotient by INCR. */ + if (!FASTER_TIMEFNS || incr != 0) + (mpz_sgn (*n) < 0 ? mpz_sub_ui : mpz_add_ui) (*q, *q, incr); + + /* Rescale the integer Q back to double. This step does not round. */ + return scalbn (mpz_get_d (*q), -scale); +} + +/* Convert Z to time_t, returning true if it fits. */ +static bool +mpz_time (mpz_t const z, time_t *t) +{ + if (TYPE_SIGNED (time_t)) + { + intmax_t i; + if (! (mpz_to_intmax (z, &i) && TIME_T_MIN <= i && i <= TIME_T_MAX)) + return false; + *t = i; + } + else + { + uintmax_t i; + if (! (mpz_to_uintmax (z, &i) && i <= TIME_T_MAX)) + return false; + *t = i; + } + return true; +} + /* Components of a Lisp timestamp (TICKS . HZ). Using this C struct can avoid the consing overhead of creating (TICKS . HZ). */ struct lisp_time @@ -411,6 +517,100 @@ struct lisp_time Lisp_Object hz; }; +/* Convert T to struct timespec, returning an invalid timespec + if T does not fit. */ +static struct timespec +lisp_to_timespec (struct lisp_time t) +{ + struct timespec result = invalid_timespec (); + int ns; + mpz_t *q = &mpz[0]; + mpz_t const *qt = q; + + /* Floor-divide (T.ticks * TIMESPEC_HZ) by T.hz, + yielding quotient Q (tv_sec) and remainder NS (tv_nsec). + Return an invalid timespec if Q does not fit in time_t. + For speed, prefer fixnum arithmetic if it works. */ + if (FASTER_TIMEFNS && BASE_EQ (t.hz, timespec_hz)) + { + if (FIXNUMP (t.ticks)) + { + EMACS_INT s = XFIXNUM (t.ticks) / TIMESPEC_HZ; + ns = XFIXNUM (t.ticks) % TIMESPEC_HZ; + if (ns < 0) + s--, ns += TIMESPEC_HZ; + if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) + && s <= TIME_T_MAX) + { + result.tv_sec = s; + result.tv_nsec = ns; + } + return result; + } + else + ns = mpz_fdiv_q_ui (*q, *xbignum_val (t.ticks), TIMESPEC_HZ); + } + else if (FASTER_TIMEFNS && BASE_EQ (t.hz, make_fixnum (1))) + { + ns = 0; + if (FIXNUMP (t.ticks)) + { + EMACS_INT s = XFIXNUM (t.ticks); + if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) + && s <= TIME_T_MAX) + { + result.tv_sec = s; + result.tv_nsec = ns; + } + return result; + } + else + qt = xbignum_val (t.ticks); + } + else + { + mpz_mul_ui (*q, *bignum_integer (q, t.ticks), TIMESPEC_HZ); + mpz_fdiv_q (*q, *q, *bignum_integer (&mpz[1], t.hz)); + ns = mpz_fdiv_q_ui (*q, *q, TIMESPEC_HZ); + } + + /* Check that Q fits in time_t, not merely in T.tv_sec. With some versions + of MinGW, tv_sec is a 64-bit type, whereas time_t is a 32-bit type. */ + time_t sec; + if (mpz_time (*qt, &sec)) + { + result.tv_sec = sec; + result.tv_nsec = ns; + } + return result; +} + +/* C timestamp forms. This enum is passed to conversion functions to + specify the desired C timestamp form. */ +enum cform + { + CFORM_TICKS_HZ, /* struct lisp_time */ + CFORM_SECS_ONLY, /* struct lisp_time but HZ is 1 */ + CFORM_DOUBLE /* double */ + }; + +/* A C timestamp in one of the forms specified by enum cform. */ +union c_time +{ + struct lisp_time lt; + double d; +}; + +/* From a valid timestamp (TICKS . HZ), generate the corresponding + time value in CFORM form. */ +static union c_time +decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, enum cform cform) +{ + return (cform == CFORM_DOUBLE + ? (union c_time) { .d = frac_to_double (ticks, hz) } + : (union c_time) { .lt = { .ticks = ticks, .hz = hz } }); +} + /* Convert the finite number T into an Emacs time, truncating toward minus infinity. Signal an error if unsuccessful. */ static struct lisp_time @@ -613,117 +813,6 @@ timespec_to_lisp (struct timespec t) return Fcons (timespec_ticks (t), timespec_hz); } -/* Return NUMERATOR / DENOMINATOR, rounded to the nearest double. - Arguments must be Lisp integers, and DENOMINATOR must be positive. */ -static double -frac_to_double (Lisp_Object numerator, Lisp_Object denominator) -{ - intmax_t intmax_numerator, intmax_denominator; - if (FASTER_TIMEFNS - && integer_to_intmax (numerator, &intmax_numerator) - && integer_to_intmax (denominator, &intmax_denominator) - && intmax_numerator % intmax_denominator == 0) - return intmax_numerator / intmax_denominator; - - /* Compute number of base-FLT_RADIX digits in numerator and denominator. */ - mpz_t const *n = bignum_integer (&mpz[0], numerator); - mpz_t const *d = bignum_integer (&mpz[1], denominator); - ptrdiff_t ndig = mpz_sizeinbase (*n, FLT_RADIX); - ptrdiff_t ddig = mpz_sizeinbase (*d, FLT_RADIX); - - /* Scale with SCALE when doing integer division. That is, compute - (N * FLT_RADIX**SCALE) / D [or, if SCALE is negative, N / (D * - FLT_RADIX**-SCALE)] as a bignum, convert the bignum to double, - then divide the double by FLT_RADIX**SCALE. First scale N - (or scale D, if SCALE is negative) ... */ - ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG; - if (scale < 0) - { - mpz_mul_2exp (mpz[1], *d, - (scale * LOG2_FLT_RADIX)); - d = &mpz[1]; - } - else - { - /* min so we don't scale tiny numbers as if they were normalized. */ - scale = min (scale, flt_radix_power_size - 1); - - mpz_mul_2exp (mpz[0], *n, scale * LOG2_FLT_RADIX); - n = &mpz[0]; - } - /* ... and then divide, with quotient Q and remainder R. */ - mpz_t *q = &mpz[2]; - mpz_t *r = &mpz[3]; - mpz_tdiv_qr (*q, *r, *n, *d); - - /* The amount to add to the absolute value of Q so that truncating - it to double will round correctly. */ - int incr; - - /* Round the quotient before converting it to double. - If the quotient is less than FLT_RADIX ** DBL_MANT_DIG, - round to the nearest integer; otherwise, it is less than - FLT_RADIX ** (DBL_MANT_DIG + 1) and round it to the nearest - multiple of FLT_RADIX. Break ties to even. */ - if (mpz_sizeinbase (*q, FLT_RADIX) <= DBL_MANT_DIG) - { - /* Converting to double will use the whole quotient so add 1 to - its absolute value as per round-to-even; i.e., if the doubled - remainder exceeds the denominator, or exactly equals the - denominator and adding 1 would make the quotient even. */ - mpz_mul_2exp (*r, *r, 1); - int cmp = mpz_cmpabs (*r, *d); - incr = cmp > 0 || (cmp == 0 && (FASTER_TIMEFNS && FLT_RADIX == 2 - ? mpz_odd_p (*q) - : mpz_tdiv_ui (*q, FLT_RADIX) & 1)); - } - else - { - /* Converting to double will discard the quotient's low-order digit, - so add FLT_RADIX to its absolute value as per round-to-even. */ - int lo_2digits = mpz_tdiv_ui (*q, FLT_RADIX * FLT_RADIX); - eassume (0 <= lo_2digits && lo_2digits < FLT_RADIX * FLT_RADIX); - int lo_digit = lo_2digits % FLT_RADIX; - incr = ((lo_digit > FLT_RADIX / 2 - || (lo_digit == FLT_RADIX / 2 && FLT_RADIX % 2 == 0 - && ((lo_2digits / FLT_RADIX) & 1 - || mpz_sgn (*r) != 0))) - ? FLT_RADIX : 0); - } - - /* Increment the absolute value of the quotient by INCR. */ - if (!FASTER_TIMEFNS || incr != 0) - (mpz_sgn (*n) < 0 ? mpz_sub_ui : mpz_add_ui) (*q, *q, incr); - - /* Rescale the integer Q back to double. This step does not round. */ - return scalbn (mpz_get_d (*q), -scale); -} - -/* C timestamp forms. This enum is passed to conversion functions to - specify the desired C timestamp form. */ -enum cform - { - CFORM_TICKS_HZ, /* struct lisp_time */ - CFORM_SECS_ONLY, /* struct lisp_time but HZ is 1 */ - CFORM_DOUBLE /* double */ - }; - -/* A C timestamp in one of the forms specified by enum cform. */ -union c_time -{ - struct lisp_time lt; - double d; -}; - -/* From a valid timestamp (TICKS . HZ), generate the corresponding - time value in CFORM form. */ -static union c_time -decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, enum cform cform) -{ - return (cform == CFORM_DOUBLE - ? (union c_time) { .d = frac_to_double (ticks, hz) } - : (union c_time) { .lt = { .ticks = ticks, .hz = hz } }); -} - /* An (error number, C timestamp) pair. */ struct err_time { @@ -939,95 +1028,6 @@ float_time (Lisp_Object specified_time) return decode_lisp_time (specified_time, CFORM_DOUBLE).time.d; } -/* Convert Z to time_t, returning true if it fits. */ -static bool -mpz_time (mpz_t const z, time_t *t) -{ - if (TYPE_SIGNED (time_t)) - { - intmax_t i; - if (! (mpz_to_intmax (z, &i) && TIME_T_MIN <= i && i <= TIME_T_MAX)) - return false; - *t = i; - } - else - { - uintmax_t i; - if (! (mpz_to_uintmax (z, &i) && i <= TIME_T_MAX)) - return false; - *t = i; - } - return true; -} - -/* Convert T to struct timespec, returning an invalid timespec - if T does not fit. */ -static struct timespec -lisp_to_timespec (struct lisp_time t) -{ - struct timespec result = invalid_timespec (); - int ns; - mpz_t *q = &mpz[0]; - mpz_t const *qt = q; - - /* Floor-divide (T.ticks * TIMESPEC_HZ) by T.hz, - yielding quotient Q (tv_sec) and remainder NS (tv_nsec). - Return an invalid timespec if Q does not fit in time_t. - For speed, prefer fixnum arithmetic if it works. */ - if (FASTER_TIMEFNS && BASE_EQ (t.hz, timespec_hz)) - { - if (FIXNUMP (t.ticks)) - { - EMACS_INT s = XFIXNUM (t.ticks) / TIMESPEC_HZ; - ns = XFIXNUM (t.ticks) % TIMESPEC_HZ; - if (ns < 0) - s--, ns += TIMESPEC_HZ; - if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) - && s <= TIME_T_MAX) - { - result.tv_sec = s; - result.tv_nsec = ns; - } - return result; - } - else - ns = mpz_fdiv_q_ui (*q, *xbignum_val (t.ticks), TIMESPEC_HZ); - } - else if (FASTER_TIMEFNS && BASE_EQ (t.hz, make_fixnum (1))) - { - ns = 0; - if (FIXNUMP (t.ticks)) - { - EMACS_INT s = XFIXNUM (t.ticks); - if ((TYPE_SIGNED (time_t) ? TIME_T_MIN <= s : 0 <= s) - && s <= TIME_T_MAX) - { - result.tv_sec = s; - result.tv_nsec = ns; - } - return result; - } - else - qt = xbignum_val (t.ticks); - } - else - { - mpz_mul_ui (*q, *bignum_integer (q, t.ticks), TIMESPEC_HZ); - mpz_fdiv_q (*q, *q, *bignum_integer (&mpz[1], t.hz)); - ns = mpz_fdiv_q_ui (*q, *q, TIMESPEC_HZ); - } - - /* Check that Q fits in time_t, not merely in T.tv_sec. With some versions - of MinGW, tv_sec is a 64-bit type, whereas time_t is a 32-bit type. */ - time_t sec; - if (mpz_time (*qt, &sec)) - { - result.tv_sec = sec; - result.tv_nsec = ns; - } - return result; -} - /* Convert (HIGH LOW USEC PSEC) to struct timespec. Return a valid timestamp if successful, an invalid one otherwise. */ struct timespec commit 35365620e4c4c2560e13eba1f03332970129d7f8 Author: Paul Eggert Date: Sat Jul 6 21:52:08 2024 +0200 Refactor timefns more functionally Use a more-functional style in timefns.c, rather than passing pointers to objects that are filled in. Although this does not change behavior, it should help future improvements to the code. * src/keyboard.c (decode_timer): Return a possibly-invalid struct timespec instead of storing a timespec into a location specified by an arg, and returning bool. All callers changed. * src/systime.h (struct lisp_time): Move from here to src/timefns.c, since the type is private to timefns.c. * src/timefns.c (decode_float_time, decode_ticks_hz): Return timestamp instead of storing it into a location specified by an arg. All callers changed. (enum cform, union c_time, struct err_time, struct form_time): New types, to aid functional style. (decode_time_components): Return struct err_time instead of returning err and storing timestamp into a location specified by an arg. New arg cform. All callers changed. (decode_lisp_time): Return struct form_time instead of returning form and storing timestamp into a location specified by an arg. New arg cform, replacing decode_secs_only. All callers changed. (list4_to_timespec): Return possibly-invalid timestamp instead of returning a bool and storing timestamp into a location specified by an arg. All callers changed. (lisp_time_struct): Omit no-longer-needed arg PFORM. All callers changed. diff --git a/src/keyboard.c b/src/keyboard.c index c75e80d2a05..40276b4157c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4646,20 +4646,21 @@ timer_resume_idle (void) ...). Each element has the form (FUN . ARGS). */ Lisp_Object pending_funcalls; -/* Return true if TIMER is a valid timer, placing its value into *RESULT. */ -static bool -decode_timer (Lisp_Object timer, struct timespec *result) +/* Return the value of TIMER if it is a valid timer, an invalid struct + timespec otherwise. */ +static struct timespec +decode_timer (Lisp_Object timer) { Lisp_Object *vec; if (! (VECTORP (timer) && ASIZE (timer) == 10)) - return false; + return invalid_timespec (); vec = XVECTOR (timer)->contents; if (! NILP (vec[0])) - return false; + return invalid_timespec (); if (! FIXNUMP (vec[2])) - return false; - return list4_to_timespec (vec[1], vec[2], vec[3], vec[8], result); + return invalid_timespec (); + return list4_to_timespec (vec[1], vec[2], vec[3], vec[8]); } @@ -4706,7 +4707,6 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) while (CONSP (timers) || CONSP (idle_timers)) { Lisp_Object timer = Qnil, idle_timer = Qnil; - struct timespec timer_time, idle_timer_time; struct timespec difference; struct timespec timer_difference = invalid_timespec (); struct timespec idle_timer_difference = invalid_timespec (); @@ -4720,7 +4720,8 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) if (CONSP (timers)) { timer = XCAR (timers); - if (! decode_timer (timer, &timer_time)) + struct timespec timer_time = decode_timer (timer); + if (! timespec_valid_p (timer_time)) { timers = XCDR (timers); continue; @@ -4737,7 +4738,8 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) if (CONSP (idle_timers)) { idle_timer = XCAR (idle_timers); - if (! decode_timer (idle_timer, &idle_timer_time)) + struct timespec idle_timer_time = decode_timer (idle_timer); + if (! timespec_valid_p (idle_timer_time)) { idle_timers = XCDR (idle_timers); continue; diff --git a/src/systime.h b/src/systime.h index fc93ea03233..1353c7158d0 100644 --- a/src/systime.h +++ b/src/systime.h @@ -77,22 +77,12 @@ extern void set_waiting_for_input (struct timespec *); (HI << LO_TIME_BITS) + LO + US / 1e6 + PS / 1e12. */ enum { LO_TIME_BITS = 16 }; -/* Components of a new-format Lisp timestamp. */ -struct lisp_time -{ - /* Clock count as a Lisp integer. */ - Lisp_Object ticks; - - /* Clock frequency (ticks per second) as a positive Lisp integer. */ - Lisp_Object hz; -}; - /* defined in timefns.c */ extern struct timeval make_timeval (struct timespec) ATTRIBUTE_CONST; extern Lisp_Object make_lisp_time (struct timespec); extern Lisp_Object timespec_to_lisp (struct timespec); -extern bool list4_to_timespec (Lisp_Object, Lisp_Object, Lisp_Object, - Lisp_Object, struct timespec *); +extern struct timespec list4_to_timespec (Lisp_Object, Lisp_Object, + Lisp_Object, Lisp_Object); extern struct timespec lisp_time_argument (Lisp_Object); extern double float_time (Lisp_Object); extern void init_timefns (void); diff --git a/src/timefns.c b/src/timefns.c index 746e422ffb6..70961c1a560 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -400,10 +400,21 @@ enum { flt_radix_power_size = DBL_MANT_DIG - DBL_MIN_EXP + 1 }; equals FLT_RADIX**P. */ static Lisp_Object flt_radix_power; -/* Convert the finite number T into an Emacs time *RESULT, truncating +/* Components of a Lisp timestamp (TICKS . HZ). Using this C struct can + avoid the consing overhead of creating (TICKS . HZ). */ +struct lisp_time +{ + /* Clock count as a Lisp integer. */ + Lisp_Object ticks; + + /* Clock frequency (ticks per second) as a positive Lisp integer. */ + Lisp_Object hz; +}; + +/* Convert the finite number T into an Emacs time, truncating toward minus infinity. Signal an error if unsuccessful. */ -static void -decode_float_time (double t, struct lisp_time *result) +static struct lisp_time +decode_float_time (double t) { Lisp_Object ticks, hz; if (t == 0) @@ -447,8 +458,7 @@ decode_float_time (double t, struct lisp_time *result) ASET (flt_radix_power, scale, hz); } } - result->ticks = ticks; - result->hz = hz; + return (struct lisp_time) { .ticks = ticks, .hz = hz }; } /* Make a 4-element timestamp (HI LO US PS) from TICKS and HZ. @@ -688,28 +698,39 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) return scalbn (mpz_get_d (*q), -scale); } -/* From a valid timestamp (TICKS . HZ), generate the corresponding - time values. +/* C timestamp forms. This enum is passed to conversion functions to + specify the desired C timestamp form. */ +enum cform + { + CFORM_TICKS_HZ, /* struct lisp_time */ + CFORM_SECS_ONLY, /* struct lisp_time but HZ is 1 */ + CFORM_DOUBLE /* double */ + }; - If RESULT is not null, store into *RESULT the converted time. - Otherwise, store into *DRESULT the number of seconds since the - start of the POSIX Epoch. +/* A C timestamp in one of the forms specified by enum cform. */ +union c_time +{ + struct lisp_time lt; + double d; +}; - Return zero, which indicates success. */ -static int -decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, - struct lisp_time *result, double *dresult) +/* From a valid timestamp (TICKS . HZ), generate the corresponding + time value in CFORM form. */ +static union c_time +decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, enum cform cform) { - if (result) - { - result->ticks = ticks; - result->hz = hz; - } - else - *dresult = frac_to_double (ticks, hz); - return 0; + return (cform == CFORM_DOUBLE + ? (union c_time) { .d = frac_to_double (ticks, hz) } + : (union c_time) { .lt = { .ticks = ticks, .hz = hz } }); } +/* An (error number, C timestamp) pair. */ +struct err_time +{ + int err; + union c_time time; +}; + /* Lisp timestamp classification. */ enum timeform { @@ -723,111 +744,117 @@ enum timeform }; /* From the non-float form FORM and the time components HIGH, LOW, USEC - and PSEC, generate the corresponding time value. If LOW is + and PSEC, generate the corresponding time value in CFORM form. If LOW is floating point, the other components should be zero and FORM should not be TIMEFORM_TICKS_HZ. - If RESULT is not null, store into *RESULT the converted time. - Otherwise, store into *DRESULT the number of seconds since the - start of the POSIX Epoch. Unsuccessful calls may or may not store - results. - - Return zero if successful, an error number otherwise. */ -static int + Return a (0, valid timestamp) pair if successful, an (error number, + unspecified timestamp) pair otherwise. */ +static struct err_time decode_time_components (enum timeform form, Lisp_Object high, Lisp_Object low, Lisp_Object usec, Lisp_Object psec, - struct lisp_time *result, double *dresult) + enum cform cform) { + Lisp_Object ticks, hz; + switch (form) { case TIMEFORM_INVALID: - return EINVAL; + return (struct err_time) { .err = EINVAL }; case TIMEFORM_TICKS_HZ: - if (INTEGERP (high) - && !NILP (Fnatnump (low)) && !BASE_EQ (low, make_fixnum (0))) - return decode_ticks_hz (high, low, result, dresult); - return EINVAL; + if (! (INTEGERP (high) + && !NILP (Fnatnump (low)) && !BASE_EQ (low, make_fixnum (0)))) + return (struct err_time) { .err = EINVAL }; + ticks = high; + hz = low; + break; case TIMEFORM_FLOAT: eassume (false); case TIMEFORM_NIL: - return decode_ticks_hz (timespec_ticks (current_timespec ()), - timespec_hz, result, dresult); - - default: + ticks = timespec_ticks (current_timespec ()); + hz = timespec_hz; break; - } - - if (! (INTEGERP (high) && INTEGERP (low) - && FIXNUMP (usec) && FIXNUMP (psec))) - return EINVAL; - EMACS_INT us = XFIXNUM (usec); - EMACS_INT ps = XFIXNUM (psec); - - /* Normalize out-of-range lower-order components by carrying - each overflow into the next higher-order component. */ - us += ps / 1000000 - (ps % 1000000 < 0); - mpz_t *s = &mpz[1]; - mpz_set_intmax (*s, us / 1000000 - (us % 1000000 < 0)); - mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); - mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); - ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); - us = us % 1000000 + 1000000 * (us % 1000000 < 0); - Lisp_Object hz; - switch (form) - { - case TIMEFORM_HI_LO: - /* Floats and nil were handled above, so it was an integer. */ - mpz_swap (mpz[0], *s); - hz = make_fixnum (1); - break; - - case TIMEFORM_HI_LO_US: - mpz_set_ui (mpz[0], us); - mpz_addmul_ui (mpz[0], *s, 1000000); - hz = make_fixnum (1000000); - break; + default: + if (! (INTEGERP (high) && INTEGERP (low) + && FIXNUMP (usec) && FIXNUMP (psec))) + return (struct err_time) { .err = EINVAL }; - case TIMEFORM_HI_LO_US_PS: { - #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX - unsigned long i = us; - mpz_set_ui (mpz[0], i * 1000000 + ps); - mpz_addmul_ui (mpz[0], *s, TRILLION); - #else - intmax_t i = us; - mpz_set_intmax (mpz[0], i * 1000000 + ps); - mpz_addmul (mpz[0], *s, ztrillion); - #endif - hz = trillion; + EMACS_INT us = XFIXNUM (usec); + EMACS_INT ps = XFIXNUM (psec); + + /* Normalize out-of-range lower-order components by carrying + each overflow into the next higher-order component. */ + us += ps / 1000000 - (ps % 1000000 < 0); + mpz_t *s = &mpz[1]; + mpz_set_intmax (*s, us / 1000000 - (us % 1000000 < 0)); + mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); + mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); + ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); + us = us % 1000000 + 1000000 * (us % 1000000 < 0); + + switch (form) + { + case TIMEFORM_HI_LO: + /* Floats and nil were handled above, so it was an integer. */ + mpz_swap (mpz[0], *s); + hz = make_fixnum (1); + break; + + case TIMEFORM_HI_LO_US: + mpz_set_ui (mpz[0], us); + mpz_addmul_ui (mpz[0], *s, 1000000); + hz = make_fixnum (1000000); + break; + + case TIMEFORM_HI_LO_US_PS: + { + #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX + unsigned long i = us; + mpz_set_ui (mpz[0], i * 1000000 + ps); + mpz_addmul_ui (mpz[0], *s, TRILLION); + #else + intmax_t i = us; + mpz_set_intmax (mpz[0], i * 1000000 + ps); + mpz_addmul (mpz[0], *s, ztrillion); + #endif + hz = trillion; + } + break; + + default: + eassume (false); + } + ticks = make_integer_mpz (); } break; - - default: - eassume (false); } - return decode_ticks_hz (make_integer_mpz (), hz, result, dresult); + return (struct err_time) { .time = decode_ticks_hz (ticks, hz, cform) }; } +/* A (Lisp timeform, C timestamp) pair. */ +struct form_time +{ + enum timeform form; + union c_time time; +}; + /* Decode a Lisp timestamp SPECIFIED_TIME that represents a time. - If DECODE_SECS_ONLY, ignore and do not validate any sub-second + Return a (form, time) pair that is the form of SPECIFIED-TIME + and the resulting C timestamp in CFORM form. + If CFORM == CFORM_SECS_ONLY, ignore and do not validate any sub-second components of an old-format SPECIFIED_TIME. - If RESULT is not null, store into *RESULT the converted time; - otherwise, store into *DRESULT the number of seconds since the - start of the POSIX Epoch. Unsuccessful calls may or may not store - results. - - Return the form of SPECIFIED-TIME. Signal an error if unsuccessful. */ -static enum timeform -decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, - struct lisp_time *result, double *dresult) + Signal an error if unsuccessful. */ +static struct form_time +decode_lisp_time (Lisp_Object specified_time, enum cform cform) { Lisp_Object high = make_fixnum (0); Lisp_Object low = specified_time; @@ -845,7 +872,7 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, { Lisp_Object low_tail = XCDR (low); low = XCAR (low); - if (! decode_secs_only) + if (cform != CFORM_SECS_ONLY) { if (CONSP (low_tail)) { @@ -877,27 +904,31 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, form = TIMEFORM_INVALID; } else if (FASTER_TIMEFNS && INTEGERP (specified_time)) - { - decode_ticks_hz (specified_time, make_fixnum (1), result, dresult); - return form; - } + return (struct form_time) + { + .form = form, + .time = decode_ticks_hz (specified_time, make_fixnum (1), cform) + }; else if (FLOATP (specified_time)) { double d = XFLOAT_DATA (specified_time); if (!isfinite (d)) time_error (isnan (d) ? EDOM : EOVERFLOW); - if (result) - decode_float_time (d, result); - else - *dresult = d; - return TIMEFORM_FLOAT; + return (struct form_time) + { + .form = TIMEFORM_FLOAT, + .time + = (cform == CFORM_DOUBLE + ? (union c_time) { .d = d } + : (union c_time) { .lt = decode_float_time (d) }) + }; } - int err = decode_time_components (form, high, low, usec, psec, - result, dresult); - if (err) - time_error (err); - return form; + struct err_time err_time + = decode_time_components (form, high, low, usec, psec, cform); + if (err_time.err) + time_error (err_time.err); + return (struct form_time) { .form = form, .time = err_time.time }; } /* Convert a non-float Lisp timestamp SPECIFIED_TIME to double. @@ -905,9 +936,7 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, double float_time (Lisp_Object specified_time) { - double t; - decode_lisp_time (specified_time, false, 0, &t); - return t; + return decode_lisp_time (specified_time, CFORM_DOUBLE).time.d; } /* Convert Z to time_t, returning true if it fits. */ @@ -1000,32 +1029,26 @@ lisp_to_timespec (struct lisp_time t) } /* Convert (HIGH LOW USEC PSEC) to struct timespec. - Return true if successful. */ -bool + Return a valid timestamp if successful, an invalid one otherwise. */ +struct timespec list4_to_timespec (Lisp_Object high, Lisp_Object low, - Lisp_Object usec, Lisp_Object psec, - struct timespec *result) + Lisp_Object usec, Lisp_Object psec) { - struct lisp_time t; - if (decode_time_components (TIMEFORM_HI_LO_US_PS, high, low, usec, psec, - &t, 0)) - return false; - *result = lisp_to_timespec (t); - return timespec_valid_p (*result); + struct err_time err_time + = decode_time_components (TIMEFORM_HI_LO_US_PS, high, low, usec, psec, + CFORM_TICKS_HZ); + return (err_time.err + ? invalid_timespec () + : lisp_to_timespec (err_time.time.lt)); } /* Decode a Lisp list SPECIFIED_TIME that represents a time. If SPECIFIED_TIME is nil, use the current time. - Signal an error if SPECIFIED_TIME does not represent a time. - If PFORM, store the time's form into *PFORM. */ + Signal an error if SPECIFIED_TIME does not represent a time. */ static struct lisp_time -lisp_time_struct (Lisp_Object specified_time, enum timeform *pform) +lisp_time_struct (Lisp_Object specified_time) { - struct lisp_time t; - enum timeform form = decode_lisp_time (specified_time, false, &t, 0); - if (pform) - *pform = form; - return t; + return decode_lisp_time (specified_time, CFORM_TICKS_HZ).time.lt; } /* Decode a Lisp list SPECIFIED_TIME that represents a time. @@ -1035,7 +1058,7 @@ lisp_time_struct (Lisp_Object specified_time, enum timeform *pform) struct timespec lisp_time_argument (Lisp_Object specified_time) { - struct lisp_time lt = lisp_time_struct (specified_time, 0); + struct lisp_time lt = lisp_time_struct (specified_time); struct timespec t = lisp_to_timespec (lt); if (! timespec_valid_p (t)) time_overflow (); @@ -1047,9 +1070,8 @@ lisp_time_argument (Lisp_Object specified_time) static time_t lisp_seconds_argument (Lisp_Object specified_time) { - struct lisp_time lt; - decode_lisp_time (specified_time, true, <, 0); - struct timespec t = lisp_to_timespec (lt); + struct form_time ft = decode_lisp_time (specified_time, CFORM_SECS_ONLY); + struct timespec t = lisp_to_timespec (ft.time.lt); if (! timespec_valid_p (t)) time_overflow (); return t.tv_sec; @@ -1096,9 +1118,11 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) static Lisp_Object time_arith (Lisp_Object a, Lisp_Object b, bool subtract) { - enum timeform aform, bform; - struct lisp_time ta = lisp_time_struct (a, &aform); - struct lisp_time tb = lisp_time_struct (b, &bform); + struct form_time + fta = decode_lisp_time (a, CFORM_TICKS_HZ), + ftb = decode_lisp_time (b, CFORM_TICKS_HZ); + enum timeform aform = fta.form, bform = ftb.form; + struct lisp_time ta = fta.time.lt, tb = ftb.time.lt; Lisp_Object ticks, hz; if (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz)) @@ -1239,8 +1263,8 @@ time_cmp (Lisp_Object a, Lisp_Object b) /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing ATICKS * BHZ to BTICKS * AHZ. */ - struct lisp_time ta = lisp_time_struct (a, 0); - struct lisp_time tb = lisp_time_struct (b, 0); + struct lisp_time ta = lisp_time_struct (a); + struct lisp_time tb = lisp_time_struct (b); mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); if (! (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz))) @@ -1517,7 +1541,7 @@ usage: (decode-time &optional TIME ZONE FORM) */) (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) { /* Compute broken-down local time LOCAL_TM from SPECIFIED_TIME and ZONE. */ - struct lisp_time lt = lisp_time_struct (specified_time, 0); + struct lisp_time lt = lisp_time_struct (specified_time); struct timespec ts = lisp_to_timespec (lt); if (! timespec_valid_p (ts)) time_overflow (); @@ -1695,8 +1719,7 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) } /* Let SEC = floor (LT.ticks / HZ), with SUBSECTICKS the remainder. */ - struct lisp_time lt; - decode_lisp_time (secarg, false, <, 0); + struct lisp_time lt = decode_lisp_time (secarg, CFORM_TICKS_HZ).time.lt; Lisp_Object hz = lt.hz, sec, subsecticks; if (FASTER_TIMEFNS && BASE_EQ (hz, make_fixnum (1))) { @@ -1765,8 +1788,8 @@ but new code should not rely on it. */) { /* FIXME: Any reason why we don't offer a `float` output format option as well, since we accept it as input? */ - struct lisp_time t; - enum timeform input_form = decode_lisp_time (time, false, &t, 0); + struct form_time form_time = decode_lisp_time (time, CFORM_TICKS_HZ); + struct lisp_time t = form_time.time.lt; form = (!NILP (form) ? maybe_remove_pos_from_symbol (form) : current_time_list ? Qlist : Qt); if (BASE_EQ (form, Qlist)) @@ -1776,7 +1799,7 @@ but new code should not rely on it. */) if (BASE_EQ (form, Qt)) form = t.hz; if (FASTER_TIMEFNS - && input_form == TIMEFORM_TICKS_HZ && BASE_EQ (form, XCDR (time))) + && form_time.form == TIMEFORM_TICKS_HZ && BASE_EQ (form, XCDR (time))) return time; return Fcons (lisp_time_hz_ticks (t, form), form); } commit ec1e300a215504bb9905a31145924d7f3d2cb9ab Author: Daniel Martín Date: Thu Jul 11 01:22:04 2024 +0200 Fix reference from buffer-stale-function docstring * lisp/files.el (buffer-stale-function): Fix reference to a non-existent Info node in doc string. (Bug#72049) diff --git a/lisp/files.el b/lisp/files.el index 66f47b4aa39..ca2d5b30cb4 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -6857,7 +6857,7 @@ For historical reasons, a value of nil means to use the default function. This should not be relied upon. For more information on how this variable is used by Auto Revert mode, -see Info node `(emacs)Supporting additional buffers'.") +see Info node `(elisp)Reverting'.") (defvar-local buffer-auto-revert-by-notification nil "Whether a buffer can rely on notification in Auto-Revert mode.