From f68e7a0a41188a7932544699ca23be7199ac3191 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 17 May 2026 09:05:13 +0300 Subject: [PATCH 001/112] ; Improve documentation of commands that move by compilation errors * lisp/simple.el (next-error): * lisp/progmodes/compile.el (compilation-next-error) (compilation-previous-error): Doc fixes. --- lisp/progmodes/compile.el | 17 ++++++++++++++--- lisp/simple.el | 5 ++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index 5222579592e..aaad8622c95 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el @@ -2821,13 +2821,23 @@ and runs `compilation-filter-hook'." (defun compilation-next-error (n &optional different-file pt) "Move point to the next error in the compilation buffer. -This function does NOT find the source line like \\[next-error]. +This function does NOT find the source line like \\[next-error], +but you can use \\[compilation-display-error] to find and +display the corresponding source code. Prefix arg N says how many error messages to move forwards (or backwards, if negative). +Where the current error ends and the next one begins is determined +by the rules from `compilation-error-regexp-alist' that matched +the compilation messages; this function moves point to where +the \\+`compilation-message' text property changes its value. +In general, all the messages that have the same line and column +numbers are considered parts of a single compilation message. + Optional arg DIFFERENT-FILE, if non-nil, means find next error for a file that is different from the current one. Optional arg PT, if non-nil, specifies the value of point to start -looking for the next message." +looking for the next message. +In interacvtive invocations, DIFFERENT-FILE and PT are always nil." (interactive "p") (or (compilation-buffer-p (current-buffer)) (error "Not in a compilation buffer")) @@ -2871,7 +2881,8 @@ looking for the next message." "Move point to the previous error in the compilation buffer. Prefix arg N says how many error messages to move backwards (or forwards, if negative). -Does NOT find the source line like \\[previous-error]." +Does NOT find the source line like \\[previous-error]. +This is like `compilation-next-error', but moves in the other direction." (interactive "p") (compilation-next-error (- n))) diff --git a/lisp/simple.el b/lisp/simple.el index 9346af5e8af..fd9ba28c762 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -362,7 +362,10 @@ until you use it in some other buffer that uses Compilation mode or Compilation Minor mode. To control which errors are matched, customize the variable -`compilation-error-regexp-alist'." +`compilation-error-regexp-alist'. The rules there determine the +boundaries between error messages. In general, messages that share +the same line and column numbers are considered parts of a single +error message." (interactive "P") (if (consp arg) (setq reset t arg nil)) (let ((buffer (next-error-find-buffer))) From 1832a93547bf71f94bdefba01e69e25836443348 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 17 May 2026 10:37:01 +0300 Subject: [PATCH 002/112] ; * src/fns.c (Fequal): Doc fix. --- src/fns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fns.c b/src/fns.c index 1041938531c..1158f100ea0 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2804,7 +2804,8 @@ DEFUN ("equal", Fequal, Sequal, 2, 2, 0, doc: /* Return t if two Lisp objects have similar structure and contents. They must have the same data type. Conses are compared by comparing the cars and the cdrs. -Vectors and strings are compared element by element. +Vectors and strings are compared element by element (so text properties +of strings are ignored). Numbers are compared via `eql', so integers do not equal floats. \(Use `=' if you want integers and floats to be able to be equal.) Symbols must match exactly. */) From d89054627c4ead0b35c09e895884d4cfca926e24 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 17 May 2026 10:57:53 +0300 Subject: [PATCH 003/112] Fix updates of embedded formulas by 'calc-embedded-update-formula' * lisp/calc/calc-embed.el (calc-embedded-update): Use 'buffer-substring' to better track the string representation of the formula when it is being edited. Suggested by gnu@publik.slmail.me. Also, update commentary. (Bug#80901) --- lisp/calc/calc-embed.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/calc/calc-embed.el b/lisp/calc/calc-embed.el index 7b3c5daaede..631efe9069b 100644 --- a/lisp/calc/calc-embed.el +++ b/lisp/calc/calc-embed.el @@ -103,7 +103,8 @@ ;; 3 Bottom of current formula (marker). ;; 4 Top of current formula's delimiters (marker). ;; 5 Bottom of current formula's delimiters (marker). -;; 6 String representation of current formula. +;; 6 String representation of current formula (actually, the +;; buffer-substring between positions given by 2 and 3 above. ;; 7 Non-nil if formula is embedded within a single line. ;; 8 Internal representation of current formula. ;; 9 Variable assigned by this formula, or nil. @@ -1140,7 +1141,8 @@ The command \\[yank] can retrieve it from there." (insert str) (set-marker (aref info 3) (+ (point) adjbot)) (set-marker (aref info 5) (+ (point) delta)) - (aset info 6 str)))))) + (aset info 6 (buffer-substring (aref info 2) + (aref info 3)))))))) (if (eq (car-safe val) 'calcFunc-evalto) (progn (setq evalled (nth 2 val) From b7825c3a271e72f46a4b9712ec78f8a49cb9503d Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sun, 17 May 2026 18:21:49 +0200 Subject: [PATCH 004/112] Fix auth-source-backends-parse * lisp/auth-source.el (auth-source-backend-parse): Drop backends of type `ignore'. (Bug#81024) (auth-source-backends): Drop duplicate backends. --- lisp/auth-source.el | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lisp/auth-source.el b/lisp/auth-source.el index bc660b2f4ab..f541dd3d141 100644 --- a/lisp/auth-source.el +++ b/lisp/auth-source.el @@ -361,9 +361,19 @@ soon as a function returns non-nil.") (defun auth-source-backend-parse (entry) "Create an `auth-source-backend' from an ENTRY in `auth-sources'." - (let ((backend - (run-hook-with-args-until-success 'auth-source-backend-parser-functions - entry))) + (let* ((auth-source-backend-parser-functions + ;; The functions shall drop backends of type `ignore', in + ;; order to let the hook continue. + (mapcar + (lambda (fun) + `(lambda (entry) + (and-let* ((result (funcall ',fun entry)) + ((not (eq (slot-value result 'type) 'ignore))) + result)))) + auth-source-backend-parser-functions)) + (backend + (run-hook-with-args-until-success + 'auth-source-backend-parser-functions entry))) (unless backend ;; none of the parsers worked @@ -378,12 +388,12 @@ soon as a function returns non-nil.") "List of usable backends from `auth-sources'. Filter out backends with type `ignore'. A fallback backend is added to ensure, that at least `read-passwd' is called." - `(or (seq-keep + `(or (seq-uniq (seq-keep (lambda (entry) (and-let* ((backend (auth-source-backend-parse entry)) ((not (eq (slot-value backend 'type) 'ignore))) backend))) - auth-sources) + auth-sources)) ;; Fallback. (list (auth-source-backend :source "" From 0977d5915d1918b0c9e3e37971b4e1b6484425ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 17 May 2026 13:01:48 +0100 Subject: [PATCH 005/112] Eglot: add left-fringe code action indicator (bug#80326) The fringe indicator uses a custom lightning-bolt bitmap, an alternative to the margin indicator on GUI frames. It is non-interactive, however. * lisp/progmodes/eglot.el (eglot--fringe-action): New fringe bitmap. (eglot-code-action-indications): Add 'left-fringe' to default value and to docstring. Update incompatibility note. (eglot-code-action-suggestion): Handle 'left-fringe' indication. --- lisp/progmodes/eglot.el | 49 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 3d2c267650e..07d64d8209c 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -595,15 +595,16 @@ servers." :type 'boolean) (defface eglot-code-action-indicator-face - '((t (:inherit font-lock-escape-face :weight bold))) + '((t (:inherit warning :weight bold))) "Face used for code action suggestions.") (defcustom eglot-code-action-indications - '(eldoc-hint margin) + '(eldoc-hint left-fringe margin) "How Eglot indicates there's are code actions available at point. Value is a list of symbols, more than one can be specified: - `eldoc-hint': ElDoc is used to hint about at-point actions; +- `left-fringe': A special indicator appears on the left fringe; - `margin': A special indicator appears in the margin; - `nearby': A special indicator appears near point; - `mode-line': A special indicator appears in the mode-line. @@ -612,10 +613,13 @@ If the list is empty, Eglot will not hint about code actions at point. Note additionally: -- `margin' and `nearby' are incompatible. If both are specified, - the latter takes priority; -- `mode-line' only works if `eglot-mode-line-action-suggestion' exists in - `eglot-mode-line-format' (which see)." +- Some values are incompatible; if one or more of `nearby', + `left-fringe' and `margin' are specified, earlier values take + precedence. +- The indicators for many of these are customizable via + `eglot-code-action-indicator' (which see), except for `left-fringe'. +- `mode-line' only works if `eglot-mode-line-action-suggestion' exists + in `eglot-mode-line-format' (which see)." :type '(set :tag "Tick the ones you're interested in" (const :tag "ElDoc textual hint" eldoc-hint) @@ -4720,6 +4724,19 @@ at point. With prefix argument, prompt for ACTION-KIND." (eglot--code-action eglot-code-action-rewrite "refactor.rewrite") (eglot--code-action eglot-code-action-quickfix "quickfix") +(define-fringe-bitmap 'eglot--fringe-action + [#b00000111 + #b00001110 + #b00011100 + #b00111000 + #b01111111 + #b00001110 + #b01011100 + #b01111000 + #b01110000 + #b01111000] + nil nil 'center) + (defun eglot-code-action-suggestion (cb &rest _ignored) "A member of `eldoc-documentation-functions', for suggesting actions." (when (and (eglot-server-capable :codeActionProvider) @@ -4759,13 +4776,19 @@ at point. With prefix argument, prompt for ACTION-KIND." (overlay-put ov 'before-string - (cond ((memq 'nearby eglot-code-action-indications) - tooltip) - ((memq 'margin eglot-code-action-indications) - (propertize "⚡" - 'display - `((margin left-margin) - ,tooltip))))) + (cond + ((memq 'nearby eglot-code-action-indications) + tooltip) + ((and + (memq 'left-fringe eglot-code-action-indications) + (< 0 (nth 0 (window-fringes)))) + (propertize + "⚡" 'display `(left-fringe + eglot--fringe-action + eglot-code-action-indicator-face))) + ((memq 'margin eglot-code-action-indications) + (propertize + "⚡" 'display `((margin left-margin) ,tooltip))))) (setq eglot--suggestion-overlay ov)))) (when use-text-p (funcall cb blurb)))) :hint :textDocument/codeAction) From 36036e71c0c255fc80f38672ba639cc66b0c90ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 17 May 2026 15:02:57 +0100 Subject: [PATCH 006/112] Jsonrpc: migrate more tests to Python subprocess fixtures All tests now use 'jsonrpc--with-python-fixture' with a Python3 subprocess instead of the in-Emacs TCP server. Changed the "harakiri" method to be a request instead of a notification for to reduce chance of "Sentinel hasn't run" warning. The two in-Emacs-RPC-specific error tests ('errors-with--32601' and 'signals-an--32603-JSONRPC-error') are dropped with the fixture itself, as the error paths they exercise are internal to the Emacs Lisp dispatcher and have no direct Python equivalent. They will have to be re-done later on in other form. * test/lisp/jsonrpc-resources/server-emacsrpc.py: New file. * test/lisp/jsonrpc-resources/server-anxious-nested.py: Use new harakiri. * test/lisp/jsonrpc-resources/server-emacsrpc.py: Use new harakiri. * test/lisp/jsonrpc-resources/server-harakiri.py: Use new harakiri. * test/lisp/jsonrpc-resources/server-remote-during-sync-1.py: Use new harakiri. * test/lisp/jsonrpc-resources/server-remote-during-sync-2.py: Use new harakiri. * test/lisp/jsonrpc-resources/server-remote-error.py: Use new harakiri. * test/lisp/jsonrpc-resources/common.py (harakiri): New definition. * test/lisp/jsonrpc-tests.el (jsonrpc--with-python-fixture): Rework, move up. (jsonrpc-connection-ready-p): Move up. (jsonrpc--call-with-emacsrpc-fixture) (jsonrpc--with-emacsrpc-fixture) (errors-with--32601) (signals-an--32603-JSONRPC-error): Remove. (returns-3, times-out, doesnt-time-out, stretching-it-but-works) (deferred-action-toolate, deferred-action-intime) (deferred-action-complex-tests): Migrate to Python fixture. (scontrol-remote-during-sync-1, scontrol-remote-during-sync-2) (scontrol-anxious-nested, scontrol-remote-error) (shutdown-clean-after-notification): Tweak. --- test/lisp/jsonrpc-resources/common.py | 9 + .../server-anxious-nested.py | 6 +- .../lisp/jsonrpc-resources/server-emacsrpc.py | 54 ++++ .../lisp/jsonrpc-resources/server-harakiri.py | 6 +- .../server-remote-during-sync-1.py | 6 +- .../server-remote-during-sync-2.py | 6 +- .../jsonrpc-resources/server-remote-error.py | 6 +- test/lisp/jsonrpc-tests.el | 270 ++++++------------ 8 files changed, 167 insertions(+), 196 deletions(-) create mode 100644 test/lisp/jsonrpc-resources/server-emacsrpc.py diff --git a/test/lisp/jsonrpc-resources/common.py b/test/lisp/jsonrpc-resources/common.py index 6bcc1db8bba..7b103aba0c3 100644 --- a/test/lisp/jsonrpc-resources/common.py +++ b/test/lisp/jsonrpc-resources/common.py @@ -30,3 +30,12 @@ def write_msg(msg): def log(text): """Write a log line to stderr.""" print(f'[test-server] {text}', file=sys.stderr, flush=True) + +def harakiri(msg): + """Maybe handle harakiri request/notif in msg.""" + if msg.get('method') == 'harakiri': + log('-> very clean harakiri') + if (mid := msg.get('id')) is not None: + write_msg({'jsonrpc': '2.0', 'id': mid, 'result': True}) + return True + return False diff --git a/test/lisp/jsonrpc-resources/server-anxious-nested.py b/test/lisp/jsonrpc-resources/server-anxious-nested.py index 8169b0936d1..970196e619c 100755 --- a/test/lisp/jsonrpc-resources/server-anxious-nested.py +++ b/test/lisp/jsonrpc-resources/server-anxious-nested.py @@ -15,7 +15,7 @@ import os import sys sys.path.insert(0, os.path.dirname(__file__)) -from common import read_msg, write_msg, log +from common import read_msg, write_msg, log, harakiri def main(): @@ -26,9 +26,7 @@ def main(): mid = lr1.get('id') method = lr1.get('method') log(f'<- {method or "(response)"} id={mid}') - if method == 'harakiri': - log('-> very clean harakiri') - break + if harakiri(lr1): break elif method == 'LR1': # Send RR1, then immediately respond to LR1 without awaiting # anything. The response-to-LR1 will be queued as anxious on the diff --git a/test/lisp/jsonrpc-resources/server-emacsrpc.py b/test/lisp/jsonrpc-resources/server-emacsrpc.py new file mode 100644 index 00000000000..22923f5b5f2 --- /dev/null +++ b/test/lisp/jsonrpc-resources/server-emacsrpc.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""General-purpose JSONRPC server for jsonrpc.el tests. + +Handles arithmetic (+ - * /), sit-for, vconcat, append, and ignore, +mirroring the methods the in-process Emacs RPC server supports. +""" +import functools +import operator +import os +import sys +import time + +sys.path.insert(0, os.path.dirname(__file__)) +from common import log, read_msg, write_msg, harakiri + +HANDLERS = { + '+': lambda p: sum(p), + '-': lambda p: functools.reduce(operator.sub, p), + '*': lambda p: functools.reduce(operator.mul, p), + '/': lambda p: functools.reduce(operator.truediv, p), + 'vconcat': lambda p: sum(p, []), + 'append': lambda p: sum(p, []), + 'sit-for': lambda p: time.sleep(p[0]), + 'ignore': lambda _: None, +} + + +def main(): + while True: + msg = read_msg() + if msg is None: + break + mid = msg.get('id') + method = msg.get('method') + log(f'<- {method or "(response)"} id={mid}') + if harakiri(msg): break + if method is None or mid is None: + continue + handler = HANDLERS.get(method) + if handler is None: + write_msg({'jsonrpc': '2.0', 'id': mid, + 'error': {'code': -32601, 'message': 'Method not found'}}) + else: + try: + result = handler(msg.get('params', [])) + write_msg({'jsonrpc': '2.0', 'id': mid, 'result': result}) + log(f'-> (response {method}) id={mid}') + except Exception as exc: + write_msg({'jsonrpc': '2.0', 'id': mid, + 'error': {'code': -32603, 'message': str(exc)}}) + + +if __name__ == '__main__': + main() diff --git a/test/lisp/jsonrpc-resources/server-harakiri.py b/test/lisp/jsonrpc-resources/server-harakiri.py index c20a3fbdaee..ee7eae54073 100755 --- a/test/lisp/jsonrpc-resources/server-harakiri.py +++ b/test/lisp/jsonrpc-resources/server-harakiri.py @@ -5,7 +5,7 @@ """ import os, sys sys.path.insert(0, os.path.dirname(__file__)) -from common import read_msg, log +from common import read_msg, log, harakiri def main(): @@ -15,9 +15,7 @@ def main(): break method = msg.get('method') log(f'<- {method or "(response)"} id={msg.get("id")}') - if method == 'harakiri': - log('-> very clean harakiri') - break + if harakiri(msg): break if __name__ == '__main__': diff --git a/test/lisp/jsonrpc-resources/server-remote-during-sync-1.py b/test/lisp/jsonrpc-resources/server-remote-during-sync-1.py index b8cb549bbd5..d9d116e256e 100755 --- a/test/lisp/jsonrpc-resources/server-remote-during-sync-1.py +++ b/test/lisp/jsonrpc-resources/server-remote-during-sync-1.py @@ -11,7 +11,7 @@ import os import sys sys.path.insert(0, os.path.dirname(__file__)) -from common import read_msg, write_msg, log +from common import read_msg, write_msg, log, harakiri def main(): @@ -22,9 +22,7 @@ def main(): mid = msg.get('id') method = msg.get('method') log(f'<- {method or "(response)"} id={mid}') - if method == 'harakiri': - log('-> very clean harakiri') - break + if harakiri(msg): break elif method == 'LR1': # Send RR1 request write_msg({'jsonrpc': '2.0', 'id': 1000, diff --git a/test/lisp/jsonrpc-resources/server-remote-during-sync-2.py b/test/lisp/jsonrpc-resources/server-remote-during-sync-2.py index e6250a0553b..77e9a3eb005 100755 --- a/test/lisp/jsonrpc-resources/server-remote-during-sync-2.py +++ b/test/lisp/jsonrpc-resources/server-remote-during-sync-2.py @@ -11,7 +11,7 @@ import os import sys sys.path.insert(0, os.path.dirname(__file__)) -from common import read_msg, write_msg, log +from common import read_msg, write_msg, log, harakiri def main(): @@ -22,9 +22,7 @@ def main(): mid = msg.get('id') method = msg.get('method') log(f'<- {method or "(response)"} id={mid}') - if method == 'harakiri': - log('-> very clean harakiri') - break + if harakiri(msg): break elif method == 'LR1': # Send RR1 request write_msg({'jsonrpc': '2.0', 'id': 1000, diff --git a/test/lisp/jsonrpc-resources/server-remote-error.py b/test/lisp/jsonrpc-resources/server-remote-error.py index 00c907e189b..ea1dfdc7e96 100755 --- a/test/lisp/jsonrpc-resources/server-remote-error.py +++ b/test/lisp/jsonrpc-resources/server-remote-error.py @@ -13,7 +13,7 @@ """ import os, sys sys.path.insert(0, os.path.dirname(__file__)) -from common import read_msg, write_msg, log +from common import read_msg, write_msg, log, harakiri def main(): @@ -24,9 +24,7 @@ def main(): mid = msg.get('id') method = msg.get('method') log(f'<- {method or "(response)"} id={mid}') - if method == 'harakiri': - log('-> very clean harakiri') - break + if harakiri(msg): break elif method == 'LR1': # Send badMethod BEFORE responding to LR1; the client # rdispatcher will signal a jsonrpc-error for it. diff --git a/test/lisp/jsonrpc-tests.el b/test/lisp/jsonrpc-tests.el index cdb4e04fc39..ec85210c091 100644 --- a/test/lisp/jsonrpc-tests.el +++ b/test/lisp/jsonrpc-tests.el @@ -41,121 +41,55 @@ (defclass jsonrpc--test-client (jsonrpc--test-endpoint) ((hold-deferred :initform t :accessor jsonrpc--hold-deferred))) -(defun jsonrpc--call-with-emacsrpc-fixture (fn) - "Do work for `jsonrpc--with-emacsrpc-fixture'. Call FN." - (let* (listen-server endpoint) - (unwind-protect - (progn - (setq listen-server - (make-network-process - :name "Emacs RPC server" :server t :host "localhost" - :service (if (version<= emacs-version "26.1") - 44444 - ;; 26.1 can automatically find ports if - ;; one passes 0 here. - 0) - :log (lambda (listen-server client _message) - (push - (make-instance - 'jsonrpc--test-endpoint - :name (process-name client) - :process client - :request-dispatcher - (lambda (_endpoint method params) - (unless (memq method '(+ - * / vconcat append - sit-for ignore)) - (signal 'jsonrpc-error - '((jsonrpc-error-message - . "Sorry, this isn't allowed") - (jsonrpc-error-code . -32601)))) - (apply method (append params nil))) - :on-shutdown - (lambda (conn) - (setf (jsonrpc--shutdown-complete-p conn) t))) - (process-get listen-server 'handlers))))) - (setq endpoint - (make-instance - 'jsonrpc--test-client - :process - (open-network-stream "JSONRPC test tcp endpoint" - nil "localhost" - (process-contact listen-server - :service)) - :on-shutdown - (lambda (conn) - (setf (jsonrpc--shutdown-complete-p conn) t)))) - (funcall fn endpoint)) - (unwind-protect - (when endpoint - (kill-buffer (jsonrpc--events-buffer endpoint)) - (jsonrpc-shutdown endpoint)) - (when listen-server - (cl-loop do (delete-process listen-server) - while (progn (accept-process-output nil 0.1) - (process-live-p listen-server)) - do (jsonrpc--message - "test listen-server is still running, waiting")) - (cl-loop for handler in (process-get listen-server 'handlers) - do (ignore-errors (jsonrpc-shutdown handler))) - (mapc #'kill-buffer - (mapcar #'jsonrpc--events-buffer - (process-get listen-server 'handlers)))))))) -(cl-defmacro jsonrpc--with-emacsrpc-fixture ((endpoint-sym) &body body) +;;; Tests using Python subprocesses +;;; + +(defconst jsonrpc--test-dir + (file-name-directory (or load-file-name buffer-file-name)) + "Directory of this test file, captured at load time.") + +(cl-defmacro jsonrpc--with-python-fixture ((script conn &rest initargs) &body body) + "Start SCRIPT under python3 as a pipe subprocess, bind connection to CONN. +SCRIPT is a path relative to this file's directory. +INITARGS are passed to `make-instance' for `jsonrpc--test-client'." (declare (indent 1)) - `(jsonrpc--call-with-emacsrpc-fixture (lambda (,endpoint-sym) ,@body))) - -(ert-deftest returns-3 () - "A basic test for adding two numbers in our test RPC." - (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) - (should (= 3 (jsonrpc-request conn '+ [1 2]))))) - -(ert-deftest errors-with--32601 () - "Errors with -32601" - (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) - (condition-case err - (progn - (jsonrpc-request conn 'delete-directory "~/tmp") - (ert-fail "A `jsonrpc-error' should have been signaled!")) - (jsonrpc-error - (should (= -32601 (cdr (assoc 'jsonrpc-error-code (cdr err))))))))) - -(ert-deftest signals-an--32603-JSONRPC-error () - "Signals an -32603 JSONRPC error." - (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) - (condition-case err - (let ((jsonrpc-inhibit-debug-on-error t)) - (jsonrpc-request conn '+ ["a" 2]) - (ert-fail "A `jsonrpc-error' should have been signaled!")) - (jsonrpc-error - (should (= -32603 (cdr (assoc 'jsonrpc-error-code (cdr err))))))))) - -(ert-deftest times-out () - "Request for 3-sec sit-for with 1-sec timeout times out." - (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) - (should-error - (jsonrpc-request conn 'sit-for [3] :timeout 1)))) - -(ert-deftest doesnt-time-out () - :tags '(:expensive-test) - "Request for 1-sec sit-for with 2-sec timeout succeeds." - (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) - (jsonrpc-request conn 'sit-for [1] :timeout 2))) - -(ert-deftest stretching-it-but-works () - "Vector of numbers or vector of vector of numbers are serialized." - (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) - ;; (vconcat [1 2 3] [3 4 5]) => [1 2 3 3 4 5] which can be - ;; serialized. - (should (equal - [1 2 3 3 4 5] - (jsonrpc-request conn 'vconcat [[1 2 3] [3 4 5]]))))) + `(let ((,conn nil)) + (skip-unless (executable-find "python3")) + (unwind-protect + (progn + (setq ,conn + (make-instance + 'jsonrpc--test-client + :name "jsonrpc-python-test" + :process (make-process + :name "jsonrpc-python-test" + :command (list "python3" + (expand-file-name + ,script + jsonrpc--test-dir)) + :connection-type 'pipe + :noquery t) + ,@initargs)) + (with-timeout (5 + (when ,conn + (let ((buf (jsonrpc--events-buffer ,conn))) + (when (buffer-live-p buf) + (if noninteractive + (progn + (message "contents of `%s':" (buffer-name buf)) + (princ (with-current-buffer buf (buffer-string)) + #'external-debugging-output)) + (message "Preserved for inspection: %s" + (buffer-name buf)))))) + (ert-fail "Test timed out after 5s")) + ,@body)) + (when ,conn + (ignore-errors + (jsonrpc-request ,conn 'harakiri nil :timeout 1) + (accept-process-output nil 0.1) + (kill-buffer (jsonrpc--events-buffer ,conn)) + (jsonrpc-shutdown ,conn)))))) (cl-defmethod jsonrpc-connection-ready-p ((conn jsonrpc--test-client) what) @@ -163,11 +97,46 @@ (or (not (string-match "deferred" what)) (not (jsonrpc--hold-deferred conn))))) +(ert-deftest returns-3 () + "A basic test for adding two numbers in our test RPC." + (skip-when (eq system-type 'windows-nt)) + (jsonrpc--with-python-fixture + ("jsonrpc-resources/server-emacsrpc.py" conn) + (should (= 3 (jsonrpc-request conn '+ [1 2]))))) + +(ert-deftest times-out () + "Request for 3-sec sit-for with 1-sec timeout times out." + (skip-when (eq system-type 'windows-nt)) + (jsonrpc--with-python-fixture + ("jsonrpc-resources/server-emacsrpc.py" conn) + (should-error + (jsonrpc-request conn 'sit-for [3] :timeout 1)))) + +(ert-deftest doesnt-time-out () + :tags '(:expensive-test) + "Request for 1-sec sit-for with 2-sec timeout succeeds." + (skip-when (eq system-type 'windows-nt)) + (jsonrpc--with-python-fixture + ("jsonrpc-resources/server-emacsrpc.py" conn) + (jsonrpc-request conn 'sit-for [1] :timeout 2))) + +(ert-deftest stretching-it-but-works () + "Vector of numbers or vector of vector of numbers are serialized." + (skip-when (eq system-type 'windows-nt)) + (jsonrpc--with-python-fixture + ("jsonrpc-resources/server-emacsrpc.py" conn) + ;; (vconcat [1 2 3] [3 4 5]) => [1 2 3 3 4 5] which can be + ;; serialized. + (should (equal + [1 2 3 3 4 5] + (jsonrpc-request conn 'vconcat [[1 2 3] [3 4 5]]))))) + (ert-deftest deferred-action-toolate () :tags '(:expensive-test) "Deferred request fails because no one clears the flag." (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) + (jsonrpc--with-python-fixture + ("jsonrpc-resources/server-emacsrpc.py" conn) (should-error (jsonrpc-request conn '+ [1 2] :deferred "deferred-testing" :timeout 0.5) @@ -182,7 +151,8 @@ (skip-when (eq system-type 'windows-nt)) ;; Send an async request, which returns immediately. However the ;; success fun which sets the flag only runs after some time. - (jsonrpc--with-emacsrpc-fixture (conn) + (jsonrpc--with-python-fixture + ("jsonrpc-resources/server-emacsrpc.py" conn) (jsonrpc-async-request conn 'sit-for [0.5] :success-fn @@ -199,7 +169,8 @@ :tags '(:expensive-test) "Test a more complex situation with deferred requests." (skip-when (eq system-type 'windows-nt)) - (jsonrpc--with-emacsrpc-fixture (conn) + (jsonrpc--with-python-fixture + ("jsonrpc-resources/server-emacsrpc.py" conn) (let (n-deferred-1 n-deferred-2 second-deferred-went-through-p) @@ -252,60 +223,11 @@ (should (eq 2 n-deferred-2)) (should (eq 0 (hash-table-count (jsonrpc--deferred-actions conn))))))) - -;;; Tests using Python subprocesses (scontrol / anxious mechanism) -;;; - -(defconst jsonrpc--test-dir - (file-name-directory (or load-file-name buffer-file-name)) - "Directory of this test file, captured at load time.") - -(cl-defmacro jsonrpc--with-python-fixture ((script conn &rest initargs) &body body) - "Start SCRIPT under python3 as a pipe subprocess, bind connection to CONN. -SCRIPT is a path relative to this file's directory. -INITARGS are passed to `make-instance' for `jsonrpc-process-connection'." - (declare (indent 1)) - `(let ((,conn nil)) - (unwind-protect - (progn - (setq ,conn - (make-instance - 'jsonrpc-process-connection - :name "jsonrpc-python-test" - :process (make-process - :name "jsonrpc-python-test" - :command (list "python3" - (expand-file-name - ,script - jsonrpc--test-dir)) - :connection-type 'pipe - :noquery t) - ,@initargs)) - (with-timeout (5 - (when ,conn - (let ((buf (jsonrpc--events-buffer ,conn))) - (when (buffer-live-p buf) - (if noninteractive - (progn - (message "contents of `%s':" (buffer-name buf)) - (princ (with-current-buffer buf (buffer-string)) - #'external-debugging-output)) - (message "Preserved for inspection: %s" - (buffer-name buf)))))) - (ert-fail "Test timed out after 5s")) - ,@body)) - (when ,conn - (ignore-errors - (jsonrpc-notify ,conn 'harakiri nil) - (kill-buffer (jsonrpc--events-buffer ,conn)) - (jsonrpc-shutdown ,conn)))))) - (ert-deftest scontrol-remote-during-sync-1 () "Anxious local continuations. Endpoint sends a remote request RR1 on LR1, then replies to LR1 immediately before waiting for RR1 to resolve. This is what JETLS does (bug#80623)." - (skip-unless (executable-find "python3")) (skip-when (eq system-type 'windows-nt)) (jsonrpc--with-python-fixture ("jsonrpc-resources/server-remote-during-sync-1.py" conn @@ -322,7 +244,6 @@ Exactly the same test as 2, but different endpoint, which now still sends RR1 on LR1 but now waits for RR1 to resolve before replying to LR1. This is what GoPls does (bug#80623)." - (skip-unless (executable-find "python3")) (skip-when (eq system-type 'windows-nt)) (jsonrpc--with-python-fixture ("jsonrpc-resources/server-remote-during-sync-2.py" conn @@ -337,7 +258,6 @@ This is what GoPls does (bug#80623)." "Nested anxious continuations Two local sync requests LR1 and LR2 with a remote RR1 in between. Vaguely similar to Julia's JETLS (bug#80623), but more complex." - (skip-unless (executable-find "python3")) (skip-when (eq system-type 'windows-nt)) (let (lr2-result completed) (jsonrpc--with-python-fixture @@ -349,7 +269,8 @@ Vaguely similar to Julia's JETLS (bug#80623), but more complex." (setq lr2-result (jsonrpc-request conn 'LR2 [] :timeout 5)) (push "lr2" completed) - (push "rr1" completed)) + (push "rr1" completed) + "rr1-ok") (_ (error "unexpected method: %s" method))))) (should (equal "lr1-ok" (jsonrpc-request conn 'LR1 [] :timeout 5))) (push "lr1" completed) @@ -358,7 +279,6 @@ Vaguely similar to Julia's JETLS (bug#80623), but more complex." (ert-deftest scontrol-remote-error () "Anxious continuation even when rdispatcher signals errors." - (skip-unless (executable-find "python3")) (skip-when (eq system-type 'windows-nt)) (jsonrpc--with-python-fixture ("jsonrpc-resources/server-remote-error.py" conn @@ -372,10 +292,9 @@ Vaguely similar to Julia's JETLS (bug#80623), but more complex." (_ (error "unexpected method: %s" method))))) (should (equal "ok" (jsonrpc-request conn 'LR1 [] :timeout 5))))) -(ert-deftest shutdown-clean-after-notification () - "Server exits cleanly after harakiri notification. +(ert-deftest shutdown-clean-after-request () + "Server exits cleanly after harakiri request. `jsonrpc-shutdown' should not emit a \"Sentinel hasn't run\" warning." - (skip-unless (executable-find "python3")) (skip-when (eq system-type 'windows-nt)) (let (warned) (cl-letf (((symbol-function 'jsonrpc--warn) @@ -383,10 +302,9 @@ Vaguely similar to Julia's JETLS (bug#80623), but more complex." (setq warned (apply #'format fmt args))))) (jsonrpc--with-python-fixture ("jsonrpc-resources/server-harakiri.py" conn) - (jsonrpc-notify conn 'harakiri nil) - ;; Give the server time to exit before shutdown checks the sentinel. - (accept-process-output nil 0.3) - (jsonrpc-shutdown conn))) + (jsonrpc-request conn 'harakiri nil :timeout 3) + (jsonrpc-shutdown conn) + (setq conn nil))) (should-not warned))) (provide 'jsonrpc-tests) From 6c1829bf4c5acd3e676b0cb802a096d36fdd33bc Mon Sep 17 00:00:00 2001 From: Brian Leung Date: Sun, 17 May 2026 19:22:39 +0100 Subject: [PATCH 007/112] Eglot: fix thinko in recent markdown-related commit (bug#81063) * lisp/progmodes/eglot.el (eglot--format-markup): Correct return value for gfm-view-mode. --- lisp/progmodes/eglot.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 07d64d8209c..02fc4615acf 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -2255,12 +2255,13 @@ If MODE, force MODE to be used for fontifying MARKUP." for to = (or (next-single-property-change from 'invisible) (point-max)) when inv - do (put-text-property from to 'invisible t))) + do (put-text-property from to 'invisible t) + finally return (buffer-string))) (calc2 (forced-mode) (cond (forced-mode `(,forced-mode)) (built-in `(,#'markdown-ts-view-mode)) - ((fboundp 'gfm-view-mode) `(,#'gfm-view-mode #'gfm-extract)) + ((fboundp 'gfm-view-mode) `(,#'gfm-view-mode ,#'gfm-extract)) (t `(#'text-mode)))) (calc (s &optional (forced-mode mode) &aux (x (calc2 forced-mode))) (setq string s render (car x) extract (or (cadr x) #'buffer-string)))) From 1d7d6ffedbcefaf691777d81f40846ba62ffdee5 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 18 May 2026 16:36:05 +0300 Subject: [PATCH 008/112] ; * etc/PROBLEMS: Fix entries about display of Emoji on TTY (bug#81052). --- etc/PROBLEMS | 72 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 2ae82292e04..b619c6e7f37 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -2649,6 +2649,45 @@ all such characters will look the same on display, and the only way of knowing what is the real codepoint in the buffer is to go to the character and type "C-u C-x =". +*** Display problems with Emoji on text terminals + +Some text-mode terminals cause problems with Emoji sequences: when +displaying them, the Emacs text-mode frame could show gaps, misalignment +between the display and cursor motion, and other visual artifacts and +display problems. + +This can happen if the terminal and Emacs differ in their notions of how +many columns (a.k.a. "character cells") a given sequence of characters +takes on the screen when displayed. As one example, Emoji sequences +that begin with a non-Emoji character and end in U+FE0F VARIATION +SELECTOR 16 are composed on display into an Emoji glyph, but the width +of this glyph is up to the terminal and the font it uses to show the +Emoji. If the non-Emoji character that begins the sequence has the +width 1, Emacs will think that its composition with VS-16 also takes 1 +column on the screen, because VS-16 has width of zero. But some +terminals which support Emoji sequences will show a double-width Emoji +glyph in this case, without any way for Emacs to know that. This causes +cursor addressing to get out of sync and eventually messes up the +display. In particular, Kitty, Alacritty, Ghostty, and some other +terminal emulators are known to behave like that. + +Similar problems can happen with composition of characters other than +Emoji. + +The solution is to disable 'auto-composition-mode' on these +terminals, for example, like this: + + (setq auto-composition-mode "alacritty") + +This disables 'auto-composition-mode' on frames that display on +terminals of the named type. More generally, customizing the +'auto-composition-mode' variable to have as value a string that the +'tty-type' function returns on a terminal will disable compositions in +windows shown on terminals of that type. (You can also disable +'auto-composition-mode' globally, if all your frames are on terminals +that have this problem, by setting 'auto-composition-mode' to the nil +value.) + *** Messed-up display on the Kitty text terminal This terminal has its own peculiar ideas about display of unusual @@ -2674,33 +2713,6 @@ Another workaround is to set 'nobreak-char-ascii-display' to a non-nil value, which will cause any non-ASCII space and hyphen characters to be displayed as their ASCII counterparts, with a special face. -Kitty also differs from many other character terminals in how it -handles character compositions. As one example, Emoji sequences that -begin with a non-Emoji character and end in U+FE0F VARIATION SELECTOR -16 should be composed into an Emoji glyph; Kitty assumes that all such -Emoji glyphs have 2-column width, whereas Emacs and many other text -terminals display them as 1-column glyphs. Again, this causes cursor -addressing to get out of sync and eventually messes up the display. - -One possible workaround for problems caused by character composition -is to turn off 'auto-composition-mode' on Kitty terminals, e.g. by -customizing the 'auto-composition-mode' variable to have as value a -string that the 'tty-type' function returns on those terminals. - -*** Display artifacts on the Alacritty text terminal - -This terminal is known to cause problems with Emoji sequences: when -displaying them, the Emacs text-mode frame could show gaps and other -visual artifacts. - -The solution is to disable 'auto-composition-mode' on these -terminals, for example, like this: - - (setq auto-composition-mode "alacritty") - -This disables 'auto-composition-mode' on frames that display on -terminals of this type. - ** Screen readers get confused about character position The Emacs display code sometimes emits TAB characters purely for motion @@ -2713,6 +2725,12 @@ This can confuse screen reader software under certain terminal emulators in the terminal before starting Emacs may mitigate this. See also the discussion in Bug#78474 . +Starting from version 31.1, Emacs by default no longer outputs series of +TAB characters followed by BACKSPACE, which used to confuse some of the +screen readers. If you encounter some problems in this area, verify +that the variable 'tty-cursor-movement-use-TAB-BS' is set to its default +nil value. + * Runtime problems specific to individual Unix variants ** GNU/Linux From eb90c528f38af557f0cfe927463c01c02f1b13e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 18 May 2026 16:27:35 +0100 Subject: [PATCH 009/112] ; * lisp/progmodes/eglot.el (eglot-code-action-indications): Tweak. --- lisp/progmodes/eglot.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 02fc4615acf..f00a3a265c5 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -625,6 +625,7 @@ Note additionally: (const :tag "ElDoc textual hint" eldoc-hint) (const :tag "Right besides point" nearby) (const :tag "In mode line" mode-line) + (const :tag "In left fringe" left-fringe) (const :tag "In margin" margin)) :package-version '(Eglot . "1.19")) From d4cb550dba6c01223167ca71b02698f452f3d141 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Mon, 18 May 2026 08:34:50 -0700 Subject: [PATCH 010/112] ; Improve last change * test/src/process-tests.el (process-tests/broken-pipe): Use CONNECTION-TYPE. (process-tests/broken-pipe/pipe-all) (process-tests/broken-pipe/pipe-stdin): Skip via 'skip-when'. (process-tests/broken-pipe/pty) (process-tests/broken-pipe/pty-stdin): Remove these invalid tests; EPIPE from a PTY doesn't make sense. --- test/src/process-tests.el | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/test/src/process-tests.el b/test/src/process-tests.el index 1b1a9dfb07f..3048cada03d 100644 --- a/test/src/process-tests.el +++ b/test/src/process-tests.el @@ -1073,7 +1073,7 @@ should also run to completion, printing out the line of text it read." (message "closed stream") (sit-for 1) (message "%s" line)))) - :connection-type 'pipe))) + :connection-type connection-type))) (process-send-string proc "hello\n") (while (not (string-prefix-p "closed stream\n" (buffer-string))) (accept-process-output)) @@ -1102,20 +1102,15 @@ should also run to completion, printing out the line of text it read." ;; These tests only works when running Emacs interactively, since we ;; don't catch SIGPIPE in batch mode. TODO: Fixing bug#66186 would ;; probably allow running these tests in batch mode. -(when (not noninteractive) - (ert-deftest process-tests/broken-pipe/pipe () - (process-tests/broken-pipe 'pipe)) +(ert-deftest process-tests/broken-pipe/pipe-all () + (skip-when noninteractive) + (process-tests/broken-pipe 'pipe)) - ;; Emacs doesn't support PTYs on MS-Windows. - (unless (memq system-type '(ms-dos windows-nt)) - (ert-deftest process-tests/broken-pipe/pty () - (process-tests/broken-pipe 'pty)) - - (ert-deftest process-tests/broken-pipe/pipe-stdin () - (process-tests/broken-pipe '(pipe . pty))) - - (ert-deftest process-tests/broken-pipe/pty-stdin () - (process-tests/broken-pipe '(pty . pipe))))) +(ert-deftest process-tests/broken-pipe/pipe-stdin () + (skip-when (or noninteractive + ;; Emacs doesn't support PTYs on MS-Windows. + (not (memq system-type '(ms-dos windows-nt))))) + (process-tests/broken-pipe '(pipe . pty))) (ert-deftest process-num-processors () "Sanity checks for num-processors." From 6bd73af24136b70baa932fbe5c187edd97154b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 18 May 2026 17:09:19 +0100 Subject: [PATCH 011/112] ; * test/lisp/jsonrpc-tests.el: Adjust timeouts for CI EMBA testing --- test/lisp/jsonrpc-tests.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/lisp/jsonrpc-tests.el b/test/lisp/jsonrpc-tests.el index ec85210c091..28f7740ab32 100644 --- a/test/lisp/jsonrpc-tests.el +++ b/test/lisp/jsonrpc-tests.el @@ -177,25 +177,26 @@ INITARGS are passed to `make-instance' for `jsonrpc--test-client'." ;; This returns immediately (jsonrpc-async-request conn - 'sit-for [0.1] + 'sit-for [0.01] :success-fn (lambda (_result) ;; this only gets runs after the "first deferred" is stashed. (setq n-deferred-1 (hash-table-count (jsonrpc--deferred-actions conn))))) (should-error - ;; This stashes the request and waits. It will error because - ;; no-one clears the "hold deferred" flag. + ;; This stashes the request and waits. It will error with a + ;; timeout after blocking for 1 sec because no-one clears the + ;; "hold deferred" flag. (jsonrpc-request conn 'ignore ["first deferred"] :deferred "first deferred" - :timeout 0.5) + :timeout 1.0) :type 'jsonrpc-error) ;; The error means the deferred actions stash is now empty (should (zerop (hash-table-count (jsonrpc--deferred-actions conn)))) ;; Again, this returns immediately. (jsonrpc-async-request conn - 'sit-for [0.1] + 'sit-for [0.01] :success-fn (lambda (_result) ;; This gets run while "third deferred" below is waiting for From 10e91e096d8bb07ac12d960a5bc6b473e30bb812 Mon Sep 17 00:00:00 2001 From: Joshua Murphy Date: Sat, 16 May 2026 13:35:23 -0400 Subject: [PATCH 012/112] Get selected item in newsticker list view * lisp/net/newst-treeview.el (newsticker--treeview-get-selected-item): If an item is already selected, use it. (Bug#80972) Copyright-paperwork-exempt: yes --- lisp/net/newst-treeview.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/net/newst-treeview.el b/lisp/net/newst-treeview.el index 04d796b0b90..8b5f8a8528f 100644 --- a/lisp/net/newst-treeview.el +++ b/lisp/net/newst-treeview.el @@ -1387,8 +1387,10 @@ Will move to previous feed until an item is found." (defun newsticker--treeview-get-selected-item () "Return item that is currently selected in list buffer." (with-current-buffer (newsticker--treeview-list-buffer) - (beginning-of-line) - (get-text-property (point) :nt-item))) + (goto-char (point-min)) + (if-let* ((selected (text-property-search-forward :nt-selected t t))) + (get-text-property (prop-match-beginning selected) :nt-item) + (get-text-property (point-min) :nt-item)))) (defun newsticker-treeview-mark-item-old (&optional dont-proceed) "Mark current item as old unless it is obsolete. From 389874c533bbd2a5594ce490510ad25bca147899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 18 May 2026 20:33:44 +0100 Subject: [PATCH 013/112] Eglot: unbreak for treesit-less builds * lisp/progmodes/eglot.el (eglot--builtin-mdown-p): New helper. (eglot--accepted-formats) (eglot--format-markup): Use it. --- lisp/progmodes/eglot.el | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index f00a3a265c5..e55928556f9 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -726,11 +726,15 @@ This can be useful when using docker to run a language server.") (executable-find command))) (declare-function treesit-grammar-location "treesit.c") + +(defun eglot--builtin-mdown-p () + (and (fboundp 'markdown-ts-view-mode) + (fboundp 'treesit-grammar-location) + (treesit-grammar-location 'markdown))) + (defun eglot--accepted-formats () (if (and (not eglot-prefer-plaintext) - (or (fboundp 'gfm-view-mode) - (and (fboundp 'markdown-ts-view-mode) - (treesit-grammar-location 'markdown)))) + (or (fboundp 'gfm-view-mode) (eglot--builtin-mdown-p))) ["markdown" "plaintext"] ["plaintext"])) @@ -2237,9 +2241,7 @@ Doubles as an indicator of snippet support." (cl-defun eglot--format-markup (markup &optional mode - &aux string lang render extract - (built-in (and (fboundp 'markdown-ts-view-mode) - (treesit-grammar-location 'markdown)))) + &aux string lang render extract) "Format MARKUP according to LSP's spec. MARKUP is either an LSP MarkedString or MarkupContent object. If MODE, force MODE to be used for fontifying MARKUP." @@ -2261,7 +2263,7 @@ If MODE, force MODE to be used for fontifying MARKUP." (calc2 (forced-mode) (cond (forced-mode `(,forced-mode)) - (built-in `(,#'markdown-ts-view-mode)) + ((eglot--builtin-mdown-p) `(,#'markdown-ts-view-mode)) ((fboundp 'gfm-view-mode) `(,#'gfm-view-mode ,#'gfm-extract)) (t `(#'text-mode)))) (calc (s &optional (forced-mode mode) &aux (x (calc2 forced-mode))) From 28a13b01c7d7ccfd50e02cb34f5d119b28173df9 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 18 May 2026 22:15:29 +0100 Subject: [PATCH 014/112] vc-refresh-state: Override default-directory for backend functions I ran into the issue described in the comment with the current code in project-find-file-in and project-find-dir, when using 'C-x p p' to switch between projects. * lisp/vc/vc-hooks.el (vc-refresh-state): When calling into the backend, override any let-bindings of default-directory. --- lisp/vc/vc-hooks.el | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el index d0f292d2c9d..64ad4d5daec 100644 --- a/lisp/vc/vc-hooks.el +++ b/lisp/vc/vc-hooks.el @@ -955,10 +955,16 @@ In the latter case, VC mode is deactivated for this buffer." (cond ((setq backend (with-demoted-errors "VC refresh error: %S" (vc-backend buffer-file-name))) - ;; Let the backend setup any buffer-local things he needs. - (vc-call-backend backend 'find-file-hook) - ;; Compute the state and put it in the mode line. - (vc-mode-line buffer-file-name backend) + ;; When `auto-revert-handler' calls us then `default-directory' + ;; may be let-bound to something else for the purpose of some + ;; command that's currently doing some minibuffer prompting. + ;; Backend find-file-hook and mode-line-string functions should + ;; not need to be written so as to handle that possibility. + (let ((default-directory (buffer-local-toplevel-value 'default-directory))) + ;; Let the backend setup any buffer-local things it needs. + (vc-call-backend backend 'find-file-hook) + ;; Compute the state and put it in the mode line. + (vc-mode-line buffer-file-name backend)) (unless vc-make-backup-files ;; Use this variable, not make-backup-files, ;; because this is for things that depend on the file name. From 9ba65aa96568bf37e6f240dbb1d3dc5fb40d831d Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Mon, 18 May 2026 11:57:16 -0700 Subject: [PATCH 015/112] Fix missing margin face on display prop in erc-stamp * lisp/erc/erc-stamp.el (erc-insert-timestamp-right): Explicitly add face to right-hand stamp's `display' margin string. Commit d24b10ca "Introduce 'margin' face for window margin background" did away with the "fall-through" behavior in which a margin spec's string that lacks its own face property inherited whatever the associated `display' char happened to have. (Bug#80693) ;; The old language in "(elisp) Display Margins" said "if the ;; string to be displayed in the margin doesn't specify a face, its ;; face is determined using the same rules and priorities as it is ;; for strings displayed in the text area (see Displaying Faces)," ;; and that "if this results in undesirable 'leaking' of faces into ;; the margin, make sure the string has an explicit face specified ;; for it." It seems ERC and likely more than a few other packages ;; never came to heed this guidance and have erroneously depended ;; on such behavior for years if not decades. ;; ;; * test/lisp/erc/resources/fill/snapshots/merge-01-start.eld: ;; * test/lisp/erc/resources/fill/snapshots/merge-02-right.eld: ;; * test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld: ;; * test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld: ;; * test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld: ;; * test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld: ;; * test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld: ;; * test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld: ;; * test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld: Update ;; snapshot. --- lisp/erc/erc-stamp.el | 1 + test/lisp/erc/resources/fill/snapshots/merge-01-start.eld | 2 +- test/lisp/erc/resources/fill/snapshots/merge-02-right.eld | 2 +- test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld | 2 +- .../resources/fill/snapshots/merge-wrap-indicator-pre-01.eld | 2 +- test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld | 2 +- test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld | 2 +- test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld | 2 +- test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld | 2 +- test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld | 2 +- 10 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 7aacad3b125..bf1018f58b6 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -621,6 +621,7 @@ printed just after each line's text (no alignment)." (pcase erc-timestamp-use-align-to ((guard erc-stamp--display-margin-mode) (let ((s (propertize (substring-no-properties string) + 'font-lock-face 'erc-timestamp-face 'invisible erc-stamp--invisible-property))) (insert " ") (put-text-property 0 (length string) 'display diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld index 166ed59e292..d1dde661020 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n one.\n two.\n three.\n four.\n five.\n six.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 456 457 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #5=(space :width (- 27 (6)))) 457 460 (wrap-prefix #1# line-prefix #5#) 460 467 (wrap-prefix #1# line-prefix #5#) 467 468 (field erc-timestamp wrap-prefix #1# line-prefix #5#) 468 475 (field erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 476 477 (erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #8=(space :width (- 27 (8)))) 477 482 (wrap-prefix #1# line-prefix #8#) 482 488 (wrap-prefix #1# line-prefix #8#) 489 490 (erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #9=(space :width (- 27 0)) erc-fill--wrap-merge #7="" display #7#) 490 495 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 495 497 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 497 501 (wrap-prefix #1# line-prefix #9#) 502 503 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 503 506 (wrap-prefix #1# line-prefix #10#) 506 514 (wrap-prefix #1# line-prefix #10#) 515 516 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) erc-fill--wrap-merge #7# display #7#) 516 519 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 519 521 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 521 526 (wrap-prefix #1# line-prefix #11#) 527 528 (erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=(space :width (- 27 (8)))) 528 533 (wrap-prefix #1# line-prefix #12#) 533 540 (wrap-prefix #1# line-prefix #12#) 541 542 (erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 0)) erc-fill--wrap-merge #7# display #7#) 542 547 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 547 549 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 549 553 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n one.\n two.\n three.\n four.\n five.\n six.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#6=(margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 456 457 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #5=(space :width (- 27 (6)))) 457 460 (wrap-prefix #1# line-prefix #5#) 460 467 (wrap-prefix #1# line-prefix #5#) 467 468 (field erc-timestamp wrap-prefix #1# line-prefix #5#) 468 475 (field erc-timestamp wrap-prefix #1# line-prefix #5# display (#6# #("[07:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 476 477 (erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #8=(space :width (- 27 (8)))) 477 482 (wrap-prefix #1# line-prefix #8#) 482 488 (wrap-prefix #1# line-prefix #8#) 489 490 (erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #9=(space :width (- 27 0)) erc-fill--wrap-merge #7="" display #7#) 490 495 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 495 497 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 497 501 (wrap-prefix #1# line-prefix #9#) 502 503 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 503 506 (wrap-prefix #1# line-prefix #10#) 506 514 (wrap-prefix #1# line-prefix #10#) 515 516 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) erc-fill--wrap-merge #7# display #7#) 516 519 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 519 521 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 521 526 (wrap-prefix #1# line-prefix #11#) 527 528 (erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=(space :width (- 27 (8)))) 528 533 (wrap-prefix #1# line-prefix #12#) 533 540 (wrap-prefix #1# line-prefix #12#) 541 542 (erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 0)) erc-fill--wrap-merge #7# display #7#) 542 547 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 547 549 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 549 553 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld index 8b502373807..f2770ce1c62 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n one.\n two.\n three.\n four.\n five.\n six.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (wrap-prefix #1=(space :width 29) line-prefix (space :width (- 29 (18))) field erc-timestamp) 21 22 (wrap-prefix #1# line-prefix #2=(space :width (- 29 (4))) erc--msg notice erc--ts 0) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (wrap-prefix #1# line-prefix #2# field erc-timestamp) 184 191 (wrap-prefix #1# line-prefix #2# field erc-timestamp display (#6=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (wrap-prefix #1# line-prefix #3=(space :width (- 29 (8))) erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix (space :width (- 29 (8)))) 350 351 (wrap-prefix #1# line-prefix #4=(space :width (- 29 (6))) erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (wrap-prefix #1# line-prefix (space :width (- 29 (18))) field erc-timestamp) 456 457 (wrap-prefix #1# line-prefix #5=(space :width (- 29 (6))) erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG) 457 460 (wrap-prefix #1# line-prefix #5#) 460 467 (wrap-prefix #1# line-prefix #5#) 467 468 (wrap-prefix #1# line-prefix #5# field erc-timestamp) 468 475 (wrap-prefix #1# line-prefix #5# field erc-timestamp display (#6# #("[07:00]" 0 7 (invisible timestamp)))) 476 477 (wrap-prefix #1# line-prefix #8=(space :width (- 29 (8))) erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG) 477 482 (wrap-prefix #1# line-prefix #8#) 482 488 (wrap-prefix #1# line-prefix #8#) 489 490 (wrap-prefix #1# line-prefix #9=(space :width (- 29 0)) erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG erc-fill--wrap-merge #7="" display #7#) 490 495 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 495 497 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 497 501 (wrap-prefix #1# line-prefix #9#) 502 503 (wrap-prefix #1# line-prefix #10=(space :width (- 29 (6))) erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG) 503 506 (wrap-prefix #1# line-prefix #10#) 506 514 (wrap-prefix #1# line-prefix #10#) 515 516 (wrap-prefix #1# line-prefix #11=(space :width (- 29 0)) erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc-fill--wrap-merge #7# display #7#) 516 519 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 519 521 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 521 526 (wrap-prefix #1# line-prefix #11#) 527 528 (wrap-prefix #1# line-prefix #12=(space :width (- 29 (8))) erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG) 528 533 (wrap-prefix #1# line-prefix #12#) 533 540 (wrap-prefix #1# line-prefix #12#) 541 542 (wrap-prefix #1# line-prefix #13=(space :width (- 29 0)) erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG erc-fill--wrap-merge #7# display #7#) 542 547 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 547 549 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 549 553 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n one.\n two.\n three.\n four.\n five.\n six.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (wrap-prefix #1=(space :width 29) line-prefix (space :width (- 29 (18))) field erc-timestamp) 21 22 (wrap-prefix #1# line-prefix #2=(space :width (- 29 (4))) erc--msg notice erc--ts 0) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (wrap-prefix #1# line-prefix #2# field erc-timestamp) 184 191 (wrap-prefix #1# line-prefix #2# field erc-timestamp display (#6=(margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (wrap-prefix #1# line-prefix #3=(space :width (- 29 (8))) erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix (space :width (- 29 (8)))) 350 351 (wrap-prefix #1# line-prefix #4=(space :width (- 29 (6))) erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (wrap-prefix #1# line-prefix (space :width (- 29 (18))) field erc-timestamp) 456 457 (wrap-prefix #1# line-prefix #5=(space :width (- 29 (6))) erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG) 457 460 (wrap-prefix #1# line-prefix #5#) 460 467 (wrap-prefix #1# line-prefix #5#) 467 468 (wrap-prefix #1# line-prefix #5# field erc-timestamp) 468 475 (wrap-prefix #1# line-prefix #5# field erc-timestamp display (#6# #("[07:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 476 477 (wrap-prefix #1# line-prefix #8=(space :width (- 29 (8))) erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG) 477 482 (wrap-prefix #1# line-prefix #8#) 482 488 (wrap-prefix #1# line-prefix #8#) 489 490 (wrap-prefix #1# line-prefix #9=(space :width (- 29 0)) erc--msg msg erc--spkr "alice" erc--ts 1680332400 erc--cmd PRIVMSG erc-fill--wrap-merge #7="" display #7#) 490 495 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 495 497 (wrap-prefix #1# line-prefix #9# erc-fill--wrap-merge #7# display #7#) 497 501 (wrap-prefix #1# line-prefix #9#) 502 503 (wrap-prefix #1# line-prefix #10=(space :width (- 29 (6))) erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG) 503 506 (wrap-prefix #1# line-prefix #10#) 506 514 (wrap-prefix #1# line-prefix #10#) 515 516 (wrap-prefix #1# line-prefix #11=(space :width (- 29 0)) erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc-fill--wrap-merge #7# display #7#) 516 519 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 519 521 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #7# display #7#) 521 526 (wrap-prefix #1# line-prefix #11#) 527 528 (wrap-prefix #1# line-prefix #12=(space :width (- 29 (8))) erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG) 528 533 (wrap-prefix #1# line-prefix #12#) 533 540 (wrap-prefix #1# line-prefix #12#) 541 542 (wrap-prefix #1# line-prefix #13=(space :width (- 29 0)) erc--msg msg erc--spkr "Dummy" erc--ts 1680332400 erc--cmd PRIVMSG erc-fill--wrap-merge #7# display #7#) 542 547 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 547 549 (wrap-prefix #1# line-prefix #13# erc-fill--wrap-merge #7# display #7#) 549 553 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld index 9744e659813..fc011e14530 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 456 457 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 457 460 (wrap-prefix #1# line-prefix #6#) 460 467 (wrap-prefix #1# line-prefix #6#) 467 468 (field erc-timestamp wrap-prefix #1# line-prefix #6#) 468 475 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 476 477 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 0)) erc-fill--wrap-merge #8="" display #8#) 477 480 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge #8# display #8#) 480 482 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge #8# display #8#) 482 485 (wrap-prefix #1# line-prefix #7#) 486 487 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 487 488 (wrap-prefix #1# line-prefix #9#) 488 491 (wrap-prefix #1# line-prefix #9#) 491 496 (wrap-prefix #1# line-prefix #9#) 497 498 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 498 501 (wrap-prefix #1# line-prefix #10#) 501 507 (wrap-prefix #1# line-prefix #10#) 508 509 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) erc-fill--wrap-merge #8# display #8#) 509 512 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #8# display #8#) 512 514 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #8# display #8#) 514 517 (wrap-prefix #1# line-prefix #11#) 518 519 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #12=(space :width (- 27 (2)))) 519 520 (wrap-prefix #1# line-prefix #12#) 520 523 (wrap-prefix #1# line-prefix #12#) 523 529 (wrap-prefix #1# line-prefix #12#) 530 531 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 (6)))) 531 534 (wrap-prefix #1# line-prefix #13#) 534 541 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 456 457 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 457 460 (wrap-prefix #1# line-prefix #6#) 460 467 (wrap-prefix #1# line-prefix #6#) 467 468 (field erc-timestamp wrap-prefix #1# line-prefix #6#) 468 475 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 476 477 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 0)) erc-fill--wrap-merge #8="" display #8#) 477 480 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge #8# display #8#) 480 482 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge #8# display #8#) 482 485 (wrap-prefix #1# line-prefix #7#) 486 487 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 487 488 (wrap-prefix #1# line-prefix #9#) 488 491 (wrap-prefix #1# line-prefix #9#) 491 496 (wrap-prefix #1# line-prefix #9#) 497 498 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #10=(space :width (- 27 (6)))) 498 501 (wrap-prefix #1# line-prefix #10#) 501 507 (wrap-prefix #1# line-prefix #10#) 508 509 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 0)) erc-fill--wrap-merge #8# display #8#) 509 512 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #8# display #8#) 512 514 (wrap-prefix #1# line-prefix #11# erc-fill--wrap-merge #8# display #8#) 514 517 (wrap-prefix #1# line-prefix #11#) 518 519 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #12=(space :width (- 27 (2)))) 519 520 (wrap-prefix #1# line-prefix #12#) 520 523 (wrap-prefix #1# line-prefix #12#) 523 529 (wrap-prefix #1# line-prefix #12#) 530 531 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #13=(space :width (- 27 (6)))) 531 534 (wrap-prefix #1# line-prefix #13#) 534 541 (wrap-prefix #1# line-prefix #13#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld index 36729b890be..ad9bec913a7 100644 --- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld +++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 456 457 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 457 460 (wrap-prefix #1# line-prefix #6#) 460 467 (wrap-prefix #1# line-prefix #6#) 467 468 (field erc-timestamp wrap-prefix #1# line-prefix #6#) 468 475 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (invisible timestamp)))) 476 477 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 #10=(2))) erc-fill--wrap-merge t display #8=#("> " 0 1 (font-lock-face shadow))) 477 480 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge t display #8#) 480 482 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge t display #8#) 482 485 (wrap-prefix #1# line-prefix #7#) 486 487 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 487 488 (wrap-prefix #1# line-prefix #9#) 488 491 (wrap-prefix #1# line-prefix #9#) 491 496 (wrap-prefix #1# line-prefix #9#) 497 498 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 (6)))) 498 501 (wrap-prefix #1# line-prefix #11#) 501 507 (wrap-prefix #1# line-prefix #11#) 508 509 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=(space :width (- 27 #10#)) erc-fill--wrap-merge t display #8#) 509 512 (wrap-prefix #1# line-prefix #12# erc-fill--wrap-merge t display #8#) 512 514 (wrap-prefix #1# line-prefix #12# erc-fill--wrap-merge t display #8#) 514 517 (wrap-prefix #1# line-prefix #12#) 518 519 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #13=(space :width (- 27 (2)))) 519 520 (wrap-prefix #1# line-prefix #13#) 520 523 (wrap-prefix #1# line-prefix #13#) 523 529 (wrap-prefix #1# line-prefix #13#) 530 531 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #14=(space :width (- 27 (6)))) 531 534 (wrap-prefix #1# line-prefix #14#) 534 541 (wrap-prefix #1# line-prefix #14#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr 1 2023]\n zero. [07:00]\n 0.5\n* bob one.\n two.\n 2.5\n* bob three\n four.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display (#5=(margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 437 438 (erc--msg datestamp erc--ts 1680307200 field erc-timestamp) 438 455 (field erc-timestamp wrap-prefix #1# line-prefix (space :width (- 27 (18)))) 456 457 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #6=(space :width (- 27 (6)))) 457 460 (wrap-prefix #1# line-prefix #6#) 460 467 (wrap-prefix #1# line-prefix #6#) 467 468 (field erc-timestamp wrap-prefix #1# line-prefix #6#) 468 475 (field erc-timestamp wrap-prefix #1# line-prefix #6# display (#5# #("[07:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 476 477 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #7=(space :width (- 27 #10=(2))) erc-fill--wrap-merge t display #8=#("> " 0 1 (font-lock-face shadow))) 477 480 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge t display #8#) 480 482 (wrap-prefix #1# line-prefix #7# erc-fill--wrap-merge t display #8#) 482 485 (wrap-prefix #1# line-prefix #7#) 486 487 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 487 488 (wrap-prefix #1# line-prefix #9#) 488 491 (wrap-prefix #1# line-prefix #9#) 491 496 (wrap-prefix #1# line-prefix #9#) 497 498 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #11=(space :width (- 27 (6)))) 498 501 (wrap-prefix #1# line-prefix #11#) 501 507 (wrap-prefix #1# line-prefix #11#) 508 509 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #12=(space :width (- 27 #10#)) erc-fill--wrap-merge t display #8#) 509 512 (wrap-prefix #1# line-prefix #12# erc-fill--wrap-merge t display #8#) 512 514 (wrap-prefix #1# line-prefix #12# erc-fill--wrap-merge t display #8#) 514 517 (wrap-prefix #1# line-prefix #12#) 518 519 (erc--msg ctcp-action erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG erc--ctcp ACTION wrap-prefix #1# line-prefix #13=(space :width (- 27 (2)))) 519 520 (wrap-prefix #1# line-prefix #13#) 520 523 (wrap-prefix #1# line-prefix #13#) 523 529 (wrap-prefix #1# line-prefix #13#) 530 531 (erc--msg msg erc--spkr "bob" erc--ts 1680332400 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #14=(space :width (- 27 (6)))) 531 534 (wrap-prefix #1# line-prefix #14#) 534 541 (wrap-prefix #1# line-prefix #14#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld index 0228e716731..8fee2a8d0d8 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld index 9ab89041b53..e0d529dd8a4 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 29 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 29 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 29) line-prefix (space :width (- 29 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 29 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 29 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 29 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld index 87ea4692d9d..cd8c0298ad1 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 25) line-prefix (space :width (- 25 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 25 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 25 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 25) line-prefix (space :width (- 25 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 25 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 25 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 25 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld index 0228e716731..8fee2a8d0d8 100644 --- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld +++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#)) \ No newline at end of file diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld index 5405ca2a7dc..211e9afac22 100644 --- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld +++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld @@ -1 +1 @@ -#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n This buffer is for text.\n*** one two three\n*** four five six\n Somebody stop me\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (invisible timestamp)))) 191 192 (line-spacing 0.5) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 349 350 (line-spacing 0.5) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 436 437 (line-spacing 0.5) 437 438 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #5=(space :width (- 27 0)) erc-fill--wrap-merge #6="" display #6#) 438 441 (wrap-prefix #1# line-prefix #5# erc-fill--wrap-merge #6# display #6#) 441 443 (wrap-prefix #1# line-prefix #5# erc-fill--wrap-merge #6# display #6#) 443 467 (wrap-prefix #1# line-prefix #5#) 467 468 (line-spacing 0.5) 468 469 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #7=(space :width (- 27 (4)))) 469 485 (wrap-prefix #1# line-prefix #7#) 486 487 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #8=(space :width (- 27 (4)))) 487 503 (wrap-prefix #1# line-prefix #8#) 503 504 (line-spacing 0.5) 504 505 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 505 508 (wrap-prefix #1# line-prefix #9#) 508 526 (wrap-prefix #1# line-prefix #9#)) \ No newline at end of file +#("\n\n\n[Thu Jan 1 1970]\n*** This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect. [00:00]\n bob: come, you are a tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause to complain of? Come me to what was done to her.\n alice: Either your unparagoned mistress is dead, or she's outprized by a trifle.\n This buffer is for text.\n*** one two three\n*** four five six\n Somebody stop me\n" 2 3 (erc--msg datestamp erc--ts 0 field erc-timestamp) 3 20 (field erc-timestamp wrap-prefix #1=(space :width 27) line-prefix (space :width (- 27 (18)))) 21 22 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #2=(space :width (- 27 (4)))) 22 183 (wrap-prefix #1# line-prefix #2#) 183 184 (field erc-timestamp wrap-prefix #1# line-prefix #2#) 184 191 (field erc-timestamp wrap-prefix #1# line-prefix #2# display ((margin right-margin) #("[00:00]" 0 7 (font-lock-face erc-timestamp-face invisible timestamp)))) 191 192 (line-spacing 0.5) 192 193 (erc--msg msg erc--spkr "alice" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #3=(space :width (- 27 (8)))) 193 198 (wrap-prefix #1# line-prefix #3#) 198 200 (wrap-prefix #1# line-prefix #3#) 200 203 (wrap-prefix #1# line-prefix #3#) 203 316 (wrap-prefix #1# line-prefix #3#) 317 349 (wrap-prefix #1# line-prefix #3#) 349 350 (line-spacing 0.5) 350 351 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #4=(space :width (- 27 (6)))) 351 354 (wrap-prefix #1# line-prefix #4#) 354 356 (wrap-prefix #1# line-prefix #4#) 356 361 (wrap-prefix #1# line-prefix #4#) 361 436 (wrap-prefix #1# line-prefix #4#) 436 437 (line-spacing 0.5) 437 438 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #5=(space :width (- 27 0)) erc-fill--wrap-merge #6="" display #6#) 438 441 (wrap-prefix #1# line-prefix #5# erc-fill--wrap-merge #6# display #6#) 441 443 (wrap-prefix #1# line-prefix #5# erc-fill--wrap-merge #6# display #6#) 443 467 (wrap-prefix #1# line-prefix #5#) 467 468 (line-spacing 0.5) 468 469 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #7=(space :width (- 27 (4)))) 469 485 (wrap-prefix #1# line-prefix #7#) 486 487 (erc--msg notice erc--ts 0 wrap-prefix #1# line-prefix #8=(space :width (- 27 (4)))) 487 503 (wrap-prefix #1# line-prefix #8#) 503 504 (line-spacing 0.5) 504 505 (erc--msg msg erc--spkr "bob" erc--ts 0 erc--cmd PRIVMSG wrap-prefix #1# line-prefix #9=(space :width (- 27 (6)))) 505 508 (wrap-prefix #1# line-prefix #9#) 508 526 (wrap-prefix #1# line-prefix #9#)) \ No newline at end of file From 9436d92c5daae66d2be82544cb135d1356ba4ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 18 May 2026 23:14:16 +0100 Subject: [PATCH 016/112] Eglot: fix eglot--format-makrup when MARKUP just a string * lisp/progmodes/eglot.el (eglot--format-markup): Fix case where markup is string. --- lisp/progmodes/eglot.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index e55928556f9..ad21cd84d2f 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -2268,7 +2268,7 @@ If MODE, force MODE to be used for fontifying MARKUP." (t `(#'text-mode)))) (calc (s &optional (forced-mode mode) &aux (x (calc2 forced-mode))) (setq string s render (car x) extract (or (cadr x) #'buffer-string)))) - (cond ((stringp markup) (calc string)) ; plain string + (cond ((stringp markup) (calc markup)) ; plain string ((setq lang (plist-get markup :language)) ; deprecated MarkedString (calc (format "```%s\n%s\n```" lang (plist-get markup :value)))) (t (calc (plist-get markup :value) ; Assume MarkupContent From 8095fbef7720d2c62b80743141483fc93d1d3534 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 18 May 2026 18:47:47 -0400 Subject: [PATCH 017/112] doc/lispref/text.texi: Add complement to commit f4a1c006569f * doc/lispref/text.texi (Examining Properties): Mention the change in cursor-sensor-functions. --- doc/lispref/text.texi | 5 +++++ etc/NEWS | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 22bce370197..7f43c631482 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -3042,6 +3042,7 @@ followed by the text properties. If @var{object} is a string, only text properties are considered, since strings never have overlays. @end defun +@anchor{Boundaries of text and overlay properties} @defun get-pos-property position prop &optional object This function is like @code{get-char-property}, except that it pays attention to properties' stickiness and overlays' advancement settings @@ -4019,6 +4020,10 @@ The movement can be @code{entered} or @code{left}, depending on whether the cursor is entering the text that has this property or leaving it, or @code{moved} when the cursor moved within that text. Other values for the direction should be ignored. +Whether the boundary positions (at the beginning and end of an overlay or +a stretch of text-property) are considered as inside or outside follows +the same rules as for @code{get-pos-property}, see @pxref{Boundaries of +text and overlay properties}. The functions are called only when the minor mode @code{cursor-sensor-mode} is turned on. diff --git a/etc/NEWS b/etc/NEWS index a746ca7b1a3..3021ad42a12 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3987,6 +3987,21 @@ all versions, sleep events require Windows 8 or later). * Incompatible Lisp Changes in Emacs 31.1 ++++ +** Boundaries of 'cursor-sensor-functions' now obey stickiness. +'cursor-sensor-mode' now uses 'get-pos-property' to decide whether a +boundary is considered as inside or outside. + +This means that by default, the boundaries have changed: the end +position of a stretch of a 'cursor-sensor-functions' text property +used to be considered outside of the stretch whereas it is now +considered as inside. You can recover the previous behavior by +controlling the stickiness, for example with a call like: + + (add-text-properties BEG END + '(cursor-sensor-functions (MY-FUNCTION) + rear-nonsticky (cursor-sensor-functions))) + +++ ** 'makunbound' on a variable alias undoes the alias. Previously, it had the effect of applying the 'makunbound' on the From 8c71b0d6b8800066b21794eb08cd0281d3ee9c60 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 18 May 2026 19:03:51 -0400 Subject: [PATCH 018/112] shr.el: Don't insert image at outdated destination (bug#80945) When fetching images asynchronously, keep track of the destination region and refrain from inserting the image if that region has been modified in the mean time. * lisp/net/shr.el (shr--image-fetched, shr--async-put-image): New functions. (shr-insert-image, shr-zoom-image, shr-image-displayer, shr-tag-img): Use them. * lisp/mail/rmailmm.el (rmail-mime-render-html-shr): Add FIXME. --- lisp/mail/rmailmm.el | 1 + lisp/net/shr.el | 56 ++++++++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/lisp/mail/rmailmm.el b/lisp/mail/rmailmm.el index 9226976c114..1f9d1310782 100644 --- a/lisp/mail/rmailmm.el +++ b/lisp/mail/rmailmm.el @@ -763,6 +763,7 @@ HEADER is a header component of a MIME-entity object (see ;; Image retrieval happens asynchronously, but meanwhile ;; `rmail-swap-buffers' may have been run, leaving ;; `shr-image-fetched' trying to insert the image in the wrong buffer. + ;; FIXME: With `shr--async-put-image' this should now work correctly. (shr-inhibit-images t) ;; Bind shr-width to nil to force shr-insert-document break ;; the lines at the window margin. The default is diff --git a/lisp/net/shr.el b/lisp/net/shr.el index 7e47d93d81c..a199150bd19 100644 --- a/lisp/net/shr.el +++ b/lisp/net/shr.el @@ -636,9 +636,8 @@ the URL of the image to the kill buffer instead." (if (not url) (message "No image under point") (message "Inserting %s..." url) - (url-retrieve url #'shr-image-fetched - (list (current-buffer) (1- (point)) (point-marker)) - t)))) + (shr--async-put-image url (1- (point)) (point-marker) + :silent t)))) (defvar shr-image-zoom-level-alist `((fit "Zoom to fit" shr-rescale-image) @@ -689,11 +688,9 @@ full-buffer size." (url-is-cached url)) (shr-replace-image (shr-get-image-data url) start (set-marker (make-marker) end) flags) - (url-retrieve url #'shr-image-fetched - `(,(current-buffer) ,start - ,(set-marker (make-marker) end) - ,flags) - t)))))) + (shr--async-put-image url start end + :flags flags + :silent t)))))) ;;; Utility functions. @@ -1154,7 +1151,7 @@ the mouse click event." (defun shr-image-fetched (status buffer start end &optional flags) (let ((image-buffer (current-buffer))) - (when (and (buffer-name buffer) + (when (and (buffer-live-p buffer) (not (plist-get status :error))) (url-store-in-cache image-buffer) (goto-char (point-min)) @@ -1165,6 +1162,30 @@ the mouse click event." (shr-replace-image data start end flags))))) (kill-buffer image-buffer))) +(defun shr--image-fetched (status ol flags) + (unwind-protect + (shr-image-fetched status (overlay-buffer ol) + (overlay-start ol) + (overlay-end ol) + flags) + (delete-overlay ol))) + +(cl-defun shr--async-put-image (url beg end + &key flags silent inhibit-cookies queue) + "Fetch image from URL and place it on BEG..END. +FLAGS has the same meaning as for `shr-put-image'. +SILENT and inhibit-cookies have the same meaning as for `ulkr-retrieve.'. +If QUEUE is non-nil use `url-queue-retrieve’ instead of `url-retrieve’." + (let ((ol (make-overlay beg end nil t))) + ;; We could also try to delete the overlay when the text between BEG..END + ;; is modified (via `modification-hooks'), but then we'd have to be careful + ;; not to do it too eagerly (e.g. it's normal for text-properties to be + ;; applied). + (overlay-put ol 'evaporate t) + (funcall (if queue #'url-queue-retrieve #'url-retrieve) + url #'shr--image-fetched + (list ol flags) silent inhibit-cookies))) + (defun shr-image-from-data (data) "Return an image from the data: URI content DATA." (when (string-match @@ -1383,9 +1404,8 @@ START, and END. Note that START and END should be markers." (funcall shr-put-image-function image (buffer-substring start end)) (delete-region (point) end)))) - (url-retrieve url #'shr-image-fetched - (list (current-buffer) start end) - t t))))) + (shr--async-put-image url start end + :silent t :inhibit-cookies t))))) (defun shr-heading (dom &rest types) (shr-ensure-paragraph) @@ -1972,12 +1992,12 @@ The preference is a float determined from `shr-prefer-media-type'." (or (string-trim alt) "")) ;; No SVG support. Just use a space as our placeholder. (insert " ")) - (url-queue-retrieve - url #'shr-image-fetched - (list (current-buffer) start (set-marker (make-marker) (point)) - (list :width width :height height)) - t - (not (shr--use-cookies-p url shr-base))))) + (shr--async-put-image url start (point) + :flags (list :width width :height height) + :queue t + :silent t + :inhibit-cookies + (not (shr--use-cookies-p url shr-base))))) (when (zerop shr-table-depth) ;; We are not in a table. (put-text-property start (point) 'keymap shr-image-map) (put-text-property start (point) 'shr-alt alt) From 56ae704e5b2fad285dc00e28d7c5e78f05133a8b Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 17 May 2026 19:47:52 -0700 Subject: [PATCH 019/112] Fix (ash -1 1) undefined behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem discovered with GCC 16.1.1 -fsanitize=undefined. * src/data.c (Fash): Don’t left-shift a negative number; behavior is undefined (ISO C23 § 6.5.8 ¶ 4). --- src/data.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data.c b/src/data.c index b269ec6d501..2f245ce8061 100644 --- a/src/data.c +++ b/src/data.c @@ -3599,10 +3599,10 @@ discarding bits. */) else if (FIXNUMP (value)) { EMACS_INT v = XFIXNUM (value); - EMACS_UINT uv = v < 0 ? ~v : v; - EMACS_INT lz = stdc_leading_zeros (uv); + EMACS_UINT uv = v, uvcomp = v < 0 ? ~uv : uv; + EMACS_INT lz = stdc_leading_zeros (uvcomp); if (EMACS_INT_WIDTH - FIXNUM_BITS < lz - c) - return make_fixnum (v << c); + return make_fixnum ((EMACS_INT) {uv << c}); } mpz_t const *zval = bignum_integer (&mpz[0], value); From f5c3ddd9ad3f6f116c1c224e55b2aecad0461863 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 17 May 2026 19:55:12 -0700 Subject: [PATCH 020/112] Prefer singed type to size_t in Fdefine_charset_internal * src/charset.c (Fdefine_charset_internal): Prefer int to size_t for a variable that has only int values. --- src/charset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/charset.c b/src/charset.c index 9ff3191b7e3..b86304024fe 100644 --- a/src/charset.c +++ b/src/charset.c @@ -1139,7 +1139,7 @@ usage: (define-charset-internal ...) */) charset_table.start = new_table; charset_table.size = new_size; Lisp_Object new_attr_table = make_vector (new_size, Qnil); - for (size_t i = 0; i < old_size; i++) + for (int i = 0; i < old_size; i++) ASET (new_attr_table, i, AREF (charset_table.attributes_table, i)); charset_table.attributes_table = new_attr_table; From b9e20e39953ad27c720e265311fa71bd7c6c749e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 17 May 2026 22:17:47 -0700 Subject: [PATCH 021/112] Avoid malloc/free pairs in emit_static_object * src/comp.c (emit_static_object): Avoid an malloc/free of a 1 KiB buffer; just put it on the stack. Use strnlen+mempcpy instead of strncpy as there is no need to zero-fill buff. Use int for values that must fit in int since we are passing them to gcc_jit_context_new_rvalue_from_int. --- src/comp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/comp.c b/src/comp.c index 0ac980e6276..c70b37bfdac 100644 --- a/src/comp.c +++ b/src/comp.c @@ -2783,16 +2783,17 @@ emit_static_object (const char *name, Lisp_Object obj) . Adjust if possible to reduce the number of function calls. */ - size_t chunk_size = NILP (Fcomp_libgccjit_version ()) ? 200 : 1024; - char *buff = xmalloc (chunk_size); + char buff[1024]; + int chunk_size = NILP (Fcomp_libgccjit_version ()) ? 200 : sizeof buff; for (ptrdiff_t i = 0; i < len;) { - strncpy (buff, p, chunk_size); - buff[chunk_size - 1] = 0; - uintptr_t l = strlen (buff); + int l = strnlen (p, chunk_size - 1); if (l != 0) { + char *buff_end = mempcpy (buff, p, l); + *buff_end = '\0'; + p += l; i += l; @@ -2836,7 +2837,6 @@ emit_static_object (const char *name, Lisp_Object obj) NULL)); } } - xfree (buff); gcc_jit_block_add_assignment ( block, From 7587bb2654a6c22f8c9709cefd3ad8d45938b199 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 17 May 2026 22:31:26 -0700 Subject: [PATCH 022/112] Simplify module_extract_big_integer size calcs * src/emacs-module.c (module_bignum_count_max): Now of type ptrdiff_t, instead of likely being of type size_t. (module_extract_big_integer): Omit now-unnecessary prefix +, a now-unnecessary eassert against PTRDIFF_MAX, and and an unnecessary cast to ptrdiff_t. --- src/emacs-module.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/emacs-module.c b/src/emacs-module.c index 142ca675734..3c49490e5c4 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -1046,7 +1046,7 @@ import/export overhead on most platforms. /* Documented maximum count of magnitude elements. */ #define module_bignum_count_max \ - ((ptrdiff_t) min (SIZE_MAX, PTRDIFF_MAX) / sizeof (emacs_limb_t)) + ((ptrdiff_t) (min (SIZE_MAX, PTRDIFF_MAX) / sizeof (emacs_limb_t))) /* Verify that emacs_limb_t indeed has unique object representations. */ @@ -1100,7 +1100,7 @@ module_extract_big_integer (emacs_env *env, emacs_value arg, int *sign, suffice. */ EMACS_UINT u; enum { required = (sizeof u + size - 1) / size }; - static_assert (0 < required && +required <= module_bignum_count_max); + static_assert (0 < required && required <= module_bignum_count_max); if (magnitude == NULL) { *count = required; @@ -1132,9 +1132,8 @@ module_extract_big_integer (emacs_env *env, emacs_value arg, int *sign, return true; } size_t required_size = (mpz_sizeinbase (*x, 2) + numb - 1) / numb; - eassert (required_size <= PTRDIFF_MAX); - ptrdiff_t required = (ptrdiff_t) required_size; - eassert (required <= module_bignum_count_max); + eassert (required_size <= module_bignum_count_max); + ptrdiff_t required = required_size; if (magnitude == NULL) { *count = required; From 07fe0b297bc7b9c4e344eedd8244a73edda95c77 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 17 May 2026 22:49:44 -0700 Subject: [PATCH 023/112] Fix undefined behavior in maybe_resize_hash_table Problem discovered with GCC 16.1.1 -fsanitize=undefined. * src/fns.c (maybe_resize_hash_table): Avoid undefined behavior when h->key_and_value or h->hash are null pointers, in which case we call memcpy (destination, NULL, 0) which has undefined behavior in C89 through C23. --- src/fns.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fns.c b/src/fns.c index 1158f100ea0..a2312ffa1b9 100644 --- a/src/fns.c +++ b/src/fns.c @@ -4975,13 +4975,15 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) Lisp_Object *key_and_value = hash_table_alloc_bytes (2 * new_size * sizeof *key_and_value); - memcpy (key_and_value, h->key_and_value, - 2 * old_size * sizeof *key_and_value); + if (old_size) + memcpy (key_and_value, h->key_and_value, + 2 * old_size * sizeof *key_and_value); for (ptrdiff_t i = 2 * old_size; i < 2 * new_size; i++) key_and_value[i] = HASH_UNUSED_ENTRY_KEY; hash_hash_t *hash = hash_table_alloc_bytes (new_size * sizeof *hash); - memcpy (hash, h->hash, old_size * sizeof *hash); + if (old_size) + memcpy (hash, h->hash, old_size * sizeof *hash); ptrdiff_t old_index_size = hash_table_index_size (h); ptrdiff_t index_bits = compute_hash_index_bits (new_size); From 71336e837a51986aa12ca7e27e6ae0549d509aec Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 May 2026 22:47:37 -0700 Subject: [PATCH 024/112] Pacify GCC 16.1.1 -Wanalyzer-null-dereference * src/regex-emacs.c (forall_firstchar): Avoid undefined behavior in the 2nd eassert when !bufp && !pend. This pacifies GCC 16.1.1 20260501 (Red Hat 16.1.1-1) x86-64 when Emacs is configured with --enable-gcc-warnings. --- src/regex-emacs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/regex-emacs.c b/src/regex-emacs.c index 7c8ee144257..03c4ba3e4e9 100644 --- a/src/regex-emacs.c +++ b/src/regex-emacs.c @@ -3044,8 +3044,7 @@ static bool forall_firstchar (struct re_pattern_buffer *bufp, re_char *p, re_char *pend, bool f (re_char *p, void *arg), void *arg) { - eassert (!bufp || bufp->used); - eassert (pend || bufp->used); + eassert (bufp ? !!bufp->used : !!pend); return forall_firstchar_1 (p, pend, bufp ? bufp->buffer - 1 : p, bufp ? bufp->buffer + bufp->used + 1 : pend, From efb83df331425ae66e9d031a1ac35c2215612b52 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 May 2026 22:59:45 -0700 Subject: [PATCH 025/112] =?UTF-8?q?Don=E2=80=99t=20trust=20RLIMIT=5FNOFILE?= =?UTF-8?q?=20in=20src/process.c?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem discovered on Fedora 44 x86-64 when using GCC 16.1.1 with -fsanitize=address, with test/src/process-tests.el tests that use process-tests--with-raised-rlimit. This function overrides the default of 1024 for the maximum number of open files, which causes undefined behavior (subscript errors) in src/process.c. * src/process.c (inrange_fd, inrange_pipe): New functions. (allocate_pty, create_process, create_pty, Fmake_pipe_process) (Fmake_serial_process, connect_network_socket) (network_interface_info, server_accept_connection) (Fprocess_send_eof, child_signal_init): Check that all newly allocated file descriptors are less than FD_SETSIZE; close them and fail otherwise. (create_pty, Fmake_pipe_process, Fmake_serial_process) (connect_network_socket, server_accept_connection) (child_signal_init): Remove no-longer-needed comparisons to FD_SETSIZE, now that inrange_fd and inrange_pipe do the checking for us. --- src/process.c | 115 ++++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/src/process.c b/src/process.c index 9ea2b66533b..9e807bef44e 100644 --- a/src/process.c +++ b/src/process.c @@ -476,6 +476,44 @@ clear_fd_callback_data (struct fd_callback_data* elem) elem->waiting_thread = NULL; } +/* If FD is out of range, close it and return -1, setting errno to + EMFILE. Otherwise, return FD. This module routinely does this for + file descriptors so that fd_set-based primitives work even on + platforms lacking setrlimit (RLIMIT_NOFILE, ...) or if some Emacs + module or even some other process raises Emacs's RLIMIT_NOFILE limit. */ +static int +inrange_fd (int fd) +{ + if (fd < FD_SETSIZE) + return fd; + emacs_close (fd); + errno = EMFILE; + return -1; +} + +/* Create a pipe into FD[0] and fd[1], refusing to create file + descriptors out of range. This is like inrange_fd, that it + only. */ +static int +inrange_pipe (int fd[2]) +{ + int pipefd[2]; + int result = emacs_pipe (pipefd); + if (result < 0) + return result; + else if (pipefd[0] < FD_SETSIZE && pipefd[1] < FD_SETSIZE) + { + fd[0] = pipefd[0]; + fd[1] = pipefd[1]; + return result; + } + else + { + inrange_fd (pipefd[0]); + inrange_fd (pipefd[1]); + return -1; + } +} /* Add a file descriptor FD to be monitored for when read is possible. When read is possible, call FUNC with argument DATA. */ @@ -493,7 +531,7 @@ add_read_fd (int fd, fd_callback func, void *data) void add_non_keyboard_read_fd (int fd, fd_callback func, void *data) { - add_read_fd(fd, func, data); + add_read_fd (fd, func, data); fd_callback_info[fd].flags &= ~KEYBOARD_FD; } @@ -863,6 +901,8 @@ allocate_pty (char pty_name[PTY_NAME_SIZE]) fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0); #endif /* no PTY_OPEN */ + fd = inrange_fd (fd); + if (fd >= 0) { #ifdef PTY_TTY_NAME_SPRINTF @@ -892,6 +932,8 @@ allocate_pty (char pty_name[PTY_NAME_SIZE]) setup_pty (fd); return fd; } + else if (errno == EMFILE) + return fd; } #endif /* HAVE_PTYS */ return -1; @@ -2184,7 +2226,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) then close it and reopen it in the child. */ /* Don't let this terminal become our controlling terminal (in case we don't have one). */ - pty_tty = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); + pty_tty = inrange_fd (emacs_open (pty_name, O_RDWR | O_NOCTTY, 0)); if (pty_tty < 0) report_file_error ("Opening pty", Qnil); #endif /* not USG, or USG_SUBTTY_WORKS */ @@ -2201,7 +2243,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) } else { - if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0) + if (inrange_pipe (p->open_fd + SUBPROCESS_STDIN) < 0) report_file_error ("Creating pipe", Qnil); forkin = p->open_fd[SUBPROCESS_STDIN]; outchannel = p->open_fd[WRITE_TO_SUBPROCESS]; @@ -2215,7 +2257,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) } else { - if (emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0) + if (inrange_pipe (p->open_fd + READ_FROM_SUBPROCESS) < 0) report_file_error ("Creating pipe", Qnil); inchannel = p->open_fd[READ_FROM_SUBPROCESS]; forkout = p->open_fd[SUBPROCESS_STDOUT]; @@ -2239,11 +2281,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]); } - if (FD_SETSIZE <= inchannel || FD_SETSIZE <= outchannel) - report_file_errno ("Creating pipe", Qnil, EMFILE); - #ifndef WINDOWSNT - if (emacs_pipe (p->open_fd + READ_FROM_EXEC_MONITOR) != 0) + if (inrange_pipe (p->open_fd + READ_FROM_EXEC_MONITOR) < 0) report_file_error ("Creating pipe", Qnil); #endif @@ -2351,14 +2390,12 @@ create_pty (Lisp_Object process) if (pty_fd >= 0) { p->open_fd[SUBPROCESS_STDIN] = pty_fd; - if (FD_SETSIZE <= pty_fd) - report_file_errno ("Opening pty", Qnil, EMFILE); #if ! defined (USG) || defined (USG_SUBTTY_WORKS) /* On most USG systems it does not work to open the pty's tty here, then close it and reopen it in the child. */ /* Don't let this terminal become our controlling terminal (in case we don't have one). */ - int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); + int forkout = inrange_fd (emacs_open (pty_name, O_RDWR | O_NOCTTY, 0)); if (forkout < 0) report_file_error ("Opening pty", Qnil); p->open_fd[WRITE_TO_SUBPROCESS] = forkout; @@ -2455,15 +2492,11 @@ usage: (make-pipe-process &rest ARGS) */) record_unwind_protect (remove_process, proc); p = XPROCESS (proc); - if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0 - || emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0) + if (inrange_pipe (p->open_fd + SUBPROCESS_STDIN) < 0 + || inrange_pipe (p->open_fd + READ_FROM_SUBPROCESS) < 0) report_file_error ("Creating pipe", Qnil); outchannel = p->open_fd[WRITE_TO_SUBPROCESS]; inchannel = p->open_fd[READ_FROM_SUBPROCESS]; - - if (FD_SETSIZE <= inchannel || FD_SETSIZE <= outchannel) - report_file_errno ("Creating pipe", Qnil, EMFILE); - fcntl (inchannel, F_SETFL, O_NONBLOCK); fcntl (outchannel, F_SETFL, O_NONBLOCK); @@ -3209,10 +3242,10 @@ usage: (make-serial-process &rest ARGS) */) record_unwind_protect (remove_process, proc); p = XPROCESS (proc); - fd = serial_open (port); + fd = inrange_fd (serial_open (port)); + if (fd < 0) + report_file_error ("Opening serial port", port); p->open_fd[SUBPROCESS_STDIN] = fd; - if (FD_SETSIZE <= fd) - report_file_errno ("Opening serial port", port, EMFILE); p->infd = fd; p->outfd = fd; if (fd > max_desc) @@ -3471,20 +3504,12 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos, int socktype = p->socktype | SOCK_CLOEXEC; if (p->is_non_blocking_client) socktype |= SOCK_NONBLOCK; - s = socket (family, socktype, protocol); + s = inrange_fd (socket (family, socktype, protocol)); if (s < 0) { xerrno = errno; continue; } - /* Reject file descriptors that would be too large. */ - if (FD_SETSIZE <= s) - { - emacs_close (s); - s = -1; - xerrno = EMFILE; - continue; - } } if (p->is_non_blocking_client && ! (SOCK_NONBLOCK && socket_to_use < 0)) @@ -4500,7 +4525,7 @@ network_interface_info (Lisp_Object ifname) error ("Interface name too long"); lispstpcpy (rq.ifr_name, ifname); - s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); + s = inrange_fd (socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)); if (s < 0) return Qnil; specpdl_ref count = SPECPDL_INDEX (); @@ -4979,14 +5004,7 @@ server_accept_connection (Lisp_Object server, int channel) union u_sockaddr saddr; socklen_t len = sizeof saddr; - s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC); - - if (FD_SETSIZE <= s) - { - emacs_close (s); - s = -1; - errno = EMFILE; - } + s = inrange_fd (accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC)); if (s < 0) { @@ -7484,7 +7502,7 @@ process has been transmitted to the serial port. */) shutdown (old_outfd, 1); #endif close_process_fd (&p->open_fd[WRITE_TO_SUBPROCESS]); - new_outfd = emacs_open (NULL_DEVICE, O_WRONLY, 0); + new_outfd = inrange_fd (emacs_open (NULL_DEVICE, O_WRONLY, 0)); if (new_outfd < 0) report_file_error ("Opening null device", Qnil); p->open_fd[WRITE_TO_SUBPROCESS] = new_outfd; @@ -7567,17 +7585,8 @@ child_signal_init (void) return; /* already done */ int fds[2]; - if (emacs_pipe (fds) < 0) + if (inrange_pipe (fds) < 0) report_file_error ("Creating pipe for child signal", Qnil); - if (FD_SETSIZE <= fds[0]) - { - /* Since we need to `pselect' on the read end, it has to fit - into an `fd_set'. */ - emacs_close (fds[0]); - emacs_close (fds[1]); - report_file_errno ("Creating pipe for child signal", Qnil, - EMFILE); - } /* We leave the file descriptors open until the Emacs process exits. */ @@ -8726,7 +8735,13 @@ init_process_emacs (int sockfd) #endif #ifdef HAVE_SETRLIMIT - /* Don't allocate more than FD_SETSIZE file descriptors for Emacs itself. */ + /* Don't allocate more than FD_SETSIZE file descriptors for Emacs itself. + This is for performance, so that we needn't open file descriptors + only to immediately close them and fail. The rest of this module + does not rely on emacs_open, accept4, socket, emacs_pipe, etc. + to always return values less than FD_SETSIZE, since not every + platform has setrlimit, and even for those that do, an Emacs + module or even some other process can raise Emacs's limit. */ if (getrlimit (RLIMIT_NOFILE, &nofile_limit) != 0) nofile_limit.rlim_cur = 0; else if (FD_SETSIZE < nofile_limit.rlim_cur) From 520c5b7c71b38464f8fdcee0e61532086a96b466 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 19 May 2026 13:57:47 +0300 Subject: [PATCH 026/112] ; * doc/lispref/text.texi (Special Properties): Fix last change. --- doc/lispref/text.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 7f43c631482..5ef6cbebfb9 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -4022,7 +4022,7 @@ the cursor is entering the text that has this property or leaving it, or Other values for the direction should be ignored. Whether the boundary positions (at the beginning and end of an overlay or a stretch of text-property) are considered as inside or outside follows -the same rules as for @code{get-pos-property}, see @pxref{Boundaries of +the same rules as for @code{get-pos-property}, @pxref{Boundaries of text and overlay properties}. The functions are called only when the minor mode @code{cursor-sensor-mode} is turned on. From e90cafc2886dec40d241db16cc5cf89d44d34502 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 19 May 2026 15:13:04 +0300 Subject: [PATCH 027/112] ; * doc/lispref/display.texi (Displaying Faces): Mention 'margin' face. --- doc/lispref/display.texi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 763a8be7ce9..09022883f71 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -3538,6 +3538,11 @@ attributes, Emacs applies the face attributes of the ``underlying'' buffer text. Note that this is so even if the overlay or display string is displayed in the display margins (@pxref{Display Margins}). +@item +If the text is to be shown in the display margins, and any given +attribute has not been specified during the preceding steps, Emacs +applies the attribute of the @code{margin} face. + @item If any given attribute has not been specified during the preceding steps, Emacs applies the attribute of the @code{default} face. From 7d84e69a3493f821a3cc3076a726d0dedf1727c5 Mon Sep 17 00:00:00 2001 From: Lin Sun Date: Thu, 14 May 2026 06:31:09 +0000 Subject: [PATCH 028/112] hideshow: Menu entry for 'hs-toggle-all' * lisp/progmodes/hideshow.el: Menu entry for hs-toggle-all (bug#81045). --- lisp/progmodes/hideshow.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el index 44b50584bf4..92a85473bc0 100644 --- a/lisp/progmodes/hideshow.el +++ b/lisp/progmodes/hideshow.el @@ -567,8 +567,10 @@ KEYMAP, KEY and DEFINITION are the same arguments as the ones of :help "Show all the blocks in the buffer"] ["Hide Level" hs-hide-level :help "Hide all block at levels below the current block"] - ["Toggle Hiding" hs-toggle-hiding + ["Toggle Hiding Current Block" hs-toggle-hiding :help "Toggle the hiding state of the current block"] + ["Toggle Hiding All Blocks" hs-toggle-all + :help "Toggle the hiding state of all the blocks"] "----" ["Hide comments when hiding all" (setq hs-hide-comments-when-hiding-all From c80d22dcfcc3a0b5ef8629bb4e12d18b2be01e2c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 May 2026 08:49:09 -0700 Subject: [PATCH 029/112] Remove stray inrange_pipe comment --- src/process.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/process.c b/src/process.c index 9e807bef44e..c4d9d657e4f 100644 --- a/src/process.c +++ b/src/process.c @@ -492,8 +492,7 @@ inrange_fd (int fd) } /* Create a pipe into FD[0] and fd[1], refusing to create file - descriptors out of range. This is like inrange_fd, that it - only. */ + descriptors out of range. */ static int inrange_pipe (int fd[2]) { From b3b3e203cc92b6dddee3059dc53255ea9657093f Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 May 2026 08:58:18 -0700 Subject: [PATCH 030/112] Fix unlikely dump_off overflow in pdumper * src/pdumper.c (dump_grow_buffer): Remove. (dump_write): Use xpalloc instead. Avoid undefined behavior if (ctx->offset + nbyte) exceeds DUMP_OFF_MAX. --- src/pdumper.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/pdumper.c b/src/pdumper.c index b0f40c6e3ce..259ecf7301d 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -607,13 +607,6 @@ static struct link_weight const /* Dump file creation */ -static void dump_grow_buffer (struct dump_context *ctx) -{ - ctx->buf = xrealloc (ctx->buf, ctx->buf_size = (ctx->buf_size ? - (ctx->buf_size * 2) - : 8 * 1024 * 1024)); -} - static dump_off dump_object (struct dump_context *ctx, Lisp_Object object); static dump_off dump_object_for_offset (struct dump_context *ctx, Lisp_Object object); @@ -786,9 +779,17 @@ dump_write (struct dump_context *ctx, const void *buf, dump_off nbyte) eassert (nbyte == 0 || buf != NULL); eassert (ctx->obj_offset == 0); eassert (ctx->flags.dump_object_contents); - while (ctx->offset + nbyte > ctx->buf_size) - dump_grow_buffer (ctx); - memcpy ((char *)ctx->buf + ctx->offset, buf, nbyte); + dump_off avail = ctx->buf_size - ctx->offset; + if (avail < nbyte) + { + static_assert (DUMP_OFF_MAX <= PTRDIFF_MAX); + ptrdiff_t buf_size = ctx->buf_size; + ctx->buf = xpalloc (ctx->buf, &buf_size, + max (nbyte - avail, 8 * 1024 * 1024), + DUMP_OFF_MAX, 1); + ctx->buf_size = buf_size; + } + memcpy ((char *) {ctx->buf} + ctx->offset, buf, nbyte); ctx->offset += nbyte; } From fe33900747e4260c698508fc43e8c4391fa5c53a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 May 2026 09:06:37 -0700 Subject: [PATCH 031/112] Simplify serial_open * src/sysdep.c (serial_open): On failure, simply return -1 and set errno; do not call report_file_error, as the caller is supposed to do that if needed. --- src/sysdep.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sysdep.c b/src/sysdep.c index 10269e4d0ce..b2cd769784c 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -2980,10 +2980,9 @@ int serial_open (Lisp_Object port) { int fd = emacs_open (SSDATA (port), O_RDWR | O_NOCTTY | O_NONBLOCK, 0); - if (fd < 0) - report_file_error ("Opening serial port", port); #ifdef TIOCEXCL - ioctl (fd, TIOCEXCL, (char *) 0); + if (0 <= fd) + ioctl (fd, TIOCEXCL, (char *) 0); #endif return fd; From 2dbfed05322bde0703c2a8a841c8a90174120454 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 May 2026 09:09:21 -0700 Subject: [PATCH 032/112] display_tty_menu_item eassert for absurdly long item texts * src/xdisp.c (display_tty_menu_item): Add an eassert. --- src/xdisp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xdisp.c b/src/xdisp.c index c1d6fedb553..b00a4b2e1e7 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -27922,6 +27922,11 @@ display_tty_menu_item (const char *item_text, int width, int face_id, struct glyph_row *row; size_t item_len = strlen (item_text); + /* FIXME: callers do not seem to guarantee that the length is sane. + If it gets close to or greater than INT_MAX, things will go squirrelly. + Also, shouldn't this use menu_item_width rather than strlen? */ + eassert (item_len <= INT_MAX / 2); + struct frame *rf = NULL; if (FRAME_PARENT_FRAME (f) && !FRAME_WINDOW_P (f) From a8b9fad89720847a869bf288eb41473b6c82b833 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 May 2026 10:21:56 -0700 Subject: [PATCH 033/112] Make X_ERROR_MESSAGE_SIZE dependency more explicit This avoids an alloca in x_set_mouse_color. * src/xfns.c (x_set_mouse_color): Use local array rather than alloca, since the string is small. * src/xterm.c (X_ERROR_MESSAGE_SIZE): Move defn from here ... * src/xterm.h: ... to here, and make it an enum not a macro. --- src/xfns.c | 7 +++---- src/xterm.c | 2 -- src/xterm.h | 2 ++ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/xfns.c b/src/xfns.c index 7427144b103..7ec6025ab66 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1398,10 +1398,9 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) if (x_had_errors_p (dpy)) { const char *bad_cursor_name = NULL; - /* Bounded by X_ERROR_MESSAGE_SIZE in xterm.c. */ - size_t message_length = strlen (cursor_data.error_string); - char *xmessage = alloca (1 + message_length); - memcpy (xmessage, cursor_data.error_string, message_length); + char xmessage[X_ERROR_MESSAGE_SIZE]; + eassert (strlen (cursor_data.error_string) < sizeof xmessage); + strcpy (xmessage, cursor_data.error_string); x_uncatch_errors_after_check (); diff --git a/src/xterm.c b/src/xterm.c index 1401693541c..b2a0d2cadcc 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -26321,8 +26321,6 @@ x_unwind_errors_to (int depth) x_uncatch_errors (); } -#define X_ERROR_MESSAGE_SIZE 200 - /* An X error handler which stores the error message in the first applicable handler in the x_error_message stack. This is called from *x_error_handler if an x_catch_errors for DISPLAY is in diff --git a/src/xterm.h b/src/xterm.h index 962c856e772..28b720c9222 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -129,6 +129,8 @@ typedef GtkWidget *xt_or_gtk_widget; #include "dispextern.h" #include "termhooks.h" +enum { X_ERROR_MESSAGE_SIZE = 200 }; + INLINE_HEADER_BEGIN /* Black and white pixel values for the screen which frame F is on. */ From 997fc2cef771d05f866480153a8909ad51484d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Marks?= Date: Thu, 14 May 2026 13:44:37 -0400 Subject: [PATCH 034/112] Allow markdown-ts--run-command-in-code-block to ignore output (bug#81041) Do not assume every command run in 'markdown-ts--run-command-in-code-block' produces output that needs to be merged from the temp/work buffer into the source buffer. One example is 'xref-find-definitions', the temp buffer of which is unrelated to the source buffer. * lisp/textmodes/markdown-ts-mode.el (markdown-ts-code-block-commands): Add 'complete-symbol'. (markdown-ts-code-block-ignore-output-commands): New defvar. (markdown-ts--run-command-in-code-block): Ignore command output when necessary. --- lisp/textmodes/markdown-ts-mode.el | 41 ++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el index d2f4fcd8fa7..515d0620127 100644 --- a/lisp/textmodes/markdown-ts-mode.el +++ b/lisp/textmodes/markdown-ts-mode.el @@ -3043,6 +3043,7 @@ force mode probe. Return a valid mode symbol or nil." (defvar markdown-ts-code-block-commands '(indent-for-tab-command electric-newline-and-maybe-indent completion-at-point + complete-symbol newline comment-dwim comment-line @@ -3056,6 +3057,10 @@ See `markdown-ts--run-command-in-code-block'.") "Commands that need a \"thing\" at point in a code-block context. See `markdown-ts--run-command-in-code-block'.") +(defvar markdown-ts-code-block-ignore-output-commands '(xref-find-definitions) + "Commands whose output to ignore when executed in a code-block context. +See `markdown-ts--run-command-in-code-block'.") + (defvar markdown-ts-code-block-region-commands '(comment-or-uncomment-region) "Commands that need a region in a code-block context. See `markdown-ts--run-command-in-code-block'.") @@ -3179,6 +3184,8 @@ ARGS are captured by `markdown-ts--maybe-run-command-in-code-block'." (adj-region-beg (when region-beg (1+ (- orig-point region-beg)))) (adj-region-end (when region-end (1+ (- orig-point region-end)))) (point-delta 0) + (ignore-output + (memq command markdown-ts-code-block-ignore-output-commands)) (source-buffer (current-buffer))) (with-work-buffer (insert str) @@ -3208,22 +3215,24 @@ ARGS are captured by `markdown-ts--maybe-run-command-in-code-block'." (funcall-interactively command (car args))) (t (apply #'funcall-interactively command args))) - (setq str (buffer-substring-no-properties (point-min) (point-max))) - (setq temp-deactivate-mark deactivate-mark) - (setq point-delta (- (point) point))) - (let ((work-buffer (current-buffer))) - (with-current-buffer source-buffer - (replace-region-contents beg end work-buffer) - ;; Propagate mark deactivation to the source buffer. - (setq deactivate-mark temp-deactivate-mark) - ;; Move point if it moved in the temp buffer. - (goto-char (+ orig-point point-delta)) - ;; Record the original command. - (setq this-command command) - ;; This helps maintain discrete command actions. - (undo-boundary) - ;; Make sure the originating region is refontified. - (font-lock-flush beg end))))))) + (unless ignore-output + (setq str (buffer-substring-no-properties (point-min) (point-max))) + (setq temp-deactivate-mark deactivate-mark) + (setq point-delta (- (point) point)))) + (unless ignore-output + (let ((work-buffer (current-buffer))) + (with-current-buffer source-buffer + (replace-region-contents beg end work-buffer) + ;; Propagate mark deactivation to the source buffer. + (setq deactivate-mark temp-deactivate-mark) + ;; Move point if it moved in the temp buffer. + (goto-char (+ orig-point point-delta)) + ;; This helps maintain discrete command actions. + (undo-boundary) + ;; Make sure the originating region is refontified. + (font-lock-flush beg end)))) + ;; Record the original command. + (setq this-command command))))) (defun markdown-ts--find-code-block-delimiter (pos &optional backward) "Return the next or previous fenced_code_block_delimiter node, or nil. From e0aeee2dc5fc898eae28dd6bbacce232387fb49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Marks?= Date: Thu, 14 May 2026 14:08:02 -0400 Subject: [PATCH 035/112] Fix markdown-ts-mode atx_heading face computation (bug#81042) The grammar reports leading spaces as part of the atx_heading "marker" and we cannot use the length of the marker as a result. Instead, count the number of consecutive # after any blanks to determine its "level." * lisp/textmodes/markdown-ts-mode.el (markdown-ts--fontify-atx-heading): Count the octothorpes rather than using the length of the marker node's text. --- lisp/textmodes/markdown-ts-mode.el | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el index 515d0620127..6430e2c8119 100644 --- a/lisp/textmodes/markdown-ts-mode.el +++ b/lisp/textmodes/markdown-ts-mode.el @@ -1093,8 +1093,12 @@ CommonMark they are decorative and must be preceded by a space or tab." (let* ((n-start (treesit-node-start node)) (n-end (treesit-node-end node)) (face (let ((marker (treesit-node-child node 0))) - (intern (format "markdown-ts-heading-%d" - (length (treesit-node-text marker t))))))) + (intern + (format "markdown-ts-heading-%d" + (progn + (string-match "[[:blank:]]*\\([#]+\\)" + (treesit-node-text marker t)) + (- (match-end 1) (match-beginning 1)))))))) (font-lock--remove-face-from-text-property n-start n-end 'face face) (font-lock-append-text-property n-start (1- n-end) 'face face) (save-excursion From 133d1d591cb930010d610a1948bc3bae995bb5cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Thu, 14 May 2026 10:38:46 +0100 Subject: [PATCH 036/112] markdown-ts-mode: align default face definitions with markdown-mode Match the out-of-the-box appearance of markdown-ts-mode to the non-tree-sitter markdown-mode package, making switching between modes less jarring. * lisp/textmodes/markdown-ts-mode.el (markdown-ts-delimiter) (markdown-ts-heading-1, markdown-ts-heading-2, markdown-ts-heading-3) (markdown-ts-heading-4, markdown-ts-heading-5, markdown-ts-heading-6) (markdown-ts-block-quote, markdown-ts-code-block, markdown-ts-code-span) (markdown-ts-indented-code-block, markdown-ts-html-tag) (markdown-ts-html-block, markdown-ts-thematic-break) (markdown-ts-entity-reference, markdown-ts-numeric-character-reference) (markdown-ts-table, markdown-ts-table-header, markdown-ts-table-cell) (markdown-ts-table-delimiter-cell, markdown-ts-language-keyword) (markdown-ts-list-marker, markdown-ts-hard-line-break-backslash) (markdown-ts-hard-line-break-backslash-hidden) (markdown-ts-hard-line-break-space-hidden) (markdown-ts-task-unchecked, markdown-ts-task-checked): Tweak. --- lisp/textmodes/markdown-ts-mode.el | 54 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el index 6430e2c8119..01b7ac09995 100644 --- a/lisp/textmodes/markdown-ts-mode.el +++ b/lisp/textmodes/markdown-ts-mode.el @@ -583,11 +583,11 @@ newline." :group 'markdown-ts-faces :group 'faces) -(defface markdown-ts-delimiter '((t (:inherit shadow))) +(defface markdown-ts-delimiter '((t (:inherit shadow :slant normal :weight normal))) "Face for the # before Markdown headings." :version "31.1") -(defface markdown-ts-heading-1 '((t (:inherit outline-1))) +(defface markdown-ts-heading-1 '((t (:inherit font-lock-function-name-face :weight bold))) "Face for first level Markdown headings." :version "31.1") @@ -595,23 +595,23 @@ newline." "Face for setext Markdown headings (headings underlined by === or ---)." :version "31.1") -(defface markdown-ts-heading-2 '((t (:inherit outline-2))) +(defface markdown-ts-heading-2 '((t (:inherit font-lock-function-name-face :weight bold))) "Face for second level Markdown headings." :version "31.1") -(defface markdown-ts-heading-3 '((t (:inherit outline-3))) +(defface markdown-ts-heading-3 '((t (:inherit font-lock-function-name-face :weight bold))) "Face for third level Markdown headings." :version "31.1") -(defface markdown-ts-heading-4 '((t (:inherit outline-4))) +(defface markdown-ts-heading-4 '((t (:inherit font-lock-function-name-face :weight bold))) "Face for fourth level Markdown headings." :version "31.1") -(defface markdown-ts-heading-5 '((t (:inherit outline-5))) +(defface markdown-ts-heading-5 '((t (:inherit font-lock-function-name-face :weight bold))) "Face for fifth level Markdown headings." :version "31.1") -(defface markdown-ts-heading-6 '((t (:inherit outline-6))) +(defface markdown-ts-heading-6 '((t (:inherit font-lock-function-name-face :weight bold))) "Face for sixth level Markdown headings." :version "31.1") @@ -627,7 +627,7 @@ newline." "Face for Markdown strikethrough text." :version "31.1") -(defface markdown-ts-block-quote '((t (:inherit italic))) +(defface markdown-ts-block-quote '((t (:inherit font-lock-doc-face))) "Face for Markdown block quotes." :version "31.1") @@ -639,11 +639,11 @@ newline." "Face for Markdown link destinations (URLs)." :version "31.1") -(defface markdown-ts-code-span '((t (:inherit font-lock-keyword-face))) +(defface markdown-ts-code-span '((t (:inherit (markdown-ts-code-block font-lock-constant-face)))) "Face for Markdown inline code spans." :version "31.1") -(defface markdown-ts-code-block '((t (:extend t))) +(defface markdown-ts-code-block '((t (:inherit fixed-pitch :extend t))) "Face for Markdown fenced code block content. Alter this face to add a `:background' for a visually distinct code block region, e.g.: @@ -666,29 +666,29 @@ Used instead of `markdown-ts-code-block' when `markdown-ts-hide-markup' is non-nil." :version "31.1") -(defface markdown-ts-indented-code-block '((t (:inherit font-lock-string-face))) +(defface markdown-ts-indented-code-block '((t (:inherit (markdown-ts-code-block font-lock-constant-face)))) "Face for Markdown indented code blocks." :version "31.1") -(defface markdown-ts-html-tag '((t (:inherit font-lock-doc-markup-face))) +(defface markdown-ts-html-tag '((t (:inherit font-lock-type-face))) "Face for inline HTML tags in Markdown." :version "31.1") -(defface markdown-ts-html-block '((t (:inherit font-lock-doc-markup-face))) +(defface markdown-ts-html-block '((t (:inherit font-lock-type-face))) "Face for HTML blocks in Markdown." :version "31.1") -(defface markdown-ts-thematic-break '((t (:inherit shadow :extend t))) +(defface markdown-ts-thematic-break '((t (:inherit markdown-ts-delimiter :extend t))) "Face for Markdown thematic breaks (horizontal rules). Customize this face to add a :background for a full-width visual rule." :version "31.1") -(defface markdown-ts-entity-reference '((t (:inherit font-lock-builtin-face))) +(defface markdown-ts-entity-reference '((t (:inherit font-lock-variable-name-face))) "Face for named HTML entity references like & and ©." :version "31.1") (defface markdown-ts-numeric-character-reference - '((t (:inherit font-lock-escape-face))) + '((t (:inherit font-lock-variable-name-face))) "Face for numeric character references like A and A." :version "31.1") @@ -696,19 +696,19 @@ Customize this face to add a :background for a full-width visual rule." "Face for LaTeX / math content in Markdown ($...$ and $$...$$)." :version "31.1") -(defface markdown-ts-table-header '((t (:inherit (bold font-lock-doc-face)))) +(defface markdown-ts-table-header '((t (:inherit markdown-ts-table))) "Face for Markdown pipe table header cells." :version "31.1") -(defface markdown-ts-table-cell '((t (:inherit default))) +(defface markdown-ts-table-cell '((t (:inherit markdown-ts-table))) "Face for Markdown pipe table data cells." :version "31.1") -(defface markdown-ts-table-delimiter-cell '((t (:inherit font-lock-doc-face))) +(defface markdown-ts-table-delimiter-cell '((t (:inherit markdown-ts-table))) "Face for Markdown pipe table delimiter cells (--- separators)." :version "31.1") -(defface markdown-ts-table '((t (:extend t))) +(defface markdown-ts-table '((t (:inherit (markdown-ts-code-block) :extend t))) "Face for Markdown table. Alter this face to add a `:background' for a visually distinct table region, e.g.: @@ -722,21 +722,21 @@ region, e.g.: (set-face-attribute \\='markdown-ts-in-table nil :background \"gray95\")" :version "31.1") -(defface markdown-ts-language-keyword '((t (:inherit font-lock-keyword-face))) +(defface markdown-ts-language-keyword '((t (:inherit font-lock-type-face))) "Face for the language keyword for Markdown code blocks." :version "31.1") -(defface markdown-ts-list-marker '((t (:inherit shadow))) +(defface markdown-ts-list-marker '((t (:inherit shadow :slant normal :weight normal))) "Face for Markdown list markers like - and *." :version "31.1") (defface markdown-ts-hard-line-break-backslash - '((t (:inherit outline-4 :weight bold))) + '((t (:inherit font-lock-constant-face :underline t))) "Face for Markdown hard line breaks introduced by a trailing backslash." :version "31.1") (defface markdown-ts-hard-line-break-backslash-hidden - '((t (:inherit outline-4 :weight bold))) + '((t (:inherit font-lock-constant-face :underline t))) "Face for trailing-backslash hard line break when markup is hidden." :version "31.1") @@ -749,15 +749,15 @@ shadow-colored block." :version "31.1") (defface markdown-ts-hard-line-break-space-hidden - '((t (:inherit outline-4 :weight bold))) + '((t (:inherit font-lock-constant-face :underline t))) "Face for trailing-spaces hard line break when markup is hidden." :version "31.1") -(defface markdown-ts-task-unchecked '((t (:inherit markdown-ts-list-marker))) +(defface markdown-ts-task-unchecked '((t (:inherit font-lock-builtin-face))) "Face for Markdown unchecked task list markers." :version "31.1") -(defface markdown-ts-task-checked '((t (:inherit markdown-ts-list-marker))) +(defface markdown-ts-task-checked '((t (:inherit font-lock-builtin-face))) "Face for Markdown checked task list markers." :version "31.1") From aad170d1edf70485995aafbabf4af6f4bcbca192 Mon Sep 17 00:00:00 2001 From: Rahul Martim Juliato Date: Tue, 19 May 2026 17:26:09 -0300 Subject: [PATCH 037/112] markdown-ts-mode: hide fence lines in view-mode (bug#81081) * lisp/textmodes/markdown-ts-mode.el (markdown-ts--fontify-delimiter): When `markdown-ts-hide-markup' is enabled in `markdown-ts-view-mode', also hide the whole line containing a `fenced_code_block_delimiter' (including its terminating newline) so Eldoc/LSP markdown snippets render without stray blank lines around the code block. Scoped to view-mode and to fenced delimiters on purpose: the same handler is shared by inline delimiters (emphasis, code span, link brackets) where munching surrounding whitespace would collapse word separators, and tuning rendering for hide-markup-while-editing is not a goal. --- lisp/textmodes/markdown-ts-mode.el | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el index 01b7ac09995..7f87ff5d0bc 100644 --- a/lisp/textmodes/markdown-ts-mode.el +++ b/lisp/textmodes/markdown-ts-mode.el @@ -842,8 +842,27 @@ OVERRIDE, START, and END are passed through to (treesit-node-start node) (treesit-node-end node) 'markdown-ts-delimiter override start end) (when markdown-ts-hide-markup - (put-text-property (treesit-node-start node) (treesit-node-end node) - 'invisible 'markdown-ts--markup))) + (if (and (derived-mode-p 'markdown-ts-view-mode) + (equal (treesit-node-type node) "fenced_code_block_delimiter")) + ;; In view-mode only, hide the whole line containing the fence + ;; (including its terminating newline) so Eldoc/LSP markdown + ;; snippets render without stray blank lines around the code + ;; block. Restricted to view-mode because hide-markup while + ;; editing already has UX hazards (point movement, backspace + ;; across invisible regions) and we should not tune rendering + ;; for that mode. Restricted to fenced_code_block_delimiter + ;; because the same handler is shared by inline delimiters + ;; (emphasis, code span, link brackets) where munching + ;; surrounding whitespace would collapse word separators. + (save-excursion + (goto-char (treesit-node-start node)) + (let ((bol (pos-bol)) + (eol+1 (progn (goto-char (treesit-node-end node)) + (min (point-max) (1+ (pos-eol)))))) + (put-text-property bol eol+1 + 'invisible 'markdown-ts--markup))) + (put-text-property (treesit-node-start node) (treesit-node-end node) + 'invisible 'markdown-ts--markup)))) (defun markdown-ts--fontify-atx-delimiter (node override start end &rest _) "Fontify atx_heading delimiter NODE and optionally hide its markup. From 8f31ccbf823bffa9ac46514e3c0ab1e464979c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Wed, 20 May 2026 00:51:57 +0100 Subject: [PATCH 038/112] Eglot: announce markdown support for completion docs No reason not to. Tested with gfm-view-mode and markdown-ts-mode * lisp/progmodes/eglot.el (eglot-client-capabilities): Annouce markdown support for completion docs. --- lisp/progmodes/eglot.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index ad21cd84d2f..a913271a41a 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1110,6 +1110,7 @@ object." t :json-false) :deprecatedSupport t + :documentationFormat ,(eglot--accepted-formats) :resolveSupport (:properties ["documentation" "details" From 1754015c6034d65b047d0ada23a406f114d7850d Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Wed, 20 May 2026 10:10:30 +0200 Subject: [PATCH 039/112] Improve auth-source-backend-parse * lisp/auth-source.el (auth-source-backend-parse): Use `run-hook-wrapped'. Suggested by Augusto Stoffel . Transform a warning into a debug message. --- lisp/auth-source.el | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/lisp/auth-source.el b/lisp/auth-source.el index f541dd3d141..ec48ab31580 100644 --- a/lisp/auth-source.el +++ b/lisp/auth-source.el @@ -361,23 +361,18 @@ soon as a function returns non-nil.") (defun auth-source-backend-parse (entry) "Create an `auth-source-backend' from an ENTRY in `auth-sources'." - (let* ((auth-source-backend-parser-functions - ;; The functions shall drop backends of type `ignore', in - ;; order to let the hook continue. - (mapcar - (lambda (fun) - `(lambda (entry) - (and-let* ((result (funcall ',fun entry)) - ((not (eq (slot-value result 'type) 'ignore))) - result)))) - auth-source-backend-parser-functions)) - (backend - (run-hook-with-args-until-success - 'auth-source-backend-parser-functions entry))) + (let* ((backend + (run-hook-wrapped + 'auth-source-backend-parser-functions + (lambda (fun entry) + (when-let* ((result (funcall fun entry)) + (_ (not (eq (slot-value result 'type) 'ignore)))) + result)) + entry))) (unless backend ;; none of the parsers worked - (auth-source-do-warn + (auth-source-do-debug "auth-source-backend-parse: invalid backend spec: %S" entry) (setq backend (make-instance 'auth-source-backend :source "" From 0b5ead9923516c18bbf45d499661a0641fb07731 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sun, 17 May 2026 15:27:03 +0000 Subject: [PATCH 040/112] Detect some API violations in combine-change-calls (bug#80877) Quickly verify that the number of unchanged characters before and after the region that changes are supposed to be limited to doesn't change. Suggested by Stefan Monnier. * lisp/subr.el (combine-change-calls-1): Copy BEG into a marker, and count the characters after the changed region. After the changes, ensure the character counts still match. * test/lisp/subr-tests.el (subr-test-combine-change-calls-error): New. --- lisp/subr.el | 15 +++++++++++++-- test/lisp/subr-tests.el | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lisp/subr.el b/lisp/subr.el index d97598ab61f..08eee8646a4 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -5664,10 +5664,17 @@ the function `undo--wrap-and-run-primitive-undo'." (if (markerp beg) (setq beg (marker-position beg))) (if (markerp end) (setq end (marker-position end))) (let ((old-bul buffer-undo-list) + (beg-marker (copy-marker beg)) + (unchanged-after (- (point-max) end)) (end-marker (copy-marker end t)) result) (if undo--combining-change-calls - (setq result (funcall body)) + (progn + (setq result (funcall body)) + (unless (and (= beg-marker beg) + (= unchanged-after (- (point-max) end-marker))) + (error "Modifications outside the announced region")) + (set-marker beg-marker nil)) (let ((undo--combining-change-calls t)) (if (not inhibit-modification-hooks) (run-hook-with-args 'before-change-functions beg end)) @@ -5686,7 +5693,11 @@ the function `undo--wrap-and-run-primitive-undo'." (if (memq #'syntax-ppss-flush-cache bcf) '(syntax-ppss-flush-cache))) (setq-local after-change-functions nil) - (setq result (funcall body))) + (setq result (funcall body)) + (unless (and (= beg-marker beg) + (= unchanged-after (- (point-max) end-marker))) + (error "Modifications outside the announced region")) + (set-marker beg-marker nil)) (if local-bcf (setq before-change-functions bcf) (kill-local-variable 'before-change-functions)) (if local-acf (setq after-change-functions acf) diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el index b99328459d6..b6e9eb92855 100644 --- a/test/lisp/subr-tests.el +++ b/test/lisp/subr-tests.el @@ -1773,5 +1773,24 @@ The argument names are important." '("foo" "bar" "bazzzzzz")) '(("foo" "bar") ("bazzzzzz")))))) +(ert-deftest subr-test-combine-change-calls-error () + "Test detection of unexpected changes in `combine-change-calls'." + (with-temp-buffer + (insert "a\nb\nc\n") + (combine-change-calls 3 5 + (goto-char (point-min)) + (search-forward "b") + (replace-match "bbb")) + (should-error + (combine-change-calls 3 7 + (goto-char (point-min)) + (search-forward "a") + (replace-match "aaa"))) + (should-error + (combine-change-calls 5 9 + (goto-char (point-min)) + (search-forward "c") + (replace-match "ccc"))))) + (provide 'subr-tests) ;;; subr-tests.el ends here From 3131d5660691749420467788b0aae14b1e3531d6 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Wed, 20 May 2026 13:53:47 +0000 Subject: [PATCH 041/112] Avoid crash in doprnt * src/doprnt.c (doprnt): Don't access string[-1]. --- src/doprnt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doprnt.c b/src/doprnt.c index 1a71752ddc0..69752abc3dc 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -434,7 +434,7 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, { /* Truncate the string at character boundary. */ tem = bufsize; - do + while (tem != 0) { tem--; if (CHAR_HEAD_P (string[tem])) @@ -444,7 +444,6 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, break; } } - while (tem != 0); memcpy (bufptr, string, tem); while (tem < bufsize) From 655302cc21222fe64078cde08eb75eb81bf2da7e Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Wed, 20 May 2026 18:41:59 +0300 Subject: [PATCH 042/112] Fix 'shr-outline-search' (bug#81073) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lisp/net/shr.el (shr-outline-search): Don't check for the beginning of the line. Suggested by Omar Antolín Camarena . Confirmed by Rahguzar . --- lisp/net/shr.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/net/shr.el b/lisp/net/shr.el index 7e47d93d81c..7c556cd88b8 100644 --- a/lisp/net/shr.el +++ b/lisp/net/shr.el @@ -2290,8 +2290,7 @@ See `outline-search-function' for BOUND, MOVE, BACKWARD and LOOKING-AT." (bound (or bound (if backward (point-min) (point-max))))) (save-excursion - (when (and (not (bolp)) - (get-text-property (point) 'outline-level)) + (when (get-text-property (point) 'outline-level) (forward-line (if backward -1 1))) (if backward (unless (get-text-property (point) 'outline-level) From 13b29eebc1663152ca10f55f8fcd659f48b80d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Thu, 21 May 2026 10:33:37 +0100 Subject: [PATCH 043/112] Eglot: use standard face for completion annotations (bug#81088) * lisp/progmodes/eglot.el (eglot-completion-at-point): Use completions-annotations face, not font-lock-function-name-face. --- lisp/progmodes/eglot.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index a913271a41a..e945dfb9739 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -4014,7 +4014,7 @@ for which LSP on-type-formatting should be requested." (when annotation (concat " " (propertize annotation - 'face 'font-lock-function-name-face)))))) + 'face 'completions-annotations)))))) :company-kind ;; Associate each lsp-item with a lsp-kind symbol. (lambda (proxy) From 0d5680665bc12d3b23383d222a0519d6cac2864a Mon Sep 17 00:00:00 2001 From: Roland Winkler Date: Thu, 21 May 2026 16:45:41 -0500 Subject: [PATCH 044/112] Etags handling of fortran files (bug#81086). * lib-src/etags.c: Tag fortran modules. Honor file extensions "f95", "f03", "f08" for fortran files. * doc/emacs/maintaining.texi: Update accordingly. --- doc/emacs/maintaining.texi | 3 ++- lib-src/etags.c | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index a1825c5e515..d103e7f961f 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -3250,7 +3250,8 @@ In Erlang code, the tags are the functions, records and macros defined in the file. @item -In Fortran code, functions, subroutines and block data are tags. +In Fortran code, modules, subroutines, functions, entries and block data +are tags. @item In Go code, packages, functions, and types are tags. diff --git a/lib-src/etags.c b/lib-src/etags.c index 89462dd5e7f..f218dba2902 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -652,9 +652,10 @@ static const char Forth_help [] = constant, code, create, defer, value, variable, buffer:, field."; static const char *Fortran_suffixes [] = - { "F", "f", "f90", "for", NULL }; + { "F", "f", "for", "f90", "f95", "f03", "f08", NULL }; static const char Fortran_help [] = -"In Fortran code, functions, subroutines and block data are tags."; +"In Fortran code, modules, subroutines, functions, entries\n\ +and block data are tags."; static const char *Go_suffixes [] = {"go", NULL}; static const char Go_help [] = @@ -4567,6 +4568,10 @@ Fortran_functions (FILE *inf) continue; switch (c_tolower (*dbp)) { + case 'm': + if (nocase_tail ("module")) + F_getit (inf); + continue; case 'f': if (nocase_tail ("function")) F_getit (inf); From 98348a0bdc97f305d3d18569c0d93afc8af1bac9 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Fri, 22 May 2026 01:50:03 +0300 Subject: [PATCH 045/112] [Xt] Fix child frame resizing glitch * src/widget.c (EmacsFrameResize): Exit early for child frames (bug#81077). --- src/widget.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/widget.c b/src/widget.c index b843bca1fb9..f05818fcc76 100644 --- a/src/widget.c +++ b/src/widget.c @@ -428,8 +428,7 @@ EmacsFrameResize (Widget widget) ew->core.width, ew->core.height, f->new_width, f->new_height); - if (FRAME_PIXEL_WIDTH (f) == ew->core.width - && FRAME_PIXEL_HEIGHT (f) == ew->core.height) + if (FRAME_PARENT_FRAME (f)) /* Size always up to date. */ return; change_frame_size (f, ew->core.width, ew->core.height, From 2936b36164ded60e0257f1ee872ff333bc4f4abd Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Fri, 22 May 2026 06:46:47 +0300 Subject: [PATCH 046/112] Fix "assertion 'GTK_IS_WINDOW (window)' failed" * src/gtkutil.c (xg_frame_set_size_and_position): Remove a gtk_window_resize call which used a wrong value type (GdkX11Window instead of GtkWindow). The original motivation for that line seems to be fixed by later changes (bug#80662). --- src/gtkutil.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gtkutil.c b/src/gtkutil.c index daa3fd1b993..4fc6b3e0108 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -1352,8 +1352,6 @@ xg_frame_set_size_and_position (struct frame *f, int width, int height) gdk_window_move_resize (gwin, x, y, outer_width, outer_height); if (FRAME_PARENT_FRAME (f)) { - /* Record the dimensions for GTK to remember after remapping. */ - gtk_window_resize (GTK_WINDOW (gwin), outer_width, outer_height); /* Resize all inner widgets and Cairo surface right away so the next redisplay drawing isn't clipped to the old size. */ GtkAllocation alloc = {0, 0, outer_width, outer_height}; From cda03bebfc061174229bb8b9816f04a9ed537038 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 22 May 2026 12:31:04 +0300 Subject: [PATCH 047/112] Improve w32 implementations of 'signal' and 'raise' * src/w32proc.c (w32_raise): A more complete, Posix-compliant implementation. (sys_signal): Support SIGBREAK. * src/syssignal.h (raise): Redirect to 'w32_raise'. * src/atimer.c: Don't redirect 'raise', now done in syssignal.h. (Bug#80760) --- src/atimer.c | 4 ---- src/syssignal.h | 5 +++++ src/w32proc.c | 57 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/atimer.c b/src/atimer.c index c205f658d74..72e33656b4a 100644 --- a/src/atimer.c +++ b/src/atimer.c @@ -18,10 +18,6 @@ along with GNU Emacs. If not, see . */ #include -#ifdef WINDOWSNT -#define raise(s) w32_raise(s) -#endif - #include "lisp.h" #include "keyboard.h" #include "syssignal.h" diff --git a/src/syssignal.h b/src/syssignal.h index 4a90ece68fe..84a2a6760e4 100644 --- a/src/syssignal.h +++ b/src/syssignal.h @@ -70,6 +70,11 @@ char const *safe_strsignal (int) ATTRIBUTE_CONST; # define SA_SIGINFO 0 #endif +#ifdef WINDOWSNT +#define raise(sig) w32_raise(sig) +int w32_raise (int); +#endif + #ifndef emacs_raise # define emacs_raise(sig) raise (sig) #endif diff --git a/src/w32proc.c b/src/w32proc.c index 57530b5d8e5..b89979c7314 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -63,8 +63,6 @@ along with GNU Emacs. If not, see . */ #include "w32term.h" #include "coding.h" -void w32_raise (int); - #define RVA_TO_PTR(var,section,filedata) \ ((void *)((section)->PointerToRawData \ + ((DWORD_PTR)(var) - (section)->VirtualAddress) \ @@ -169,7 +167,7 @@ sys_signal (int sig, signal_handler handler) /* SIGCHLD is needed for supporting subprocesses, see sys_kill below. SIGALRM and SIGPROF are used by setitimer. All the others are the only ones supported by the MS runtime. */ - if (!(sig == SIGINT || sig == SIGSEGV || sig == SIGILL + if (!(sig == SIGINT || sig == SIGSEGV || sig == SIGILL || sig == SIGBREAK || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM || sig == SIGCHLD || sig == SIGALRM || sig == SIGPROF)) { @@ -313,19 +311,52 @@ sigismember (const sigset_t *set, int signo) return (*set & (1U << signo)) != 0; } -/* A fuller emulation of 'raise', which supports signals that MS - runtime doesn't know about. */ -void +/* A fuller emulation of 'raise', which supports signals that MS runtime + doesn't know about, and avoids the danger of invoking the + invalid-argument handler. syssignal.h redirects 'raise' to this. */ + +#undef raise + +int w32_raise (int signo) { - if (!(signo == SIGCHLD || signo == SIGALRM || signo == SIGPROF)) - raise (signo); + signal_handler handler; - /* Call the handler directly for the signals that we handle - ourselves. */ - signal_handler handler = sig_handlers[signo]; - if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR)) - handler (signo); + switch (signo) + { + /* Signals supported by MS runtime: */ + case SIGINT: + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGBREAK: + case SIGABRT: + return raise (signo); + /* For signals for which we have custom support in Emacs, call the + handler directly. */ + case SIGCHLD: + case SIGALRM: + case SIGPROF: + handler = sig_handlers[signo]; + /* Implementation note: SIG_DFL does nothing, since these signals + are not supported by the MS runtime. */ + if (handler == SIG_IGN || handler == SIG_DFL) + return 0; + else if (handler == SIG_ERR) + { + errno = EINVAL; + return -1; + } + sig_handlers[signo] = SIG_DFL; /* in case handler raises same signal */ + handler (signo); + if (sig_handlers[signo] == SIG_DFL) + sig_handlers[signo] = handler; + return 0; + default: /* Any unsupported signal. */ + errno = EINVAL; + return -1; + } } pid_t From 7df8604ea635e7940af19e0fe06e5f644181f32e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 22 May 2026 14:46:13 +0300 Subject: [PATCH 048/112] ; Improve documentation of lazy-highlight in search and replace commands * lisp/isearch.el (lazy-highlight, lazy-highlight-initial-delay) (lazy-highlight-buffer, isearch-lazy-highlight, isearch-forward): * lisp/replace.el (query-replace, query-replace-lazy-highlight) (query-replace, query-replace-regexp): Doc fixes. * doc/emacs/search.texi (Search Customizations): Document 'lazy-highlight-buffer' and 'lazy-highlight-buffer-max-at-a-time'. Use @vtable to avoid the need of indexing each variable separately. --- doc/emacs/search.texi | 25 ++++++++++++++++--------- lisp/isearch.el | 18 ++++++++++++++---- lisp/replace.el | 22 ++++++++++++++++++---- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi index 2bd35380780..5f7aa1f1ef5 100644 --- a/doc/emacs/search.texi +++ b/doc/emacs/search.texi @@ -2202,24 +2202,20 @@ variable @code{isearch-lazy-highlight} to @code{nil} disables this highlighting. Here are some other variables that customize the lazy highlighting: -@table @code +@vtable @code @item lazy-highlight-initial-delay -@vindex lazy-highlight-initial-delay Time in seconds to wait before highlighting visible matches. Applies only if the search string is less than @code{lazy-highlight-no-delay-length} characters long. @item lazy-highlight-no-delay-length -@vindex lazy-highlight-no-delay-length For search strings at least as long as the value of this variable, lazy highlighting of matches starts immediately. @item lazy-highlight-interval -@vindex lazy-highlight-interval Time in seconds between highlighting successive matches. @item lazy-highlight-max-at-a-time -@vindex lazy-highlight-max-at-a-time The maximum number of matches to highlight before checking for input. A large number can take some time to highlight, so if you want to continue searching and type @kbd{C-s} or @kbd{C-r} during that time, @@ -2227,17 +2223,28 @@ Emacs will not respond until it finishes highlighting all those matches. Thus, smaller values make Emacs more responsive. @item isearch-lazy-count -@vindex isearch-lazy-count Show the current match number and the total number of matches in the search prompt. @item lazy-count-prefix-format @itemx lazy-count-suffix-format -@vindex lazy-count-prefix-format -@vindex lazy-count-suffix-format These two variables determine the format of showing the current and the total number of matches for @code{isearch-lazy-count}. -@end table + +@item lazy-highlight-buffer +If non-@code{nil}, lazy highlighting highlights the matches in the +entire buffer, not only those visible on display of the current window +(so, for example, they will also become visible in other windows showing +the same buffer). + +@item lazy-highlight-buffer-max-at-a-time +Like @code{lazy-highlight-max-at-a-time}, but used for highlighting +matches not currently visible in the window when +@code{lazy-highlight-buffer} is non-@code{nil}. It defaults to 200; set +to @code{nil} to highlight all the matches in a buffer without checking +for input. @strong{Warning:} this could make Emacs not responsive when +searching large buffers. +@end vtable @vindex search-nonincremental-instead Normally, entering @key{RET} within incremental search when the diff --git a/lisp/isearch.el b/lisp/isearch.el index 785d324cac3..92bd9af6643 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -347,6 +347,9 @@ you can define more of these faces using the same numbering scheme." When non-nil, all text currently visible on the screen matching the current search string is highlighted lazily (see `lazy-highlight-initial-delay' and `lazy-highlight-interval'). +However, if `lazy-highlight-buffer' is non-nil, all text in the +entire buffer matching the search string is highlighted lazily. +The highlighting uses the `lazy-highlight' face. When multiple windows display the current buffer, the highlighting is displayed only on the selected window, unless @@ -385,8 +388,8 @@ If this is nil, extra highlighting can be \"manually\" removed with (defcustom lazy-highlight-initial-delay 0.25 "Seconds to wait before beginning to lazily highlight all matches. -This setting only has effect when the search string is less than -`lazy-highlight-no-delay-length' characters long." +This setting only has effect when the search string is shorter than +`lazy-highlight-no-delay-length' characters." :type 'number :group 'lazy-highlight) @@ -428,7 +431,9 @@ When non-nil, all text in the buffer matching the current search string is highlighted lazily (see `lazy-highlight-initial-delay', `lazy-highlight-interval' and `lazy-highlight-buffer-max-at-a-time'). This is useful when `lazy-highlight-cleanup' is customized to nil -and doesn't remove full-buffer highlighting after a search." +and doesn't remove full-buffer highlighting after a search. +If this is nil (the default), only the text currently visible in +the window is highlighted, subject to `isearch-lazy-highlight'." :type 'boolean :group 'lazy-highlight :version "27.1") @@ -443,7 +448,9 @@ and doesn't remove full-buffer highlighting after a search." (((class color) (min-colors 8)) (:background "turquoise3" :distant-foreground "white")) (t (:underline t))) - "Face for lazy highlighting of matches other than the current one." + "Face for lazy highlighting of matches other than the current one. +Used in Isearch when `isearch-lazy-highlight' is non-nil, +and in `query-replace' when `query-replace-lazy-highlight' is non-nil." :group 'lazy-highlight :group 'basic-faces) @@ -1006,6 +1013,9 @@ Each element is an `isearch--state' struct where the slots are With a prefix argument, do an incremental regular expression search instead. \\ As you type characters, they add to the search string and are found. +Current match for the search string is highlighted using the `isearch' face, +and if `isearch-lazy-highlight' is non-nil, the other matches are +highlighted using the `lazy-highlight' face. 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. diff --git a/lisp/replace.el b/lisp/replace.el index 933249d824c..48e158de531 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -133,9 +133,11 @@ you can define more of these faces using the same numbering scheme." (defcustom query-replace-lazy-highlight t "Controls the lazy-highlighting during query replacements. -When non-nil, all text in the buffer matching the current match -is highlighted lazily using isearch lazy highlighting (see -`lazy-highlight-initial-delay' and `lazy-highlight-interval')." +When non-nil, all text matching the current match that is +currently visible in the window is highlighted lazily using +isearch lazy highlighting (see `lazy-highlight-initial-delay' +and `lazy-highlight-interval'). Uses the `lazy-highlight' face +to highlight matching text." :type 'boolean :group 'lazy-highlight :group 'matching @@ -143,7 +145,9 @@ is highlighted lazily using isearch lazy highlighting (see (defface query-replace '((t (:inherit isearch))) - "Face for highlighting query replacement matches." + "Face for highlighting query replacement matches. +Used in `query-replace' and `query-replace-regexp' +when `query-replace-highlight' is non-nil" :group 'matching :version "22.1") @@ -427,6 +431,11 @@ In Transient Mark mode, if the mark is active, operate on the contents of the region. Otherwise, operate from point to the end of the buffer's accessible portion. +The current match of FROM-STRING is highlighted using +the `query-replace' face. Other matches of FROM-STRING are highlighted +using the `lazy-highlight' face if `query-replace-lazy-highlight' is +non-nil. + In interactive use, the prefix arg (non-nil DELIMITED in non-interactive use), means replace only matches surrounded by word boundaries. A negative prefix arg means replace backward. @@ -508,6 +517,11 @@ accessible portion. When invoked interactively, matching a newline with `\\n' will not work; use \\`C-q C-j' instead. To match a tab character (`\\t'), just press \\`TAB'. +The current match of REGEXP is highlighted using +the `query-replace' face. Other matches of REGEXP are highlighted +using the `lazy-highlight' face if `query-replace-lazy-highlight' is +non-nil. + Use \\\\[next-history-element] \ to pull the last incremental search regexp to the minibuffer that reads REGEXP, or invoke replacements from From 3de7f0ce5e5fca16045b3f96ceab607d66782d4d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 22 May 2026 19:12:12 +0300 Subject: [PATCH 049/112] Fix warning message in 'markdown-ts-mode--initialize' * lisp/textmodes/markdown-ts-mode.el (markdown-ts-mode--initialize): Tweak the warning message when Tree-sitter is not available. (Bug#81100) --- lisp/textmodes/markdown-ts-mode.el | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el index 7f87ff5d0bc..be2247b870e 100644 --- a/lisp/textmodes/markdown-ts-mode.el +++ b/lisp/textmodes/markdown-ts-mode.el @@ -5402,9 +5402,12 @@ With a prefix argument, ARG, if needed, install parsers for `html', (markdown-ts--set-up)) (t (warn "markdown-ts-mode cannot be set up; using fundamental-mode. -The tree-sitter parsers `markdown' and `markdown-inline' were not found. +%s." + (if (treesit-available-p) + "The tree-sitter parsers `markdown' and `markdown-inline' were not found. Use the command `markdown-ts-mode-install-parsers' to install them. -With a prefix argument, it can also install optional parsers.") +With a prefix argument, it can also install optional parsers" + "Emacs was built without Tree-sitter support, or could not load Tree-sitter")) (fundamental-mode))))) ;;;###autoload From e0fbecaf658b95d3c53aa9f1bc078a3326a3f77c Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Fri, 22 May 2026 18:37:36 +0200 Subject: [PATCH 050/112] Adapt ert-remote-temporary-file-directory settings * lisp/emacs-lisp/ert-x.el (tramp-default-remote-shell) (tramp-encoding-shell): Declare. (tramp-methods) : Add `tramp-tmpdir'. Adapt `tramp-login-program' and `tramp-remote-shell'. --- lisp/emacs-lisp/ert-x.el | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el index 0952033a6cc..b6d52b8b3c5 100644 --- a/lisp/emacs-lisp/ert-x.el +++ b/lisp/emacs-lisp/ert-x.el @@ -379,6 +379,8 @@ The same keyword arguments are supported as in (ffap--gcc-is-clang-p)) (defvar tramp-default-host-alist) +(defvar tramp-default-remote-shell) +(defvar tramp-encoding-shell) (defvar tramp-methods) (defvar tramp-remote-path) @@ -394,16 +396,17 @@ The same keyword arguments are supported as in (cond ((getenv "REMOTE_TEMPORARY_FILE_DIRECTORY")) ((eq system-type 'windows-nt) null-device) - ;; Android's built-in shell is far too dysfunctional to support + ;; Android's built-in shell is far too dysfunctional to support. ;; Tramp. ((eq system-type 'android) null-device) (t (add-to-list 'tramp-methods - '("mock" - (tramp-login-program "sh") + `("mock" + (tramp-login-program ,tramp-encoding-shell) (tramp-login-args (("-i"))) - (tramp-direct-async ("-c")) - (tramp-remote-shell "/bin/sh") + (tramp-direct-async ("-c")) + (tramp-tmpdir ,temporary-file-directory) + (tramp-remote-shell ,tramp-default-remote-shell) (tramp-remote-shell-args ("-c")) (tramp-connection-timeout 10))) (add-to-list From d6f7b2d99bdbcc29e8784185612282a508cc3e84 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Fri, 22 May 2026 19:33:57 +0200 Subject: [PATCH 051/112] Save/restore old_buffer slot via window configurations (Bug#81097) With Emacs 31 the old_buffer slot of a window gets overwritten with the buffer unshown in that window when that window is deleted. Fset_window_configuration triggers that when calling delete_all_child_windows. If a window configuration gets saved and restored in one and the same redisplay cycle, the change time stamps of the window and its frame will be equal and 'window-buffer-change-functions' may wrongly decide that the window's buffer has not changed because its buffer and old_buffer slots refer to the same buffer (Bug#81097). Fix that by saving and restoring the old_buffer slot. * src/window.c (struct saved_window): Add 'old_buffer' slot. (Fset_window_configuration): Restore old_buffer slot. (save_window_save): Save old_buffer slot. --- src/window.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/window.c b/src/window.c index 3dbf1530d78..792c43d0555 100644 --- a/src/window.c +++ b/src/window.c @@ -7611,7 +7611,7 @@ struct saved_window { union vectorlike_header header; - Lisp_Object window, buffer, start, pointm, old_pointm; + Lisp_Object window, buffer, old_buffer, start, pointm, old_pointm; Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width; Lisp_Object left_col, top_line, total_cols, total_lines; Lisp_Object normal_cols, normal_lines; @@ -7835,6 +7835,7 @@ the return value is nil. Otherwise the value is t. */) /* If we squirreled away the buffer, restore it now. */ if (BUFFERP (w->combination_limit)) wset_buffer (w, w->combination_limit); + wset_old_buffer (w, p->old_buffer); w->pixel_left = XFIXNAT (p->pixel_left); w->pixel_top = XFIXNAT (p->pixel_top); w->pixel_width = XFIXNAT (p->pixel_width); @@ -8221,6 +8222,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i) wset_temslot (w, make_fixnum (i)); i++; p->window = window; p->buffer = (WINDOW_LEAF_P (w) ? w->contents : Qnil); + p->old_buffer = w->old_buffer; p->pixel_left = make_fixnum (w->pixel_left); p->pixel_top = make_fixnum (w->pixel_top); p->pixel_width = make_fixnum (w->pixel_width); From 142b1e0d4c3f63fd5aa07ce748915137fea1ec52 Mon Sep 17 00:00:00 2001 From: Jacek Migacz Date: Thu, 21 May 2026 10:44:55 +0000 Subject: [PATCH 052/112] Fix Lisp injection via X-Draft-From in Gnus * lisp/gnus/gnus-msg.el (gnus-inews-make-draft-meta-information): Escape the group name with prin1-to-string to prevent arbitrary Lisp injection through crafted group names. The unescaped group name was embedded into a Lisp-readable string, parsed back with read-from-string in gnus-draft-setup, and eventually eval'd via message-do-actions, allowing code execution when a draft was sent. --- lisp/gnus/gnus-msg.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el index 99f1735dfec..a478093fc6c 100644 --- a/lisp/gnus/gnus-msg.el +++ b/lisp/gnus/gnus-msg.el @@ -444,7 +444,7 @@ only affect the Gcc copy, but not the original message." (defun gnus-inews-make-draft-meta-information (group articles) (when (numberp articles) (setq articles (list articles))) - (concat "(\"" group "\"" + (concat "(" (prin1-to-string (or group "")) (if articles (concat " " (mapconcat From f6281d757d35bb93790732164f9d8d11c043c00c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 23 May 2026 09:35:24 +0300 Subject: [PATCH 053/112] ; * etc/NEWS: Tell how to disable 'markdown-ts-mode'. --- etc/NEWS | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/etc/NEWS b/etc/NEWS index 3021ad42a12..1f99eb22a38 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3931,7 +3931,20 @@ A major mode based on 'conf-mode' for editing ".npmrc" files. ** New major modes based on the tree-sitter library *** New major mode 'markdown-ts-mode'. -A major mode based on the tree-sitter library for editing Markdown files. +A major mode based on the tree-sitter library for editing Markdown +files. This is now the default major mode for Markdown files. If you +don't have the necessary tree-sitter grammar libraries installed, or if +your Emacs was built without tree-sitter support, Emacs will now show a +warning to that effect when you visit a Markdown file. If you don't +want to use this mode and want to avoid these warnings, add the +following to your init file: + + (add-to-list 'auto-mode-alist '("\\.md\\'" . fundamental-mode)) + (add-to-list 'auto-mode-alist '("\\.markdown\\'" . fundamental-mode)) + (add-to-list 'auto-mode-alist '("\\.mdx\\'" . fundamental-mode)) + +This will cause Emacs to visit Markdown files in Fundamental mode, which +was the default before this mode was added to Emacs. *** New major mode 'mhtml-ts-mode'. An optional major mode based on the tree-sitter library for editing HTML From 3d2bb233f27c00dac2bec0c70a569a6232f37c54 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sat, 23 May 2026 10:25:46 +0200 Subject: [PATCH 054/112] ; Minor Tramp changes * doc/misc/tramp.texi (Frequently Asked Questions): google-drive has been disabled in GNOME 50. * lisp/net/tramp-cmds.el (tramp-enable-method): Upcase prompt. * lisp/net/tramp-sh.el (tramp-sh-handle-make-process) (tramp-sh-handle-process-file): Improve setting of environment variables. * test/lisp/net/tramp-tests.el (tramp-methods) : Add `tramp-tmpdir'. Adapt `tramp-login-program'. (ert-remote-temporary-file-directory): Improve expansion. (tramp-test35-remote-path): Adapt test. --- doc/misc/tramp.texi | 7 +++++++ lisp/net/tramp-cmds.el | 2 +- lisp/net/tramp-sh.el | 18 +++++++++++++++--- test/lisp/net/tramp-tests.el | 12 +++++------- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index ae65cf2a620..6daa2b010cf 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -6435,6 +6435,13 @@ You can change this directory by setting the user option "XDG_RUNTIME_DIR")}. +@item +I get an error @samp{Method `gdrive' not supported by GVFS}. + +@samp{google-drive} has been disabled in @acronym{GNOME} 50. It is +not clear yet whether and when it will be reenabled. +@c @uref{https://discourse.gnome.org/t/google-drive-in-gnome-50/34417} + @item How to ignore errors when changing file attributes? diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el index 95e1c5ecad8..1fc77f0e80d 100644 --- a/lisp/net/tramp-cmds.el +++ b/lisp/net/tramp-cmds.el @@ -63,7 +63,7 @@ SYNTAX can be one of the symbols `default' (default), (interactive (list (completing-read - "method: " + "Method: " (tramp-compat-seq-keep (lambda (x) (when-let* ((name (symbol-name x)) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 7b90ae9c11b..8d4dc557676 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -3107,6 +3107,11 @@ will be used." ,(concat "PS1=" (getenv-internal "PS1" env))))) (eenv (setenv-internal eenv "INSIDE_EMACS" nil nil)) (eenv (setenv-internal eenv "PS1" nil nil)) + vars + (eenv (dolist (item (reverse eenv) vars) + (setq item (split-string item "=" 'omit)) + (setcdr item (string-join (cdr item) "=")) + (push (format "%s %s" (car item) (cdr item)) vars))) (command (when (stringp program) (format "cd %s && %s exec %s %s env %s %s" @@ -3222,10 +3227,15 @@ will be used." (delete-region mark (point-max)) (narrow-to-region (point-max) (point-max)) ;; Send delayed environment. - (dolist (entry eenv) + (when eenv (tramp-send-command - v (format - "export %s" (tramp-shell-quote-argument entry)))) + v + (format + "while read var val; do export $var=\"$val\"; done <<'%s'\n%s\n%s" + tramp-end-of-heredoc + (string-join eenv "\n") + tramp-end-of-heredoc) + t)) ;; Now do it. (if command ;; Send the command. @@ -3350,6 +3360,8 @@ will be used." env "EMACSCLIENT_TRAMP" (tramp-make-tramp-file-name v 'noloc) 'keep))) (setq env (setenv-internal env "INSIDE_EMACS" (tramp-inside-emacs) 'keep)) + ;; Remove looong environment variables, for example from tramp-tests.el. + (setq env (seq-remove (lambda (x) (length> x 256)) env)) (when env (setq command (format diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index c0ad7205c5d..4d11faf64de 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -117,9 +117,10 @@ (t (add-to-list 'tramp-methods `("mock" - (tramp-login-program ,tramp-default-remote-shell) + (tramp-login-program ,tramp-encoding-shell) (tramp-login-args (("-i"))) (tramp-direct-async ("-c")) + (tramp-tmpdir ,temporary-file-directory) (tramp-remote-shell ,tramp-default-remote-shell) (tramp-remote-shell-args ("-c")) (tramp-connection-timeout 10))) @@ -225,7 +226,8 @@ auto-revert-use-notify t ert-batch-backtrace-right-margin nil ert-remote-temporary-file-directory - (expand-file-name ert-remote-temporary-file-directory) + (let ((tramp-show-ad-hoc-proxies t) (non-essential t)) + (expand-file-name ert-remote-temporary-file-directory)) password-cache-expiry nil remote-file-name-inhibit-cache nil tramp-allow-unsafe-temporary-files t @@ -6855,8 +6857,7 @@ INPUT, if non-nil, is a string sent to the process." "Check loooong `tramp-remote-path'." :tags '(:expensive-test) (skip-unless (tramp--test-enabled)) - (skip-unless (tramp--test-sh-p)) - (skip-unless (not (tramp--test-crypt-p))) + (skip-unless (tramp--test-supports-environment-variables-p)) (let* ((tmp-name1 (tramp--test-make-temp-name)) (default-directory ert-remote-temporary-file-directory) @@ -9330,9 +9331,6 @@ If INTERACTIVE is non-nil, the tests are run interactively." ;; Use `skip-when' starting with Emacs 30.1. -;; Starting with Emacs 29, use `ert-with-temp-file' and -;; `ert-with-temp-directory'. - (provide 'tramp-tests) ;;; tramp-tests.el ends here From 646702f70b38e904754a1addab138d0ed3af9411 Mon Sep 17 00:00:00 2001 From: Augusto Stoffel Date: Thu, 7 May 2026 09:13:32 +0200 Subject: [PATCH 055/112] let-alist.el: Use 'elt' instead of 'nth' The advantage is that this works also for mixtures of alists and vectors, as one obtains, e.g., from 'json-parse-buffer' and 'json-parse-string'. * lisp/emacs-lisp/let-alist.el (let-alist--list-to-sexp): Use 'elt' instead of 'nth'. (let-alist): Adapt doc string. (Bug#80992) --- lisp/emacs-lisp/let-alist.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/emacs-lisp/let-alist.el b/lisp/emacs-lisp/let-alist.el index 3140e2b243d..3e1c6f0181e 100644 --- a/lisp/emacs-lisp/let-alist.el +++ b/lisp/emacs-lisp/let-alist.el @@ -48,7 +48,7 @@ ;; ;; essentially expands to ;; -;; (let ((.title.0 (nth 0 (cdr (assq 'title alist)))) +;; (let ((.title.0 (elt (cdr (assq 'title alist)) 0)) ;; (.body (cdr (assq 'body alist))) ;; (.site (cdr (assq 'site alist))) ;; (.site.contents (cdr (assq 'contents (cdr (assq 'site alist)))))) @@ -103,7 +103,7 @@ symbol, and each cdr is the same symbol without the `.'." (rest (if (cdr list) (let-alist--list-to-sexp (cdr list) var) var))) (cond - ((numberp sym) `(nth ,sym ,rest)) + ((numberp sym) `(elt ,rest ,sym)) (t `(cdr (assq ',sym ,rest)))))) (defun let-alist--remove-dot (symbol) @@ -136,7 +136,7 @@ For instance, the following code essentially expands to - (let ((.title.0 (nth 0 (cdr (assq \\='title alist)))) + (let ((.title.0 (elt (cdr (assq \\='title alist)) 0)) (.body (cdr (assq \\='body alist))) (.site (cdr (assq \\='site alist))) (.site.contents (cdr (assq \\='contents (cdr (assq \\='site alist)))))) From 70b79b3ed8d04aa852837177636061dfc43e9b0b Mon Sep 17 00:00:00 2001 From: Richard Lawrence Date: Sun, 17 May 2026 12:54:24 +0200 Subject: [PATCH 056/112] Rename `icalendar-recur' type and related functions More context in Bug#80786 and: https://lists.gnu.org/archive/html/emacs-orgmode/2026-03/msg00286.html `icalendar-recur' as a type name for RRULE values was confusing and made the accessors for this type difficult to discover, because `icalendar-recur-' is also used as a prefix in icalendar-recur.el. This change renames the `icalendar-recur' type to `icalendar-rrule-value' and renames the accessor functions for these values appropriately. * lisp/calendar/icalendar-parser.el: Rename symbols as follows: (icalendar-recur): `icalendar-rrule-value' (icalendar-read-recur-rule-part): `icalendar-read-rrule-part' (icalendar-print-recur-rule-part): `icalendar-print-rrule-part' (icalendar-recur-rule-part): `icalendar-rrule-part' (icalendar-read-recur): `icalendar-read-rrule-value' (icalendar-print-recur): `icalendar-print-rrule-value' (icalendar--recur-value-types): `icalendar--rrule-value-types' (icalendar-recur-value-p): `icalendar-rrule-value-p' (icalendar-recur-freq): `icalendar-rrule-freq' (icalendar-recur-interval-size): `icalendar-rrule-interval-size' (icalendar-recur-until): `icalendar-rrule-until' (icalendar-recur-count): `icalendar-rrule-count' (icalendar-recur-weekstart): `icalendar-rrule-weekstart' (icalendar-recur-by*): `icalendar-rrule-by*'. (icalendar-rrule): (icalendar-index-insert): (icalendar-index-get): Update references. * lisp/calendar/icalendar-recur.el (icalendar-recur-find-interval): (icalendar-recur-nth-interval): (icalendar-recur-next-interval): (icalendar-recur-previous-interval): (icalendar-recur-refine-from-clauses): (icalendar-recur-recurrences-in-interval): (icalendar-recur-recurrences-in-window): (icalendar-recur-recurrences-to-count): (icalendar-recur-tz-observance-on): Update references. * lisp/calendar/diary-icalendar.el: Update references. * lisp/calendar/icalendar-shortdoc.el (icalendar): Update shortdoc examples. * lisp/gnus/gnus-icalendar.el: Update references. * test/lisp/calendar/diary-icalendar-tests.el: * test/lisp/calendar/icalendar-parser-tests.el: * test/lisp/calendar/icalendar-recur-tests.el: Update references in tests. --- lisp/calendar/diary-icalendar.el | 18 +-- lisp/calendar/icalendar-parser.el | 111 +++++++++-------- lisp/calendar/icalendar-recur.el | 124 +++++++++---------- lisp/calendar/icalendar-shortdoc.el | 28 ++--- lisp/gnus/gnus-icalendar.el | 6 +- test/lisp/calendar/diary-icalendar-tests.el | 46 +++---- test/lisp/calendar/icalendar-parser-tests.el | 6 +- test/lisp/calendar/icalendar-recur-tests.el | 8 +- 8 files changed, 176 insertions(+), 171 deletions(-) diff --git a/lisp/calendar/diary-icalendar.el b/lisp/calendar/diary-icalendar.el index bc58e7b5924..9604dce8e4e 100644 --- a/lisp/calendar/diary-icalendar.el +++ b/lisp/calendar/diary-icalendar.el @@ -2690,12 +2690,12 @@ recurrence rule values in these nodes are adjusted NDAYS forward." :duration (ical:period-dur-value value))) (t (ical:date/time-add value :day ndays))))))) (ical:rrule - (let ((mdays (ical:recur-by* 'BYMONTHDAY value)) - (ydays (ical:recur-by* 'BYYEARDAY value)) - (dows (ical:recur-by* 'BYDAY value)) + (let ((mdays (ical:rrule-by* 'BYMONTHDAY value)) + (ydays (ical:rrule-by* 'BYYEARDAY value)) + (dows (ical:rrule-by* 'BYDAY value)) (bad-clause - (cond ((ical:recur-by* 'BYSETPOS value) 'BYSETPOS) - ((ical:recur-by* 'BYWEEKNO value) 'BYWEEKNO)))) + (cond ((ical:rrule-by* 'BYSETPOS value) 'BYSETPOS) + ((ical:rrule-by* 'BYWEEKNO value) 'BYWEEKNO)))) ;; We can't reliably subtract days in the following cases, so bail: (when (< 28 ndays) (di:signal-export-error @@ -2970,12 +2970,12 @@ nil, if MONTHS, DAYS and YEARS are all integers)." rdates (seq-remove (apply-partially #'equal dtstart) rdates)))) ;; Return the pair of nodes (DTSTART RRULE) or (DTSTART RDATE): - (let* ((recur-value + (let* ((rrule-value (delq nil `((FREQ ,freq) ,(when bymonth (list 'BYMONTH bymonth)) ,(when bymonthday (list 'BYMONTHDAY bymonthday))))) - (rrule-node (when freq (ical:make-property ical:rrule recur-value))) + (rrule-node (when freq (ical:make-property ical:rrule rrule-value))) (rdate-node (when rdates (ical:make-property ical:rdate rdates (ical:valuetypeparam rdate-type)))) @@ -3548,7 +3548,7 @@ values (of the same type as START)." (interval (icr:find-interval date start rule))) (cl-typecase start (ical:date - (if (ical:recur-count rule) + (if (ical:rrule-count rule) (when (member date (icr:recurrences-to-count vevent)) entry) (when (member date (icr:recurrences-in-interval interval vevent)) @@ -3581,7 +3581,7 @@ values (of the same type as START)." (ical:date/time-add-duration start duration)) (di:format-time-as-local start))) (date-entry (concat entry-time " " entry))) - (when (memq (ical:recur-freq date-rule) '(HOURLY MINUTELY SECONDLY)) + (when (memq (ical:rrule-freq date-rule) '(HOURLY MINUTELY SECONDLY)) (setf (alist-get 'FREQ date-rule) 'DAILY) (setf (alist-get 'INTERVAL date-rule) 1) (setf (alist-get 'BYHOUR date-rule nil t) nil) diff --git a/lisp/calendar/icalendar-parser.el b/lisp/calendar/icalendar-parser.el index 93293f19cbf..c6100c828e4 100644 --- a/lisp/calendar/icalendar-parser.el +++ b/lisp/calendar/icalendar-parser.el @@ -1352,9 +1352,9 @@ See `icalendar-read-weekdaynum' for the format of VAL." ;; number alone just stands for a day: (car (rassq val ical:weekday-numbers)))) -(defun ical:read-recur-rule-part (s) - "Read an `icalendar-recur-rule-part' from string S. -S should have been matched against `icalendar-recur-rule-part'. +(defun ical:read-rrule-part (s) + "Read an `icalendar-rrule-part' from string S. +S should have been matched against `icalendar-rrule-part'. The return value is a list (KEYWORD VALUE), where VALUE may itself be a list, depending on the values allowed by KEYWORD." ;; TODO: this smells like a design flaw. Silence the byte compiler for now. @@ -1376,7 +1376,7 @@ itself be a list, depending on the values allowed by KEYWORD." (rx ical:weekdaynum) ",")) (WKST (cdr (assoc values ical:weekday-numbers))))))) -(defun ical:print-recur-rule-part (part) +(defun ical:print-rrule-part (part) "Serialize recur rule part PART to a string." (let ((keyword (car part)) (values (cadr part)) @@ -1398,7 +1398,7 @@ itself be a list, depending on the values allowed by KEYWORD." (concat (symbol-name keyword) "=" values-str))) -(rx-define ical:recur-rule-part +(rx-define ical:rrule-part ;; Group 11: keyword ;; Group 12: value(s) (or (seq (group-n 11 "FREQ") "=" (group-n 12 ical:freq)) @@ -1423,14 +1423,12 @@ itself be a list, depending on the values allowed by KEYWORD." (ical:comma-list ical:yeardaynum))) (seq (group-n 11 "WKST") "=" (group-n 12 ical:weekday)))) -(defun ical:read-recur (s) +(defun ical:read-rrule-value (s) "Read a recurrence rule value from string S. S should be a match against rx `icalendar-recur'." - ;; TODO: let's switch to keywords and a plist, so we can more easily - ;; write these clauses also in diary sexp entries without so many parens - (ical:read-list-with #'ical:read-recur-rule-part s (rx ical:recur-rule-part) ";")) + (ical:read-list-with #'ical:read-rrule-part s (rx ical:rrule-part) ";")) -(defun ical:print-recur (val) +(defun ical:print-rrule-value (val) "Serialize a recurrence rule value VAL to a string." ;; RFC5545 sec. 3.3.10: "to ensure backward compatibility with ;; applications that pre-date this revision of iCalendar the @@ -1438,15 +1436,15 @@ S should be a match against rx `icalendar-recur'." ;; RECUR value." (string-join (cons - (ical:print-recur-rule-part (assq 'FREQ val)) - (mapcar #'ical:print-recur-rule-part + (ical:print-rrule-part (assq 'FREQ val)) + (mapcar #'ical:print-rrule-part (seq-filter (lambda (part) (not (eq 'FREQ (car part)))) val))) ";")) -(defconst ical:-recur-value-types +(defconst ical:-rrule-value-types ;; `list-of' is not a cl-type specifier, just a symbol here; it is - ;; handled specially when checking types in `ical:recur-value-p': + ;; handled specially when checking types in `ical:rrule-value-p': '(FREQ (member YEARLY MONTHLY WEEKLY DAILY HOURLY MINUTELY SECONDLY) UNTIL (or ical:date-time ical:date) COUNT (integer 1 *) @@ -1470,7 +1468,7 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (cl-typep (car val) '(integer 0 6)) (cl-typep (cdr val) '(or (integer -53 -1) (integer 1 53))))) -(defun ical:recur-value-p (vals) +(defun ical:rrule-value-p (vals) "Return non-nil if VALS is an iCalendar recurrence rule value." (and (listp vals) ;; FREQ is always required: @@ -1487,11 +1485,11 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (assq 'BYHOUR vals) (assq 'BYMINUTE vals) (assq 'BYSECOND vals)) - (let ((freq (ical:recur-freq vals)) - (byday (ical:recur-by* 'BYDAY vals)) - (byweekno (ical:recur-by* 'BYWEEKNO vals)) - (bymonthday (ical:recur-by* 'BYMONTHDAY vals)) - (byyearday (ical:recur-by* 'BYYEARDAY vals))) + (let ((freq (ical:rrule-freq vals)) + (byday (ical:rrule-by* 'BYDAY vals)) + (byweekno (ical:rrule-by* 'BYWEEKNO vals)) + (bymonthday (ical:rrule-by* 'BYMONTHDAY vals)) + (byyearday (ical:rrule-by* 'BYYEARDAY vals))) (and ;; "The BYDAY rule part MUST NOT be specified with a numeric ;; value when the FREQ rule part is not set to MONTHLY or @@ -1518,7 +1516,7 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (when (consp kv) (let* ((keyword (car kv)) (val (cadr kv)) - (type (plist-get ical:-recur-value-types keyword))) + (type (plist-get ical:-rrule-value-types keyword))) (and keyword val type (if (and (consp type) (eq (car type) 'list-of)) @@ -1526,7 +1524,14 @@ DAYNO must be in [0..6] and OFFSET in [-53..53], excluding 0." (cl-typep val type)))))) vals))) -(ical:define-type ical:recur "RECUR" +(ical:define-type ical:rrule-value + ;; Renamed from "ical:recur", which turns out to + ;; produce confusing names downstream. Thus I've + ;; deviated from the standard here, and call + ;; `ical:rrule-value' what the standard calls a RECUR + ;; value. (`ical:rrule' is not available because that + ;; names the *property* containing such a value.) + "RECUR" "Type for Recurrence Rule values. When printed, a recurrence rule value looks like @@ -1587,39 +1592,39 @@ Some examples: Notice that singleton values are still wrapped in a list when the KEY accepts a list of values, but not when the KEY always has a single (e.g. integer) value." - '(satisfies ical:recur-value-p) - (ical:semicolon-list ical:recur-rule-part) - :reader ical:read-recur - :printer ical:print-recur + '(satisfies ical:rrule-value-p) + (ical:semicolon-list ical:rrule-part) + :reader ical:read-rrule-value + :printer ical:print-rrule-value :link "https://www.rfc-editor.org/rfc/rfc5545#section-3.3.10") -(defun ical:recur-freq (recur-value) - "Return the frequency in RECUR-VALUE." - (car (alist-get 'FREQ recur-value))) +(defun ical:rrule-freq (rrule) + "Return the frequency in RRULE." + (car (alist-get 'FREQ rrule))) -(defun ical:recur-interval-size (recur-value) - "Return the interval size in RECUR-VALUE, or the default of 1." - (or (car (alist-get 'INTERVAL recur-value)) 1)) +(defun ical:rrule-interval-size (rrule) + "Return the interval size in RRULE, or the default of 1." + (or (car (alist-get 'INTERVAL rrule)) 1)) -(defun ical:recur-until (recur-value) - "Return the UNTIL date(-time) in RECUR-VALUE." - (car (alist-get 'UNTIL recur-value))) +(defun ical:rrule-until (rrule) + "Return the UNTIL date(-time) in RRULE." + (car (alist-get 'UNTIL rrule))) -(defun ical:recur-count (recur-value) - "Return the COUNT in RECUR-VALUE." - (car (alist-get 'COUNT recur-value))) +(defun ical:rrule-count (rrule) + "Return the COUNT in RRULE." + (car (alist-get 'COUNT rrule))) -(defun ical:recur-weekstart (recur-value) - "Return the weekday which starts the work week in RECUR-VALUE. -If no starting weekday is specified in RECUR-VALUE, returns the default, +(defun ical:rrule-weekstart (rrule) + "Return the weekday which starts the work week in RRULE. +If no starting weekday is specified in RRULE, returns the default, 1 (= Monday)." - (or (car (alist-get 'WKST recur-value)) 1)) + (or (car (alist-get 'WKST rrule)) 1)) -(defun ical:recur-by* (byunit recur-value) - "Return the values in the BYUNIT clause in RECUR-VALUE. +(defun ical:rrule-by* (byunit rrule) + "Return the values in the BYUNIT clause in RRULE. BYUNIT should be a symbol: \\='BYMONTH, \\='BYDAY, etc. -See `icalendar-recur' for all the possible BYUNIT values." - (car (alist-get byunit recur-value))) +See `icalendar-rrule-value' for all the possible BYUNIT values." + (car (alist-get byunit rrule))) ;;;; 3.3.11 Text (rx-define ical:escaped-char @@ -3272,7 +3277,7 @@ and times on which an `icalendar-vevent', `icalendar-todo', `icalendar-daylight' component recurs. Together with the `icalendar-dtstart', `icalendar-rdate', and `icalendar-exdate' properties, it defines the recurrence set of the component." - ical:recur + ical:rrule-value ;; TODO: faces for subexpressions? :child-spec (:zero-or-more (ical:otherparam)) :link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.5.3") @@ -4567,7 +4572,7 @@ which see." (ical:dtend :first dtend-node :value dtend) (ical:due :value due) (ical:duration :value duration) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) (ical:exdate :all exdate-nodes) (ical:uid :value uid)) @@ -4592,7 +4597,7 @@ which see." ;; If the component has an RRULE that specifies a fixed number ;; of recurrences, compute them now and index them for each date ;; in each recurrence: - ((and recur-value (ical:recur-count recur-value)) + ((and rrule (ical:rrule-count rrule)) (let* ((tz (gethash (ical:with-param-of dtstart-node 'ical:tzidparam) tzid-index)) (recs (cons dtstart (icr:recurrences-to-count component tz)))) @@ -4605,7 +4610,7 @@ which see." (list (ical:date/time-to-date (ical:date/time-to-local rec)))))))))) ;; Same with RDATEs when there's no RRULE: - ((and rdates (not recur-value)) + ((and rdates (not rrule)) (dolist (rec (cons dtstart rdates)) (unless (or (cl-typep rec 'ical:period) (member rec exdates)) (let ((end-time @@ -4624,7 +4629,7 @@ which see." (setq dates (append dates (ical:dates-until start end t))))))) ;; A non-recurring event also gets an index entry for each date ;; until its end time: - ((not recur-value) + ((not rrule) (let ((end-time (or dtend due (when duration @@ -4703,13 +4708,13 @@ Only one keyword argument can be queried at a time." (dolist (component recurring) (ical:with-component component ((ical:dtstart :first dtstart-node :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) (ical:duration :value duration)) (unless (ical:date/time<= date dtstart) (let* ((tz (ical:with-param-of dtstart-node 'ical:tzidparam nil (gethash value (plist-get index :bytzid)))) - (int (icr:find-interval date dtstart recur-value tz)) + (int (icr:find-interval date dtstart rrule tz)) (recs (icr:recurrences-in-interval int component tz))) (catch 'found (dolist (rec recs) diff --git a/lisp/calendar/icalendar-recur.el b/lisp/calendar/icalendar-recur.el index fcebbc9c6f0..b6c766962c9 100644 --- a/lisp/calendar/icalendar-recur.el +++ b/lisp/calendar/icalendar-recur.el @@ -451,29 +451,29 @@ See `icalendar-recur-find-interval' for arguments' meanings." ;; Return the bounds: (icr:make-interval low high next-low))) -(defun icr:find-interval (target dtstart recur-value &optional vtimezone) +(defun icr:find-interval (target dtstart rrule &optional vtimezone) "Return the recurrence interval around TARGET. TARGET and DTSTART should be `icalendar-date' or `icalendar-date-time' -values. RECUR-VALUE should be an `icalendar-recur'. +values. RRULE should be an `icalendar-recur'. The returned value is an interval [LOW HIGH NEXT-LOW] which represents the lower and upper bounds of a recurrence interval around TARGET. For some N, LOW is equal to START + N*INTERVALSIZE units, HIGH is equal to START + (N+1)*INTERVALSIZE units, and LOW <= TARGET < HIGH. -START here is a time derived from DTSTART depending on RECUR-VALUE's +START here is a time derived from DTSTART depending on RRULE's FREQ part: the first day of the year for a \\='YEARLY rule, first day of the month for a \\='MONTHLY rule, etc. -RECUR-VALUE's interval determines INTERVALSIZE, and its frequency +RRULE's interval determines INTERVALSIZE, and its frequency determines the units: a month for \\='MONTHLY, etc. If VTIMEZONE is provided, it is used to set time zone information in the returned interval bounds. Otherwise, the bounds contain no time zone information and represent floating local times." - (let ((freq (ical:recur-freq recur-value)) - (intsize (ical:recur-interval-size recur-value)) - (weekstart (ical:recur-weekstart recur-value))) + (let ((freq (ical:rrule-freq rrule)) + (intsize (ical:rrule-interval-size rrule)) + (weekstart (ical:rrule-weekstart rrule))) (cl-case freq (SECONDLY (icr:find-secondly-interval target dtstart intsize vtimezone)) (MINUTELY (icr:find-minutely-interval target dtstart intsize vtimezone)) @@ -484,22 +484,22 @@ information and represent floating local times." (MONTHLY (icr:find-monthly-interval target dtstart intsize vtimezone)) (YEARLY (icr:find-yearly-interval target dtstart intsize vtimezone))))) -(defun icr:nth-interval (n dtstart recur-value &optional vtimezone) +(defun icr:nth-interval (n dtstart rrule &optional vtimezone) "Return the Nth recurrence interval after DTSTART. The returned value is an interval [LOW HIGH NEXT-LOW] which is the Nth recurrence interval after DTSTART. LOW is equal to START + N*INTERVALSIZE units, HIGH is equal to START + (N+1)*INTERVALSIZE units, and LOW <= TARGET < HIGH. START here is a time derived from DTSTART -depending on RECUR-VALUE's FREQ part: the first day of the year for a +depending on RRULE's FREQ part: the first day of the year for a \\='YEARLY rule, first day of the month for a \\='MONTHLY rule, etc. -RECUR-VALUE's interval determines INTERVALSIZE, and its frequency +RRULE's interval determines INTERVALSIZE, and its frequency determines the units: a month for \\='MONTHLY, etc. N should be a non-negative integer. Interval 0 is the interval containing DTSTART. DTSTART should be an `icalendar-date' or -`icalendar-date-time' value. RECUR-VALUE should be an +`icalendar-date-time' value. RRULE should be an `icalendar-recur'. If VTIMEZONE is provided, it is used to set time zone information in the @@ -509,8 +509,8 @@ information and represent floating local times." (let* ((start-dt (if (cl-typep dtstart 'ical:date) (ical:date-to-date-time dtstart :tz vtimezone) dtstart)) - (freq (ical:recur-freq recur-value)) - (intervalsize (ical:recur-interval-size recur-value)) + (freq (ical:rrule-freq rrule)) + (intervalsize (ical:rrule-interval-size rrule)) (unit (cl-case freq (YEARLY :year) (MONTHLY :month) @@ -520,16 +520,16 @@ information and represent floating local times." (MINUTELY :minute) (SECONDLY :second))) (target (ical:date/time-add start-dt unit (* n intervalsize) vtimezone))) - (icr:find-interval target dtstart recur-value vtimezone))) + (icr:find-interval target dtstart rrule vtimezone))) -(defun icr:next-interval (interval recur-value &optional vtimezone) +(defun icr:next-interval (interval rrule &optional vtimezone) "Return the next recurrence interval after INTERVAL. Given a recurrence interval [LOW HIGH NEXT], returns the next interval [NEXT HIGHER HIGHER-NEXT], where HIGHER and HIGHER-NEXT are determined -by the frequency and interval sizes of RECUR-VALUE." +by the frequency and interval sizes of RRULE." (let* ((new-low (icr:interval-next interval)) - (freq (ical:recur-freq recur-value)) + (freq (ical:rrule-freq rrule)) (unit (cl-case freq (YEARLY :year) (MONTHLY :month) @@ -538,7 +538,7 @@ by the frequency and interval sizes of RECUR-VALUE." (HOURLY :hour) (MINUTELY :minute) (SECONDLY :second))) - (intervalsize (ical:recur-interval-size recur-value)) + (intervalsize (ical:rrule-interval-size rrule)) (new-high (ical:date/time-add new-low unit 1 vtimezone)) (new-next (when (< 1 intervalsize) @@ -552,17 +552,17 @@ by the frequency and interval sizes of RECUR-VALUE." (icr:make-interval new-low new-high new-next))) -(defun icr:previous-interval (interval recur-value dtstart &optional vtimezone) +(defun icr:previous-interval (interval rrule dtstart &optional vtimezone) "Given a recurrence INTERVAL, return the previous interval. For an interval [LOW HIGH NEXT-LOW], the previous interval is [PREV-LOW PREV-HIGH LOW], where PREV-LOW and PREV-HIGH are determined by -the frequency and interval sizes of RECUR-VALUE (see +the frequency and interval sizes of RRULE (see `icalendar-recur-find-interval'). If the resulting period of time between PREV-LOW and PREV-HIGH occurs entirely before DTSTART, then the interval does not exist; in this case nil is returned." (let* ((upper (icr:interval-low interval)) - (freq (ical:recur-freq recur-value)) + (freq (ical:rrule-freq rrule)) (unit (cl-case freq (YEARLY :year) (MONTHLY :month) @@ -571,7 +571,7 @@ interval does not exist; in this case nil is returned." (HOURLY :hour) (MINUTELY :minute) (SECONDLY :second))) - (intervalsize (ical:recur-interval-size recur-value)) + (intervalsize (ical:rrule-interval-size rrule)) (new-low (ical:date/time-add upper unit (* -1 intervalsize) vtimezone)) (new-high (if (< 1 intervalsize) @@ -1032,12 +1032,12 @@ The returned value is RECURRENCES filtered by index." (pop dts)) (nreverse r))) -(defun icr:refine-from-clauses (interval recur-value dtstart +(defun icr:refine-from-clauses (interval rrule dtstart &optional vtimezone) - "Resolve INTERVAL into subintervals based on the clauses in RECUR-VALUE. + "Resolve INTERVAL into subintervals based on the clauses in RRULE. The resulting list of subintervals represents all times in INTERVAL -which match the BY* clauses of RECUR-VALUE except BYSETPOS, as well as +which match the BY* clauses of RRULE except BYSETPOS, as well as the constraints implicit in DTSTART. (For example, if there is no BYMINUTE clause, subintervals will have the same minute value as DTSTART.) @@ -1047,14 +1047,14 @@ components and TZID should be the `icalendar-tzid' property value of one of those timezones. In this case, TZID states the time zone of DTSTART, and the offsets effective in that time zone on the dates and times of recurrences will be local to that time zone." - (let ((freq (ical:recur-freq recur-value)) - (weekstart (ical:recur-weekstart recur-value)) + (let ((freq (ical:rrule-freq rrule)) + (weekstart (ical:rrule-weekstart rrule)) (subintervals (list interval))) (dolist (byunit (list 'BYMONTH 'BYWEEKNO 'BYYEARDAY 'BYMONTHDAY 'BYDAY 'BYHOUR 'BYMINUTE 'BYSECOND)) - (let ((values (ical:recur-by* byunit recur-value)) + (let ((values (ical:rrule-by* byunit rrule)) (in-month nil)) ;; When there is no explicit BY* clause, use the value implicit ;; in DTSTART. (These conditions are adapted from RFC8984: @@ -1086,26 +1086,26 @@ recurrences will be local to that time zone." (setq values (list (ical:date/time-weekday dtstart)))) (when (and (eq byunit 'BYMONTHDAY) (eq freq 'MONTHLY) - (not (ical:recur-by* 'BYDAY recur-value)) + (not (ical:rrule-by* 'BYDAY rrule)) (not values)) (setq values (list (ical:date/time-monthday dtstart)))) (when (and (eq freq 'YEARLY) - (not (ical:recur-by* 'BYYEARDAY recur-value))) + (not (ical:rrule-by* 'BYYEARDAY rrule))) (when (and (eq byunit 'BYMONTH) (not values) - (not (ical:recur-by* 'BYWEEKNO recur-value)) - (or (ical:recur-by* 'BYMONTHDAY recur-value) - (not (ical:recur-by* 'BYDAY recur-value)))) + (not (ical:rrule-by* 'BYWEEKNO rrule)) + (or (ical:rrule-by* 'BYMONTHDAY rrule) + (not (ical:rrule-by* 'BYDAY rrule)))) (setq values (list (ical:date/time-month dtstart)))) (when (and (eq byunit 'BYMONTHDAY) (not values) - (not (ical:recur-by* 'BYWEEKNO recur-value)) - (not (ical:recur-by* 'BYDAY recur-value))) + (not (ical:rrule-by* 'BYWEEKNO rrule)) + (not (ical:rrule-by* 'BYDAY rrule))) (setq values (list (ical:date/time-monthday dtstart)))) (when (and (eq byunit 'BYDAY) (not values) - (ical:recur-by* 'BYWEEKNO recur-value) - (not (ical:recur-by* 'BYMONTHDAY recur-value))) + (ical:rrule-by* 'BYWEEKNO rrule) + (not (ical:rrule-by* 'BYMONTHDAY rrule))) (setq values (list (ical:date/time-weekday dtstart))))) ;; Handle offsets in a BYDAY clause: @@ -1120,7 +1120,7 @@ recurrences will be local to that time zone." (when (and (eq byunit 'BYDAY) (or (eq freq 'MONTHLY) (and (eq freq 'YEARLY) - (ical:recur-by* 'BYMONTH recur-value)))) + (ical:rrule-by* 'BYMONTH rrule)))) (setq in-month t)) ;; On each iteration of the loop, we refine the subintervals @@ -1246,10 +1246,10 @@ retrieved on subsequent calls with the same arguments." (ical:with-component component ((ical:dtstart :value dtstart) (ical:tzoffsetfrom :value offset-from) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) ;; TODO: these can also be ical:period values (ical:exdate :all exdate-nodes)) - (if (not (or recur-value rdate-nodes)) + (if (not (or rrule rdate-nodes)) ;; No recurrences to calculate, so just return early: nil ;; Otherwise, calculate recurrences in the interval: @@ -1267,19 +1267,19 @@ retrieved on subsequent calls with the same arguments." (t (let* (;; Start by generating all the recurrences matching the ;; BY* clauses except for BYSETPOS: - (subs (icr:refine-from-clauses interval recur-value dtstart + (subs (icr:refine-from-clauses interval rrule dtstart vtimezone)) (sub-recs (icr:subintervals-to-recurrences subs dtstart vtimezone)) ;; Apply any BYSETPOS clause to this set: - (keep-indices (ical:recur-by* 'BYSETPOS recur-value)) + (keep-indices (ical:rrule-by* 'BYSETPOS rrule)) (pos-recs (if keep-indices (icr:bysetpos-filter keep-indices sub-recs) sub-recs)) ;; Remove any recurrences before DTSTART or after UNTIL ;; (both of which are inclusive bounds): - (until (ical:recur-until recur-value)) + (until (ical:rrule-until rrule)) (until-recs (seq-filter (lambda (rec) (and (ical:date/time<= dtstart rec) @@ -1345,9 +1345,9 @@ UTC offsets local to that time zone." (ical:with-component component ((ical:dtstart :value dtstart) (ical:tzoffsetfrom :value offset-from) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes)) - (if (not (or recur-value rdate-nodes)) + (if (not (or rrule rdate-nodes)) ;; No recurrences to calculate, so just return early: nil ;; Otherwise, calculate the recurrences in the window: @@ -1362,11 +1362,11 @@ UTC offsets local to that time zone." (let* (;; don't look for nonexistent intervals: (low-start (if (ical:date/time< lower dtstart) dtstart lower)) - (until (ical:recur-until recur-value)) + (until (ical:rrule-until rrule)) (high-end (if (and until (ical:date/time< until upper)) until upper)) - (curr-interval (icr:find-interval low-start dtstart recur-value + (curr-interval (icr:find-interval low-start dtstart rrule vtimezone)) - (high-interval (icr:find-interval high-end dtstart recur-value + (high-interval (icr:find-interval high-end dtstart rrule vtimezone)) (high-intbound (icr:interval-high high-interval)) (recurrences nil)) @@ -1376,7 +1376,7 @@ UTC offsets local to that time zone." (nconc (icr:recurrences-in-interval curr-interval component vtimezone) recurrences)) - (setq curr-interval (icr:next-interval curr-interval recur-value + (setq curr-interval (icr:next-interval curr-interval rrule vtimezone))) ;; exclude any recurrences inside the first and last intervals but @@ -1447,7 +1447,7 @@ UTC offsets local to that time zone." (ical:with-component component ((ical:dtstart :value dtstart) (ical:tzoffsetfrom :value offset-from) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes)) (when (memq (ical:ast-node-type component) '(ical:standard ical:daylight)) ;; in time zone observances, set the zone field in dtstart @@ -1457,18 +1457,18 @@ UTC offsets local to that time zone." :zone offset-from :dst (not (ical:daylight-component-p component))))) - (unless (or recur-value rdate-nodes) + (unless (or rrule rdate-nodes) (error "No recurrence data in component: %s" component)) - (unless (ical:recur-count recur-value) + (unless (ical:rrule-count rrule) (error "Recurrence rule has no COUNT clause")) - (let ((count (ical:recur-count recur-value)) - (int (icr:nth-interval 0 dtstart recur-value vtimezone)) + (let ((count (ical:rrule-count rrule)) + (int (icr:nth-interval 0 dtstart rrule vtimezone)) recs) (while (length< recs count) (setq recs (nconc recs (icr:recurrences-in-interval int component vtimezone (- count (length recs))))) - (setq int (icr:next-interval int recur-value vtimezone))) + (setq int (icr:next-interval int rrule vtimezone))) recs))) @@ -1771,7 +1771,7 @@ ignored." (dolist (obs (append stds dls)) (ical:with-component obs ((ical:dtstart :value start) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:rdate :all rdate-nodes) (ical:tzoffsetfrom :value offset-from)) ;; DTSTART of the observance must be given as local time, and is @@ -1781,7 +1781,7 @@ ignored." (effective-start (ical:date-time-variant start :zone offset-from :dst (not is-daylight))) - (until (ical:recur-until recur-value)) + (until (ical:rrule-until rrule)) (bound ;; Optimization: compute a rough upper bound for when ;; an observance might apply, thus allowing us to skip @@ -1796,8 +1796,8 @@ ignored." (when until (ical:date-time-variant until :year (+ (decoded-time-year until) - (ical:recur-interval-size - recur-value))))) + (ical:rrule-interval-size + rrule))))) (observance-might-apply (if given-clock-time (icr:-w/in-locally-p given-clock-time effective-start bound) @@ -1859,11 +1859,11 @@ ignored." ;; start of each observance onset), which ;; `icr:tz-set-zone' knows to handle specially without ;; calling this function. - (when recur-value + (when rrule (let* ((target (or given-clock-time (decode-time given-abs-time offset-from))) (int (icr:find-interval - target effective-start recur-value offset-from)) + target effective-start rrule offset-from)) (<=given (if given-clock-time (lambda (rec) @@ -1883,7 +1883,7 @@ ignored." ;; actually be in the previous interval, e.g. ;; if `dt' is in January after an annual change to ;; Standard Time in November. So check that as well. - (setq int (icr:previous-interval int recur-value + (setq int (icr:previous-interval int rrule effective-start offset-from)) (setq int-recs diff --git a/lisp/calendar/icalendar-shortdoc.el b/lisp/calendar/icalendar-shortdoc.el index ef6f23cdfb9..cf706f54672 100644 --- a/lisp/calendar/icalendar-shortdoc.el +++ b/lisp/calendar/icalendar-shortdoc.el @@ -252,22 +252,22 @@ "(icalendar-recur-recurrences-to-count '(1 1 2026) '(12 31 2026) vevent)" :eg-result-string "((1 10 2026) (2 10 2026) (3 10 2026))") - (icalendar-recur-freq + (icalendar-rrule-freq :eval - (icalendar-recur-freq '((FREQ MONTHLY) (INTERVAL 3) (BYDAY ((5 . -1)))))) - (icalendar-recur-interval-size - :eval (icalendar-recur-interval-size '((FREQ MONTHLY) (BYDAY ((5 . -1))))) - :eval (icalendar-recur-interval-size '((FREQ MONTHLY) (INTERVAL 3)))) - (icalendar-recur-count - :eval (icalendar-recur-count '((FREQ MONTHLY) (INTERVAL 2) (COUNT 6)))) - (icalendar-recur-until - :eval (icalendar-recur-until '((FREQ WEEKLY) (UNTIL (12 31 2026))))) - (icalendar-recur-by* - :eval (icalendar-recur-by* 'BYDAY '((FREQ MONTHLY) (BYDAY ((5 . -1)))))) - (icalendar-recur-weekstart + (icalendar-rrule-freq '((FREQ MONTHLY) (INTERVAL 3) (BYDAY ((5 . -1)))))) + (icalendar-rrule-interval-size + :eval (icalendar-rrule-interval-size '((FREQ MONTHLY) (BYDAY ((5 . -1))))) + :eval (icalendar-rrule-interval-size '((FREQ MONTHLY) (INTERVAL 3)))) + (icalendar-rrule-count + :eval (icalendar-rrule-count '((FREQ MONTHLY) (INTERVAL 2) (COUNT 6)))) + (icalendar-rrule-until + :eval (icalendar-rrule-until '((FREQ WEEKLY) (UNTIL (12 31 2026))))) + (icalendar-rrule-by* + :eval (icalendar-rrule-by* 'BYDAY '((FREQ MONTHLY) (BYDAY ((5 . -1)))))) + (icalendar-rrule-weekstart :eval - (icalendar-recur-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)) (WKST 0))) + (icalendar-rrule-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)) (WKST 0))) :eval - (icalendar-recur-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)))))) + (icalendar-rrule-weekstart '((FREQ WEEKLY) (UNTIL (12 31 2026)))))) (provide 'icalendar-shortdoc) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 0097f590b43..54f105f6fda 100644 --- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -131,18 +131,18 @@ (cl-defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event)) "Return recurring frequency of EVENT." - (ical:recur-freq (gnus-icalendar-event:recur event))) + (ical:rrule-freq (gnus-icalendar-event:recur event))) (cl-defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event)) "Return recurring interval of EVENT." - (ical:recur-interval-size (gnus-icalendar-event:recur event))) + (ical:rrule-interval-size (gnus-icalendar-event:recur event))) (cl-defmethod gnus-icalendar-event:recurring-days ((event gnus-icalendar-event)) "Return, when available, the week day numbers on which the EVENT recurs." (let ((rrule (gnus-icalendar-event:recur event))) (when rrule (mapcar (lambda (el) (if (consp el) (car el) el)) - (ical:recur-by* 'BYDAY rrule))))) + (ical:rrule-by* 'BYDAY rrule))))) (cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event)) (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event))) diff --git a/test/lisp/calendar/diary-icalendar-tests.el b/test/lisp/calendar/diary-icalendar-tests.el index 22faeb7aa23..06272a39cf4 100644 --- a/test/lisp/calendar/diary-icalendar-tests.el +++ b/test/lisp/calendar/diary-icalendar-tests.el @@ -817,8 +817,8 @@ SOURCE, if given, should be a symbol; it is used to name the test." (should (equal (ical:date-time-to-date dtstart) (calendar-nth-named-day 1 4 1 di:recurring-start-year))) (should (= 16 (decoded-time-hour dtstart))) - (should (eq (ical:recur-freq rrule) 'WEEKLY)) - (should (equal (ical:recur-by* 'BYDAY rrule) (list 4))))) + (should (eq (ical:rrule-freq rrule) 'WEEKLY)) + (should (equal (ical:rrule-by* 'BYDAY rrule) (list 4))))) (dit:parse-test ;; Multiline entry, parsed as one event: @@ -961,10 +961,10 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart '(5 28 1995))) - (should (eq (ical:recur-freq recur-value) 'YEARLY)) + (should (eq (ical:rrule-freq rrule) 'YEARLY)) (should (equal summary "H's birthday")))) (dit:parse-test @@ -977,11 +977,11 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart '(6 24 2012))) - (should (equal (ical:recur-freq recur-value) 'DAILY)) - (should (equal (ical:recur-until recur-value) '(7 10 2012))) + (should (equal (ical:rrule-freq rrule) 'DAILY)) + (should (equal (ical:rrule-until rrule) '(7 10 2012))) (should (equal summary "Vacation")))) (dit:parse-test @@ -994,11 +994,11 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart '(3 1 2012))) - (should (eq (ical:recur-freq recur-value) 'DAILY)) - (should (eq (ical:recur-interval-size recur-value) 50)) + (should (eq (ical:rrule-freq rrule) 'DAILY)) + (should (eq (ical:rrule-interval-size rrule) 50)) (should (equal summary "Renew medication")))) (dit:parse-test @@ -1011,13 +1011,13 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart (calendar-nth-named-day 4 4 11 di:recurring-start-year))) - (should (eq (ical:recur-freq recur-value) 'MONTHLY)) - (should (equal (ical:recur-by* 'BYMONTH recur-value) (list 11))) - (should (equal (ical:recur-by* 'BYDAY recur-value) (list '(4 . 4)))) + (should (eq (ical:rrule-freq rrule) 'MONTHLY)) + (should (equal (ical:rrule-by* 'BYMONTH rrule) (list 11))) + (should (equal (ical:rrule-by* 'BYDAY rrule) (list '(4 . 4)))) (should (equal summary "American Thanksgiving")))) (dit:parse-test @@ -1030,13 +1030,13 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart (calendar-nth-named-day 4 5 1 di:recurring-start-year))) - (should (eq (ical:recur-freq recur-value) 'MONTHLY)) + (should (eq (ical:rrule-freq rrule) 'MONTHLY)) ;; day 3 is Wednesday, so offset of 2 means Friday (=5): - (should (equal (ical:recur-by* 'BYDAY recur-value) (list '(5 . 4)))) + (should (equal (ical:rrule-by* 'BYDAY rrule) (list '(5 . 4)))) (should (equal summary "Monthly committee meeting")))) (dit:parse-test @@ -1052,11 +1052,11 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:exdate :values exdates) (ical:summary :value summary)) (should (equal dtstart '(11 11 2024))) - (should (eq (ical:recur-freq recur-value) 'WEEKLY)) + (should (eq (ical:rrule-freq rrule) 'WEEKLY)) (should (equal exdates '((12 23 2024) (12 30 2024)))) (should (equal summary "Reading group")))) @@ -1070,12 +1070,12 @@ SOURCE, if given, should be a symbol; it is used to name the test." :tests (ical:with-component (car parsed) ((ical:dtstart :value dtstart) - (ical:rrule :value recur-value) + (ical:rrule :value rrule) (ical:summary :value summary)) (should (equal dtstart (list 10 22 di:recurring-start-year))) - (should (eq (ical:recur-freq recur-value) 'YEARLY)) - (should (equal (ical:recur-by* 'BYMONTH recur-value) (list 10 11 12))) - (should (equal (ical:recur-by* 'BYMONTHDAY recur-value) (list 22))) + (should (eq (ical:rrule-freq rrule) 'YEARLY)) + (should (equal (ical:rrule-by* 'BYMONTH rrule) (list 10 11 12))) + (should (equal (ical:rrule-by* 'BYMONTHDAY rrule) (list 22))) (should (equal summary "Rake leaves")))) (dit:parse-test diff --git a/test/lisp/calendar/icalendar-parser-tests.el b/test/lisp/calendar/icalendar-parser-tests.el index f3c5de35c87..8215f977e26 100644 --- a/test/lisp/calendar/icalendar-parser-tests.el +++ b/test/lisp/calendar/icalendar-parser-tests.el @@ -388,21 +388,21 @@ test." (ipt:parse/print-test "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1" -:type icalendar-recur +:type icalendar-rrule-value :parser icalendar-parse-value-node :printer icalendar-print-value-node :source rfc5545-sec3.3.10/1) (ipt:parse/print-test "FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30" -:type icalendar-recur +:type icalendar-rrule-value :parser icalendar-parse-value-node :printer icalendar-print-value-node :source rfc5545-sec3.3.10/2) (ipt:parse/print-test "FREQ=DAILY;COUNT=10;INTERVAL=2" -:type icalendar-recur +:type icalendar-rrule-value :parser icalendar-parse-value-node :printer icalendar-print-value-node :source rfc5545-sec3.3.10/3) diff --git a/test/lisp/calendar/icalendar-recur-tests.el b/test/lisp/calendar/icalendar-recur-tests.el index c1f7bb90974..199d6c4aa25 100644 --- a/test/lisp/calendar/icalendar-recur-tests.el +++ b/test/lisp/calendar/icalendar-recur-tests.el @@ -1383,7 +1383,7 @@ END:VTIMEZONE (ts-obs/onset (icr:tz-observance-on ts ict:tz-eastern))) (should (eq 'ical:daylight (ical:ast-node-type obs))) (should (equal dt onset)) - (should (equal end (ical:recur-until + (should (equal end (ical:rrule-until (ical:with-property-of obs 'ical:rrule nil value)))) (should (equal obs/onset ts-obs/onset))) @@ -1534,10 +1534,10 @@ SOURCE should be a symbol; it is used to name the test." ,(format "Parse and evaluate recur-value example from `%s':\n%s" source doc) :tags ,tags - (let* ((parsed (ical:parse-from-string 'ical:recur ,recur-string)) + (let* ((parsed (ical:parse-from-string 'ical:rrule-value ,recur-string)) (recvalue (ical:ast-node-value parsed)) - (until (ical:recur-until recvalue)) - (count (ical:recur-count recvalue)) + (until (ical:rrule-until recvalue)) + (count (ical:rrule-count recvalue)) (dtstart ,dtstart) (tzid (when (cl-typep dtstart 'ical:date-time) From f13287fde0d0900fe834cda9df77a072dd35d685 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 23 May 2026 13:27:49 +0300 Subject: [PATCH 057/112] Revert "sh-script: Mark + and * as punctuation rather than a symbol constituent" This reverts commit b3c0aee42b086af4b3c6e26da1a5d81490b6128b. It caused regressions in 'sh-script', see bug#80794 and bug#80854. --- lisp/progmodes/sh-script.el | 2 -- 1 file changed, 2 deletions(-) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index ffa8407b9bc..8479c3cfd9a 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -406,8 +406,6 @@ name symbol." ;; to work fine. This is needed so that dabbrev-expand ;; $VARNAME works. ?$ "'" - ?* "." - ?+ "." ?! "." ?% "." ?: "." From 741feca4972ad046fa463b9015942c4196c83bcc Mon Sep 17 00:00:00 2001 From: Elias Gabriel Perez Date: Thu, 19 Mar 2026 23:04:27 -0600 Subject: [PATCH 058/112] New tool bar icons for artist-mode * etc/images/artist-mode/README: * etc/images/artist-mode/char-for-spray.xpm: * etc/images/artist-mode/char-to-fill.xpm: * etc/images/artist-mode/ellipse.xpm: * etc/images/artist-mode/eraser.xpm: * etc/images/artist-mode/fill.xpm: * etc/images/artist-mode/line.xpm: * etc/images/artist-mode/pen.xpm: * etc/images/artist-mode/poly-line.xpm: * etc/images/artist-mode/rectangle.xpm: * etc/images/artist-mode/spray.xpm: * etc/images/artist-mode/square.xpm: * etc/images/artist-mode/text.xpm: * etc/images/artist-mode/char-for-spray.pbm: * etc/images/artist-mode/char-to-fill.pbm: * etc/images/artist-mode/ellipse.pbm: * etc/images/artist-mode/eraser.pbm: * etc/images/artist-mode/fill.pbm: * etc/images/artist-mode/line.pbm: * etc/images/artist-mode/pen.pbm: * etc/images/artist-mode/poly-line.pbm: * etc/images/artist-mode/rectangle.pbm: * etc/images/artist-mode/spray.pbm: * etc/images/artist-mode/square.pbm: * etc/images/artist-mode/text.pbm: New files. * lisp/textmodes/artist.el (artist-tool-bar-map): New variable. (artist-mode, artist-mode-exit): Use it (bug#80644). --- etc/images/artist-mode/README | 19 ++ etc/images/artist-mode/char-for-spray.pbm | Bin 0 -> 149 bytes etc/images/artist-mode/char-for-spray.xpm | 281 ++++++++++++++++++++ etc/images/artist-mode/char-to-fill.pbm | Bin 0 -> 149 bytes etc/images/artist-mode/char-to-fill.xpm | 301 ++++++++++++++++++++++ etc/images/artist-mode/ellipse.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/ellipse.xpm | 29 +++ etc/images/artist-mode/eraser.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/eraser.xpm | 138 ++++++++++ etc/images/artist-mode/fill.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/fill.xpm | 186 +++++++++++++ etc/images/artist-mode/line.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/line.xpm | 29 +++ etc/images/artist-mode/pen.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/pen.xpm | 130 ++++++++++ etc/images/artist-mode/poly-line.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/poly-line.xpm | 29 +++ etc/images/artist-mode/rectangle.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/rectangle.xpm | 30 +++ etc/images/artist-mode/spray.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/spray.xpm | 139 ++++++++++ etc/images/artist-mode/square.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/square.xpm | 30 +++ etc/images/artist-mode/text.pbm | Bin 0 -> 125 bytes etc/images/artist-mode/text.xpm | 164 ++++++++++++ lisp/textmodes/artist.el | 61 ++++- 26 files changed, 1565 insertions(+), 1 deletion(-) create mode 100644 etc/images/artist-mode/README create mode 100644 etc/images/artist-mode/char-for-spray.pbm create mode 100644 etc/images/artist-mode/char-for-spray.xpm create mode 100644 etc/images/artist-mode/char-to-fill.pbm create mode 100644 etc/images/artist-mode/char-to-fill.xpm create mode 100644 etc/images/artist-mode/ellipse.pbm create mode 100644 etc/images/artist-mode/ellipse.xpm create mode 100644 etc/images/artist-mode/eraser.pbm create mode 100644 etc/images/artist-mode/eraser.xpm create mode 100644 etc/images/artist-mode/fill.pbm create mode 100644 etc/images/artist-mode/fill.xpm create mode 100644 etc/images/artist-mode/line.pbm create mode 100644 etc/images/artist-mode/line.xpm create mode 100644 etc/images/artist-mode/pen.pbm create mode 100644 etc/images/artist-mode/pen.xpm create mode 100644 etc/images/artist-mode/poly-line.pbm create mode 100644 etc/images/artist-mode/poly-line.xpm create mode 100644 etc/images/artist-mode/rectangle.pbm create mode 100644 etc/images/artist-mode/rectangle.xpm create mode 100644 etc/images/artist-mode/spray.pbm create mode 100644 etc/images/artist-mode/spray.xpm create mode 100644 etc/images/artist-mode/square.pbm create mode 100644 etc/images/artist-mode/square.xpm create mode 100644 etc/images/artist-mode/text.pbm create mode 100644 etc/images/artist-mode/text.xpm diff --git a/etc/images/artist-mode/README b/etc/images/artist-mode/README new file mode 100644 index 00000000000..3123cfc76c8 --- /dev/null +++ b/etc/images/artist-mode/README @@ -0,0 +1,19 @@ +COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES -*- coding: utf-8 -*- + +The following icons were derived from GIMP 3.2.X icons, modified for +Emacs by Elías Gabriel Pérez . +Copyright (C) 2026 Free Software Foundation, Inc. +License: GNU General Public License version 3 or later (see COPYING) + + char-for-spray.xpm char-for-spray.pbm + char-to-fill.xpm char-to-fill.pbm + ellipse.xpm ellipse.pbm + eraser.xpm eraser.pbm + fill.xpm fill.pbm + line.xpm line.pbm + pen.xpm pen.pbm + poly-line.xpm poly-line.pbm + rectangle.xpm rectangle.pbm + spray.xpm spray.pbm + square.xpm square.pbm + text.xpm text.pbm diff --git a/etc/images/artist-mode/char-for-spray.pbm b/etc/images/artist-mode/char-for-spray.pbm new file mode 100644 index 0000000000000000000000000000000000000000..f41de01ca49a6df23858c91362c4e1768a3a3c55 GIT binary patch literal 149 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W+ zFf!p{00Q~{|G?P(|9=Jx`~M8~`~Nf8$kj7g&jVpU1`9hD2K#>r5ZtD~U|+_}U{}AK e!49Y%jGqH(-d7Fwe?J1v`N1In{U69!FaQAN^)ZhC literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/char-for-spray.xpm b/etc/images/artist-mode/char-for-spray.xpm new file mode 100644 index 00000000000..e0b9534fc24 --- /dev/null +++ b/etc/images/artist-mode/char-for-spray.xpm @@ -0,0 +1,281 @@ +/* XPM */ +static char * char_for_spray_xpm[] = { +"26 24 254 2", +" c None", +". c #A1A39E", +"+ c #CDCECC", +"@ c #CFD0CD", +"# c #CDCDCB", +"$ c #A1A29F", +"% c #E1E1DF", +"& c #CCCEC8", +"* c #C8CAC4", +"= c #E0E1DF", +"- c #959691", +"; c #E4E5E3", +"> c #CACCC7", +", c #BDBEBA", +"' c #ABADA9", +") c #BDBFBB", +"! c #939792", +"~ c #E6E7E4", +"{ c #CCCEC9", +"] c #575856", +"^ c #333432", +"/ c #444543", +"( c #212120", +"_ c #4E4E4C", +": c #CBCDC8", +"< c #959792", +"[ c #E7E8E5", +"} c #CED0CB", +"| c #282827", +"1 c #959793", +"2 c #E8E9E6", +"3 c #D0D2CD", +"4 c #9A9C98", +"5 c #3B3B3A", +"6 c #2F302F", +"7 c #373837", +"8 c #141413", +"9 c #767775", +"0 c #CDCFCA", +"a c #000000", +"b c #C9CBC6", +"c c #E9EAE7", +"d c #C7C9C4", +"e c #090909", +"f c #AAACA8", +"g c #D2D4CF", +"h c #3C3D3B", +"i c #737472", +"j c #CFD1CC", +"k c #959893", +"l c #EAEBE9", +"m c #C0C1BD", +"n c #050505", +"o c #BEBEBB", +"p c #D5D6D2", +"q c #A5A6A3", +"r c #060606", +"s c #757573", +"t c #D2D3CF", +"u c #8B8B89", +"v c #2E2E2D", +"w c #393938", +"x c #B4B4B1", +"y c #DDDEDC", +"z c #494D4C", +"A c #2F3235", +"B c #979893", +"C c #EBECEA", +"D c #D7D8D4", +"E c #767774", +"F c #1E1E1E", +"G c #313130", +"H c #50504F", +"I c #5E5E5C", +"J c #898A88", +"K c #D4D5D1", +"L c #5D5D5B", +"M c #030303", +"N c #232322", +"O c #C4C5C2", +"P c #686B6B", +"Q c #4A4D4D", +"R c #303537", +"S c #979895", +"T c #ECEDEB", +"U c #D9DAD6", +"V c #D6D7D3", +"W c #BBBCB9", +"X c #414140", +"Y c #0D1012", +"Z c #5C605F", +"` c #575A58", +" . c #323939", +".. c #EDEEEC", +"+. c #DBDCD8", +"@. c #D8D9D5", +"#. c #010101", +"$. c #C4C4C1", +"%. c #4D4D4C", +"&. c #333839", +"*. c #555957", +"=. c #454948", +"-. c #3B4040", +";. c #2F3536", +">. c #979A95", +",. c #EEEFED", +"'. c #DDDEDA", +"). c #AFB0AD", +"!. c #474746", +"~. c #424241", +"{. c #373736", +"]. c #A8A9A6", +"^. c #DADBD7", +"/. c #171A1C", +"(. c #303538", +"_. c #7A7C7A", +":. c #34393A", +"<. c #525654", +"[. c #3E4343", +"}. c #6D716E", +"|. c #989A95", +"1. c #EFF0EE", +"2. c #DFE0DD", +"3. c #A4A4A2", +"4. c #111110", +"5. c #BCBDBA", +"6. c #40403F", +"7. c #939492", +"8. c #DBDCDA", +"9. c #000101", +"0. c #293030", +"a. c #3D4242", +"b. c #434848", +"c. c #484C4B", +"d. c #353B3B", +"e. c #B3B4B3", +"f. c #989A97", +"g. c #F0F1EF", +"h. c #E1E2DF", +"i. c #DEDFDC", +"j. c #181818", +"k. c #737372", +"l. c #B5B6B3", +"m. c #D2D3D0", +"n. c #BABBB8", +"o. c #696B68", +"p. c #6B6D6D", +"q. c #3B4141", +"r. c #A8A9A7", +"s. c #F1F2F0", +"t. c #E3E4E1", +"u. c #A9AAA8", +"v. c #B9BAB8", +"w. c #D3D5D2", +"x. c #818380", +"y. c #C1C1C1", +"z. c #DEDEDE", +"A. c #A4A4A3", +"B. c #878988", +"C. c #9A9B97", +"D. c #F3F3F1", +"E. c #E6E6E3", +"F. c #939391", +"G. c #DDDDDA", +"H. c #E3E3E0", +"I. c #D9D9D7", +"J. c #D5D5D2", +"K. c #888986", +"L. c #CCCCCC", +"M. c #E4E4E4", +"N. c #BFBFBE", +"O. c #B5B5B5", +"P. c #7C7C7B", +"Q. c #CBCBC9", +"R. c #232323", +"S. c #F4F4F2", +"T. c #E8E8E5", +"U. c #AEAEAC", +"V. c #CACAC7", +"W. c #747473", +"X. c #737371", +"Y. c #E7E7E4", +"Z. c #C3C3C0", +"`. c #A3A5A3", +" + c #E6E6E5", +".+ c #A3A4A2", +"++ c #7A7B79", +"@+ c #ADAEAD", +"#+ c #8F8F8F", +"$+ c #AFAFAD", +"%+ c #8B8B88", +"&+ c #5D5D5D", +"*+ c #585858", +"=+ c #9A9B98", +"-+ c #F5F5F4", +";+ c #EAEAE8", +">+ c #666665", +",+ c #2D2D2D", +"'+ c #767675", +")+ c #575756", +"!+ c #6C6C6B", +"~+ c #E7E7E5", +"{+ c #757774", +"]+ c #B0B3AD", +"^+ c #A0A19E", +"/+ c #B0B0AE", +"(+ c #BBBBB9", +"_+ c #6A6B68", +":+ c #626262", +"<+ c #C3C3C2", +"[+ c #595959", +"}+ c #7F7F7F", +"|+ c #9B9D99", +"1+ c #ECECEA", +"2+ c #E5E5E3", +"3+ c #C9C9C7", +"4+ c #E3E3E1", +"5+ c #777775", +"6+ c #939591", +"7+ c #B9BAB7", +"8+ c #4D4E4D", +"9+ c #767676", +"0+ c #747474", +"a+ c #777777", +"b+ c #545454", +"c+ c #EBEBEA", +"d+ c #EFEFED", +"e+ c #EEEEEC", +"f+ c #E8E9E8", +"g+ c #9AA2B5", +"h+ c #BDBDBB", +"i+ c #B7B8B5", +"j+ c #EBEBE9", +"k+ c #EDEDEB", +"l+ c #C0C0BE", +"m+ c #4B4B4A", +"n+ c #595958", +"o+ c #3F3F3F", +"p+ c #969894", +"q+ c #D0D1D0", +"r+ c #D9D9D8", +"s+ c #DADAD9", +"t+ c #C6C8CB", +"u+ c #A5ABB8", +"v+ c #466293", +"w+ c #818DA6", +"x+ c #D7D7D6", +"y+ c #D8D8D7", +"z+ c #939390", +"A+ c #375A8F", +"B+ c #38598F", +"C+ c #37578C", +"D+ c #37588E", +"E+ c #355887", +" ", +" . + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # $ ", +" % & * * * * * * * * * * * * * * * * & = ", +" - ; > > , ' ) > > > > > > > > > > > > > ; - ", +" ! ~ { ] ^ / ( _ : { { { { { { { { { { { ~ ! ", +" < [ } > } } { | 1 } } } } } } } } } } } [ < ", +" < 2 3 4 5 6 7 8 9 3 3 3 0 a a b 3 3 3 3 2 < ", +" 1 c d e f g g h i g g g j a a : g g g g c 1 ", +" k l m n o p q r s p p p t a a u v w x p y z A ", +" B C D E F G H I J D D D K a a G L M N O P Q R ", +" S T U U U U U U U U U U V a a W U X Y Z ` z . ", +" S ..+.+.+.+.+.+.+.+.+.+.@.a #.$.D %.&.*.=.-.;. ", +" >.,.'.'.'.'.).!.H ~.{.].^.a /.(._.:.<.z [.}. ", +" |.1.2.2.2.3.4.5.2.2.6.7.8.9.0.:.a.b.c.d.e.|. ", +" f.g.h.h.i.j.k.h.h.h.l.m.h.m.n.o.e.p.q.r...f. ", +" f.s.t.t.u.a v.t.t.t.t.t.t.w.x.y.z.A.B.t.s.f. ", +" C.D.E.E.F.a G.E.E.H.I.E.J.K.L.M.N.O.P.Q.D.C. R.", +" C.S.T.T.U.a V.T.T.W.X.Y.Z.`. +.+++@+#+$+D.%+&+*+", +" =+-+;+;+;+>+,+'+)+!+~+% {+]+^+/+(+_+#+:+<+[+}+ ", +" |+-+1+1+1+1+2+3+4+1+1+4+5+6+7+1+1+(+8+9+0+a+b+ ", +" c+d+e+e+e+e+e+e+T f+g+h+i+j+e+e+k+l+m+n+o+ ", +" p+q+r+s+r+r+r+t+u+v+w+x+y+r+r+r+s+y+# z+ ", +" A+B+C+ ", +" D+E+ "}; diff --git a/etc/images/artist-mode/char-to-fill.pbm b/etc/images/artist-mode/char-to-fill.pbm new file mode 100644 index 0000000000000000000000000000000000000000..91a3eae85d8912ca09efa102063ff85dadbb2882 GIT binary patch literal 149 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W+ zFf!p{00Q~{|G?P(|9=Jx`~M8~`~Nf8$kj7g&jVq91`9iO2K#^MK%B>5-)6^PUslIp gSNo5_4yYc88^Bope*;ke0eK)Fh=Hd50pbD%08chHp#T5? literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/char-to-fill.xpm b/etc/images/artist-mode/char-to-fill.xpm new file mode 100644 index 00000000000..cb3ed3185b8 --- /dev/null +++ b/etc/images/artist-mode/char-to-fill.xpm @@ -0,0 +1,301 @@ +/* XPM */ +static char * char_to_fill_xpm[] = { +"26 24 274 2", +" c None", +". c #A1A39E", +"+ c #CDCECC", +"@ c #CFD0CD", +"# c #CDCDCB", +"$ c #A1A29F", +"% c #E1E1DF", +"& c #CCCEC8", +"* c #C8CAC4", +"= c #E0E1DF", +"- c #959691", +"; c #E4E5E3", +"> c #CACCC7", +", c #BDBEBA", +"' c #ABADA9", +") c #BDBFBB", +"! c #939792", +"~ c #E6E7E4", +"{ c #CCCEC9", +"] c #575856", +"^ c #333432", +"/ c #444543", +"( c #212120", +"_ c #4E4E4C", +": c #CBCDC8", +"< c #959792", +"[ c #E7E8E5", +"} c #CED0CB", +"| c #282827", +"1 c #959793", +"2 c #E8E9E6", +"3 c #D0D2CD", +"4 c #9A9C98", +"5 c #3B3B3A", +"6 c #2F302F", +"7 c #373837", +"8 c #141413", +"9 c #767775", +"0 c #CDCFCA", +"a c #000000", +"b c #C9CBC6", +"c c #E9EAE7", +"d c #C7C9C4", +"e c #090909", +"f c #AAACA8", +"g c #D2D4CF", +"h c #3C3D3B", +"i c #737472", +"j c #CFD1CC", +"k c #959893", +"l c #EAEBE9", +"m c #C0C1BD", +"n c #050505", +"o c #BEBEBB", +"p c #D5D6D2", +"q c #A5A6A3", +"r c #060606", +"s c #757573", +"t c #D2D3CF", +"u c #8B8B89", +"v c #2E2E2D", +"w c #393938", +"x c #B4B4B1", +"y c #979893", +"z c #EBECEA", +"A c #D7D8D4", +"B c #767774", +"C c #1E1E1E", +"D c #313130", +"E c #50504F", +"F c #5E5E5C", +"G c #898A88", +"H c #D4D5D1", +"I c #5D5D5B", +"J c #30312E", +"K c #454744", +"L c #979995", +"M c #C7C8C6", +"N c #979895", +"O c #ECEDEB", +"P c #D9DAD6", +"Q c #D6D7D3", +"R c #BBBCB9", +"S c #BEBFBB", +"T c #4D4E4C", +"U c #353533", +"V c #A2A3A0", +"W c #B2B4B1", +"X c #80817E", +"Y c #EDEEEC", +"Z c #DBDCD8", +"` c #D8D9D5", +" . c #CCCCC9", +".. c #ADAEAB", +"+. c #5D5E5C", +"@. c #858684", +"#. c #969795", +"$. c #DDDEDC", +"%. c #747673", +"&. c #979A95", +"*. c #EEEFED", +"=. c #DDDEDA", +"-. c #AFB0AD", +";. c #474746", +">. c #424241", +",. c #373736", +"'. c #A8A9A6", +"). c #DADBD7", +"!. c #0A0A09", +"~. c #70706E", +"{. c #787A77", +"]. c #C5C5C4", +"^. c #E8E8E8", +"/. c #BABBB9", +"(. c #747773", +"_. c #989A95", +":. c #EFF0EE", +"<. c #DFE0DD", +"[. c #A4A4A2", +"}. c #111110", +"|. c #BCBDBA", +"1. c #C8CBCE", +"2. c #4A5269", +"3. c #808592", +"4. c #B7BAC2", +"5. c #363C4A", +"6. c #6B6D6C", +"7. c #BABAB9", +"8. c #ADAEAD", +"9. c #D1D1D1", +"0. c #DBDBDB", +"a. c #9EA09E", +"b. c #737571", +"c. c #989A97", +"d. c #F0F1EF", +"e. c #E1E2DF", +"f. c #DEDFDC", +"g. c #181818", +"h. c #737372", +"i. c #C4C7CC", +"j. c #91A1C0", +"k. c #8AA6D0", +"l. c #7190BF", +"m. c #667289", +"n. c #A6A9AD", +"o. c #E7E7E7", +"p. c #F2F3F3", +"q. c #B5B6B5", +"r. c #C0C0C0", +"s. c #D0D0D0", +"t. c #D8D8D8", +"u. c #C5C6C5", +"v. c #757774", +"w. c #F1F2F0", +"x. c #E3E4E1", +"y. c #A9AAA8", +"z. c #B9BAB8", +"A. c #B1B5C1", +"B. c #AABFDE", +"C. c #95AED0", +"D. c #7F868F", +"E. c #D2D3D3", +"F. c #F2F2F2", +"G. c #F9F9F9", +"H. c #797A78", +"I. c #C7C7C6", +"J. c #CDCDCD", +"K. c #E0E0E0", +"L. c #949593", +"M. c #9A9B97", +"N. c #F3F3F1", +"O. c #E6E6E3", +"P. c #939391", +"Q. c #DDDDDA", +"R. c #B0B4C0", +"S. c #AFC5E3", +"T. c #93AACC", +"U. c #A4A5A8", +"V. c #EAEAEA", +"W. c #F0F0F0", +"X. c #8B8C8A", +"Y. c #8F908F", +"Z. c #8E8F8E", +"`. c #959795", +" + c #D2D2D2", +".+ c #D0D1D0", +"++ c #F4F4F2", +"@+ c #E8E8E5", +"#+ c #AEAEAC", +"$+ c #CACAC7", +"%+ c #B0C5E3", +"&+ c #94AED6", +"*+ c #787D8A", +"=+ c #D9DAD9", +"-+ c #DFDFDF", +";+ c #E6E6E6", +">+ c #959594", +",+ c #8D8E8C", +"'+ c #A4A5A4", +")+ c #CECECE", +"!+ c #DBDBDA", +"~+ c #A5A6A4", +"{+ c #9A9B98", +"]+ c #F5F5F4", +"^+ c #EAEAE8", +"/+ c #666665", +"(+ c #2D2D2D", +"_+ c #767675", +":+ c #58617C", +"<+ c #B0B4BC", +"[+ c #A4A5A3", +"}+ c #DEDEDE", +"|+ c #AFB0AF", +"1+ c #B1B2B1", +"2+ c #E1E1E0", +"3+ c #DDDDDD", +"4+ c #D3D3D3", +"5+ c #757673", +"6+ c #9B9D99", +"7+ c #ECECEA", +"8+ c #E5E5E3", +"9+ c #C9C9C7", +"0+ c #AEB2BF", +"a+ c #93ADD5", +"b+ c #C4C6CE", +"c+ c #C3C3C1", +"d+ c #C8C8C7", +"e+ c #F8F8F8", +"f+ c #F7F7F7", +"g+ c #EDEDED", +"h+ c #E3E3E3", +"i+ c #D9D9D9", +"j+ c #D7D7D7", +"k+ c #777875", +"l+ c #EBEBEA", +"m+ c #EFEFED", +"n+ c #EEEEEC", +"o+ c #BEC2CC", +"p+ c #9AADCF", +"q+ c #8AA0C8", +"r+ c #CCCED4", +"s+ c #B4B4B2", +"t+ c #EFEFEF", +"u+ c #FAFAFA", +"v+ c #F3F3F3", +"w+ c #E1E2E1", +"x+ c #9C9D9B", +"y+ c #656764", +"z+ c #969894", +"A+ c #D9D9D8", +"B+ c #DADAD9", +"C+ c #CECFD2", +"D+ c #A6ABBA", +"E+ c #AAAEBD", +"F+ c #D1D2D3", +"G+ c #BBBBBA", +"H+ c #CFCFCF", +"I+ c #DCDCDC", +"J+ c #EAEBEA", +"K+ c #C6C7C6", +"L+ c #7A7A78", +"M+ c #838583", +"N+ c #E6E6E5", +"O+ c #E1E1E1", +"P+ c #D6D6D5", +"Q+ c #979896", +"R+ c #636561", +"S+ c #50534B", +"T+ c #595C57", +"U+ c #A1A3A1", +"V+ c #DDDEDD", +"W+ c #6D6E6B", +"X+ c #50534C", +"Y+ c #4F524A", +" ", +" . + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # $ ", +" % & * * * * * * * * * * * * * * * * & = ", +" - ; > > , ' ) > > > > > > > > > > > > > ; - ", +" ! ~ { ] ^ / ( _ : { { { { { { { { { { { ~ ! ", +" < [ } > } } { | 1 } } } } } } } } } } } [ < ", +" < 2 3 4 5 6 7 8 9 3 3 3 0 a a b 3 3 3 3 2 < ", +" 1 c d e f g g h i g g g j a a : g g g g c 1 ", +" k l m n o p q r s p p p t a a u v w x p l k ", +" y z A B C D E F G A A A H a a D I J K L M - ", +" N O P P P P P P P P P P Q a a R S T U V W X ", +" N Y Z Z Z Z Z Z Z Z Z Z ` a a ...+.@.#.$.%. ", +" &.*.=.=.=.=.-.;.E >.,.'.).a !.~.{.].^./.+ (. ", +" _.:.<.<.<.[.}.|.$.1.2.3.4.5.6.7.8.].9.0.a.b. ", +" c.d.e.e.f.g.h.e.i.j.k.l.m.n.o.p.q.r.s.t.u.v. ", +" c.w.x.x.y.a z.x.A.B.C.D.E.F.G.t.H.@.I.J.K.L. ", +" M.N.O.O.P.a Q.O.R.S.T.U.V.K.W.X.Y.Z.`. +9..+H. ", +" M.++@+@+#+a $+@+A.%+&+*+=+-+;+>+,+G '+t.)+!+~+ ", +" {+]+^+^+^+/+(+_+:+%+&+<+[+;+}+K.|+1+2+3+4+ + +5+", +" 6+]+7+7+7+7+8+9+0+S.a+b+c+d+-+;+e+f+g+h+i+j+h+k+", +" l+m+n+n+n+n+n+o+p+q+r+8+s+3+3+t+u+v+V.o.w+x+y+", +" z+.+A+B+A+A+A+C+D+E+F+A+G+H+I+h+f+G.J+K+L+ ", +" M+N+O+F.P+Q+R+ ", +" S+S+T+U+V+x+W+X+Y+S+ "}; diff --git a/etc/images/artist-mode/ellipse.pbm b/etc/images/artist-mode/ellipse.pbm new file mode 100644 index 0000000000000000000000000000000000000000..dc6251208a3068027c9db7223aef877e7d3255f0 GIT binary patch literal 125 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W) vFf!p{0D^xE%>NtM84vIstVM9?hs literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/eraser.xpm b/etc/images/artist-mode/eraser.xpm new file mode 100644 index 00000000000..130926153f9 --- /dev/null +++ b/etc/images/artist-mode/eraser.xpm @@ -0,0 +1,138 @@ +/* XPM */ +static char * eraser_xpm[] = { +"24 24 111 2", +" c None", +". c #ED2F2F", +"+ c #EF2929", +"@ c #EF2C2B", +"# c #ED3030", +"$ c #EE2C2C", +"% c #EF6968", +"& c #EDD0CC", +"* c #EDD6D1", +"= c #EDCFCB", +"- c #EE5252", +"; c #EF3535", +"> c #EDCEC8", +", c #E4B6AE", +"' c #E1ABA2", +") c #E1ACA2", +"! c #EDCFCA", +"~ c #F28D8B", +"{ c #EF2D2D", +"] c #EF2E2E", +"^ c #EEA29F", +"/ c #EAC5BE", +"( c #E2ABA2", +"_ c #E6BBB3", +": c #EEC5C2", +"< c #F49491", +"[ c #F03F3E", +"} c #EE5857", +"| c #EDD1CC", +"1 c #E3AEA5", +"2 c #E2AAA1", +"3 c #E2ABA1", +"4 c #ECCEC9", +"5 c #F3A2A0", +"6 c #F59290", +"7 c #F05453", +"8 c #F02F2E", +"9 c #EFC3BF", +"0 c #E6BAB3", +"a c #E3A9A1", +"b c #EEC5C1", +"c c #F5908D", +"d c #F48C8A", +"e c #ED2E2E", +"f c #ED2C2C", +"g c #EF8B89", +"h c #EBC9C3", +"i c #E3A9A0", +"j c #E3AAA0", +"k c #EDCDC8", +"l c #F49F9D", +"m c #F58F8C", +"n c #F15F5E", +"o c #DB2B2B", +"p c #EF4242", +"q c #EDD1CB", +"r c #E5B0A8", +"s c #E4A8A0", +"t c #E7B9B2", +"u c #EFC4C0", +"v c #F68C8A", +"w c #F68A88", +"x c #EC302F", +"y c #F02E2E", +"z c #F0B3B0", +"A c #E9BEB6", +"B c #E5A89F", +"C c #E5A99F", +"D c #EDCEC9", +"E c #F49D9A", +"F c #F68B89", +"G c #F26463", +"H c #DC2B2B", +"I c #EE2A2A", +"J c #EDD5D1", +"K c #E6A8A1", +"L c #E5A79F", +"M c #E8B8B1", +"N c #F78886", +"O c #F68886", +"P c #EC3131", +"Q c #EDD2CD", +"R c #F59794", +"S c #F78785", +"T c #F46766", +"U c #E32C2C", +"V c #FB7575", +"W c #FA7776", +"X c #FA7877", +"Y c #FA7979", +"Z c #FA7A7A", +"` c #F97C7B", +" . c #F97D7C", +".. c #F97E7D", +"+. c #F97F7E", +"@. c #F88180", +"#. c #F88281", +"$. c #F88382", +"%. c #F88583", +"&. c #F78684", +"*. c #EC3636", +"=. c #FB7474", +"-. c #F56A68", +";. c #E52B2B", +">. c #EE2B2B", +",. c #F86363", +"'. c #F77D7C", +"). c #ED3636", +"!. c #A01B1B", +"~. c #ED2B2B", +"{. c #C82727", +" ", +" ", +" ", +" ", +" . + + + + + + + + + + @ # ", +" $ % & * * * * * * * * * = - ", +" ; > , ' ' ' ' ' ' ' ' ) ! ~ { ", +" ] ^ / ( ( ( ( ( ( ( ( ( _ : < [ ", +" } | 1 2 2 2 2 2 2 2 2 3 4 5 6 7 ", +" 8 9 0 a a a a a a a a a 0 b c d e ", +" f g h i i i i i i i i i j k l m n o ", +" p q r s s s s s s s s s t u v w x ", +" y z A B B B B B B B B B C D E F G H ", +" I J K L L L L L L L L L M 9 N O P ", +" + * * * * * * * * * * * Q R S T U ", +" + V W X Y Z ` ...+.@.#.$.%.&.*. ", +" + =.V W X Y Z ` ...+.@.#.$.-.;. ", +" >.,.=.V W X Y Z ` ...+.@.'.).!. ", +" ~.+ + + + + + + + + + + ~.{. ", +" ", +" ", +" ", +" ", +" "}; diff --git a/etc/images/artist-mode/fill.pbm b/etc/images/artist-mode/fill.pbm new file mode 100644 index 0000000000000000000000000000000000000000..7c3877949519fe36e18805db6c5c300796ecbb23 GIT binary patch literal 125 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W) zFf!p{00Q;~2A%{4ZUqMZ1q|{F80sI`|9{~8|A9XUeE_2$-v9pqktYcKF!=w0;r{`K P`UZwN1_m3D0YCr%HRdj| literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/fill.xpm b/etc/images/artist-mode/fill.xpm new file mode 100644 index 00000000000..3266c875a7c --- /dev/null +++ b/etc/images/artist-mode/fill.xpm @@ -0,0 +1,186 @@ +/* XPM */ +static char * fill_xpm[] = { +"24 24 159 2", +" c None", +". c #555753", +"+ c #585A56", +"@ c #595A57", +"# c #555653", +"$ c #5A5C59", +"% c #9FA09F", +"& c #A8A9A8", +"* c #595B57", +"= c #5C5F5B", +"- c #565854", +"; c #E3E3E2", +"> c #F2F2F2", +", c #F6F6F6", +"' c #676965", +") c #595B58", +"! c #626460", +"~ c #D2D3D2", +"{ c #DDDDDD", +"] c #CBCBCB", +"^ c #DFDFDF", +"/ c #CDCECD", +"( c #5A5C57", +"_ c #5F719F", +": c #596C9B", +"< c #586A9A", +"[ c #566485", +"} c #5C5F61", +"| c #B0B2B1", +"1 c #FAFAFA", +"2 c #F3F3F3", +"3 c #D1D2D1", +"4 c #CFCFCF", +"5 c #C9C9C9", +"6 c #F5F5F5", +"7 c #777976", +"8 c #5E709F", +"9 c #8B9FC4", +"0 c #A0BCE3", +"a c #8DB2E2", +"b c #6E92C2", +"c c #5C636E", +"d c #838684", +"e c #F4F4F4", +"f c #FDFDFD", +"g c #E9E9E9", +"h c #D6D6D6", +"i c #D3D3D3", +"j c #CCCCCC", +"k c #D7D7D7", +"l c #E0E0E0", +"m c #5B6D9C", +"n c #BACFEB", +"o c #A4C0E5", +"p c #677589", +"q c #666866", +"r c #D6D7D6", +"s c #FBFBFB", +"t c #F7F7F7", +"u c #FCFCFC", +"v c #EEEEEE", +"w c #858683", +"x c #575855", +"y c #838582", +"z c #D1D1D1", +"A c #D0D0D0", +"B c #C8C8C8", +"C c #F0F0F0", +"D c #838481", +"E c #C0D5F0", +"F c #A3BEE2", +"G c #585B5B", +"H c #E5E5E5", +"I c #ECECEC", +"J c #8D8E8B", +"K c #666865", +"L c #8A8B8A", +"M c #6E6F6D", +"N c #7E807D", +"O c #D4D4D4", +"P c #CDCDCD", +"Q c #EDEEED", +"R c #5D5F5B", +"S c #A6C3E9", +"T c #57637D", +"U c #90918E", +"V c #E4E4E4", +"W c #6D6E6B", +"X c #8B8C8B", +"Y c #BBBBBB", +"Z c #A3A4A3", +"` c #666864", +" . c #D8D8D8", +".. c #A8AAA7", +"+. c #A6C2E9", +"@. c #576999", +"#. c #5A5B58", +"$. c #E2E2E2", +"%. c #DCDCDC", +"&. c #EBEBEB", +"*. c #8D8E8C", +"=. c #6B6C6A", +"-. c #9FA09E", +";. c #747673", +">. c #898B88", +",. c #D5D5D5", +"'. c #A5C2E8", +"). c #7B7D7A", +"!. c #969895", +"~. c #727470", +"{. c #8C8D8B", +"]. c #E1E1E1", +"^. c #D9D9D9", +"/. c #D2D2D2", +"(. c #CACACA", +"_. c #BFC0BF", +":. c #5B5C58", +"<. c #DADADA", +"[. c #CECECE", +"}. c #5B5D58", +"|. c #A4C1E7", +"1. c #6D6F6C", +"2. c #F8F8F8", +"3. c #EFEFEF", +"4. c #FEFEFE", +"5. c #EAEAEA", +"6. c #E3E3E3", +"7. c #5A5C58", +"8. c #5D6F9E", +"9. c #A2B6D7", +"0. c #92ACD4", +"a. c #5A6D9D", +"b. c #595B56", +"c. c #C7C7C6", +"d. c #E7E7E7", +"e. c #EDEDED", +"f. c #C9CAC9", +"g. c #5F605C", +"h. c #5C6E9D", +"i. c #5B6D9D", +"j. c #646662", +"k. c #F9F9F9", +"l. c #797A77", +"m. c #5B5C59", +"n. c #B6B7B6", +"o. c #E8E8E8", +"p. c #A3A5A3", +"q. c #5D5F5C", +"r. c #F4F4F3", +"s. c #DBDBDB", +"t. c #CFCFCE", +"u. c #666763", +"v. c #535650", +"w. c #535652", +"x. c #838683", +"y. c #F6F7F6", +"z. c #E0E0DF", +"A. c #797A76", +"B. c #50554D", +" ", +" . . . . ", +" . . . . ", +" . + @ . ", +" # $ % & * . ", +" = - ; > , ' . ", +" ) ! ~ * { ] ^ / ( . ", +" _ : < < < [ } | 1 2 + 3 4 5 6 7 # ", +" 8 9 0 a b c d e f 2 g + h i j k l . ", +" m n o p q r s t u v w x y z A B C D ", +" < E F G H v ^ I s J K L M N O P z Q R ", +" < E S T U 6 h V > W X Y Z ` .z 5 g .. ", +" < E +.@.#.$.l %.&.*.=.-.;.>.%.,.P j e ! ", +" < E '.< ).t ,.$.I !.~.{.$.].^./.(.$._.* ", +" < E '.< :.,.$.<.g t s 2 I H { h [.P > }. ", +" < E |.< 1.2.O ].3.4.2.C g ].<.,.5.6.7. ", +" 8.9.0.a. b.c.H ^.d.6 u e e.H g 2.f.g. ", +" h.i. j.t O ^ e.u k.2 k.5.l.m. ", +" + n.o.k H e 4.k.p.R ", +" q.r.s.o.1 t.u.v. ", +" w.x.y.z.A.* ", +" - ( #.B. ", +" ", +" "}; diff --git a/etc/images/artist-mode/line.pbm b/etc/images/artist-mode/line.pbm new file mode 100644 index 0000000000000000000000000000000000000000..0952ab5e76111a0867767b0ae3126cb32da17351 GIT binary patch literal 125 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W) oFf!p{009;T20jJ`83qOm28IF#h6fCc2N;+e7}$vtRsb6T0MY6d-~a#s literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/line.xpm b/etc/images/artist-mode/line.xpm new file mode 100644 index 00000000000..f21cf5c50a8 --- /dev/null +++ b/etc/images/artist-mode/line.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * line_xpm[] = { +"24 24 2 1", +" c None", +". c #204A88", +" ", +" . ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" ... ", +" . ", +" "}; diff --git a/etc/images/artist-mode/pen.pbm b/etc/images/artist-mode/pen.pbm new file mode 100644 index 0000000000000000000000000000000000000000..11a7865c9d8e5466ae98dd4897225e5019dd5de7 GIT binary patch literal 125 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W) zFf!p{009981`7s;0tSW)42&BXm=ze<5*T<6Fi0L?5I(@b+`z!jz`zVv2qu66Y!4WC O9x%us03rJZkSG8y0~v_` literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/pen.xpm b/etc/images/artist-mode/pen.xpm new file mode 100644 index 00000000000..e38835c12bd --- /dev/null +++ b/etc/images/artist-mode/pen.xpm @@ -0,0 +1,130 @@ +/* XPM */ +static char * pen_xpm[] = { +"24 24 103 2", +" c None", +". c #683907", +"+ c #764108", +"@ c #6B3B07", +"# c #673907", +"$ c #985B1B", +"% c #854A0A", +"& c #9C652C", +"* c #D48E45", +"= c #6B3D0D", +"- c #673908", +"; c #95632D", +"> c #E49745", +", c #996731", +"' c #885C2D", +") c #E79137", +"! c #B67836", +"~ c #71471B", +"{ c #7B5226", +"] c #D48839", +"^ c #BB6C19", +"/ c #8C653A", +"( c #693A09", +"_ c #764D1F", +": c #C1803B", +"< c #C97113", +"[ c #956430", +"} c #7C5021", +"| c #734719", +"1 c #AF763C", +"2 c #DB7C18", +"3 c #985916", +"4 c #876239", +"5 c #6A3B09", +"6 c #6E4213", +"7 c #9B6D3C", +"8 c #E8851D", +"9 c #A45B0D", +"0 c #785631", +"a c #86541E", +"b c #837868", +"c c #897862", +"d c #CB7B27", +"e c #B6640E", +"f c #7D5223", +"g c #976632", +"h c #8A8C88", +"i c #B2B3B1", +"j c #AEAFAC", +"k c #8A8A83", +"l c #845B2E", +"m c #966A3B", +"n c #70400D", +"o c #92948F", +"p c #F4F4F4", +"q c #E7E7E7", +"r c #ADADAC", +"s c #898982", +"t c #845A2B", +"u c #6D3C07", +"v c #8B8E89", +"w c #C8C8C7", +"x c #F9F9F9", +"y c #C6C6C6", +"z c #A3A3A3", +"A c #9FA19D", +"B c #868073", +"C c #8B8D88", +"D c #F6F6F6", +"E c #E0E0E0", +"F c #AFAFAF", +"G c #A6A7A5", +"H c #8C8E89", +"I c #898D88", +"J c #C1C2C0", +"K c #F8F8F8", +"L c #BBBBBB", +"M c #9E9F9D", +"N c #8B8C88", +"O c #1E1E1E", +"P c #3E3E3D", +"Q c #595958", +"R c #A2A2A2", +"S c #999A98", +"T c #161616", +"U c #757575", +"V c #848484", +"W c #3F3F3F", +"X c #202020", +"Y c #6E706B", +"Z c #000000", +"` c #1A1A1A", +" . c #929292", +".. c #484848", +"+. c #242424", +"@. c #101010", +"#. c #0D0D0D", +"$. c #2B2B2B", +"%. c #3B3B3B", +"&. c #303030", +"*. c #0A0A0A", +"=. c #141414", +"-. c #0E0E0E", +" ", +" . ", +" . + @ ", +" # $ % ", +" # & * = ", +" - ; > , # ", +" # ' ) ! ~ ", +" # { ] ^ / ( ", +" # _ : < [ } ", +" # | 1 2 3 4 5 ", +" 6 7 8 9 0 a @ ", +" b c d e f g @ ", +" h i j k l m n ", +" o p q r s t u ", +" v w x y z A B ", +" C D E F G H ", +" I J K L M N ", +" O P Q R S C ", +" T U V W X Y ", +" Z ` .z ..+.@. ", +" Z Z #.$.%.&.T ", +" Z Z Z *.=.-.Z ", +" Z Z Z Z Z Z Z ", +" "}; diff --git a/etc/images/artist-mode/poly-line.pbm b/etc/images/artist-mode/poly-line.pbm new file mode 100644 index 0000000000000000000000000000000000000000..a06f19e95a9e3118db059fb454b0bbb05a2bf133 GIT binary patch literal 125 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W) zFf!p{U|=X c #3B413F", +", c #2D3435", +"' c #6A6C69", +") c #323739", +"! c #2E3436", +"~ c #2C3434", +"{ c #696C69", +"] c #3C4140", +"^ c #2D3537", +"/ c #353A3A", +"( c #696B68", +"_ c #323839", +": c #2D3434", +"< c #2F3436", +"[ c #4B4E4B", +"} c #393F3F", +"| c #444949", +"1 c #545651", +"2 c #838482", +"3 c #DADADA", +"4 c #33393A", +"5 c #545752", +"6 c #EEEEEE", +"7 c #DDDDDD", +"8 c #999A98", +"9 c #3B3F40", +"0 c #F5F5F5", +"a c #E4E4E4", +"b c #B4B5B3", +"c c #AEAEAD", +"d c #4E504E", +"e c #545652", +"f c #80827F", +"g c #F9F9F9", +"h c #EBEBEB", +"i c #A2A3A1", +"j c #C2C2C2", +"k c #C1C1C1", +"l c #747474", +"m c #313531", +"n c #1A1A1A", +"o c #252525", +"p c #555652", +"q c #D2D3D2", +"r c #F1F1F1", +"s c #A3A4A2", +"t c #565753", +"u c #6A6D69", +"v c #B9B9B9", +"w c #ABABAB", +"x c #313231", +"y c #303030", +"z c #7E7E7E", +"A c #585855", +"B c #777C73", +"C c #C4C7C1", +"D c #A6A7A5", +"E c #565754", +"F c #555753", +"G c #5D5F5C", +"H c #A7A7A7", +"I c #797979", +"J c #121212", +"K c #131313", +"L c #898989", +"M c #545653", +"N c #D0D0CE", +"O c #ABAEA7", +"P c #60635E", +"Q c #3D3F3A", +"R c #494B49", +"S c #949494", +"T c #636363", +"U c #3E3E3E", +"V c #7D7D7D", +"W c #757575", +"X c #555551", +"Y c #5C5F59", +"Z c #222522", +"` c #393939", +" . c #8E8E8E", +".. c #919191", +"+. c #818181", +"@. c #292929", +"#. c #365990", +"$. c #52524E", +"%. c #080D08", +"&. c #050505", +"*. c #101010", +"=. c #1B1B1B", +"-. c #385A90", +";. c #375A90", +">. c #375A8F", +",. c #365A90", +"'. c #385990", +"). c #37588F", +"!. c #375A8D", +"~. c #37598E", +"{. c #37568D", +"]. c #355A8D", +" ", +" ", +" . + ", +" . @ # . ", +" $ % & * = ", +" $ % - ; > , ", +" . % ' ) > ! ", +" $ ~ . % { ) ] ! ", +" , $ ^ / % ( _ > ! ", +" : < [ } | _ > , ", +" 1 2 3 % 4 ! ", +" 5 2 6 7 8 9 ", +" 5 2 0 a b c d ", +" e f g h i j k l m n o ", +" p q r s t u v w x y z ", +" A B C D E F G H I J K L ", +" M N O P Q R S T U V W ", +" X ' Y Z ` ...+.@. ", +" #. $. %.&.*.=. ", +" -.;.>. ", +" ,.-.'.). ", +" !.~.~. ", +" {.]. ", +" "}; diff --git a/etc/images/artist-mode/square.pbm b/etc/images/artist-mode/square.pbm new file mode 100644 index 0000000000000000000000000000000000000000..f3761b7dc0725f53102e2d8e998accc686c61ee5 GIT binary patch literal 125 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W) YFf!p{00aB~|A5GVfsIrI(FimH0F9a(b^rhX literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/square.xpm b/etc/images/artist-mode/square.xpm new file mode 100644 index 00000000000..c0da53b9153 --- /dev/null +++ b/etc/images/artist-mode/square.xpm @@ -0,0 +1,30 @@ +/* XPM */ +static char * square_xpm[] = { +"24 24 3 1", +" c None", +". c #204A88", +"+ c #719FCF", +" ", +" ", +" ..................... ", +" ..................... ", +" ..+++++++++++++++++.. ", +" ..+++++++++++++++++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..++ ++.. ", +" ..+++++++++++++++++.. ", +" ..+++++++++++++++++.. ", +" ..................... ", +" ..................... ", +" "}; diff --git a/etc/images/artist-mode/text.pbm b/etc/images/artist-mode/text.pbm new file mode 100644 index 0000000000000000000000000000000000000000..7a4110a977fe0359f6b4f684e586250004f16f47 GIT binary patch literal 125 zcmWGA;Zjy`E=o--Nlj5ms#I|I^bJrbOD!tS%+FIW)-%#GPzdnzRVc_QP1nuL<1#W) zFf!p{fPgv%hW`u=m7Ko15E!9u>XI+{`>*!^AG&bKX4!ZApidd1lj-p SW8d(np5Y%5)iD4yGXMbYxG&NG literal 0 HcmV?d00001 diff --git a/etc/images/artist-mode/text.xpm b/etc/images/artist-mode/text.xpm new file mode 100644 index 00000000000..84f63b9113e --- /dev/null +++ b/etc/images/artist-mode/text.xpm @@ -0,0 +1,164 @@ +/* XPM */ +static char * text_xpm[] = { +"24 24 137 2", +" c None", +". c #9C9C9C", +"+ c #585858", +"@ c #828282", +"# c #BEBEBE", +"$ c #BFBFBF", +"% c #272727", +"& c #393939", +"* c #4E4E4E", +"= c #4C4C4C", +"- c #4B4B4B", +"; c #444444", +"> c #070707", +", c #B3B3B3", +"' c #A0A0A0", +") c #121212", +"! c #949494", +"~ c #808080", +"{ c #7D7D7D", +"] c #7A7A7A", +"^ c #787878", +"/ c #212121", +"( c #717171", +"_ c #BDBDBD", +": c #505050", +"< c #838383", +"[ c #545454", +"} c #515151", +"| c #4D4D4D", +"1 c #4A4A4A", +"2 c #5A5A5A", +"3 c #363636", +"4 c #252525", +"5 c #BABABA", +"6 c #0E0E0E", +"7 c #818181", +"8 c #656565", +"9 c #474747", +"0 c #3F3F3F", +"a c #050505", +"b c #9F9F9F", +"c c #7B7B7B", +"d c #2C2C2C", +"e c #8B8B8B", +"f c #484848", +"g c #373737", +"h c #353535", +"i c #3E3E3E", +"j c #3B3B3B", +"k c #161616", +"l c #535353", +"m c #2D2D2D", +"n c #626262", +"o c #6C6C6C", +"p c #464646", +"q c #424242", +"r c #141414", +"s c #131313", +"t c #383838", +"u c #313131", +"v c #222222", +"w c #0D0D0D", +"x c #A3A3A3", +"y c #0C0C0C", +"z c #878787", +"A c #404040", +"B c #030303", +"C c #040404", +"D c #2A2A2A", +"E c #2F2F2F", +"F c #2B2B2B", +"G c #282828", +"H c #0A0A0A", +"I c #575757", +"J c #434343", +"K c #767676", +"L c #3A3A3A", +"M c #1D1D1D", +"N c #333333", +"O c #3D3D3D", +"P c #292929", +"Q c #262626", +"R c #101010", +"S c #0F0F0F", +"T c #707070", +"U c #343434", +"V c #7C7C7C", +"W c #888888", +"X c #080808", +"Y c #202020", +"Z c #1F1F1F", +"` c #1B1B1B", +" . c #ADADAD", +".. c #232323", +"+. c #7F7F7F", +"@. c #323232", +"#. c #242424", +"$. c #B1B1B1", +"%. c #151515", +"&. c #676767", +"*. c #C0C0C0", +"=. c #5F5F5F", +"-. c #616161", +";. c #1A1A1A", +">. c #A9A9A9", +",. c #777777", +"'. c #ABABAB", +"). c #020202", +"!. c #1C1C1C", +"~. c #1E1E1E", +"{. c #969696", +"]. c #696969", +"^. c #010101", +"/. c #000000", +"(. c #606060", +"_. c #595959", +":. c #181818", +"<. c #B6B6B6", +"[. c #8A8A8A", +"}. c #060606", +"|. c #111111", +"1. c #494949", +"2. c #6B6B6B", +"3. c #909090", +"4. c #A6A6A6", +"5. c #666666", +"6. c #B5B5B5", +"7. c #5E5E5E", +"8. c #191919", +"9. c #686868", +"0. c #979797", +"a. c #090909", +"b. c #B4B4B4", +"c. c #B9B9B9", +"d. c #8C8C8C", +"e. c #8E8E8E", +"f. c #B8B8B8", +" ", +" ", +" . + + + + + + @ # ", +" $ % & * * = - ; > , ", +" ' ) ! ~ { ] ^ ~ / ( ", +" _ : : < [ } | 1 2 3 4 $ ", +" 5 6 7 8 * - 9 ; ; 0 a b ", +" c d e | f g h i j g k l ", +" _ m n o p q r s t h u v w 5 ", +" x y z | A h B C D E F G H < ", +" I J K i L M N O k P Q v R 3 $ ", +" 5 S T [ t U w V W X v Y Z ` B . ", +" < ..+.g @.#.> $. r %.Z Z Z 6 &. ", +" *.N } =.E d s p -.S Z Z Z r ;.$ ", +" >.X ,.j P 4 > < '.'.. ).!.Z Z ~.a {. ", +" =.g ].% #.` ^./././././.%.Z Z Z R 1 ", +" _ r (.O / Z 3 _._._._._._.; Z Z Z :.X <. ", +" [.:.=./ Z Z / % % % % % % v Z Z Z Z y V ", +" & O j Z Z ) }.}.}.}.}.}.}.}.S Z Z Z |.d $ ", +" .}.1.#.Z Z y 2.{.{.{.{.{.{.3.).!.Z Z !.B 4. ", +" 5.#.t Z Z ;.C 6. # Q ) Z Z Z 6 7. ", +"$ 8.d P Z Z |.N 9.R Z Z Z %.s # ", +"0./.R S S S }.,. x ).H H H a./.{.", +"b.@ +.+.+.+.@ c. {.d.d.d.d.e.f."}; diff --git a/lisp/textmodes/artist.el b/lisp/textmodes/artist.el index f01e636e981..7c44cca5014 100644 --- a/lisp/textmodes/artist.el +++ b/lisp/textmodes/artist.el @@ -567,6 +567,63 @@ This variable is initialized by the `artist-make-prev-next-op-alist' function.") ["Characters for Spray" artist-select-spray-chars :help "Choose characters for sprayed by the spray-can"])) +(defvar artist-tool-bar-map + (let ((map (make-sparse-keymap))) + ;; Tools + (tool-bar-local-item "artist-mode/pen" + #'artist-select-op-pen-line + #'artist-select-op-pen-line + map :help "Use pen") + (tool-bar-local-item "artist-mode/spray" + #'artist-select-op-spray-can + #'artist-select-op-spray-can + map :help "Use spray") + (tool-bar-local-item "artist-mode/eraser" + #'artist-select-op-erase-char + #'artist-select-op-erase-char + map :help "Use eraser") + (tool-bar-local-item "artist-mode/fill" + #'artist-select-op-flood-fill + #'artist-select-op-flood-fill + map :help "Fill") + (tool-bar-local-item "artist-mode/text" + #'artist-select-op-text-overwrite + #'artist-select-op-text-overwrite + map :help "Insert Figlet Text (figlet must be installed)") + (define-key-after map [separator-1] menu-bar-separator) + ;; Shapes + (tool-bar-local-item "artist-mode/line" + #'artist-select-op-straight-line + #'artist-select-op-straight-line + map :help "Draw straight line") + (tool-bar-local-item "artist-mode/ellipse" + #'artist-select-op-ellipse + #'artist-select-op-ellipse + map :help "Draw ellipse") + (tool-bar-local-item "artist-mode/square" + #'artist-select-op-square + #'artist-select-op-square + map :help "Draw square") + (tool-bar-local-item "artist-mode/rectangle" + #'artist-select-op-rectangle + #'artist-select-op-rectangle + map :help "Draw rectangle") + (tool-bar-local-item "artist-mode/poly-line" + #'artist-select-op-poly-line + #'artist-select-op-poly-line + map :help "Draw poly lines") + (define-key-after map [separator-2] menu-bar-separator) + ;; Configurations + (tool-bar-local-item "artist-mode/char-to-fill" + #'artist-select-fill-char + #'artist-select-fill-char + map :help "Change current fill character") + (tool-bar-local-item "artist-mode/char-for-spray" + #'artist-select-spray-chars + #'artist-select-spray-chars + map :help "Change current spray characters") + map)) + (defvar artist-replacement-table (make-vector 256 0) "Replacement table for `artist-replace-char'.") @@ -1367,6 +1424,7 @@ Keymap summary (t ;; Turn mode on (artist-mode-init) + (setq-local tool-bar-map artist-tool-bar-map) (let* ((font (face-attribute 'default :font)) (spacing-prop (if (fontp font) (font-get font :spacing) @@ -1414,7 +1472,8 @@ Keymap summary "Exit Artist mode. This will call the hook `artist-mode-hook'." (if (and artist-picture-compatibility (eq major-mode 'picture-mode)) (picture-mode-exit)) - (kill-local-variable 'next-line-add-newlines)) + (kill-local-variable 'next-line-add-newlines) + (kill-local-variable 'tool-bar-map)) (defun artist-mode-off () "Turn Artist mode off." From 7a17f97baa7d483cba5cde3cd22c34e0597e60b5 Mon Sep 17 00:00:00 2001 From: Manuel Giraud Date: Mon, 4 May 2026 10:14:36 +0200 Subject: [PATCH 059/112] Prettify special glyphs * lisp/disp-table.el (prettify-special-glyphs-mode): New mode to display nicer special glyphs. (special-glyphs): New face for displaying special glyphs when the minor mode is active. (prettify-special-glyphs-saved-truncation) (prettify-special-glyphs-saved-continuation): Internal variables to save previous special glyphs. * etc/NEWS: Announce the change. (Bug#80628) --- etc/NEWS | 6 ++++++ lisp/disp-table.el | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 1f99eb22a38..083e6b50ea4 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -169,6 +169,12 @@ behavior, customize 'find-function-mode-lower-precedence' to non-nil. --- ** 'find-function' can now find 'cl-defmethod' invocations inside macros. +--- +** New minor mode 'prettify-special-glyphs-mode'. +The new minor mode prettifies the special character glyphs (truncation +and continuation) on TTY frames (and GUI frames without fringes). You +can customize the associated new face 'special-glyphs'. + ** Minibuffer and Completions +++ diff --git a/lisp/disp-table.el b/lisp/disp-table.el index 9f2971a6fc3..467430f30ef 100644 --- a/lisp/disp-table.el +++ b/lisp/disp-table.el @@ -458,6 +458,50 @@ which characters can be displayed and which cannot." (insert ")\n")) (pop-to-buffer buf))) +(defface special-glyphs + '((t :inherit (shadow default))) + "Face for displaying special glyphs." + :group 'basic-faces + :version "31.1") + +(defvar prettify-special-glyphs-saved-truncation) +(defvar prettify-special-glyphs-saved-continuation) + +;;;###autoload +(define-minor-mode prettify-special-glyphs-mode + "Mode to display pretty special character glyphs. +If you have already customized your special character glyphs, only the +`special-glyphs' face is applied to them. This mode only applies to the +`standard-display-table'. Window or buffer display table, if defined, +still take precedence." + :global t + :group 'display + (if prettify-special-glyphs-mode + (let ((tbl standard-display-table) + truncation wrap) + ;; Save current glyphs. + (setq prettify-special-glyphs-saved-truncation + (display-table-slot tbl 'truncation) + prettify-special-glyphs-saved-continuation + (display-table-slot tbl 'wrap)) + ;; Prepare new ones with face. + (setq truncation + (if prettify-special-glyphs-saved-truncation + (make-glyph-code prettify-special-glyphs-saved-truncation + 'special-glyphs) + (make-glyph-code ?→ 'special-glyphs)) + wrap + (if prettify-special-glyphs-saved-continuation + (make-glyph-code prettify-special-glyphs-saved-continuation + 'special-glyphs) + (make-glyph-code ?↩ 'special-glyphs))) + ;; Alter display-table. + (set-display-table-slot tbl 'truncation truncation) + (set-display-table-slot tbl 'wrap wrap)) + (let ((tbl standard-display-table)) + ;; Reset saved glyphs. + (set-display-table-slot tbl 'truncation prettify-special-glyphs-saved-truncation) + (set-display-table-slot tbl 'wrap prettify-special-glyphs-saved-continuation)))) (provide 'disp-table) From 7fe595465bcca3a7ef59feadfd29b38a75315c65 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Mon, 18 May 2026 22:35:22 +0100 Subject: [PATCH 060/112] vc-refresh-state: Use cond* This is okay with regard to bootstrapping because vc-hooks.el is loaded after loaddefs.el in loadup.el. * lisp/emacs-lisp/cond-star.el (cl-lib): Don't require, so we can use cond* in preloaded files. (cond*-convert-condition): Replace calls to cl-assert. * lisp/vc/vc-hooks.el (vc-refresh-state): Use cond*. --- lisp/emacs-lisp/cond-star.el | 9 ++- lisp/vc/vc-hooks.el | 108 +++++++++++++++++------------------ 2 files changed, 56 insertions(+), 61 deletions(-) diff --git a/lisp/emacs-lisp/cond-star.el b/lisp/emacs-lisp/cond-star.el index 98d4b93583a..ef0af260e89 100644 --- a/lisp/emacs-lisp/cond-star.el +++ b/lisp/emacs-lisp/cond-star.el @@ -48,8 +48,6 @@ ;;; Code: -(require 'cl-lib) ; for cl-assert - ;;;###autoload (defmacro cond* (&rest clauses) "Extended form of traditional Lisp `cond' construct. @@ -370,12 +368,13 @@ This is used for conditional exit clauses." ;; where ELSE is supposed to run after THEN also (and ;; with access to `x' and `y'). (error ":non-exit not supported with `pcase*'")) - (cl-assert (or (null iffalse) rest)) + (unless (or (null iffalse) rest) + (error "Assertion failed: (or (null iffalse) rest)")) `(pcase ,(nth 2 condition) (,(nth 1 condition) ,@true-exps) (_ ,iffalse))) - (cl-assert (null iffalse)) - (cl-assert (null rest)) + (unless (and (null iffalse) (null rest)) + (error "Assertion failed: (and (null iffalse) (null rest))")) `(pcase-let ((,(nth 1 condition) ,(nth 2 condition))) (cond* . ,uncondit-clauses)))) ((eq pat-type 'match*) diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el index 64ad4d5daec..7267c37851d 100644 --- a/lisp/vc/vc-hooks.el +++ b/lisp/vc/vc-hooks.el @@ -951,62 +951,58 @@ In the latter case, VC mode is deactivated for this buffer." (vc-file-clearprops buffer-file-name) ;; FIXME: Why use a hook? Why pass it buffer-file-name? (add-hook 'vc-mode-line-hook #'vc-mode-line nil t) - (let (backend) - (cond - ((setq backend (with-demoted-errors "VC refresh error: %S" - (vc-backend buffer-file-name))) - ;; When `auto-revert-handler' calls us then `default-directory' - ;; may be let-bound to something else for the purpose of some - ;; command that's currently doing some minibuffer prompting. - ;; Backend find-file-hook and mode-line-string functions should - ;; not need to be written so as to handle that possibility. - (let ((default-directory (buffer-local-toplevel-value 'default-directory))) - ;; Let the backend setup any buffer-local things it needs. - (vc-call-backend backend 'find-file-hook) - ;; Compute the state and put it in the mode line. - (vc-mode-line buffer-file-name backend)) - (unless vc-make-backup-files - ;; Use this variable, not make-backup-files, - ;; because this is for things that depend on the file name. - (setq-local backup-inhibited t))) - ((let* ((truename (and buffer-file-truename - (expand-file-name buffer-file-truename))) - (link-type (and truename - (not (equal buffer-file-name truename)) - (vc-backend truename)))) - (cond ((not link-type) nil) ;Nothing to do. - ((not vc-follow-symlinks) - (message "Warning: symbolic link to %s-controlled source file" - link-type)) - ((or (not (eq vc-follow-symlinks 'ask)) - ;; Assume we cannot ask, default to yes. - noninteractive - ;; Copied from server-start. Seems like there should - ;; be a better way to ask "can we get user input?"... - ;; Use `frame-initial-p'? - (and (daemonp) - (null (cdr (frame-list))) - (eq (selected-frame) terminal-frame)) - ;; If we already visited this file by following - ;; the link, don't ask again if we try to visit - ;; it again. GUD does that, and repeated questions - ;; are painful. - (get-file-buffer - (abbreviate-file-name - (file-chase-links buffer-file-name)))) - - (vc-follow-link) - (message "Followed link to %s" buffer-file-name) - (vc-refresh-state)) - (t - (if (yes-or-no-p (format - "Symbolic link to %s-controlled source file; follow link? " link-type)) - (progn (vc-follow-link) - (message "Followed link to %s" buffer-file-name) - (vc-refresh-state)) - (message - "Warning: editing through the link bypasses version control") - ))))))))) + (cond* + ((bind-and* (backend (with-demoted-errors "VC refresh error: %S" + (vc-backend buffer-file-name)))) + ;; When `auto-revert-handler' calls us then `default-directory' + ;; may be let-bound to something else for the purpose of some + ;; command that's currently doing some minibuffer prompting. + ;; Backend find-file-hook and mode-line-string functions should + ;; not need to be written so as to handle that possibility. + (let ((default-directory (buffer-local-toplevel-value 'default-directory))) + ;; Let the backend setup any buffer-local things it needs. + (vc-call-backend backend 'find-file-hook) + ;; Compute the state and put it in the mode line. + (vc-mode-line buffer-file-name backend)) + (unless vc-make-backup-files + ;; Use this variable, not make-backup-files, + ;; because this is for things that depend on the file name. + (setq-local backup-inhibited t))) + ((bind* (truename (and buffer-file-truename + (expand-file-name buffer-file-truename))) + (link-type (and truename + (not (equal buffer-file-name truename)) + (vc-backend truename))))) + ((null link-type) nil) ; Nothing to do. + ((not vc-follow-symlinks) + (message "Warning: symbolic link to %s-controlled source file" + link-type)) + ((or (not (eq vc-follow-symlinks 'ask)) + ;; Assume we cannot ask, default to yes. + noninteractive + ;; Copied from server-start. Seems like there should + ;; be a better way to ask "can we get user input?"... + ;; Use `frame-initial-p'? + (and (daemonp) + (null (cdr (frame-list))) + (eq (selected-frame) terminal-frame)) + ;; If we already visited this file by following the link, + ;; don't ask again if we try to visit it again. + ;; GUD does that, and repeated questions are painful. + (get-file-buffer + (abbreviate-file-name + (file-chase-links buffer-file-name)))) + (vc-follow-link) + (message "Followed link to %s" buffer-file-name) + (vc-refresh-state)) + ((yes-or-no-p + (format "Symbolic link to %s-controlled source file; follow link? " + link-type)) + (vc-follow-link) + (message "Followed link to %s" buffer-file-name) + (vc-refresh-state)) + (t + (message "Warning: editing through the link bypasses version control"))))) (add-hook 'find-file-hook #'vc-refresh-state) (define-obsolete-function-alias 'vc-find-file-hook #'vc-refresh-state "25.1") From eb653865c3a35af115360273fb5147b4943ba2ef Mon Sep 17 00:00:00 2001 From: Rahul Martim Juliato Date: Sat, 23 May 2026 09:18:40 -0300 Subject: [PATCH 061/112] markdown-ts-mode: Don't enable unconditionally by default * lisp/textmodes/markdown-ts-mode.el (markdown-ts-mode-maybe): New function. (auto-mode-alist): Bind ".md", ".markdown", and ".mdx" to 'markdown-ts-mode-maybe' instead of 'markdown-ts-mode'. * etc/NEWS: Update the 'markdown-ts-mode' entry. --- etc/NEWS | 17 +++++------------ lisp/textmodes/markdown-ts-mode.el | 24 +++++++++++++++++++----- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 083e6b50ea4..7fc998ff547 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3938,19 +3938,12 @@ A major mode based on 'conf-mode' for editing ".npmrc" files. *** New major mode 'markdown-ts-mode'. A major mode based on the tree-sitter library for editing Markdown -files. This is now the default major mode for Markdown files. If you -don't have the necessary tree-sitter grammar libraries installed, or if -your Emacs was built without tree-sitter support, Emacs will now show a -warning to that effect when you visit a Markdown file. If you don't -want to use this mode and want to avoid these warnings, add the -following to your init file: +files. Markdown files are visited using this mode when the required +tree-sitter grammars ('markdown' and 'markdown-inline') are available, +or when the user has opted in via 'treesit-enabled-modes'. Otherwise, +Markdown files fall back to 'text-mode'. - (add-to-list 'auto-mode-alist '("\\.md\\'" . fundamental-mode)) - (add-to-list 'auto-mode-alist '("\\.markdown\\'" . fundamental-mode)) - (add-to-list 'auto-mode-alist '("\\.mdx\\'" . fundamental-mode)) - -This will cause Emacs to visit Markdown files in Fundamental mode, which -was the default before this mode was added to Emacs. +To install the grammars, use 'M-x markdown-ts-mode-install-parsers'. *** New major mode 'mhtml-ts-mode'. An optional major mode based on the tree-sitter library for editing HTML diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el index be2247b870e..fed6ded192c 100644 --- a/lisp/textmodes/markdown-ts-mode.el +++ b/lisp/textmodes/markdown-ts-mode.el @@ -5401,14 +5401,14 @@ With a prefix argument, ARG, if needed, install parsers for `html', (cond ((treesit-ready-p '(markdown markdown-inline) t) (markdown-ts--set-up)) (t - (warn "markdown-ts-mode cannot be set up; using fundamental-mode. + (warn "markdown-ts-mode cannot be set up; using text-mode. %s." (if (treesit-available-p) "The tree-sitter parsers `markdown' and `markdown-inline' were not found. Use the command `markdown-ts-mode-install-parsers' to install them. With a prefix argument, it can also install optional parsers" "Emacs was built without Tree-sitter support, or could not load Tree-sitter")) - (fundamental-mode))))) + (text-mode))))) ;;;###autoload (define-derived-mode markdown-ts-mode text-mode "Markdown" @@ -5619,11 +5619,25 @@ If non-nil and `point' is in a table, enable (remove-hook 'post-command-hook #'markdown-ts--enable-in-table-mode 'local)))) +;;;###autoload +(defun markdown-ts-mode-maybe () + "Enable `markdown-ts-mode' when its grammars are available. +Also propose to install the grammars when `treesit-enabled-modes' +is t or contains the mode name." + (declare-function treesit-language-available-p "treesit.c") + (if (or (and (treesit-language-available-p 'markdown) + (treesit-language-available-p 'markdown-inline)) + (eq treesit-enabled-modes t) + (memq 'markdown-ts-mode treesit-enabled-modes)) + (markdown-ts-mode) + (text-mode))) + ;;;###autoload (when (boundp 'treesit-major-mode-remap-alist) - (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-ts-mode)) - (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-ts-mode)) - (add-to-list 'auto-mode-alist '("\\.mdx\\'" . markdown-ts-mode)) + (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-ts-mode-maybe)) + (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-ts-mode-maybe)) + (add-to-list 'auto-mode-alist '("\\.mdx\\'" . markdown-ts-mode-maybe)) + ;; To be able to toggle between an external package and core ts-mode: (add-to-list 'treesit-major-mode-remap-alist '(markdown-mode . markdown-ts-mode))) From dd42133315b9aea8ed8ce54191a5e85249417a0c Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sat, 23 May 2026 16:53:36 +0100 Subject: [PATCH 062/112] vc-test--rename-file: Disable part of test for SCCS * test/lisp/vc/vc-tests/vc-tests.el (vc-test--rename-file): Disable part of test for SCCS. --- test/lisp/vc/vc-tests/vc-tests.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lisp/vc/vc-tests/vc-tests.el b/test/lisp/vc/vc-tests/vc-tests.el index 1fb17842478..8e2ae2c4454 100644 --- a/test/lisp/vc/vc-tests/vc-tests.el +++ b/test/lisp/vc/vc-tests/vc-tests.el @@ -592,8 +592,8 @@ This checks also `vc-backend' and `vc-responsible-backend'." 'added)))) ;; Test OK-IF-ALREADY-EXISTS. - ;; RCS and SRC don't support `vc-delete-file'. - (unless (memq backend '(RCS SRC)) + ;; RCS, SRC and SCCS don't support `vc-delete-file'. + (unless (memq backend '(RCS SRC SCCS)) (let ((tmp-name (expand-file-name "qux" default-directory)) (new-name (expand-file-name "quuux" default-directory))) (write-region "qux" nil tmp-name nil 'nomessage) From 4f13f52a3aade6e43e42f14f9f94b0c43d6b4b12 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sat, 23 May 2026 17:25:07 +0100 Subject: [PATCH 063/112] * build-aux/git-hooks/commit-msg: Replace Markdown-style quotation. --- build-aux/git-hooks/commit-msg | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/build-aux/git-hooks/commit-msg b/build-aux/git-hooks/commit-msg index 159990b1406..ddde1b4e586 100755 --- a/build-aux/git-hooks/commit-msg +++ b/build-aux/git-hooks/commit-msg @@ -75,6 +75,7 @@ exec $awk \ } c_lower = "abcdefghijklmnopqrstuvwxyz" unsafe_gnu_url = "(http|ftp)://([" c_lower ".]*\\.)?(gnu|fsf)\\.org" + markdown_quotation = "(^|[^\\\\])`[^'\''`]+`" } { input[NR] = $0 } @@ -92,11 +93,6 @@ exec $awk \ status = 1 } - /(^|[^\\])`[^'\''`]+`/ { - print "Markdown-style quotes in commit message" - status = 1 - } - nlines == 0 && $0 !~ non_space { next } { nlines++ } @@ -141,7 +137,7 @@ exec $awk \ status = 1 } - $0 ~ unsafe_gnu_url { + $0 ~ unsafe_gnu_url || $0 ~ markdown_quotation { needs_rewriting = 1 } @@ -167,7 +163,13 @@ exec $awk \ suffix = substr(line, RSTART) line = prefix "https:" substr(suffix, 5 + (suffix ~ /^http:/)) } - print line >file + while (match(line, markdown_quotation)) { + prefix = substr(line, 1, RSTART) + within = substr(line, RSTART + 2, RLENGTH - 3) + suffix = substr(line, RSTART + RLENGTH) + line = prefix "'\''" within "'\''" suffix + } + print line >file } if (close(file) != 0) { print "Cannot rewrite: " file From 1eb2e052bb55184d62c1dec265f6d327be4e9113 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 May 2026 18:39:09 -0700 Subject: [PATCH 064/112] New function memory_full_up * src/alloc.c (memory_full_up): New function. Replace all callers of memory_full (SIZE_MAX) with callers to this function. This simplifies callers and should make future changes easier. It also saves a whopping 296 bytes in executable size with gcc 16.1.1 20260515 (Red Hat 16.1.1-2) x86-64. --- src/alloc.c | 24 +++++++++++++++++------- src/android.c | 2 +- src/androidselect.c | 2 +- src/androidterm.c | 2 +- src/buffer.c | 6 +++--- src/callint.c | 2 +- src/ccl.c | 2 +- src/coding.c | 2 +- src/composite.c | 2 +- src/dispnew.c | 4 ++-- src/editfns.c | 4 ++-- src/eval.c | 2 +- src/fns.c | 6 +++--- src/gnutls.c | 2 +- src/gtkutil.c | 4 ++-- src/haikufns.c | 2 +- src/haikufont.c | 2 +- src/haikuselect.c | 6 +++--- src/haikuterm.c | 4 ++-- src/image.c | 6 +++--- src/json.c | 2 +- src/keymap.c | 2 +- src/lisp.h | 3 ++- src/macfont.m | 2 +- src/nsfont.m | 2 +- src/pgtkterm.c | 2 +- src/sfntfont-android.c | 4 ++-- src/sfntfont.c | 2 +- src/term.c | 4 ++-- src/timefns.c | 6 +++--- src/tparam.c | 2 +- src/w32term.c | 2 +- src/xselect.c | 6 +++--- src/xsmfns.c | 2 +- src/xterm.c | 2 +- src/xwidget.c | 2 +- 36 files changed, 71 insertions(+), 60 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 5da38cadb5d..a73e7df1dc7 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -711,7 +711,7 @@ xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size) eassert (0 <= nitems && 0 < item_size); ptrdiff_t nbytes; if (ckd_mul (&nbytes, nitems, item_size) || SIZE_MAX < nbytes) - memory_full (SIZE_MAX); + memory_full_up (); return xmalloc (nbytes); } @@ -725,7 +725,7 @@ xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size) eassert (0 <= nitems && 0 < item_size); ptrdiff_t nbytes; if (ckd_mul (&nbytes, nitems, item_size) || SIZE_MAX < nbytes) - memory_full (SIZE_MAX); + memory_full_up (); return xrealloc (pa, nbytes); } @@ -792,7 +792,7 @@ xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min, && (ckd_add (&n, n0, nitems_incr_min) || (0 <= nitems_max && nitems_max < n) || ckd_mul (&nbytes, n, item_size))) - memory_full (SIZE_MAX); + memory_full_up (); pa = xrealloc (pa, nbytes); *nitems = n; return pa; @@ -1111,7 +1111,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type) { lisp_malloc_loser = base; free (base); - memory_full (SIZE_MAX); + memory_full_up (); } } #endif @@ -2181,7 +2181,7 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) CHECK_FIXNAT (length); EMACS_INT len = XFIXNAT (length); if (BOOL_VECTOR_LENGTH_MAX < len) - memory_full (SIZE_MAX); + memory_full_up (); Lisp_Object val = make_clear_bool_vector (len, NILP (init)); return NILP (init) ? val : bool_vector_fill (val, init); } @@ -2193,7 +2193,7 @@ usage: (bool-vector &rest OBJECTS) */) (ptrdiff_t nargs, Lisp_Object *args) { if (BOOL_VECTOR_LENGTH_MAX < nargs) - memory_full (SIZE_MAX); + memory_full_up (); Lisp_Object vector = make_clear_bool_vector (nargs, true); for (ptrdiff_t i = 0; i < nargs; i++) if (!NILP (args[i])) @@ -3397,7 +3397,7 @@ allocate_clear_vector (ptrdiff_t len, bool clearit) if (len == 0) return XVECTOR (zero_vector); if (VECTOR_ELTS_MAX < len) - memory_full (SIZE_MAX); + memory_full_up (); struct Lisp_Vector *v = allocate_vectorlike (len, clearit); v->header.size = len; return v; @@ -4142,6 +4142,16 @@ memory_full (size_t nbytes) xsignal (Qnil, Vmemory_signal_data); } +/* Report memory exhaustion because size calculations overflowed, + or perhaps malloc was invoked successfully but the + resulting pointer had problems fitting into a tagged EMACS_INT. */ + +void +memory_full_up (void) +{ + memory_full (SIZE_MAX); +} + /* If we released our reserve (due to running out of memory), and we have a fair amount free once again, try to set aside another reserve in case we run out once more. diff --git a/src/android.c b/src/android.c index c1b2b9c98ac..cd950d3c51c 100644 --- a/src/android.c +++ b/src/android.c @@ -4948,7 +4948,7 @@ android_get_image (android_drawable handle, (size_t) bitmap_info.height)) { ANDROID_DELETE_LOCAL_REF (bitmap); - memory_full (0); + memory_full_up (); } } else diff --git a/src/androidselect.c b/src/androidselect.c index 8bdbc0fcd36..ce02c4f42ba 100644 --- a/src/androidselect.c +++ b/src/androidselect.c @@ -618,7 +618,7 @@ does not have any corresponding data. In that case, use if (ckd_add (&length, length, rc) || PTRDIFF_MAX - length < BUFSIZ) - memory_full (PTRDIFF_MAX); + memory_full_up (); if (rc < 0) return unbind_to (ref, Qnil); diff --git a/src/androidterm.c b/src/androidterm.c index a74b595d499..18d6d2eb56a 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -6831,7 +6831,7 @@ android_term_init (void) static char const at[] = " at "; ptrdiff_t nbytes = sizeof (title) + sizeof (at); if (ckd_add (&nbytes, nbytes, SBYTES (system_name))) - memory_full (SIZE_MAX); + memory_full_up (); dpyinfo->x_id_name = xmalloc (nbytes); sprintf (dpyinfo->x_id_name, "%s%s%s", title, at, SDATA (system_name)); diff --git a/src/buffer.c b/src/buffer.c index ec26ff82c78..8963ec4e197 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -3413,7 +3413,7 @@ record_overlay_string (struct sortstrlist *ssl, Lisp_Object str, nbytes = SBYTES (str); if (ckd_add (&nbytes, nbytes, ssl->bytes)) - memory_full (SIZE_MAX); + memory_full_up (); ssl->bytes = nbytes; if (STRINGP (str2)) @@ -3427,7 +3427,7 @@ record_overlay_string (struct sortstrlist *ssl, Lisp_Object str, nbytes = SBYTES (str2); if (ckd_add (&nbytes, nbytes, ssl->bytes)) - memory_full (SIZE_MAX); + memory_full_up (); ssl->bytes = nbytes; } } @@ -3499,7 +3499,7 @@ overlay_strings (ptrdiff_t pos, struct window *w, unsigned char **pstr) ptrdiff_t total; if (ckd_add (&total, overlay_heads.bytes, overlay_tails.bytes)) - memory_full (SIZE_MAX); + memory_full_up (); if (total > overlay_str_len) overlay_str_buf = xpalloc (overlay_str_buf, &overlay_str_len, total - overlay_str_len, -1, 1); diff --git a/src/callint.c b/src/callint.c index 398bfde468b..1746dd57704 100644 --- a/src/callint.c +++ b/src/callint.c @@ -431,7 +431,7 @@ invoke it (via an `interactive' spec that contains, for instance, an if (MOST_POSITIVE_FIXNUM < min (PTRDIFF_MAX, SIZE_MAX) / word_size && MOST_POSITIVE_FIXNUM < nargs) - memory_full (SIZE_MAX); + memory_full_up (); /* ARGS will contain the array of arguments to pass to the function. VISARGS will contain the same list but in a nicer form, so that if we diff --git a/src/ccl.c b/src/ccl.c index c581d6ecd95..2fe26be5759 100644 --- a/src/ccl.c +++ b/src/ccl.c @@ -2166,7 +2166,7 @@ usage: (ccl-execute-on-string CCL-PROGRAM STATUS STRING &optional CONTINUE UNIBY outbufsize = str_bytes; if (ckd_mul (&outbufsize, outbufsize, buf_magnification) || ckd_add (&outbufsize, outbufsize, 256)) - memory_full (SIZE_MAX); + memory_full_up (); outp = outbuf = xmalloc (outbufsize); consumed_chars = consumed_bytes = 0; diff --git a/src/coding.c b/src/coding.c index dd767c80ab4..aea4c0cea5f 100644 --- a/src/coding.c +++ b/src/coding.c @@ -7045,7 +7045,7 @@ produce_chars (struct coding_system *coding, Lisp_Object translation_table, ptrdiff_t dst_size; if (ckd_mul (&dst_size, to_nchars, MAX_MULTIBYTE_LENGTH) || ckd_add (&dst_size, dst_size, buf_end - buf)) - memory_full (SIZE_MAX); + memory_full_up (); dst = alloc_destination (coding, dst_size, dst); if (EQ (coding->src_object, coding->dst_object) /* Input and output are not C buffers, which are safe to diff --git a/src/composite.c b/src/composite.c index e36e1670d8d..2898ea9651e 100644 --- a/src/composite.c +++ b/src/composite.c @@ -315,7 +315,7 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars, : ASIZE (key)); if (GLYPH_LEN_MAX < glyph_len) - memory_full (SIZE_MAX); + memory_full_up (); /* Register the composition in composition_table. */ cmp = xmalloc (sizeof *cmp); diff --git a/src/dispnew.c b/src/dispnew.c index 284a0eb175f..be15a5ab694 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1403,7 +1403,7 @@ realloc_glyph_pool (struct glyph_pool *pool, struct dim matrix_dim) /* Enlarge the glyph pool. */ if (ckd_mul (&needed, matrix_dim.height, matrix_dim.width)) - memory_full (SIZE_MAX); + memory_full_up (); if (needed > pool->nglyphs) { ptrdiff_t old_nglyphs = pool->nglyphs; @@ -5412,7 +5412,7 @@ scrolling_window (struct window *w, int tab_line_p) - next_almost_prime_increment_max); ptrdiff_t current_nrows_max = row_table_max - desired_matrix->nrows; if (current_nrows_max < current_matrix->nrows) - memory_full (SIZE_MAX); + memory_full_up (); } /* Reallocate vectors, tables etc. if necessary. */ diff --git a/src/editfns.c b/src/editfns.c index cad41a36f7f..341e241dfcb 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -2080,7 +2080,7 @@ a buffer or a string. But this is deprecated. */) ptrdiff_t bytes_needed; if (ckd_mul (&bytes_needed, diags, 2 * sizeof *buffer) || ckd_add (&bytes_needed, bytes_needed, del_bytes + ins_bytes)) - memory_full (SIZE_MAX); + memory_full_up (); USE_SAFE_ALLOCA; buffer = SAFE_ALLOCA (bytes_needed); unsigned char *deletions_insertions = memset (buffer + 2 * diags, 0, @@ -3510,7 +3510,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) v |= ckd_add (&alloca_size, info_size, format_and_discarded_size); v |= SIZE_MAX < alloca_size; if (v) - memory_full (SIZE_MAX); + memory_full_up (); /* The info table. */ info = SAFE_ALLOCA (alloca_size); /* A copy of the format string's bytes, needed because the original diff --git a/src/eval.c b/src/eval.c index b61bda4a024..1fdc6653cfc 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1601,7 +1601,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, SAFE_ALLOCA won't work here due to the setjmp, so impose a MAX_ALLOCA limit. */ if (MAX_ALLOCA / word_size < clausenb) - memory_full (SIZE_MAX); + memory_full_up (); Lisp_Object volatile *clauses = alloca (clausenb * sizeof *clauses); clauses += clausenb; *--clauses = make_fixnum (0); diff --git a/src/fns.c b/src/fns.c index a2312ffa1b9..8e7e5f980a1 100644 --- a/src/fns.c +++ b/src/fns.c @@ -902,7 +902,7 @@ concat_to_string (ptrdiff_t nargs, Lisp_Object *args) result_len += len; if (MOST_POSITIVE_FIXNUM < result_len) - memory_full (SIZE_MAX); + memory_full_up (); } if (dest_multibyte && some_unibyte) @@ -1122,7 +1122,7 @@ concat_to_vector (ptrdiff_t nargs, Lisp_Object *args) EMACS_INT len = XFIXNAT (Flength (arg)); result_len += len; if (MOST_POSITIVE_FIXNUM < result_len) - memory_full (SIZE_MAX); + memory_full_up (); } /* Create the output vector. */ @@ -4672,7 +4672,7 @@ larger_vector (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max) incr_max = n_max - old_size; incr = max (incr_min, min (old_size >> 1, incr_max)); if (incr_max < incr) - memory_full (SIZE_MAX); + memory_full_up (); new_size = old_size + incr; v = allocate_vector (new_size); memcpy (v->contents, XVECTOR (vec)->contents, old_size * sizeof *v->contents); diff --git a/src/gnutls.c b/src/gnutls.c index 4a4567a5174..3ba9b1b290f 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -2424,7 +2424,7 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, ptrdiff_t tagged_size; if (ckd_add (&tagged_size, isize, cipher_tag_size) || SIZE_MAX < tagged_size) - memory_full (SIZE_MAX); + memory_full_up (); size_t storage_length = tagged_size; USE_SAFE_ALLOCA; char *storage = SAFE_ALLOCA (storage_length); diff --git a/src/gtkutil.c b/src/gtkutil.c index 4fc6b3e0108..df41fb91110 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -698,7 +698,7 @@ get_utf8_string (const char *str) if (ckd_mul (&alloc, nr_bad, 4) || ckd_add (&alloc, alloc, len + 1) || SIZE_MAX < alloc) - memory_full (SIZE_MAX); + memory_full_up (); up = utf8_str = xmalloc (alloc); p = (unsigned char *)str; @@ -4382,7 +4382,7 @@ xg_store_widget_in_map (GtkWidget *w) { ptrdiff_t new_size; if (TYPE_MAXIMUM (Window) - ID_TO_WIDGET_INCR < id_to_widget.max_size) - memory_full (SIZE_MAX); + memory_full_up (); new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR; id_to_widget.widgets = xnrealloc (id_to_widget.widgets, diff --git a/src/haikufns.c b/src/haikufns.c index e24dfd2193e..3568c1bc0bc 100644 --- a/src/haikufns.c +++ b/src/haikufns.c @@ -2025,7 +2025,7 @@ haiku_create_colored_cursor (struct user_cursor_bitmap_info *info, bitmap = BBitmap_new (width, height, false); if (!bitmap) - memory_full (SIZE_MAX); + memory_full_up (); for (y = 0; y < height; ++y) { diff --git a/src/haikufont.c b/src/haikufont.c index cc9cb47b395..09edffc08a9 100644 --- a/src/haikufont.c +++ b/src/haikufont.c @@ -1033,7 +1033,7 @@ haikufont_shape (Lisp_Object lgstring, Lisp_Object direction) len = i; if (INT_MAX / 2 < len) - memory_full (SIZE_MAX); + memory_full_up (); block_input (); diff --git a/src/haikuselect.c b/src/haikuselect.c index 93449357806..f8dac897d97 100644 --- a/src/haikuselect.c +++ b/src/haikuselect.c @@ -249,7 +249,7 @@ haiku_message_to_lisp (void *message) case 'MSGG': msg = be_get_message_message (message, name, j); if (!msg) - memory_full (SIZE_MAX); + memory_full_up (); t1 = haiku_message_to_lisp (msg); BMessage_delete (msg); @@ -270,7 +270,7 @@ haiku_message_to_lisp (void *message) } if (!pbuf) - memory_full (SIZE_MAX); + memory_full_up (); t1 = DECODE_FILE (build_string (pbuf)); @@ -837,7 +837,7 @@ haiku_report_system_error (status_t code, const char *format) break; case B_NO_MEMORY: - memory_full (SIZE_MAX); + memory_full_up (); break; default: diff --git a/src/haikuterm.c b/src/haikuterm.c index b2b864188af..065a2d262b2 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -2909,7 +2909,7 @@ haiku_define_fringe_bitmap (int which, unsigned short *bits, block_input (); fringe_bmps[which] = BBitmap_new (wd, h, 1); if (!fringe_bmps[which]) - memory_full (SIZE_MAX); + memory_full_up (); BBitmap_import_fringe_bitmap (fringe_bmps[which], bits, wd, h); unblock_input (); } @@ -4526,7 +4526,7 @@ haiku_term_init (void) nbytes = sizeof "GNU Emacs" + sizeof " at "; if (ckd_add (&nbytes, nbytes, SBYTES (system_name))) - memory_full (SIZE_MAX); + memory_full_up (); name_buffer = alloca (nbytes); sprintf (name_buffer, "%s%s%s", "GNU Emacs", diff --git a/src/image.c b/src/image.c index 9d0a620188f..38f9d1416a7 100644 --- a/src/image.c +++ b/src/image.c @@ -6950,7 +6950,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) if (ckd_mul (&nbytes, sizeof *colors, img->width) || ckd_mul (&nbytes, nbytes, img->height) || SIZE_MAX < nbytes) - memory_full (SIZE_MAX); + memory_full_up (); colors = xmalloc (nbytes); /* Get the X image or create a memory device context for IMG. */ @@ -7100,7 +7100,7 @@ image_detect_edges (struct frame *f, struct image *img, if (ckd_mul (&nbytes, sizeof *new, img->width) || ckd_mul (&nbytes, nbytes, img->height)) - memory_full (SIZE_MAX); + memory_full_up (); new = xmalloc (nbytes); for (y = 0; y < img->height; ++y) @@ -8486,7 +8486,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c) /* Allocate memory for the image. */ if (ckd_mul (&nbytes, row_bytes, sizeof *pixels) || ckd_mul (&nbytes, nbytes, height)) - memory_full (SIZE_MAX); + memory_full_up (); c->pixels = pixels = xmalloc (nbytes); c->rows = rows = xmalloc (height * sizeof *rows); for (i = 0; i < height; ++i) diff --git a/src/json.c b/src/json.c index ccbbae615d0..9b07f8ced26 100644 --- a/src/json.c +++ b/src/json.c @@ -142,7 +142,7 @@ make_symset_table (int bits, struct symset_tbl *up) { int maxbits = min (SIZE_WIDTH - 2 - (word_size < 8 ? 2 : 3), 32); if (bits > maxbits) - memory_full (PTRDIFF_MAX); /* Will never happen in practice. */ + memory_full_up (); /* Will never happen in practice. */ struct symset_tbl *st = xmalloc (sizeof *st + (sizeof *st->entries << bits)); st->up = up; ptrdiff_t size = symset_size (bits); diff --git a/src/keymap.c b/src/keymap.c index 9c2aa7634fc..dc40d68089a 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -2109,7 +2109,7 @@ For an approximate inverse of this, see `kbd'. */) /* This has one extra element at the end that we don't pass to Fconcat. */ ptrdiff_t size4; if (ckd_mul (&size4, nkeys + nprefix, 4)) - memory_full (SIZE_MAX); + memory_full_up (); SAFE_ALLOCA_LISP (args, size4); /* In effect, this computes diff --git a/src/lisp.h b/src/lisp.h index a5082146da7..bf80cfec3ad 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4430,6 +4430,7 @@ extern void parse_str_as_multibyte (const unsigned char *, ptrdiff_t, extern intptr_t garbage_collection_inhibited; extern void malloc_warning (const char *); extern AVOID memory_full (size_t); +extern AVOID memory_full_up (void); extern AVOID buffer_memory_full (ptrdiff_t); extern bool survives_gc_p (Lisp_Object); extern void mark_object (Lisp_Object); @@ -5704,7 +5705,7 @@ safe_free_unbind_to (specpdl_ref count, specpdl_ref sa_count, Lisp_Object val) ptrdiff_t alloca_nbytes; \ if (ckd_mul (&alloca_nbytes, nelt, word_size) \ || SIZE_MAX < alloca_nbytes) \ - memory_full (SIZE_MAX); \ + memory_full_up (); \ else if (alloca_nbytes <= sa_avail) \ (buf) = AVAIL_ALLOCA (alloca_nbytes); \ else \ diff --git a/src/macfont.m b/src/macfont.m index 84e3e0e8e21..1916e5c0287 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -3119,7 +3119,7 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no len = i; if (INT_MAX / 2 < len) - memory_full (SIZE_MAX); + memory_full_up (); unichars = alloca (sizeof (UniChar) * (len + nonbmp_len)); nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1)); diff --git a/src/nsfont.m b/src/nsfont.m index 655a4c3b569..71ebf9d8b3d 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1484,7 +1484,7 @@ is false when (FROM > 0 || TO < S->nchars). */ len = i; if (INT_MAX / 2 < len) - memory_full (SIZE_MAX); + memory_full_up (); block_input (); diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 757ff57a9f2..6362f795eff 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -7150,7 +7150,7 @@ pgtk_term_init (Lisp_Object display_name, char *resource_name) Lisp_Object system_name = Fsystem_name (); ptrdiff_t nbytes; if (ckd_add (&nbytes, SBYTES (Vinvocation_name), SBYTES (system_name) + 2)) - memory_full (SIZE_MAX); + memory_full_up (); dpyinfo->x_id = ++x_display_id; dpyinfo->x_id_name = xmalloc (nbytes); char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name); diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c index 3a5daa67ff8..30cf1876191 100644 --- a/src/sfntfont-android.c +++ b/src/sfntfont-android.c @@ -79,7 +79,7 @@ static size_t max_scanline_buffer_size; size_t _size; \ \ if (ckd_mul (&_size, height, stride)) \ - memory_full (SIZE_MAX); \ + memory_full_up (); \ \ if (_size < MAX_ALLOCA) \ (buffer) = alloca (_size); \ @@ -113,7 +113,7 @@ static size_t max_scanline_buffer_size; void *_temp; \ \ if (ckd_mul (&_size, height, stride)) \ - memory_full (SIZE_MAX); \ + memory_full_up (); \ \ if (_size > scanline_buffer.buffer_size) \ { \ diff --git a/src/sfntfont.c b/src/sfntfont.c index 0cbb41a1f2e..4f49f03d744 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -613,7 +613,7 @@ sfnt_parse_languages (struct sfnt_meta_table *meta, /* Now copy metadata and add a trailing NULL byte. */ if (map.data_length >= SIZE_MAX) - memory_full (SIZE_MAX); + memory_full_up (); metadata = SAFE_ALLOCA ((size_t) map.data_length + 1); memcpy (metadata, data, map.data_length); diff --git a/src/term.c b/src/term.c index 354375085e2..e4fdb85831c 100644 --- a/src/term.c +++ b/src/term.c @@ -554,7 +554,7 @@ encode_terminal_code (struct glyph *src, int src_len, Vglyph_table contains a string or a composite glyph is encountered. */ if (ckd_mul (&required, src_len, MAX_MULTIBYTE_LENGTH)) - memory_full (SIZE_MAX); + memory_full_up (); if (encode_terminal_src_size < required) encode_terminal_src = xpalloc (encode_terminal_src, &encode_terminal_src_size, @@ -1245,7 +1245,7 @@ calculate_costs (struct frame *frame) max_frame_cols = max (max_frame_cols, FRAME_COLS (frame)); if ((min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) - 1) / 2 < max_frame_cols) - memory_full (SIZE_MAX); + memory_full_up (); char_ins_del_vector = xrealloc (char_ins_del_vector, diff --git a/src/timefns.c b/src/timefns.c index 4bfb267c5c1..88f5504fe35 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -213,7 +213,7 @@ emacs_localtime_rz (timezone_t tz, time_t const *t, struct tm *tm) #endif tm = localtime_rz (tz, t, tm); if (!tm && errno == ENOMEM) - memory_full (SIZE_MAX); + memory_full_up (); return tm; } @@ -317,7 +317,7 @@ tzlookup (Lisp_Object zone, bool settz) if (!new_tz) { if (errno == ENOMEM) - memory_full (SIZE_MAX); + memory_full_up (); invalid_time_zone_specification (zone); } } @@ -367,7 +367,7 @@ time_error (int err) { switch (err) { - case ENOMEM: memory_full (SIZE_MAX); + case ENOMEM: memory_full_up (); case EOVERFLOW: time_overflow (); default: time_spec_invalid (); } diff --git a/src/tparam.c b/src/tparam.c index 261ef02a55e..d37fb67cfac 100644 --- a/src/tparam.c +++ b/src/tparam.c @@ -173,7 +173,7 @@ tparam1 (const char *string, char *outstring, int len, else doleft++, append_len_incr = strlen (left); if (ckd_add (&append_len, append_len, append_len_incr)) - memory_full (SIZE_MAX); + memory_full_up (); } } *op++ = tem ? tem : 0200; diff --git a/src/w32term.c b/src/w32term.c index 43d2440854b..ccf5d14cb10 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -7820,7 +7820,7 @@ w32_initialize_display_info (Lisp_Object display_name) static char const at[] = " at "; ptrdiff_t nbytes = sizeof (title) + sizeof (at); if (ckd_add (&nbytes, nbytes, SCHARS (Vsystem_name))) - memory_full (SIZE_MAX); + memory_full_up (); dpyinfo->w32_id_name = xmalloc (nbytes); sprintf (dpyinfo->w32_id_name, "%s%s%s", title, at, SDATA (Vsystem_name)); } diff --git a/src/xselect.c b/src/xselect.c index 93057c2d6c5..5be009af0d7 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -1882,7 +1882,7 @@ x_get_window_property (Display *display, Window window, Atom property, if (data) xfree (data); unblock_input (); - memory_full (SIZE_MAX); + memory_full_up (); } /* Use xfree, not XFree, to free the data obtained with this function. */ @@ -1903,7 +1903,7 @@ receive_incremental_selection (struct x_display_info *dpyinfo, Display *display = dpyinfo->display; if (min (PTRDIFF_MAX, SIZE_MAX) < min_size_bytes) - memory_full (SIZE_MAX); + memory_full_up (); *data_ret = xmalloc (min_size_bytes); *size_bytes_ret = min_size_bytes; @@ -3063,7 +3063,7 @@ x_property_data_to_lisp (struct frame *f, const unsigned char *data, ptrdiff_t format_bytes = format >> 3; ptrdiff_t data_bytes; if (ckd_mul (&data_bytes, size, format_bytes)) - memory_full (SIZE_MAX); + memory_full_up (); return selection_data_to_lisp_data (FRAME_DISPLAY_INFO (f), data, data_bytes, type, format); } diff --git a/src/xsmfns.c b/src/xsmfns.c index c3e6224b49a..5fec0e8913e 100644 --- a/src/xsmfns.c +++ b/src/xsmfns.c @@ -224,7 +224,7 @@ smc_save_yourself_CB (SmcConn smcConn, props[props_idx]->type = xstrdup (SmLISTofARRAY8); /* /path/to/emacs, --smid=xxx --no-splash --chdir=dir ... */ if (ckd_add (&i, initial_argc, 3)) - memory_full (SIZE_MAX); + memory_full_up (); props[props_idx]->num_vals = i; vp = xnmalloc (i, sizeof *vp); props[props_idx]->vals = vp; diff --git a/src/xterm.c b/src/xterm.c index b2a0d2cadcc..6580bda9fef 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -30989,7 +30989,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) static char const at[] = " at "; ptrdiff_t nbytes = sizeof (title) + sizeof (at); if (ckd_add (&nbytes, nbytes, SBYTES (system_name))) - memory_full (SIZE_MAX); + memory_full_up (); dpyinfo->x_id_name = xmalloc (nbytes); sprintf (dpyinfo->x_id_name, "%s%s%s", title, at, SDATA (system_name)); } diff --git a/src/xwidget.c b/src/xwidget.c index 0b890375c30..e554dc63bbf 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -2462,7 +2462,7 @@ webkit_js_to_lisp (JSCValue *value) Lisp_Object obj; if (! (0 <= dlen && dlen < G_MAXINT32)) - memory_full (SIZE_MAX); + memory_full_up (); ptrdiff_t n = dlen; struct Lisp_Vector *p = allocate_nil_vector (n); From 59b2f8f1dc4513df32e81a7a0d38d5b09c0d6049 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 19 May 2026 22:17:40 -0700 Subject: [PATCH 065/112] Plug default_PATH memory leak * src/emacs.c (default_PATH): Fix very-unlikely memory leak. --- src/emacs.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/emacs.c b/src/emacs.c index 11fe567737a..465a7a0b108 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -753,21 +753,24 @@ default_PATH (void) { #ifdef _CS_PATH char *buf = staticbuf; - size_t bufsize = sizeof staticbuf, s; + size_t bufsize = sizeof staticbuf; - /* If necessary call confstr a second time with a bigger buffer. */ - while (bufsize < (s = confstr (_CS_PATH, buf, bufsize))) + /* If necessary call confstr again with a bigger buffer. */ + for (size_t s; + ! (s = confstr (_CS_PATH, buf, bufsize)) || bufsize < s; ) { + if (buf != staticbuf) + xfree (buf); + if (!s) + { + staticbuf[0] = 1; + buf = NULL; + break; + } buf = xmalloc (s); bufsize = s; } - if (s == 0) - { - staticbuf[0] = 1; - buf = NULL; - } - path = buf; #elif defined DOS_NT From 9851c5ea3410589dadfc43e809fd65ee66b58d28 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 20 May 2026 08:32:41 -0700 Subject: [PATCH 066/112] Shrink STRING_BYTES_MAX slightly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/alloc.c (STRING_BYTES_MAX): Also don’t allow sizes to exceed PTRDIFF_MAX in internal calculations when calling malloc, as those are problematic even if the final number of bytes does not exceed PTRDIFF_MAX. --- src/alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc.c b/src/alloc.c index a73e7df1dc7..387b196bbee 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1501,7 +1501,7 @@ sdata_size (ptrdiff_t n) calculating a value to be passed to malloc. */ static ptrdiff_t const STRING_BYTES_MAX = min (STRING_BYTES_BOUND, - ((SIZE_MAX + ((min (PTRDIFF_MAX, SIZE_MAX) - GC_STRING_EXTRA - offsetof (struct sblock, data) - SDATA_DATA_OFFSET) From 5fd1e0bbef85119527129da8bc645c102434ab28 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 20 May 2026 08:39:44 -0700 Subject: [PATCH 067/112] Coalesce load_seccomp comparisons * src/emacs.c (load_seccomp): One comparison, not two. --- src/emacs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/emacs.c b/src/emacs.c index 465a7a0b108..a9b970effb4 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1228,8 +1228,7 @@ load_seccomp (const char *file) goto out; } struct sock_fprog program; - if (stat.st_size <= 0 || SIZE_MAX <= stat.st_size - || PTRDIFF_MAX <= stat.st_size + if (stat.st_size <= 0 || min (PTRDIFF_MAX, SIZE_MAX) <= stat.st_size || stat.st_size % sizeof *program.filter != 0) { fprintf (stderr, "seccomp filter %s has invalid size %ld\n", From 4d85084509a13fdc15ca38e6885a6a8e30e77425 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 20 May 2026 09:09:21 -0700 Subject: [PATCH 068/112] Fix unlikely json.c size overflow calculations * src/json.c (json_out_grow_buf) (json_make_object_workspace_for_slow_path) (json_byte_workspace_put_slow_path): Use xpalloc rather than doing it by hand. * src/json.c (json_out_grow_buf): Change arg from needed bytes to minimum increment of bytes. Caller changed. --- src/json.c | 86 ++++++++++++++++++------------------------------------ 1 file changed, 29 insertions(+), 57 deletions(-) diff --git a/src/json.c b/src/json.c index 9b07f8ced26..720654bac43 100644 --- a/src/json.c +++ b/src/json.c @@ -244,13 +244,10 @@ symset_add (json_out_t *jo, symset_t *ss, Lisp_Object sym) } static NO_INLINE void -json_out_grow_buf (json_out_t *jo, ptrdiff_t bytes) +json_out_grow_buf (json_out_t *jo, ptrdiff_t incr_min) { - ptrdiff_t need = jo->size + bytes; - ptrdiff_t new_size = max (jo->capacity, 512); - while (new_size < need) - new_size <<= 1; - jo->buf = xrealloc (jo->buf, new_size); + ptrdiff_t new_size = jo->capacity; + jo->buf = xpalloc (jo->buf, &new_size, incr_min, -1, 1); jo->capacity = new_size; } @@ -267,8 +264,9 @@ cleanup_json_out (void *arg) static void json_make_room (json_out_t *jo, ptrdiff_t bytes) { - if (bytes > jo->capacity - jo->size) - json_out_grow_buf (jo, bytes); + ptrdiff_t avail = jo->capacity - jo->size; + if (avail < bytes) + json_out_grow_buf (jo, bytes - avail); } #define JSON_OUT_STR(jo, str) (json_out_str (jo, str, sizeof (str) - 1)) @@ -803,36 +801,20 @@ json_parser_done (void *parser) Lisp_Objects */ NO_INLINE static void json_make_object_workspace_for_slow_path (struct json_parser *parser, - size_t size) + ptrdiff_t size) { - size_t needed_workspace_size - = (parser->object_workspace_current + size); - size_t new_workspace_size = parser->object_workspace_size; - while (new_workspace_size < needed_workspace_size) - { - if (ckd_mul (&new_workspace_size, new_workspace_size, 2)) - { - json_signal_error (parser, Qjson_out_of_memory); - } - } - - Lisp_Object *new_workspace_ptr; - if (parser->object_workspace_size - == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE) - { - new_workspace_ptr - = xnmalloc (new_workspace_size, sizeof (Lisp_Object)); - memcpy (new_workspace_ptr, parser->object_workspace, - (sizeof (Lisp_Object) - * parser->object_workspace_current)); - } - else - { - new_workspace_ptr - = xnrealloc (parser->object_workspace, new_workspace_size, - sizeof (Lisp_Object)); - } - + bool internal = (parser->object_workspace_size + == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE); + ptrdiff_t new_workspace_size = parser->object_workspace_size; + Lisp_Object *new_workspace_ptr + = xpalloc (internal ? NULL : parser->object_workspace, + &new_workspace_size, + size - (parser->object_workspace_size + - parser->object_workspace_current), + -1, sizeof (Lisp_Object)); + if (internal) + memcpy (new_workspace_ptr, parser->object_workspace, + sizeof (Lisp_Object) * parser->object_workspace_current); parser->object_workspace = new_workspace_ptr; parser->object_workspace_size = new_workspace_size; } @@ -854,33 +836,23 @@ json_byte_workspace_reset (struct json_parser *parser) parser->byte_workspace_current = parser->byte_workspace; } -/* Puts 'value' into the byte_workspace. If there is no space - available, it allocates space */ +/* Put VALUE into the byte_workspace, allocating space. */ NO_INLINE static void json_byte_workspace_put_slow_path (struct json_parser *parser, unsigned char value) { - size_t new_workspace_size + ptrdiff_t new_workspace_size = parser->byte_workspace_end - parser->byte_workspace; - if (ckd_mul (&new_workspace_size, new_workspace_size, 2)) - { - json_signal_error (parser, Qjson_out_of_memory); - } - - size_t offset + ptrdiff_t offset = parser->byte_workspace_current - parser->byte_workspace; - if (parser->byte_workspace == parser->internal_byte_workspace) - { - parser->byte_workspace = xmalloc (new_workspace_size); - memcpy (parser->byte_workspace, parser->internal_byte_workspace, - offset); - } - else - { - parser->byte_workspace - = xrealloc (parser->byte_workspace, new_workspace_size); - } + bool internal = parser->byte_workspace == parser->internal_byte_workspace; + unsigned char *new + = xpalloc (internal ? NULL : parser->byte_workspace, + &new_workspace_size, 1, -1, 1); + if (internal) + memcpy (new, parser->byte_workspace, offset); + parser->byte_workspace = new; parser->byte_workspace_end = parser->byte_workspace + new_workspace_size; parser->byte_workspace_current = parser->byte_workspace + offset; From b1d338d89ae1e6484306e0ba7c32bd4163b3b54d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 20 May 2026 09:24:19 -0700 Subject: [PATCH 069/112] Fix misleading x_dnd_begin_drag_and_drop API * src/xterm.c (x_dnd_begin_drag_and_drop): The n_ask_actions arg is an int, not a size_t, as XChangeProperty supports only int and our caller passes an int. --- src/xterm.c | 6 +++--- src/xterm.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index 6580bda9fef..941297a77ce 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -12696,7 +12696,7 @@ x_dnd_process_quit (struct frame *f, Time timestamp) Lisp_Object x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, Lisp_Object return_frame, Atom *ask_action_list, - const char **ask_action_names, size_t n_ask_actions, + const char **ask_action_names, int n_ask_actions, bool allow_current_frame, Atom *target_atoms, int ntargets, Lisp_Object selection_target_list, bool follow_tooltip) @@ -12710,7 +12710,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, char *atom_name, *ask_actions; Lisp_Object action, ltimestamp, val; specpdl_ref ref, count, base; - ptrdiff_t i, end, fill; + ptrdiff_t end, fill; XTextProperty prop; Lisp_Object frame_object, x, y, frame, local_value; bool signals_were_pending, need_sync; @@ -12802,7 +12802,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, end = 0; count = SPECPDL_INDEX (); - for (i = 0; i < n_ask_actions; ++i) + for (int i = 0; i < n_ask_actions; i++) { fill = end; end += strlen (ask_action_names[i]) + 1; diff --git a/src/xterm.h b/src/xterm.h index 28b720c9222..a81bf589b13 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1858,7 +1858,7 @@ extern void x_handle_pending_selection_requests (void); extern bool x_detect_pending_selection_requests (void); extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, Lisp_Object, Atom *, const char **, - size_t, bool, Atom *, int, + int, bool, Atom *, int, Lisp_Object, bool); extern int x_display_pixel_height (struct x_display_info *); extern int x_display_pixel_width (struct x_display_info *); From 25a07c30e5e19f13c32c7ab561391aefa38bc33d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 20 May 2026 19:22:37 -0700 Subject: [PATCH 070/112] =?UTF-8?q?Don=E2=80=99t=20use=20VLA=20in=20etags.?= =?UTF-8?q?c=20mercury=5Fdecl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lib-src/etags.c (mercury_decl): Don’t use a VLA, as C11+ says VLAs are optional. Instead, redo to omit the need for an array at all. --- lib-src/etags.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/lib-src/etags.c b/lib-src/etags.c index f218dba2902..4114ba6b655 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -6654,6 +6654,14 @@ static const char *Mercury_decl_tags[] = {"type", "solver type", "pred", "initialise", "finalise", "mutable", "module", "interface", "implementation", "import_module", "use_module", "include_module", "end_module", "some", "all"}; +/* Return true if array of char BUF, of length LEN, equals STR. */ + +static bool +memstreq (char const *buf, ptrdiff_t len, char const *str) +{ + return strlen (str) == len && memeq (buf, str, len); +} + static mercury_pos_t mercury_decl (char *s, size_t pos) { @@ -6661,27 +6669,24 @@ mercury_decl (char *s, size_t pos) if (s == NULL) return null_pos; - size_t origpos; - origpos = pos; + size_t origpos = pos; + char *decl_type = s + origpos; while (c_isalnum (s[pos]) || s[pos] == '_') pos++; - unsigned char decl_type_length = pos - origpos; - char buf[decl_type_length + 1]; - memset (buf, 0, decl_type_length + 1); + ptrdiff_t decl_type_length = pos - origpos; /* Mercury declaration tags. Consume them, then check the declaration item following :- is legitimate, then go on as in the prolog case. */ - memcpy (buf, &s[origpos], decl_type_length); - bool found_decl_tag = false; if (is_mercury_quantifier) { - if (strcmp (buf, "pred") != 0 && strcmp (buf, "func") != 0) /* Bad syntax. */ - return null_pos; + if (! (memstreq (decl_type, decl_type_length, "pred") + || memstreq (decl_type, decl_type_length, "func"))) + return null_pos; /* Bad syntax. */ is_mercury_quantifier = false; /* Reset to base value. */ found_decl_tag = true; @@ -6690,14 +6695,14 @@ mercury_decl (char *s, size_t pos) { for (int j = 0; j < sizeof (Mercury_decl_tags) / sizeof (char*); ++j) { - if (strcmp (buf, Mercury_decl_tags[j]) == 0) + if (memstreq (decl_type, decl_type_length, Mercury_decl_tags[j])) { found_decl_tag = true; - if (strcmp (buf, "type") == 0) + if (memstreq (decl_type, decl_type_length, "type")) is_mercury_type = true; - if (strcmp (buf, "some") == 0 - || strcmp (buf, "all") == 0) + if (memstreq (decl_type, decl_type_length, "some") + || memstreq (decl_type, decl_type_length, "all")) { is_mercury_quantifier = true; } @@ -6707,18 +6712,15 @@ mercury_decl (char *s, size_t pos) else /* 'solver type' has a blank in the middle, so this is the hard case. */ - if (strcmp (buf, "solver") == 0) + if (memstreq (decl_type, decl_type_length, "solver")) { do pos++; while (c_isalnum (s[pos]) || s[pos] == '_'); decl_type_length = pos - origpos; - char buf2[decl_type_length + 1]; - memset (buf2, 0, decl_type_length + 1); - memcpy (buf2, &s[origpos], decl_type_length); - if (strcmp (buf2, "solver type") == 0) + if (memstreq (decl_type, decl_type_length, "solver type")) { found_decl_tag = false; break; /* Found declaration tag of rank j. */ From 3461b450c5eae3ed53192aa9514e0b1ac1b1c8f2 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 20 May 2026 20:52:28 -0700 Subject: [PATCH 071/112] =?UTF-8?q?Don=E2=80=99t=20silently=20truncate=20f?= =?UTF-8?q?ile=20names=20in=20exec.c?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * exec/exec.c (format_pid): Simplify. No need for a local array. (exec_0): Shrink local buffer. If names are too long, fail instead of silently truncating them. Be cautious in case symlink is zero length (shouldn’t be possible in Android, but it’s easy to be safe). --- exec/exec.c | 96 ++++++++++++++++++++++++++-------------------------- exec/trace.c | 2 +- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/exec/exec.c b/exec/exec.c index 7736c0dab27..ace62dd0191 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -863,32 +863,25 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs, -/* Format PID, an unsigned process identifier, in base 10. Place the - result in *IN, and return a pointer to the byte after the - result. REM should be NULL. */ +/* Format PID, a nonnegative process identifier, in base 10. + Place the result in *IN. Do not null-terminate the result. + Possibly modify the bytes in IN that are after the result. + Return a pointer to the byte after the result. */ char * -format_pid (char *in, unsigned int pid) +format_pid (char in[INT_STRLEN_BOUND (pid_t)], pid_t pid) { - unsigned int digits[32], *fill; + char *pend = in + INT_STRLEN_BOUND (pid_t); + char *p = pend; - fill = digits; + do + *--p = '0' + pid % 10; + while ((pid /= 10) != 0); - for (; pid != 0; pid = pid / 10) - *fill++ = pid % 10; + do + *in++ = *p++; + while (p < pend); - /* Insert 0 if the number would otherwise be empty. */ - - if (fill == digits) - *fill++ = 0; - - while (fill != digits) - { - --fill; - *in++ = '0' + *fill; - } - - *in = '\0'; return in; } @@ -904,10 +897,13 @@ format_pid (char *in, unsigned int pid) Finally, use REGS to add the required interpreter arguments to the caller's argv. + NAME must be a null-terminated string in a buffer of size PATH_MAX. + It might be updated to be a string no longer than PATH_MAX - 1. + Value is NULL upon failure, with errno set accordingly. */ char * -exec_0 (char *name, struct exec_tracee *tracee, +exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, size_t *size, USER_REGS_STRUCT *regs) { int fd, rc, i; @@ -916,14 +912,13 @@ exec_0 (char *name, struct exec_tracee *tracee, program_header program; USER_WORD entry, program_entry, offset; USER_WORD header_offset; + ptrdiff_t nlen; USER_WORD name_len, aligned_len; struct exec_jump_command jump; /* This also encompasses !__LP64__. */ #if defined __mips__ && !defined MIPS_NABI int fpu_mode; #endif /* defined __mips__ && !defined MIPS_NABI */ - char buffer[80], buffer1[PATH_MAX + 80], *rewrite; - ssize_t link_size; size_t remaining; /* If the process is trying to run /proc/self/exe, make it run @@ -931,8 +926,13 @@ exec_0 (char *name, struct exec_tracee *tracee, if (!strcmp (name, "/proc/self/exe") && tracee->exec_file) { - strncpy (name, tracee->exec_file, PATH_MAX - 1); - name[PATH_MAX] = '\0'; + nlen = strnlen (tracee->exec_file, PATH_MAX); + if (PATH_MAX <= nlen) + { + errno = ENAMETOOLONG; + return NULL; + } + memcpy (name, tracee->exec_file, nlen + 1); } else { @@ -940,45 +940,45 @@ exec_0 (char *name, struct exec_tracee *tracee, cwd. Do not use sprintf at it is not reentrant and it mishandles results longer than INT_MAX. */ + nlen = strlen (name); + if (name[0] && name[0] != '/') { - /* Clear both buffers. */ - memset (buffer, 0, sizeof buffer); - memset (buffer1, 0, sizeof buffer1); + char buffer[sizeof "/proc//cwd" + INT_STRLEN_BOUND (pid_t)]; + char buffer1[PATH_MAX]; - /* Copy over /proc, the PID, and /cwd/. */ - rewrite = stpcpy (buffer, "/proc/"); + /* Copy over "/proc/", the PID, and "/cwd". */ + char *rewrite = stpcpy (buffer, "/proc/"); rewrite = format_pid (rewrite, tracee->pid); strcpy (rewrite, "/cwd"); /* Resolve this symbolic link. */ - link_size = readlink (buffer, buffer1, - PATH_MAX + 1); - + ssize_t link_size = readlink (buffer, buffer1, sizeof buffer1); if (link_size < 0) return NULL; - /* Check that the name is a reasonable size. */ + /* Check that the link is reasonable. */ - if (link_size > PATH_MAX) + if (link_size == 0 || buffer1[0] != '/') + { + errno = EINVAL; + return NULL; + } + + ptrdiff_t link_len = link_size - (buffer1[link_size - 1] == '/'); + if (PATH_MAX <= link_len + 1 + nlen) { - /* The name is too long. */ errno = ENAMETOOLONG; return NULL; } - /* Add a directory separator if necessary. */ - - if (!link_size || buffer1[link_size - 1] != '/') - buffer1[link_size] = '/', link_size++; - - rewrite = buffer1 + link_size; - remaining = buffer1 + sizeof buffer1 - rewrite - 1; - memcpy (rewrite, name, strnlen (name, remaining)); - - /* Replace name with buffer1. */ - strcpy (name, buffer1); + /* Replace name with link contents, + then '/' if needed, then name. */ + memmove (name + link_len + 1, name, nlen + 1); + memcpy (name, buffer1, link_len); + name[link_len] = '/'; + nlen += link_len + 1; } } @@ -1151,7 +1151,7 @@ exec_0 (char *name, struct exec_tracee *tracee, loader_area_used += sizeof jump; /* Copy the length of NAME and NAME itself to the loader area. */ - name_len = strlen (name); + name_len = nlen; aligned_len = ((name_len + 1 + sizeof name_len - 1) & -sizeof name_len); if (sizeof loader_area - loader_area_used diff --git a/exec/trace.c b/exec/trace.c index da9ac96c6ff..d3d6f223eb8 100644 --- a/exec/trace.c +++ b/exec/trace.c @@ -732,7 +732,7 @@ check_signal (struct exec_tracee *tracee, int status) static int handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) { - char buffer[PATH_MAX + 80], *area; + char buffer[PATH_MAX], *area; USER_REGS_STRUCT original; size_t size, loader_size; USER_WORD loader; From 1e0b0bed2874098fa5a0b322d6d0f69bd805ef50 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 08:17:05 -0700 Subject: [PATCH 072/112] Avoid a memset in allocate_widget_instance * lwlib/lwlib.c (allocate_widget_instance): Simplify via xzalloc. --- lwlib/lwlib.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lwlib/lwlib.c b/lwlib/lwlib.c index c7b80a83338..5fb6b5f7f49 100644 --- a/lwlib/lwlib.c +++ b/lwlib/lwlib.c @@ -205,9 +205,7 @@ mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data) static widget_instance * allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p) { - widget_instance* instance = - (widget_instance*) xmalloc (sizeof (widget_instance)); - memset (instance, 0, sizeof *instance); + widget_instance *instance = xzalloc (sizeof *instance); instance->parent = parent; instance->pop_up_p = pop_up_p; instance->info = info; From 8c69ba718e85749d704bdc8a6d310f6b802520ab Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 08:20:15 -0700 Subject: [PATCH 073/112] Fix emit_static_object comment (no bzero call) --- src/comp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/comp.c b/src/comp.c index c70b37bfdac..545d13b6bfd 100644 --- a/src/comp.c +++ b/src/comp.c @@ -2823,8 +2823,7 @@ emit_static_object (const char *name, Lisp_Object obj) /* If strlen returned 0 that means that the static object contains a NULL byte. In that case just move over to the next block. We can rely on the byte being zero because - of the previous call to bzero and because the dynamic - linker cleared it. */ + the dynamic linker cleared it. */ p++; i++; gcc_jit_block_add_assignment ( From ad8af430e6c867bde8dc6acc6cd74b9573ce84d2 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 08:23:05 -0700 Subject: [PATCH 074/112] Avoid a memset in alloc-colors.c * admin/alloc-colors.c (main): Simplify. --- admin/alloc-colors.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/admin/alloc-colors.c b/admin/alloc-colors.c index bcbc899cf3d..b479535724a 100644 --- a/admin/alloc-colors.c +++ b/admin/alloc-colors.c @@ -52,7 +52,7 @@ main (int argc, char **argv) int opt, ncolors = 0, i; XColor *allocated; int nallocated; - XColor color; + XColor color = {0}; Colormap cmap; while ((opt = getopt (argc, argv, "n:")) != EOF) @@ -76,7 +76,6 @@ main (int argc, char **argv) allocated = malloc (ncolors * sizeof *allocated); nallocated = 0; - memset (&color, 0, sizeof color); while (nallocated < ncolors && color.red < 65536) From 17215532dc72cc2de1a1c235a0eba9cbfb05ab8c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 08:28:40 -0700 Subject: [PATCH 075/112] Avoid a memset in emacsclient get_server_config * lib-src/emacsclient.c (get_server_config): Rewrite memset+assignments to compound literal. --- lib-src/emacsclient.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 0769c94a89d..e0da2c88121 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -1034,10 +1034,12 @@ get_server_config (const char *config_file, struct sockaddr_in *server, exit (EXIT_FAILURE); } - memset (server, 0, sizeof *server); - server->sin_family = AF_INET; - server->sin_addr.s_addr = inet_addr (dotted); - server->sin_port = htons (atoi (port)); + *server = (struct sockaddr_in) + { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr (dotted), + .sin_port = htons (atoi (port)) + }; free (dotted); if (! fread (authentication, AUTH_KEY_LENGTH, 1, config)) From 52ccc1b8d38906d9a30ce091a153915bbd85c945 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 08:35:50 -0700 Subject: [PATCH 076/112] Avoid memsets in pop.c * lib-src/pop.c (socket_connection): Rewrite memset+assignments to designated initializers. --- lib-src/pop.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib-src/pop.c b/lib-src/pop.c index 6fe487e1e21..2a4e9b4dd75 100644 --- a/lib-src/pop.c +++ b/lib-src/pop.c @@ -975,10 +975,8 @@ static int socket_connection (char *host, int flags) { struct addrinfo *res, *it; - struct addrinfo hints; int ret; struct servent *servent; - struct sockaddr_in addr; char found_port = 0; const char *service; int sock; @@ -1012,9 +1010,6 @@ socket_connection (char *host, int flags) } #endif - memset (&addr, 0, sizeof (addr)); - addr.sin_family = AF_INET; - /** "kpop" service is never used: look for 20060515 to see why **/ #ifdef KERBEROS service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE; @@ -1022,6 +1017,8 @@ socket_connection (char *host, int flags) service = POP_SERVICE; #endif + struct sockaddr_in addr = {.sin_family = AF_INET}; + #ifdef HESIOD if (! (flags & POP_NO_HESIOD)) { @@ -1063,10 +1060,12 @@ socket_connection (char *host, int flags) } - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_CANONNAME; - hints.ai_family = AF_INET; + struct addrinfo hints = + { + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_CANONNAME, + .ai_family = AF_INET, + }; do { ret = getaddrinfo (host, service, &hints, &res); From 42a8e12088b4ce08262ed158b56d60fa00e8c654 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 08:55:27 -0700 Subject: [PATCH 077/112] Avoid memsets in atimer.c * src/atimer.c (start_atimer, turn_on_atimers): Rewrite memset+assignments to xzalloc or initializers. --- src/atimer.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/atimer.c b/src/atimer.c index 72e33656b4a..e59817049f0 100644 --- a/src/atimer.c +++ b/src/atimer.c @@ -126,12 +126,12 @@ start_atimer (enum atimer_type type, struct timespec timestamp, { t = free_atimers; free_atimers = t->next; + memset (t, 0, sizeof *t); } else - t = xmalloc (sizeof *t); + t = xzalloc (sizeof *t); /* Fill the atimer structure. */ - memset (t, 0, sizeof *t); t->type = type; t->fn = fn; t->client_data = client_data; @@ -470,8 +470,7 @@ turn_on_atimers (bool on) else { #ifdef HAVE_ITIMERSPEC - struct itimerspec ispec; - memset (&ispec, 0, sizeof ispec); + struct itimerspec ispec = {0}; if (alarm_timer_ok) timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0); # ifdef HAVE_TIMERFD From ced12fa1140879d92a66475cf2a167e699e8e1c0 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 09:18:15 -0700 Subject: [PATCH 078/112] Avoid memsets in charset.c * src/charset.c (load_charset_map_from_file) (load_charset_map_from_vector, Fdefine_charset_internal): Rewrite memset to xzalloc or initializers. --- src/charset.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/charset.c b/src/charset.c index b86304024fe..971dafc2b9d 100644 --- a/src/charset.c +++ b/src/charset.c @@ -496,11 +496,9 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, set_unwind_protect_ptr (count, fclose_unwind, fp); unbind_to (specpdl_ref_add (count, 1), Qnil); - /* Use record_xmalloc, as `charset_map_entries' is - large (larger than MAX_ALLOCA). */ - head = record_xmalloc (sizeof *head); - entries = head; - memset (entries, 0, sizeof (struct charset_map_entries)); + /* charset_map_entries is large, so don't SAFE_ALLOCA. */ + entries = head = xzalloc (sizeof *head); + record_unwind_protect_ptr (xfree, entries); n_entries = 0; int ch = -1; @@ -532,9 +530,8 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, if (n_entries == 0x10000) { - entries->next = record_xmalloc (sizeof *entries->next); - entries = entries->next; - memset (entries, 0, sizeof (struct charset_map_entries)); + entries = entries->next = xzalloc (sizeof *entries->next); + record_unwind_protect_ptr (xfree, entries); n_entries = 0; } int idx = n_entries; @@ -559,7 +556,7 @@ load_charset_map_from_vector (struct charset *charset, Lisp_Object vec, int cont int n_entries; int len = ASIZE (vec); int i; - USE_SAFE_ALLOCA; + specpdl_ref count = SPECPDL_INDEX (); if (len % 2 == 1) { @@ -567,11 +564,9 @@ load_charset_map_from_vector (struct charset *charset, Lisp_Object vec, int cont return; } - /* Use SAFE_ALLOCA instead of alloca, as `charset_map_entries' is - large (larger than MAX_ALLOCA). */ - head = SAFE_ALLOCA (sizeof *head); - entries = head; - memset (entries, 0, sizeof (struct charset_map_entries)); + /* charset_map_entries is large, so don't SAFE_ALLOCA. */ + entries = head = xzalloc (sizeof *head); + record_unwind_protect_ptr (xfree, entries); n_entries = 0; for (i = 0; i < len; i += 2) @@ -600,9 +595,8 @@ load_charset_map_from_vector (struct charset *charset, Lisp_Object vec, int cont if (n_entries > 0 && (n_entries % 0x10000) == 0) { - entries->next = SAFE_ALLOCA (sizeof *entries->next); - entries = entries->next; - memset (entries, 0, sizeof (struct charset_map_entries)); + entries = entries->next = xzalloc (sizeof *entries->next); + record_unwind_protect_ptr (xfree, entries); } idx = n_entries % 0x10000; entries->entry[idx].from = from; @@ -612,7 +606,7 @@ load_charset_map_from_vector (struct charset *charset, Lisp_Object vec, int cont } load_charset_map (charset, head, n_entries, control_flag); - SAFE_FREE (); + unbind_to (count, Qnil); } @@ -852,14 +846,12 @@ usage: (define-charset-internal ...) */) Lisp_Object val; struct Lisp_Hash_Table *hash_table = XHASH_TABLE (Vcharset_hash_table); int i, j; - struct charset charset; + struct charset charset = {0}; int id; int dimension; bool new_definition_p; int nchars; - memset (&charset, 0, sizeof (charset)); - if (nargs != charset_arg_max) Fsignal (Qwrong_number_of_arguments, Fcons (Qdefine_charset_internal, From c72e6cdc464e295d821da24232a2913bbcecf3f8 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 09:21:18 -0700 Subject: [PATCH 079/112] Avoid memsets in coding.c * src/coding.c (detect_coding_utf_16, Fset_coding_system_priority): Rewrite memset to initializers. --- src/coding.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/coding.c b/src/coding.c index aea4c0cea5f..9aba2a7eacc 100644 --- a/src/coding.c +++ b/src/coding.c @@ -1534,11 +1534,9 @@ detect_coding_utf_16 (struct coding_system *coding, { /* We check the dispersion of Eth and Oth bytes where E is even and O is odd. If both are high, we assume binary data.*/ - unsigned char e[256], o[256]; + unsigned char e[256] = {0}, o[256] = {0}; unsigned e_num = 1, o_num = 1; - memset (e, 0, 256); - memset (o, 0, 256); e[c1] = 1; o[c2] = 1; @@ -10886,11 +10884,9 @@ usage: (set-coding-system-priority &rest coding-systems) */) (ptrdiff_t nargs, Lisp_Object *args) { ptrdiff_t i, j; - bool changed[coding_category_max]; + bool changed[coding_category_max] = {0}; enum coding_category priorities[coding_category_max]; - memset (changed, 0, sizeof changed); - for (i = j = 0; i < nargs; i++) { enum coding_category category; From 64eb869b68835e15b46a217a6d955605b78044bc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 21 May 2026 17:13:42 -0700 Subject: [PATCH 080/112] Be more careful about size multiplication * src/alloc.c (xcalloc): New function. * src/dispnew.c (save_current_matrix): * src/fns.c (Finternal__hash_table_histogram): * src/nsfns.m (Fns_display_monitor_attributes_list): * src/pgtkfns.c (Fpgtk_display_monitor_attributes_list): * src/pgtkselect.c (pgtk_own_selection): * src/profiler.c (make_log): * src/sfnt.c (sfnt_poly_edges_exact): * src/xfns.c (x_get_monitor_attributes_xinerama) (x_get_monitor_attributes_xrandr, Fx_display_monitor_attributes_list): Use it instead of multiplying by hand, conceivably with overflow. * src/profiler.c (make_log): Check for overflow in internal size calculations. Use xnmalloc instead of multiply + xmalloc. * src/sfnt.c (xzalloc) [TEST]: Remove, replacing with ... (xicalloc) [TEST]: ... this new function. All callers changed. (eassert) [TEST]: New macro. * src/treesit.c (treesit_calloc_wrapper): Remove, replacing its use with xcalloc. --- src/alloc.c | 20 +++++++++++++++++++- src/dispnew.c | 2 +- src/fns.c | 2 +- src/lisp.h | 2 ++ src/nsfns.m | 2 +- src/pgtkfns.c | 2 +- src/pgtkselect.c | 2 +- src/profiler.c | 15 +++++++++------ src/sfnt.c | 14 ++++++-------- src/treesit.c | 8 +------- src/xfns.c | 8 ++++---- src/xterm.c | 4 ++-- 12 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 387b196bbee..6a81fed2d69 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -656,7 +656,10 @@ xmalloc (size_t size) return val; } -/* Like the above, but zeroes out the memory just allocated. */ +/* Like the above, but zero out the memory just allocated. + Calling this can be faster than allocating and zeroing, + as the calloc implementation can avoid the zeroing overhead + when obtaining memory directly from the operating system. */ void * xzalloc (size_t size) @@ -668,6 +671,21 @@ xzalloc (size_t size) return val; } +/* Like xzalloc, but for an array of N objects each of size S. */ + +void * +xcalloc (size_t n, size_t s) +{ + void *val = calloc (n, s); + if (!val) + { + size_t size; + memory_full (ckd_mul (&size, n, s) ? SIZE_MAX : size); + } + MALLOC_PROBE (n * s); + return val; +} + /* Like realloc but check for no memory and block interrupt input. */ void * diff --git a/src/dispnew.c b/src/dispnew.c index be15a5ab694..7930fa59968 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1963,7 +1963,7 @@ save_current_matrix (struct frame *f) int i; struct glyph_matrix *saved = xzalloc (sizeof *saved); saved->nrows = f->current_matrix->nrows; - saved->rows = xzalloc (saved->nrows * sizeof *saved->rows); + saved->rows = xcalloc (saved->nrows, sizeof *saved->rows); for (i = 0; i < saved->nrows; ++i) { diff --git a/src/fns.c b/src/fns.c index 8e7e5f980a1..98671fc1318 100644 --- a/src/fns.c +++ b/src/fns.c @@ -5996,7 +5996,7 @@ DEFUN ("internal--hash-table-histogram", { struct Lisp_Hash_Table *h = check_hash_table (hash_table); ptrdiff_t size = HASH_TABLE_SIZE (h); - ptrdiff_t *freq = xzalloc (size * sizeof *freq); + ptrdiff_t *freq = xcalloc (size, sizeof *freq); ptrdiff_t index_size = hash_table_index_size (h); for (ptrdiff_t i = 0; i < index_size; i++) { diff --git a/src/lisp.h b/src/lisp.h index bf80cfec3ad..d4978460f68 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -5536,6 +5536,8 @@ extern void *xmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL; extern void *xzalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL; +extern void *xcalloc (size_t, size_t) + ATTRIBUTE_MALLOC_SIZE ((1,2)) ATTRIBUTE_RETURNS_NONNULL; extern void *xrealloc (void *, size_t) ATTRIBUTE_ALLOC_SIZE ((2)) ATTRIBUTE_RETURNS_NONNULL; extern void xfree (void *); diff --git a/src/nsfns.m b/src/nsfns.m index efe622782f7..045d167e6b4 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -2768,7 +2768,7 @@ Frames are listed from topmost (first) to bottommost (last). */) if (n_monitors == 0) return Qnil; - monitors = xzalloc (n_monitors * sizeof *monitors); + monitors = xcalloc (n_monitors, sizeof *monitors); for (i = 0; i < [screens count]; ++i) { diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 4257dc45f98..e1766d2b1a6 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -2432,7 +2432,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) gdpy = dpyinfo->gdpy; n_monitors = gdk_display_get_n_monitors (gdpy); monitor_frames = make_nil_vector (n_monitors); - monitors = xzalloc (n_monitors * sizeof *monitors); + monitors = xcalloc (n_monitors, sizeof *monitors); FOR_EACH_FRAME (rest, frame) { diff --git a/src/pgtkselect.c b/src/pgtkselect.c index 425da3b8fd4..7e32252616b 100644 --- a/src/pgtkselect.c +++ b/src/pgtkselect.c @@ -213,7 +213,7 @@ pgtk_own_selection (Lisp_Object selection_name, Lisp_Object selection_value, if (VECTORP (targets)) { - gtargets = xzalloc (sizeof *gtargets * ASIZE (targets)); + gtargets = xcalloc (ASIZE (targets), sizeof *gtargets); ntargets = 0; for (i = 0; i < ASIZE (targets); ++i) diff --git a/src/profiler.c b/src/profiler.c index 67049f487ee..b8339a3c544 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -75,21 +75,24 @@ make_log (int size, int depth) int index_size = size * 2 + 1; log->index_size = index_size; - log->trace = xmalloc (depth * sizeof *log->trace); + log->trace = xnmalloc (depth, sizeof *log->trace); - log->index = xmalloc (index_size * sizeof *log->index); + log->index = xnmalloc (index_size, sizeof *log->index); for (int i = 0; i < index_size; i++) log->index[i] = -1; - log->next = xmalloc (size * sizeof *log->next); + log->next = xnmalloc (size, sizeof *log->next); for (int i = 0; i < size - 1; i++) log->next[i] = i + 1; log->next[size - 1] = -1; log->next_free = 0; - log->hash = xmalloc (size * sizeof *log->hash); - log->keys = xzalloc (size * depth * sizeof *log->keys); - log->counts = xzalloc (size * sizeof *log->counts); + log->hash = xnmalloc (size, sizeof *log->hash); + size_t size_x_depth; + if (ckd_mul (&size_x_depth, size, depth)) + memory_full_up (); + log->keys = xcalloc (size_x_depth, sizeof *log->keys); + log->counts = xcalloc (size, sizeof *log->counts); return log; } diff --git a/src/sfnt.c b/src/sfnt.c index ab6a2d5e7bc..e46ebc3a08b 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -70,11 +70,11 @@ xmalloc (size_t size) } MAYBE_UNUSED static void * -xzalloc (size_t size) +xcalloc (ptrdiff_t n, ptrdiff_t s) { void *ptr; - ptr = calloc (1, size); + ptr = calloc (n, s); if (!ptr) abort (); @@ -111,6 +111,8 @@ xfree (void *ptr) /* Also necessary. */ #define AVOID _Noreturn ATTRIBUTE_COLD void +#define eassert(expr) assert (expr) + #else #define TEST_STATIC #include "lisp.h" @@ -5047,7 +5049,7 @@ sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges, sfnt_step_raster_proc proc, void *dcontext) { int y; - size_t size, e, edges_processed; + size_t e, edges_processed; struct sfnt_fedge *active, **prev, *a, sentinel; struct sfnt_step_raster raster; struct sfnt_step_chunk *next, *last; @@ -5065,11 +5067,7 @@ sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges, raster.scanlines = height; raster.chunks = NULL; - - if (ckd_mul (&size, height, sizeof *raster.steps)) - abort (); - - raster.steps = xzalloc (size); + raster.steps = xcalloc (height, sizeof *raster.steps); for (; y != height; y += 1) { diff --git a/src/treesit.c b/src/treesit.c index 3d342be3dcc..00b97da2c5c 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -559,19 +559,13 @@ load_tree_sitter_if_necessary (bool required) #endif } -static void * -treesit_calloc_wrapper (size_t n, size_t size) -{ - return xzalloc (n * size); -} - static void treesit_initialize (void) { if (!treesit_initialized) { load_tree_sitter_if_necessary (true); - ts_set_allocator (xmalloc, treesit_calloc_wrapper, xrealloc, xfree); + ts_set_allocator (xmalloc, xcalloc, xrealloc, xfree); treesit_initialized = true; } } diff --git a/src/xfns.c b/src/xfns.c index 7ec6025ab66..ba3bf211f55 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -6254,7 +6254,7 @@ x_get_monitor_attributes_xinerama (struct x_display_info *dpyinfo) / x_display_pixel_width (dpyinfo)); mm_height_per_pixel = ((double) HeightMMOfScreen (dpyinfo->screen) / x_display_pixel_height (dpyinfo)); - monitors = xzalloc (n_monitors * sizeof *monitors); + monitors = xcalloc (n_monitors, sizeof *monitors); for (i = 0; i < n_monitors; ++i) { struct MonitorInfo *mi = &monitors[i]; @@ -6328,7 +6328,7 @@ x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo) if (!rr_monitors) goto fallback; - monitors = xzalloc (n_monitors * sizeof *monitors); + monitors = xcalloc (n_monitors, sizeof *monitors); #ifdef USE_XCB atom_name_cookies = alloca (n_monitors * sizeof *atom_name_cookies); #endif @@ -6427,7 +6427,7 @@ x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo) return Qnil; } n_monitors = resources->noutput; - monitors = xzalloc (n_monitors * sizeof *monitors); + monitors = xcalloc (n_monitors, sizeof *monitors); #if RANDR13_LIBRARY if (randr13_avail) @@ -6644,7 +6644,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) / x_display_pixel_height (dpyinfo)); #endif monitor_frames = make_nil_vector (n_monitors); - monitors = xzalloc (n_monitors * sizeof *monitors); + monitors = xcalloc (n_monitors, sizeof *monitors); FOR_EACH_FRAME (rest, frame) { diff --git a/src/xterm.c b/src/xterm.c index 941297a77ce..06fe480646e 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5730,7 +5730,7 @@ x_cache_xi_devices (struct x_display_info *dpyinfo) return; } - dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices); + dpyinfo->devices = xcalloc (ndevices, sizeof *dpyinfo->devices); for (i = 0; i < ndevices; ++i) { @@ -13881,7 +13881,7 @@ xi_disable_devices (struct x_display_info *dpyinfo, return; ndevices = 0; - devices = xzalloc (sizeof *devices * dpyinfo->num_devices); + devices = xcalloc (dpyinfo->num_devices, sizeof *devices); /* Loop through every device currently in DPYINFO, and copy it to DEVICES if it is not in TO_DISABLE. Note that this function From 19264b6912a111cfe426063ca431d202817f747d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 22 May 2026 12:29:37 -0700 Subject: [PATCH 081/112] adjust_glyph_matrix reallocation improvement * src/dispnew.c (adjust_glyph_matrix): Use xfree + xcalloc instead of xnrealloc + memset, as there is no need to preserve the old contents. --- src/dispnew.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 7930fa59968..fb313bfd1af 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -500,16 +500,15 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y while (row < end) { - /* Only realloc if matrix got wider or taller (bug#77961). */ + /* Realloc if matrix got wider or taller (bug#77961). */ if (dim.width > matrix->matrix_w || new_rows) { - row->glyphs[LEFT_MARGIN_AREA] - = xnrealloc (row->glyphs[LEFT_MARGIN_AREA], - dim.width, sizeof (struct glyph)); + xfree (row->glyphs[LEFT_MARGIN_AREA]); + row->glyphs[LEFT_MARGIN_AREA] = NULL; /* We actually need to clear only the 'frame' member, but it's easier to clear everything. */ - memset (row->glyphs[LEFT_MARGIN_AREA], 0, - dim.width * sizeof (struct glyph)); + row->glyphs[LEFT_MARGIN_AREA] + = xcalloc (dim.width, sizeof (struct glyph)); } if ((row == matrix->rows + dim.height - 1 From d12e8a94f7042a8490f3e2e40726390d3b735f58 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 22 May 2026 12:46:15 -0700 Subject: [PATCH 082/112] Update src/alloc.c comments --- src/alloc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 6a81fed2d69..1f4e5434e74 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -644,7 +644,7 @@ static_assert (MALLOC_IS_LISP_ALIGNED); malloc_probe (size); \ } while (0) -/* Like malloc but check for no memory and block interrupt input. */ +/* Like malloc but check for no memory, and profile allocations. */ void * xmalloc (size_t size) @@ -686,7 +686,7 @@ xcalloc (size_t n, size_t s) return val; } -/* Like realloc but check for no memory and block interrupt input. */ +/* Like realloc but check for no memory, and profile allocations. */ void * xrealloc (void *block, size_t size) @@ -699,7 +699,7 @@ xrealloc (void *block, size_t size) } -/* Like free but block interrupt input. */ +/* Like free but do not free pdumper objects. */ void xfree (void *block) @@ -721,7 +721,7 @@ static_assert (INT_MAX <= PTRDIFF_MAX); /* Allocate an array of NITEMS items, each of size ITEM_SIZE. - Signal an error on memory exhaustion, and block interrupt input. */ + Signal an error on memory exhaustion, and profile allocations. */ void * xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size) @@ -735,7 +735,7 @@ xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size) /* Reallocate an array PA to make it of NITEMS items, each of size ITEM_SIZE. - Signal an error on memory exhaustion, and block interrupt input. */ + Signal an error on memory exhaustion, and profile allocations. */ void * xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size) @@ -761,7 +761,7 @@ xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size) If PA is null, then allocate a new array instead of reallocating the old one. - Block interrupt input as needed. If memory exhaustion occurs, set + Profile memory allocations. If memory exhaustion occurs, set *NITEMS to zero if PA is null, and signal an error (i.e., do not return). From 4e5103a980765633a72a90b9f616bcc055306aa0 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 22 May 2026 17:19:33 -0700 Subject: [PATCH 083/112] Document PTRDIFF_MAX <= SIZE_MAX assumption * src/alloc.c: New static_assert. --- src/alloc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/alloc.c b/src/alloc.c index 1f4e5434e74..d6f11d06766 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -638,6 +638,14 @@ static_assert (LISP_ALIGNMENT % GCALIGNMENT == 0); enum { MALLOC_IS_LISP_ALIGNED = alignof (max_align_t) % LISP_ALIGNMENT == 0 }; static_assert (MALLOC_IS_LISP_ALIGNED); +/* Most of Emacs does not assume PTRDIFF_MAX <= SIZE_MAX, and may use + expressions like min (PTRDIFF_MAX, SIZE_MAX) to port even to + theoretical platforms where the assumption does not hold. + However, some parts of Emacs pass nonnegative ptrdiff_t values to + allocator functions like xmalloc that expect size_t. + This is portable in practice; check it here to document the assumption. */ +static_assert (PTRDIFF_MAX <= SIZE_MAX); + #define MALLOC_PROBE(size) \ do { \ if (profiler_memory_running) \ From ece22174e52debbd96f2129c16bb539f48e9b849 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 22 May 2026 17:32:45 -0700 Subject: [PATCH 084/112] Omit useless android_get_image casts * src/android.c (android_get_image): Omit useless and confusing casts. --- src/android.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/android.c b/src/android.c index cd950d3c51c..7ff7f26b527 100644 --- a/src/android.c +++ b/src/android.c @@ -4943,9 +4943,7 @@ android_get_image (android_drawable handle, if (bitmap_info.format != ANDROID_BITMAP_FORMAT_A_8) { - if (ckd_mul (&byte_size, - (size_t) bitmap_info.stride, - (size_t) bitmap_info.height)) + if (ckd_mul (&byte_size, bitmap_info.stride, bitmap_info.height)) { ANDROID_DELETE_LOCAL_REF (bitmap); memory_full_up (); From 1bee33c1c801adf5e3deeba7328b811b80c55f70 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 22 May 2026 18:11:09 -0700 Subject: [PATCH 085/112] sfnt_parse_languages does not need USE_SAFE_ALLOCA * src/sfntfont.c (sfnt_parse_languages): Simplify so that no local array is needed. --- src/sfntfont.c | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/src/sfntfont.c b/src/sfntfont.c index 4f49f03d744..858c5449ac7 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -581,20 +581,18 @@ static void sfnt_parse_languages (struct sfnt_meta_table *meta, struct sfnt_font_desc *desc) { - char *data, *metadata, *tag; + char *data; struct sfnt_meta_data_map map; - char *saveptr; /* Look up the ``design languages'' metadata. This is a comma (and possibly space) separated list of scripts that the font was designed for. Here is an example of one such tag: - zh-Hans,Jpan,Kore + zh-Hans,Japn,Kore for a font that covers Simplified Chinese, along with Japanese and Korean text. */ - saveptr = NULL; data = sfnt_find_metadata (meta, SFNT_META_DATA_TAG_DLNG, &map); @@ -608,34 +606,13 @@ sfnt_parse_languages (struct sfnt_meta_table *meta, return; } - USE_SAFE_ALLOCA; - - /* Now copy metadata and add a trailing NULL byte. */ - - if (map.data_length >= SIZE_MAX) - memory_full_up (); - - metadata = SAFE_ALLOCA ((size_t) map.data_length + 1); - memcpy (metadata, data, map.data_length); - metadata[map.data_length] = '\0'; - - /* Loop through each script-language tag. Note that there may be - extra leading spaces. */ - while ((tag = strtok_r (metadata, ",", &saveptr))) - { - metadata = NULL; - - if (strstr (tag, "Hans") || strstr (tag, "Hant")) - desc->languages = Fcons (Qzh, desc->languages); - - if (strstr (tag, "Japn")) - desc->languages = Fcons (Qja, desc->languages); - - if (strstr (tag, "Kore")) - desc->languages = Fcons (Qko, desc->languages); - } - - SAFE_FREE (); + if (memmem (data, map.data_length, "Hans", 4) + || memmem (data, map.data_length, "Hant", 4)) + desc->languages = Fcons (Qzh, desc->languages); + if (memmem (data, map.data_length, "Japn", 4)) + desc->languages = Fcons (Qja, desc->languages); + if (memmem (data, map.data_length, "Kore", 4)) + desc->languages = Fcons (Qko, desc->languages); } /* Return the font registry corresponding to the encoding subtable From fbd2f781b2a75554cc5571490198f7dfff18f9f3 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 23 May 2026 09:34:30 -0700 Subject: [PATCH 086/112] Be more careful about X selection sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/xselect.c (selection_data_for_offset): Offset is size_t, not long, since that’s what caller passes. (selection_data_size): Truncate large selection sizes to a value that is more likely to work without involving undefined behavior. Do not exceed X_ULONG_MAX which is all X can handle, or PTRDIFF_MAX which can confuse underlying code. (x_start_selection_transfer): Invoke selection_data_size just once. --- src/xselect.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/xselect.c b/src/xselect.c index 5be009af0d7..9e343f16544 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -712,7 +712,7 @@ x_size_for_format (int format) static unsigned char * selection_data_for_offset (struct selection_data *data, - long offset, size_t *remaining) + size_t offset, size_t *remaining) { unsigned char *base; size_t size; @@ -741,12 +741,17 @@ selection_data_for_offset (struct selection_data *data, /* Return the size, in bytes transferred to the X server, of data->size items of selection data in data->format-bit - quantities. */ + quantities. If this size is too large, silently return + the largest supported size in bytes for this format. + + FIXME: Silent truncation is bad. */ static size_t selection_data_size (struct selection_data *data) { size_t scratch; + ptrdiff_t max_selection_size = min (min (PTRDIFF_MAX, SIZE_MAX), + X_ULONG_MAX); if (!NILP (data->string)) return SBYTES (data->string); @@ -754,17 +759,19 @@ selection_data_size (struct selection_data *data) switch (data->format) { case 8: - return (size_t) data->size; + return min (data->size, max_selection_size); case 16: - if (ckd_mul (&scratch, data->size, 2)) - return SIZE_MAX; + if (ckd_mul (&scratch, data->size, 2) + || max_selection_size - max_selection_size % 2 < scratch) + return max_selection_size - max_selection_size % 2; return scratch; case 32: - if (ckd_mul (&scratch, data->size, 4)) - return SIZE_MAX; + if (ckd_mul (&scratch, data->size, 4) + || max_selection_size - max_selection_size % 4 < scratch) + return max_selection_size - max_selection_size % 4; return scratch; } @@ -885,12 +892,12 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, max_size = selection_quantum (dpyinfo->display); + size_t seldata_size = selection_data_size (&transfer->data); TRACE3 (" x_start_selection_transfer: transferring to 0x%lx. " "transfer consists of %zu bytes, quantum being %zu", - requestor, selection_data_size (&transfer->data), - max_size); + requestor, seldata_size, max_size); - if (selection_data_size (&transfer->data) > max_size) + if (max_size < seldata_size) { /* Begin incremental selection transfer. First, calculate how many elements it is ok to write for every ChangeProperty @@ -918,7 +925,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, /* Now, write the INCR property to begin incremental selection transfer. offset is currently 0. */ - data_size = selection_data_size (&transfer->data); + data_size = seldata_size; /* Set SELECTED_EVENTS before the actual XSelectInput request. */ From 82ad01b631a4ff4508bb3d37d32925d0cc6771ee Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 23 May 2026 09:38:36 -0700 Subject: [PATCH 087/112] Fix format typos in never-executed textconv.c * src/textconv.c (really_commit_text, really_replace_text): Use %td not %zd. --- src/textconv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/textconv.c b/src/textconv.c index 1331eb06a65..7a6dd4f05e6 100644 --- a/src/textconv.c +++ b/src/textconv.c @@ -633,7 +633,7 @@ really_commit_text (struct frame *f, EMACS_INT position, otherwise. */ mark = get_mark (); - TEXTCONV_DEBUG ("the mark is: %zd", mark); + TEXTCONV_DEBUG ("the mark is: %td", mark); if (MARKERP (f->conversion.compose_region_start) || mark != -1) { /* Replace its contents. Set START and END to the start and end @@ -651,7 +651,7 @@ really_commit_text (struct frame *f, EMACS_INT position, end = max (mark, PT); } - TEXTCONV_DEBUG ("replacing text in composing region: %zd, %zd", + TEXTCONV_DEBUG ("replacing text in composing region: %td, %td", start, end); /* If it transpires that the start of the compose region is not @@ -774,7 +774,7 @@ really_commit_text (struct frame *f, EMACS_INT position, call0 (Qdeactivate_mark); /* Print some debugging information. */ - TEXTCONV_DEBUG ("text inserted: %s, point now: %zd", + TEXTCONV_DEBUG ("text inserted: %s, point now: %td", SSDATA (text), PT); /* Update the ephemeral last point. */ @@ -1438,7 +1438,7 @@ really_replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end, } /* Print some debugging information. */ - TEXTCONV_DEBUG ("text inserted: %s, point now: %zd", + TEXTCONV_DEBUG ("text inserted: %s, point now: %td", SSDATA (text), PT); /* Update the ephemeral last point. */ From 2e91ed5f129a4c03f7345d15d61232bd15028a4e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 23 May 2026 09:59:25 -0700 Subject: [PATCH 088/112] Prefer ptrdiff_t to size_t when either will do Signed types are a bit safer, as they avoid some comparison confusion and -fsanitize=undefined can check more misuses of them. * src/alloc.c (lisp_malloc, lisp_align_malloc) (allocate_string_data, allocate_vector_from_block, object_bytes): * src/coding.c (from_unicode_buffer): * src/decompress.c (acc_size, accumulate_and_process_md5): * src/emacs.c (load_seccomp, shut_down_emacs): * src/fns.c (sxhash_bignum): * src/ftfont.c (get_adstyle_property): * src/image.c (lookup_image, xpm_init_color_cache) (xpm_cache_color): * src/json.c (json_out_str, struct json_parser) (json_make_object_workspace_for_slow_path) (json_make_object_workspace_for, json_parse_array) (json_parse_object): * src/sysdep.c (get_current_dir_name_or_unreachable) (init_sys_modes, convert_speed): * src/termchar.h (struct tty_display_info): * src/textconv.h (struct textconv_conversion_text): * src/xfns.c (struct x_xim_text_conversion_data) (x_encode_xim_text): * src/xselect.c (struct transfer, c_size_for_format) (x_size_for_format, selection_data_for_offset) (selection_data_size, x_start_selection_transfer) (x_continue_selection_transfer): Prefer ptrdiff_t to size_t when either will do. * src/term.c (Ftty__set_output_buffer_size): Limit output buffer size to PTRDIFF_MAX as well as to SIZE_MAX. --- src/alloc.c | 16 ++++++++-------- src/coding.c | 12 +++++------- src/decompress.c | 4 ++-- src/emacs.c | 28 +++++++++++----------------- src/fns.c | 6 +++--- src/ftfont.c | 3 +-- src/image.c | 8 ++++---- src/json.c | 26 ++++++++++++-------------- src/sysdep.c | 10 +++++----- src/term.c | 2 +- src/termchar.h | 2 +- src/textconv.h | 2 +- src/xfns.c | 4 ++-- src/xselect.c | 30 +++++++++++++++--------------- 14 files changed, 71 insertions(+), 82 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index d6f11d06766..ed0d6f4976d 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -899,7 +899,7 @@ void *lisp_malloc_loser EXTERNALLY_VISIBLE; L == make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T. */ static void * -lisp_malloc (size_t nbytes, bool clearit, enum mem_type type) +lisp_malloc (ptrdiff_t nbytes, bool clearit, enum mem_type type) { register void *val; @@ -1083,7 +1083,7 @@ pointer_align (void *ptr, int alignment) Alignment is on a multiple of BLOCK_ALIGN and `nbytes' has to be smaller or equal to BLOCK_BYTES. */ static void * -lisp_align_malloc (size_t nbytes, enum mem_type type) +lisp_align_malloc (ptrdiff_t nbytes, enum mem_type type) { void *base, *val; struct ablocks *abase; @@ -1522,7 +1522,7 @@ sdata_size (ptrdiff_t n) /* Exact bound on the number of bytes in a string, not counting the terminating null. A string cannot contain more bytes than - STRING_BYTES_BOUND, nor can it be so long that the size_t + STRING_BYTES_BOUND, nor can it be so long that the arithmetic in allocate_string_data would overflow while it is calculating a value to be passed to malloc. */ static ptrdiff_t const STRING_BYTES_MAX = @@ -1768,7 +1768,7 @@ allocate_string_data (struct Lisp_String *s, if (nbytes > LARGE_STRING_BYTES || immovable) { - size_t size = FLEXSIZEOF (struct sblock, data, needed); + ptrdiff_t size = FLEXSIZEOF (struct sblock, data, needed); #ifdef DOUG_LEA_MALLOC if (!mmap_lisp_allowed_p ()) @@ -2996,7 +2996,7 @@ allocate_vector_from_block (ptrdiff_t nbytes) { struct Lisp_Vector *vector; struct vector_block *block; - size_t index, restbytes; + ptrdiff_t index, restbytes; eassume (VBLOCK_BYTES_MIN <= nbytes && nbytes <= VBLOCK_BYTES_MAX); eassume (nbytes % roundup_size == 0); @@ -3022,7 +3022,7 @@ allocate_vector_from_block (ptrdiff_t nbytes) { /* This vector is larger than requested. */ vector = vector_free_lists[index]; - size_t vector_nbytes = pseudovector_nbytes (&vector->header); + ptrdiff_t vector_nbytes = pseudovector_nbytes (&vector->header); eassert (vector_nbytes > nbytes); ASAN_UNPOISON_VECTOR_CONTENTS (vector, nbytes - header_size); vector_free_lists[index] = next_vector (vector); @@ -5465,10 +5465,10 @@ inhibit_garbage_collection (void) } /* Return the number of bytes in N objects each of size S, guarding - against overflow if size_t is narrower than byte_ct. */ + against overflow if ptrdiff_t is narrower than byte_ct. */ static byte_ct -object_bytes (object_ct n, size_t s) +object_bytes (object_ct n, ptrdiff_t s) { byte_ct b = s; return n * b; diff --git a/src/coding.c b/src/coding.c index 9aba2a7eacc..7d2c7040ab8 100644 --- a/src/coding.c +++ b/src/coding.c @@ -8554,19 +8554,17 @@ from_unicode_buffer (const wchar_t *wstr) strings are extended to 32-bit wchar_t. */ uint16_t *words; - size_t length, i; - - length = wcslen (wstr) + 1; + ptrdiff_t length = wcslen (wstr); USE_SAFE_ALLOCA; - SAFE_NALLOCA (words, sizeof *words, length); + SAFE_NALLOCA (words, sizeof *words, length + 1); - for (i = 0; i < length - 1; ++i) + for (ptrdiff_t i = 0; i < length; i++) words[i] = wstr[i]; + words[length] = '\0'; - words[i] = '\0'; AUTO_STRING_WITH_LEN (str, (char *) words, - (length - 1) * sizeof *words); + length * sizeof *words); return unbind_to (sa_count, from_unicode (str)); #endif } diff --git a/src/decompress.c b/src/decompress.c index c81559c25f0..bb3ed6d7d6d 100644 --- a/src/decompress.c +++ b/src/decompress.c @@ -70,10 +70,10 @@ init_zlib_functions (void) # define MD5_BLOCKSIZE 32768 /* From md5.c */ static char acc_buff[2 * MD5_BLOCKSIZE]; -static size_t acc_size; +static ptrdiff_t acc_size; static void -accumulate_and_process_md5 (void *data, size_t len, struct md5_ctx *ctxt) +accumulate_and_process_md5 (void *data, ptrdiff_t len, struct md5_ctx *ctxt) { eassert (len <= MD5_BLOCKSIZE); /* We may optimize this saving some of these memcpy/move using diff --git a/src/emacs.c b/src/emacs.c index a9b970effb4..d50f817cefc 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1235,39 +1235,33 @@ load_seccomp (const char *file) file, (long) stat.st_size); goto out; } - size_t size = stat.st_size; - size_t count = size / sizeof *program.filter; - eassert (0 < count && count < SIZE_MAX); - if (USHRT_MAX < count) + if (ckd_add (&program.len, stat.st_size / sizeof *program.filter, 0)) { fprintf (stderr, "seccomp filter %s is too big\n", file); goto out; } /* Try reading one more byte to detect file size changes. */ + ptrdiff_t size = stat.st_size; buffer = malloc (size + 1); if (buffer == NULL) { emacs_perror ("malloc"); goto out; } - ptrdiff_t read = read_full (fd, buffer, size + 1); - if (read < 0) + ptrdiff_t nread = read_full (fd, buffer, size + 1); + if (nread != size) { - emacs_perror ("read"); - goto out; - } - eassert (read <= SIZE_MAX); - if (read != size) - { - fprintf (stderr, - "seccomp filter %s changed size while reading\n", - file); + if (nread < 0) + emacs_perror ("read"); + else + fprintf (stderr, + "seccomp filter %s changed size while reading\n", + file); goto out; } if (emacs_close (fd) != 0) emacs_perror ("close"); /* not a fatal error */ fd = -1; - program.len = count; program.filter = buffer; /* See man page of `seccomp' why this is necessary. Note that we @@ -3131,7 +3125,7 @@ shut_down_emacs (int sig, Lisp_Object stuff) + INT_STRLEN_BOUND (int) + 1), min (PIPE_BUF, MAX_ALLOCA))]; char const *sig_desc = safe_strsignal (sig); - size_t sig_desclen = strlen (sig_desc); + ptrdiff_t sig_desclen = strlen (sig_desc); int nlen = sprintf (buf, fmt, sig); if (nlen + sig_desclen < sizeof buf - 1) { diff --git a/src/fns.c b/src/fns.c index 98671fc1318..e3d297102ca 100644 --- a/src/fns.c +++ b/src/fns.c @@ -5480,10 +5480,10 @@ static EMACS_UINT sxhash_bignum (Lisp_Object bignum) { mpz_t const *n = xbignum_val (bignum); - size_t i, nlimbs = mpz_size (*n); - EMACS_UINT hash = mpz_sgn(*n) < 0; + ptrdiff_t nlimbs = mpz_size (*n); + EMACS_UINT hash = mpz_sgn (*n) < 0; - for (i = 0; i < nlimbs; ++i) + for (ptrdiff_t i = 0; i < nlimbs; i++) hash = sxhash_combine (hash, mpz_getlimbn (*n, i)); return hash; diff --git a/src/ftfont.c b/src/ftfont.c index 6de7110e5bb..44c22d359b5 100644 --- a/src/ftfont.c +++ b/src/ftfont.c @@ -150,7 +150,6 @@ get_adstyle_property (FcPattern *p) { FcChar8 *fcstr; char *str, *end, *tmp; - size_t i; Lisp_Object adstyle; #ifdef FC_FONTFORMAT @@ -173,7 +172,7 @@ get_adstyle_property (FcPattern *p) and therefore must be replaced by substitutes. (bug#70989) */ USE_SAFE_ALLOCA; tmp = SAFE_ALLOCA (end - str); - for (i = 0; i < end - str; ++i) + for (ptrdiff_t i = 0; i < end - str; i++) tmp[i] = ((str[i] != '?' && str[i] != '*' && str[i] != '"' diff --git a/src/image.c b/src/image.c index 38f9d1416a7..f41a08eb1a8 100644 --- a/src/image.c +++ b/src/image.c @@ -3562,7 +3562,7 @@ 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; - size_t len = strlen (font_family) + 1; + ptrdiff_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); @@ -5538,7 +5538,7 @@ static struct xpm_cached_color **xpm_color_cache; static void xpm_init_color_cache (struct frame *f, XpmAttributes *attrs) { - size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache; + ptrdiff_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache; xpm_color_cache = xzalloc (nbytes); init_color_table (); @@ -5598,8 +5598,8 @@ xpm_cache_color (struct frame *f, char *color_name, XColor *color, int bucket) if (bucket < 0) bucket = xpm_color_bucket (color_name); - size_t len = strlen (color_name) + 1; - size_t nbytes = FLEXSIZEOF (struct xpm_cached_color, name, len); + ptrdiff_t len = strlen (color_name) + 1; + ptrdiff_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; diff --git a/src/json.c b/src/json.c index 720654bac43..5186667a9d2 100644 --- a/src/json.c +++ b/src/json.c @@ -273,7 +273,7 @@ json_make_room (json_out_t *jo, ptrdiff_t bytes) /* Add `bytes` bytes from `str` to the buffer. */ static void -json_out_str (json_out_t *jo, const char *str, size_t bytes) +json_out_str (json_out_t *jo, const char *str, ptrdiff_t bytes) { json_make_room (jo, bytes); memcpy (jo->buf + jo->size, str, bytes); @@ -693,7 +693,7 @@ struct json_parser struct json_configuration conf; - size_t additional_bytes_count; + ptrdiff_t additional_bytes_count; /* Lisp_Objects are collected in this area during object/array parsing. To avoid allocations, initially @@ -704,8 +704,8 @@ struct json_parser Lisp_Object internal_object_workspace [JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE]; Lisp_Object *object_workspace; - size_t object_workspace_size; - size_t object_workspace_current; + ptrdiff_t object_workspace_size; + ptrdiff_t object_workspace_current; /* String and number parsing uses this workspace. The idea behind internal_byte_workspace is the same as the idea behind @@ -805,10 +805,9 @@ json_make_object_workspace_for_slow_path (struct json_parser *parser, { bool internal = (parser->object_workspace_size == JSON_PARSER_INTERNAL_OBJECT_WORKSPACE_SIZE); - ptrdiff_t new_workspace_size = parser->object_workspace_size; Lisp_Object *new_workspace_ptr = xpalloc (internal ? NULL : parser->object_workspace, - &new_workspace_size, + &parser->object_workspace_size, size - (parser->object_workspace_size - parser->object_workspace_current), -1, sizeof (Lisp_Object)); @@ -816,12 +815,11 @@ json_make_object_workspace_for_slow_path (struct json_parser *parser, memcpy (new_workspace_ptr, parser->object_workspace, sizeof (Lisp_Object) * parser->object_workspace_current); parser->object_workspace = new_workspace_ptr; - parser->object_workspace_size = new_workspace_size; } INLINE void json_make_object_workspace_for (struct json_parser *parser, - size_t size) + ptrdiff_t size) { if (parser->object_workspace_size - parser->object_workspace_current < size) @@ -1350,7 +1348,7 @@ json_parse_array (struct json_parser *parser) { int c = json_skip_whitespace (parser); - const size_t first = parser->object_workspace_current; + const ptrdiff_t first = parser->object_workspace_current; Lisp_Object result = Qnil; if (c != ']') @@ -1402,10 +1400,10 @@ json_parse_array (struct json_parser *parser) { case json_array_array: { - size_t number_of_elements + ptrdiff_t number_of_elements = parser->object_workspace_current - first; result = make_vector (number_of_elements, Qnil); - for (size_t i = 0; i < number_of_elements; i++) + for (ptrdiff_t i = 0; i < number_of_elements; i++) { rarely_quit (i); ASET (result, i, parser->object_workspace[first + i]); @@ -1441,7 +1439,7 @@ json_parse_object (struct json_parser *parser) { int c = json_skip_whitespace (parser); - const size_t first = parser->object_workspace_current; + const ptrdiff_t first = parser->object_workspace_current; Lisp_Object result = Qnil; if (c != '}') @@ -1517,10 +1515,10 @@ json_parse_object (struct json_parser *parser) { case json_object_hashtable: { - EMACS_INT value = (parser->object_workspace_current - first) / 2; + EMACS_INT value = (parser->object_workspace_current - first) >> 1; result = make_hash_table (&hashtest_equal, value, Weak_None); struct Lisp_Hash_Table *h = XHASH_TABLE (result); - for (size_t i = first; i < parser->object_workspace_current; i += 2) + for (ptrdiff_t i = first; i < parser->object_workspace_current; i += 2) { hash_hash_t hash; Lisp_Object key = parser->object_workspace[i]; diff --git a/src/sysdep.c b/src/sysdep.c index b2cd769784c..2f48b7c6681 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -304,7 +304,7 @@ get_current_dir_name_or_unreachable (void) } # endif - size_t pwdlen; + ptrdiff_t pwdlen; struct stat dotstat, pwdstat; pwd = getenv ("PWD"); @@ -1310,9 +1310,9 @@ init_sys_modes (struct tty_display_info *tty_out) } #endif /* F_GETOWN */ - const size_t buffer_size = (tty_out->output_buffer_size - ? tty_out->output_buffer_size - : BUFSIZ); + const ptrdiff_t buffer_size = (tty_out->output_buffer_size + ? tty_out->output_buffer_size + : BUFSIZ); setvbuf (tty_out->output, NULL, _IOFBF, buffer_size); if (tty_out->terminal->set_terminal_modes_hook) @@ -3136,7 +3136,7 @@ static const struct speed_struct speeds[] = static speed_t convert_speed (speed_t speed) { - for (size_t i = 0; i < ARRAYELTS (speeds); i++) + for (ptrdiff_t i = 0; i < ARRAYELTS (speeds); i++) { if (speed == speeds[i].internal) return speed; diff --git a/src/term.c b/src/term.c index e4fdb85831c..8047e4102a1 100644 --- a/src/term.c +++ b/src/term.c @@ -2613,7 +2613,7 @@ This function temporarily suspends and resumes the terminal device. */) (Lisp_Object size, Lisp_Object tty) { - if (!TYPE_RANGED_FIXNUMP (size_t, size)) + if (!RANGED_FIXNUMP (0, size, min (PTRDIFF_MAX, SIZE_MAX))) error ("Invalid output buffer size"); Fsuspend_tty (tty); struct terminal *terminal = decode_tty_terminal (tty); diff --git a/src/termchar.h b/src/termchar.h index d9390db17b2..5bc2dd84bee 100644 --- a/src/termchar.h +++ b/src/termchar.h @@ -56,7 +56,7 @@ struct tty_display_info /* Size of output buffer. A value of zero means use the default of BUFIZE. If non-zero, also minimize writes to the tty by avoiding calls to flush. */ - size_t output_buffer_size; + ptrdiff_t output_buffer_size; FILE *termscript; /* If nonzero, send all terminal output characters to this stream also. */ diff --git a/src/textconv.h b/src/textconv.h index bd6bf06bb76..5ab2c052fa3 100644 --- a/src/textconv.h +++ b/src/textconv.h @@ -80,7 +80,7 @@ enum textconv_operation struct textconv_conversion_text { /* Length of the text in characters and bytes. */ - size_t length, bytes; + ptrdiff_t length, bytes; /* Pointer to the text data. This must be deallocated by the caller. */ diff --git a/src/xfns.c b/src/xfns.c index ba3bf211f55..976218819dd 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -3467,7 +3467,7 @@ struct x_xim_text_conversion_data struct coding_system *coding; char *source; struct x_display_info *dpyinfo; - size_t size; + ptrdiff_t size; }; static Lisp_Object @@ -3600,7 +3600,7 @@ x_xim_text_to_utf8_unix (struct x_display_info *dpyinfo, static char * x_encode_xim_text (struct x_display_info *dpyinfo, char *text, - size_t size, ptrdiff_t *length, + ptrdiff_t size, ptrdiff_t *length, ptrdiff_t *chars) { struct coding_system coding; diff --git a/src/xselect.c b/src/xselect.c index 9e343f16544..27b83825b34 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -522,7 +522,7 @@ struct transfer /* The current offset in items into the selection data, and the number of items to send with each ChangeProperty request. */ - size_t offset, items_per_request; + ptrdiff_t offset, items_per_request; /* The display info associated with the transfer. */ struct x_display_info *dpyinfo; @@ -669,7 +669,7 @@ x_selection_request_lisp_error (void) -static size_t +static ptrdiff_t c_size_for_format (int format) { switch (format) @@ -687,7 +687,7 @@ c_size_for_format (int format) emacs_abort (); } -static size_t +static ptrdiff_t x_size_for_format (int format) { switch (format) @@ -712,10 +712,10 @@ x_size_for_format (int format) static unsigned char * selection_data_for_offset (struct selection_data *data, - size_t offset, size_t *remaining) + ptrdiff_t offset, ptrdiff_t *remaining) { unsigned char *base; - size_t size; + ptrdiff_t size; if (!NILP (data->string)) { @@ -746,10 +746,10 @@ selection_data_for_offset (struct selection_data *data, FIXME: Silent truncation is bad. */ -static size_t +static ptrdiff_t selection_data_size (struct selection_data *data) { - size_t scratch; + ptrdiff_t scratch; ptrdiff_t max_selection_size = min (min (PTRDIFF_MAX, SIZE_MAX), X_ULONG_MAX); @@ -856,7 +856,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, intmax_t timeout; intmax_t secs; int nsecs; - size_t remaining, max_size; + ptrdiff_t remaining, max_size; unsigned char *xdata; unsigned long data_size; @@ -892,9 +892,9 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, max_size = selection_quantum (dpyinfo->display); - size_t seldata_size = selection_data_size (&transfer->data); + ptrdiff_t seldata_size = selection_data_size (&transfer->data); TRACE3 (" x_start_selection_transfer: transferring to 0x%lx. " - "transfer consists of %zu bytes, quantum being %zu", + "transfer consists of %tu bytes, quantum being %tu", requestor, seldata_size, max_size); if (max_size < seldata_size) @@ -905,7 +905,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, transfer->items_per_request = (max_size / x_size_for_format (transfer->data.format)); TRACE1 (" x_start_selection_transfer: starting incremental" - " selection transfer, with %zu items per request", + " selection transfer, with %tu items per request", transfer->items_per_request); /* Next, link the transfer onto the list of pending selection @@ -954,7 +954,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, eassert (remaining <= INT_MAX); TRACE1 (" x_start_selection_transfer: writing" - " %zu elements directly to requestor window", + " %tu elements directly to requestor window", remaining); x_ignore_errors_for_next_request (dpyinfo, 0); @@ -977,7 +977,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, static void x_continue_selection_transfer (struct transfer *transfer) { - size_t remaining; + ptrdiff_t remaining; unsigned char *xdata; xdata = selection_data_for_offset (&transfer->data, @@ -1006,8 +1006,8 @@ x_continue_selection_transfer (struct transfer *transfer) } else { - TRACE2 (" x_continue_selection_transfer: writing %zu items" - "; current offset is %zu", remaining, transfer->offset); + TRACE2 (" x_continue_selection_transfer: writing %tu items" + "; current offset is %tu", remaining, transfer->offset); eassert (remaining <= INT_MAX); transfer->offset += remaining; From 7e0d4fae01f2f1c7411297b1fb99ecdf82bfdea4 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 23 May 2026 11:52:09 -0700 Subject: [PATCH 089/112] Simplify sfnt.c by using long long MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even the earliest Android had plain ‘long long’, so use that instead of doing it by hand. * src/sfnt.c (struct sfnt_large_integer, sfnt_multiply_divide_1) (sfnt_multiply_divide_2, sfnt_large_integer_add) (sfnt_multiply_divide_round) [!INT64_MAX]: Remove. (sfnt_multiply_divide, sfnt_multiply_divide_rounded) (sfnt_mul_fixed, sfnt_mul_fixed_round, sfnt_div_fixed) (sfnt_div_f26dot6, sfnt_mul_f26dot6, sfnt_mul_f26dot6_round) (sfnt_mul_f2dot14, sfnt_dot_fix_14): Simplify by using long long. --- src/sfnt.c | 353 +++-------------------------------------------------- 1 file changed, 17 insertions(+), 336 deletions(-) diff --git a/src/sfnt.c b/src/sfnt.c index e46ebc3a08b..225b172cb40 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -3647,161 +3647,23 @@ sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed y) return outline; } -#ifndef INT64_MAX - -/* 64 bit integer type. */ - -struct sfnt_large_integer -{ - unsigned int high, low; -}; - -/* Calculate (A * B), placing the result in *VALUE. */ - -static void -sfnt_multiply_divide_1 (unsigned int a, unsigned int b, - struct sfnt_large_integer *value) -{ - unsigned int lo1, hi1, lo2, hi2, lo, hi, i1, i2; - - lo1 = a & 0x0000ffffu; - hi1 = a >> 16; - lo2 = b & 0x0000ffffu; - hi2 = b >> 16; - - lo = lo1 * lo2; - i1 = lo1 * hi2; - i2 = lo2 * hi1; - hi = hi1 * hi2; - - /* Check carry overflow of i1 + i2. */ - i1 += i2; - hi += (unsigned int) (i1 < i2) << 16; - - hi += i1 >> 16; - i1 = i1 << 16; - - /* Check carry overflow of i1 + lo. */ - lo += i1; - hi += (lo < i1); - - value->low = lo; - value->high = hi; -} - -/* Calculate AB / C. Value is a 32 bit unsigned integer. */ - -static unsigned int -sfnt_multiply_divide_2 (struct sfnt_large_integer *ab, - unsigned int c) -{ - unsigned int hi, lo; - int i; - unsigned int r, q; /* Remainder and quotient. */ - - hi = ab->high; - lo = ab->low; - - i = stdc_leading_zeros (hi); - r = (hi << i) | (lo >> (32 - i)); - lo <<= i; - q = r / c; - r -= q * c; - i = 32 - i; - - do - { - q <<= 1; - r = (r << 1) | (lo >> 31); - lo <<= 1; - - if (r >= c) - { - r -= c; - q |= 1; - } - } - while (--i); - - return q; -} - -/* Add the specified unsigned 32-bit N to the large integer - INTEGER. */ - -static void -sfnt_large_integer_add (struct sfnt_large_integer *integer, - uint32_t n) -{ - struct sfnt_large_integer number; - - number.low = integer->low + n; - number.high = integer->high + (number.low - < integer->low); - - *integer = number; -} - -#endif /* !INT64_MAX */ - -/* Calculate (A * B) / C with no rounding and return the result, using - a 64 bit integer if necessary. */ +/* Calculate (A * B) / C with no rounding and return the result. */ static unsigned int sfnt_multiply_divide (unsigned int a, unsigned int b, unsigned int c) { -#ifndef INT64_MAX - struct sfnt_large_integer temp; - - sfnt_multiply_divide_1 (a, b, &temp); - return sfnt_multiply_divide_2 (&temp, c); -#else /* INT64_MAX */ - uint64_t temp; - - temp = (uint64_t) a * (uint64_t) b; - return temp / c; -#endif /* !INT64_MAX */ + return a * (unsigned long long int) {b} / c; } -/* Calculate (A * B) / C with rounding and return the result, using a - 64 bit integer if necessary. */ +/* Calculate (A * B) / C with rounding and return the result. */ static unsigned int sfnt_multiply_divide_rounded (unsigned int a, unsigned int b, unsigned int c) { -#ifndef INT64_MAX - struct sfnt_large_integer temp; - - sfnt_multiply_divide_1 (a, b, &temp); - sfnt_large_integer_add (&temp, c / 2); - return sfnt_multiply_divide_2 (&temp, c); -#else /* INT64_MAX */ - uint64_t temp; - - temp = (uint64_t) a * (uint64_t) b + c / 2; - return temp / c; -#endif /* !INT64_MAX */ + return (a * (unsigned long long int) {b} + c / 2) / c; } -#ifndef INT64_MAX - -/* Calculate (A * B) / C, rounding the result with a threshold of N. - Use a 64 bit temporary. */ - -static unsigned int -sfnt_multiply_divide_round (unsigned int a, unsigned int b, - unsigned int n, unsigned int c) -{ - struct sfnt_large_integer temp; - - sfnt_multiply_divide_1 (a, b, &temp); - sfnt_large_integer_add (&temp, n); - return sfnt_multiply_divide_2 (&temp, c); -} - -#endif /* !INT64_MAX */ - /* The same as sfnt_multiply_divide_rounded, but handle signed values instead. */ @@ -3831,27 +3693,7 @@ sfnt_multiply_divide_signed (int a, int b, int c) static sfnt_fixed sfnt_mul_fixed (sfnt_fixed x, sfnt_fixed y) { -#ifdef INT64_MAX - int64_t product; - - product = (int64_t) x * (int64_t) y; - - /* This can be done quickly with int64_t. */ - return product / (int64_t) 65536; -#else /* !INT64_MAX */ - int sign; - - sign = 1; - - if (x < 0) - sign = -sign; - - if (y < 0) - sign = -sign; - - return sfnt_multiply_divide (abs (x), abs (y), - 65536) * sign; -#endif /* INT64_MAX */ + return x * (long long int) {y} / (1 << 16); } /* Multiply the two 16.16 fixed point numbers X and Y, with rounding @@ -3860,28 +3702,8 @@ sfnt_mul_fixed (sfnt_fixed x, sfnt_fixed y) static sfnt_fixed sfnt_mul_fixed_round (sfnt_fixed x, sfnt_fixed y) { -#ifdef INT64_MAX - int64_t product, round; - - product = (int64_t) x * (int64_t) y; - round = product < 0 ? -32768 : 32768; - - /* This can be done quickly with int64_t. */ - return (product + round) / (int64_t) 65536; -#else /* !INT64_MAX */ - int sign; - - sign = 1; - - if (x < 0) - sign = -sign; - - if (y < 0) - sign = -sign; - - return sfnt_multiply_divide_round (abs (x), abs (y), - 32768, 65536) * sign; -#endif /* INT64_MAX */ + long long int product = x * (long long int) {y}; + return (product + (product < 0 ? -(1 << 15) : 1 << 15)) / (1 << 16); } /* Set the pen size to the specified point and return. POINT will be @@ -3924,29 +3746,7 @@ sfnt_line_to_and_build (struct sfnt_point point, void *dcontext) static sfnt_fixed sfnt_div_fixed (sfnt_fixed x, sfnt_fixed y) { -#ifdef INT64_MAX - int64_t result; - - result = ((int64_t) x * 65536) / y; - - return result; -#else - int sign; - unsigned int a, b; - - sign = 1; - - if (x < 0) - sign = -sign; - - if (y < 0) - sign = -sign; - - a = abs (x); - b = abs (y); - - return sfnt_multiply_divide (a, 65536, b) * sign; -#endif + return x * (1LL << 16) / y; } /* Return the ceiling value of the specified fixed point number X. */ @@ -6391,29 +6191,7 @@ sfnt_read_prep_table (int fd, struct sfnt_offset_subtable *subtable) static sfnt_f26dot6 sfnt_div_f26dot6 (sfnt_f26dot6 x, sfnt_f26dot6 y) { -#ifdef INT64_MAX - int64_t result; - - result = ((int64_t) x * 64) / y; - - return result; -#else - int sign; - unsigned int a, b; - - sign = 1; - - if (x < 0) - sign = -sign; - - if (y < 0) - sign = -sign; - - a = abs (x); - b = abs (y); - - return sfnt_multiply_divide (a, 64, b) * sign; -#endif + return x * (1LL << 6) / y; } /* Multiply the specified two 26.6 fixed point numbers A and B. @@ -6422,27 +6200,7 @@ sfnt_div_f26dot6 (sfnt_f26dot6 x, sfnt_f26dot6 y) static sfnt_f26dot6 sfnt_mul_f26dot6 (sfnt_f26dot6 a, sfnt_f26dot6 b) { -#ifdef INT64_MAX - int64_t product; - - product = (int64_t) a * (int64_t) b; - - /* This can be done quickly with int64_t. */ - return product / (int64_t) 64; -#else - int sign; - - sign = 1; - - if (a < 0) - sign = -sign; - - if (b < 0) - sign = -sign; - - return sfnt_multiply_divide (abs (a), abs (b), - 64) * sign; -#endif + return a * (long long int) {b} / (1 << 6); } /* Multiply the specified two 26.6 fixed point numbers A and B, with @@ -6452,27 +6210,7 @@ sfnt_mul_f26dot6 (sfnt_f26dot6 a, sfnt_f26dot6 b) static sfnt_f26dot6 sfnt_mul_f26dot6_round (sfnt_f26dot6 a, sfnt_f26dot6 b) { -#ifdef INT64_MAX - int64_t product; - - product = (int64_t) a * (int64_t) b; - - /* This can be done quickly with int64_t. */ - return (product + 32) / (int64_t) 64; -#else /* !INT64_MAX */ - int sign; - - sign = 1; - - if (a < 0) - sign = -sign; - - if (b < 0) - sign = -sign; - - return sfnt_multiply_divide_round (abs (a), abs (b), - 32, 64) * sign; -#endif /* INT64_MAX */ + return (a * (long long int) {b} + (1 << 5)) / (1 << 6); } /* Multiply the specified 2.14 number with another signed 32 bit @@ -6481,26 +6219,7 @@ sfnt_mul_f26dot6_round (sfnt_f26dot6 a, sfnt_f26dot6 b) static int32_t sfnt_mul_f2dot14 (sfnt_f2dot14 a, int32_t b) { -#ifdef INT64_MAX - int64_t product; - - product = (int64_t) a * (int64_t) b; - - return product / (int64_t) 16384; -#else - int sign; - - sign = 1; - - if (a < 0) - sign = -sign; - - if (b < 0) - sign = -sign; - - return sfnt_multiply_divide (abs (a), abs (b), - 16384) * sign; -#endif + return a * (long long int) {b} / (1 << 14); } /* Multiply the specified 26.6 fixed point number X by the specified @@ -10596,46 +10315,9 @@ sfnt_project_onto_y_axis_vector (sfnt_f26dot6 vx, sfnt_f26dot6 vy, static int32_t sfnt_dot_fix_14 (int32_t ax, int32_t ay, int bx, int by) { -#ifndef INT64_MAX - int32_t m, s, hi1, hi2, hi; - uint32_t l, lo1, lo2, lo; - - - /* Compute ax*bx as 64-bit value. */ - l = (uint32_t) ((ax & 0xffffu) * bx); - m = (ax >> 16) * bx; - - lo1 = l + ((uint32_t) m << 16); - hi1 = (m >> 16) + ((int32_t) l >> 31) + (lo1 < l); - - /* Compute ay*by as 64-bit value. */ - l = (uint32_t) ((ay & 0xffffu) * by); - m = (ay >> 16) * by; - - lo2 = l + ((uint32_t) m << 16); - hi2 = (m >> 16) + ((int32_t) l >> 31) + (lo2 < l); - - /* Add them. */ - lo = lo1 + lo2; - hi = hi1 + hi2 + (lo < lo1); - - /* Divide the result by 2^14 with rounding. */ - s = hi >> 31; - l = lo + (uint32_t) s; - hi += s + (l < lo); - lo = l; - - l = lo + 0x2000u; - hi += (l < lo); - - return (int32_t) (((uint32_t) hi << 18) | (l >> 14)); -#else - int64_t xx, yy; - int64_t temp; - - xx = (int64_t) ax * bx; - yy = (int64_t) ay * by; - + long long int + xx = ax * (long long int) {bx}, + yy = ay * (long long int) {by}; xx += yy; yy = xx >> 63; xx += 0x2000 + yy; @@ -10643,10 +10325,9 @@ sfnt_dot_fix_14 (int32_t ax, int32_t ay, int bx, int by) /* TrueType fonts rely on "division" here truncating towards negative infinity, so compute the arithmetic right shift in place of division. */ - temp = -(xx < 0); + long long int temp = -(xx < 0); temp = (temp ^ xx) >> 14 ^ temp; - return (int32_t) (temp); -#endif + return temp; } /* Project the specified vector VX and VY onto the unit vector that is From c4e20777c26548722a37b03db93243e83a0d6188 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 23 May 2026 17:55:11 -0700 Subject: [PATCH 090/112] Better size overflow checking for sfnt.c * src/sfnt.c (memory_full_up) [TEST]: New static function. (xmalloc, xcalloc, xrealloc): Use it instead of aborting. (eassert) [TEST]: Remove; no longer needed. (xaddmalloc, xaddrealloc): New static convenience functions. (sfnt_read_cmap_format_12, sfnt_read_loca_table_short) (sfnt_read_loca_table_long, sfnt_read_glyf_table) (sfnt_read_simple_glyph, sfnt_read_compound_glyph) (sfnt_read_glyph, sfnt_build_append, sfnt_build_outline_edges) (sfnt_raster_glyph_outline, sfnt_build_outline_fedges) (sfnt_raster_glyph_outline_exact, sfnt_read_hmtx_table) (sfnt_read_name_table, sfnt_read_meta_table) (sfnt_read_ttc_header, sfnt_read_fpgm_table) (sfnt_read_prep_table, sfnt_create_uvs_context) (sfnt_read_gvar_table, sfnt_read_packed_deltas) (sfnt_vary_simple_glyph, sfnt_vary_compound_glyph): Use the new functions to test for size overflow more reliably. Use a cleaner way to decide whether a pointer addresses the heap not the stack and thus needs freeing. Fix a few more unlikely overflows. (sfnt_read_cmap_format_12): The recently-added eassert is no longer needed, so remove it. (sfnt_read_simple_glyph): Initialize glyph->simple early to simplify later code, as is done in similar functions. Complicate size test to avoid potential unsigned overflow. --- src/sfnt.c | 278 ++++++++++++++++++++++++++++------------------------- 1 file changed, 148 insertions(+), 130 deletions(-) diff --git a/src/sfnt.c b/src/sfnt.c index 225b172cb40..5c3c2c4b972 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -56,6 +56,12 @@ along with GNU Emacs. If not, see . */ #include #include +static void +memory_full_up (void) +{ + abort (); +} + static void * xmalloc (size_t size) { @@ -64,24 +70,39 @@ xmalloc (size_t size) ptr = malloc (size); if (!ptr) - abort (); + memory_full_up (); return ptr; } -MAYBE_UNUSED static void * -xcalloc (ptrdiff_t n, ptrdiff_t s) +static void * +xcalloc (size_t n, size_t s) { void *ptr; ptr = calloc (n, s); if (!ptr) - abort (); + memory_full_up (); return ptr; } +static void * +xzalloc (size_t size) +{ + return xcalloc (1, size); +} + +static void * +xnmalloc (size_t n, size_t s) +{ + size_t size; + if (ckd_mul (&size, n, s)) + memory_full_up (); + return xmalloc (size); +} + static void * xrealloc (void *ptr, size_t size) { @@ -90,7 +111,7 @@ xrealloc (void *ptr, size_t size) new_ptr = realloc (ptr, size); if (!new_ptr) - abort (); + memory_full_up (); return new_ptr; } @@ -111,13 +132,29 @@ xfree (void *ptr) /* Also necessary. */ #define AVOID _Noreturn ATTRIBUTE_COLD void -#define eassert(expr) assert (expr) - #else #define TEST_STATIC #include "lisp.h" #endif +static void * +xaddmalloc (size_t base, size_t additional) +{ + size_t size; + if (ckd_add (&size, additional, base)) + memory_full_up (); + return xmalloc (size); +} + +static void * +xaddrealloc (void *ptr, size_t base, size_t additional) +{ + size_t size; + if (ckd_add (&size, additional, base)) + memory_full_up (); + return xrealloc (ptr, size); +} + #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) @@ -738,8 +775,7 @@ sfnt_read_cmap_format_12 (int fd, return NULL; /* Allocate a buffer of sufficient size. */ - eassert (length < UINT32_MAX - sizeof *format12); - format12 = xmalloc (length + sizeof *format12); + format12 = xaddmalloc (sizeof *format12, length); format12->format = header->format; format12->reserved = header->length; format12->length = length; @@ -1594,7 +1630,7 @@ sfnt_read_loca_table_short (int fd, struct sfnt_offset_subtable *subtable) return NULL; /* Figure out how many glyphs there are based on the length. */ - loca = xmalloc (sizeof *loca + directory->length); + loca = xaddmalloc (sizeof *loca, directory->length); loca->offsets = (uint16_t *) (loca + 1); loca->num_offsets = directory->length / 2; @@ -1639,7 +1675,7 @@ sfnt_read_loca_table_long (int fd, struct sfnt_offset_subtable *subtable) return NULL; /* Figure out how many glyphs there are based on the length. */ - loca = xmalloc (sizeof *loca + directory->length); + loca = xaddmalloc (sizeof *loca, directory->length); loca->offsets = (uint32_t *) (loca + 1); loca->num_offsets = directory->length / 4; @@ -1771,7 +1807,7 @@ sfnt_read_glyf_table (int fd, struct sfnt_offset_subtable *subtable) return NULL; /* Allocate enough to hold everything. */ - glyf = xmalloc (sizeof *glyf + directory->length); + glyf = xaddmalloc (sizeof *glyf, directory->length); glyf->size = directory->length; glyf->glyphs = (unsigned char *) (glyf + 1); @@ -1885,6 +1921,8 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, unsigned char *vec_start; int16_t delta, x, y; + glyph->simple = NULL; + /* Calculate the minimum size of the glyph data. This is the size of the instruction length field followed by glyph->number_of_contours * sizeof (uint16_t). */ @@ -1893,14 +1931,11 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, + sizeof (uint16_t)); /* Check that the size is big enough. */ - if (glyf->size < offset + min_size) - { - glyph->simple = NULL; - return; - } + if (glyf->size < min_size || glyf->size - min_size < offset) + return; /* Allocate enough to read at least that. */ - simple = xmalloc (sizeof *simple + min_size); + simple = xaddmalloc (sizeof *simple, min_size); simple->end_pts_of_contours = (uint16_t *) (simple + 1); memcpy (simple->end_pts_of_contours, glyf->glyphs + offset, min_size); @@ -1928,16 +1963,15 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, else number_of_points = 0; - min_size_2 = (simple->instruction_length - + number_of_points - + (number_of_points - * sizeof (uint16_t) * 2)); - - /* Set simple->number_of_points. */ simple->number_of_points = number_of_points; /* Make simple big enough. */ - simple = xrealloc (simple, sizeof *simple + min_size + min_size_2); + size_t size; + if (ckd_mul (&min_size_2, number_of_points, sizeof (uint16_t) * 2 + 1) + || ckd_add (&min_size_2, min_size_2, simple->instruction_length) + || ckd_add (&size, min_size, min_size_2)) + memory_full_up (); + simple = xaddrealloc (simple, sizeof *simple, size); simple->end_pts_of_contours = (uint16_t *) (simple + 1); /* Set the instruction data pointer and other pointers. @@ -1958,7 +1992,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, || (instructions_start + simple->instruction_length >= glyf->glyphs + glyf->size)) { - glyph->simple = NULL; xfree (simple); return; } @@ -1973,7 +2006,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, if (flags_start >= glyf->glyphs + glyf->size) { - glyph->simple = NULL; xfree (simple); return; } @@ -1997,7 +2029,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, if (flags_start + 1 >= glyf->glyphs + glyf->size) { - glyph->simple = NULL; xfree (simple); return; } @@ -2025,7 +2056,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, if (i != number_of_points) { - glyph->simple = NULL; xfree (simple); return; } @@ -2051,7 +2081,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, if (vec_start + 1 > glyf->glyphs + glyf->size) { - glyph->simple = NULL; xfree (simple); return; } @@ -2068,7 +2097,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, if (vec_start + 2 > glyf->glyphs + glyf->size) { - glyph->simple = NULL; xfree (simple); return; } @@ -2102,7 +2130,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, if (vec_start + 1 > glyf->glyphs + glyf->size) { - glyph->simple = NULL; xfree (simple); return; } @@ -2119,7 +2146,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, if (vec_start + 2 > glyf->glyphs + glyf->size) { - glyph->simple = NULL; xfree (simple); return; } @@ -2139,7 +2165,6 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, /* All done. */ simple->y_coordinates_end = simple->y_coordinates + i; glyph->simple = simple; - return; } /* Read the compound glyph outline from the glyph GLYPH from the @@ -2209,8 +2234,7 @@ sfnt_read_compound_glyph (struct sfnt_glyph *glyph, } /* Now allocate the buffer to hold all the glyph data. */ - glyph->compound = xmalloc (sizeof *glyph->compound - + required_bytes); + glyph->compound = xaddmalloc (sizeof *glyph->compound, required_bytes); glyph->compound->components = (struct sfnt_compound_glyph_component *) (glyph->compound + 1); glyph->compound->num_components = num_components; @@ -2431,9 +2455,8 @@ sfnt_read_glyph (sfnt_glyph glyph_code, glyph.ymax = 0; glyph.advance_distortion = 0; glyph.origin_distortion = 0; - glyph.simple = xmalloc (sizeof *glyph.simple); + glyph.simple = xzalloc (sizeof *glyph.simple); glyph.compound = NULL; - memset (glyph.simple, 0, sizeof *glyph.simple); memory = xmalloc (sizeof *memory); *memory = glyph; return memory; @@ -3608,17 +3631,19 @@ sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed y) outline->outline_used++; - /* See if the outline has to be extended. Checking for overflow - should not be necessary. */ + /* See if the outline has to be extended. */ if (outline->outline_used > outline->outline_size) { + /* This can't overflow, as the old value did not overflow when + multiplied by sizeof *outline->outline. */ outline->outline_size = outline->outline_used * 2; /* Extend the outline to some size past the new size. */ - outline = xrealloc (outline, (sizeof *outline - + (outline->outline_size - * sizeof *outline->outline))); + size_t size; + if (ckd_mul (&size, outline->outline_size, sizeof *outline->outline)) + memory_full_up (); + outline = xaddrealloc (outline, sizeof *outline, size); outline->outline = (struct sfnt_glyph_outline_command *) (outline + 1); } @@ -4039,7 +4064,12 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline, sfnt_fixed dx, dy, bot, step_x, ymin, xmin; size_t top, bottom, y; - edges = alloca (outline->outline_used * sizeof *edges); + void *edges_alloc = NULL; + if (outline->outline_used < 1024 * 16 / sizeof *edges) + edges = alloca (outline->outline_used * sizeof *edges); + else + edges = edges_alloc = xnmalloc (outline->outline_used, sizeof *edges); + edge = 0; /* ymin and xmin must be the same as the offset used to set offy and @@ -4132,6 +4162,7 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline, if (edge) edge_proc (edges, edge, dcontext); + xfree (edges_alloc); } /* Sort an array of SIZE edges to increase by bottom Y position, in @@ -4484,11 +4515,15 @@ sfnt_raster_glyph_outline (struct sfnt_glyph_outline *outline) /* Get the raster parameters. */ sfnt_prepare_raster (&raster, outline); - /* Allocate the raster data. */ - data = xmalloc (sizeof *data + raster.stride * raster.height); + /* Allocate the raster data. Clear the raster; it is easier to use + xzalloc and clear everything. */ + size_t size; + if (ckd_mul (&size, raster.stride, raster.height) + || ckd_add (&size, size, sizeof *data)) + memory_full_up (); + data = xzalloc (size); *data = raster; data->cells = (unsigned char *) (data + 1); - memset (data->cells, 0, raster.stride * raster.height); /* Generate edges for the outline, polying each array of edges to the raster. */ @@ -4688,7 +4723,12 @@ sfnt_build_outline_fedges (struct sfnt_glyph_outline *outline, sfnt_fixed dx, dy, step_x, step_y, ymin, xmin; size_t top, bottom; - edges = alloca (outline->outline_used * sizeof *edges); + void *edges_alloc = NULL; + if (outline->outline_used < 1024 * 16 / sizeof *edges) + edges = alloca (outline->outline_used * sizeof *edges); + else + edges = edges_alloc = xnmalloc (outline->outline_used, sizeof *edges); + edge = 0; /* ymin and xmin must be the same as the offset used to set offy and @@ -4773,6 +4813,7 @@ sfnt_build_outline_fedges (struct sfnt_glyph_outline *outline, if (edge) edge_proc (edges, edge, dcontext); + xfree (edges_alloc); } typedef void (*sfnt_step_raster_proc) (struct sfnt_step_raster *, void *); @@ -5376,15 +5417,21 @@ TEST_STATIC struct sfnt_raster * sfnt_raster_glyph_outline_exact (struct sfnt_glyph_outline *outline) { struct sfnt_raster raster, *data; + size_t size; /* Get the raster parameters. */ sfnt_prepare_raster (&raster, outline); - /* Allocate the raster data. */ - data = xmalloc (sizeof *data + raster.stride * raster.height); + /* Allocate the raster data. Clear the raster; it is easier to use + xcalloc and clear everything. */ + if (ckd_mul (&size, raster.stride, raster.height) + || ckd_add (&size, size, sizeof *data)) + return NULL; + data = xcalloc (1, size); + if (!data) + return NULL; *data = raster; data->cells = (unsigned char *) (data + 1); - memset (data->cells, 0, raster.stride * raster.height); /* Generate edges for the outline, polying each array of edges to the raster. */ @@ -5444,7 +5491,7 @@ sfnt_read_hmtx_table (int fd, struct sfnt_offset_subtable *subtable, /* Now allocate enough to hold all of that along with the table directory structure. */ - hmtx = xmalloc (sizeof *hmtx + size); + hmtx = xaddmalloc (sizeof *hmtx, size); /* Read into hmtx + 1. */ rc = read (fd, hmtx + 1, size); @@ -5591,13 +5638,9 @@ sfnt_read_name_table (int fd, struct sfnt_offset_subtable *subtable) if (directory->length < required) return NULL; - /* Avoid overflow in xmalloc argument below. */ - if (directory->length > UINT_MAX - sizeof *name) - return NULL; - /* Allocate enough to hold the name table and variable length data. */ - name = xmalloc (sizeof *name + directory->length); + name = xaddmalloc (sizeof *name, directory->length); /* Read the fixed length data. */ rc = read (fd, name, required); @@ -5671,10 +5714,11 @@ sfnt_read_name_table (int fd, struct sfnt_offset_subtable *subtable) - (name->count * sizeof *name->name_records))) { - name = xrealloc (name, (sizeof *name - + (name->count - * sizeof *name->name_records) - + required)); + size_t size; + if (ckd_mul (&size, name->count, sizeof *name->name_records) + || ckd_add (&size, size, required)) + memory_full_up (); + name = xaddrealloc (name, sizeof *name, size); name->name_records = (struct sfnt_name_record *) (name + 1); } @@ -5801,7 +5845,7 @@ sfnt_read_meta_table (int fd, struct sfnt_offset_subtable *subtable) if (ckd_mul (&map_size, sizeof *meta->data_maps, meta->num_data_maps) /* Do so while checking for overflow from bad sfnt files. */ - || ckd_add (&data_size, map_size, sizeof *meta) + || directory->length - required < map_size || ckd_add (&data_size, data_size, directory->length)) { xfree (meta); @@ -5809,15 +5853,7 @@ sfnt_read_meta_table (int fd, struct sfnt_offset_subtable *subtable) } /* Do the reallocation. */ - meta = xrealloc (meta, data_size); - - /* Check that the remaining data is big enough to hold the data - maps. */ - if (directory->length - required < map_size) - { - xfree (meta); - return NULL; - } + meta = xaddrealloc (meta, sizeof *meta, data_size); /* Set pointers to data_maps and data. */ meta->data_maps = (struct sfnt_meta_data_map *) (meta + 1); @@ -5945,7 +5981,7 @@ sfnt_read_ttc_header (int fd) return NULL; } - ttc = xrealloc (ttc, sizeof *ttc + size); + ttc = xaddrealloc (ttc, sizeof *ttc, size); ttc->offset_table = (uint32_t *) (ttc + 1); rc = read (fd, ttc->offset_table, size); if (rc == -1 || rc < size) @@ -6113,7 +6149,7 @@ sfnt_read_fpgm_table (int fd, struct sfnt_offset_subtable *subtable) return NULL; /* Allocate enough for that much data. */ - fpgm = xmalloc (sizeof *fpgm + directory->length); + fpgm = xaddmalloc (sizeof *fpgm, directory->length); /* Now set fpgm->num_instructions as appropriate, and make fpgm->instructions point to the right place. */ @@ -6161,7 +6197,7 @@ sfnt_read_prep_table (int fd, struct sfnt_offset_subtable *subtable) return NULL; /* Allocate enough for that much data. */ - prep = xmalloc (sizeof *prep + directory->length); + prep = xaddmalloc (sizeof *prep, directory->length); /* Now set prep->num_instructions as appropriate, and make prep->instructions point to the right place. */ @@ -13498,22 +13534,17 @@ TEST_STATIC struct sfnt_uvs_context * sfnt_create_uvs_context (struct sfnt_cmap_format_14 *cmap, int fd) { struct sfnt_table_offset_rec *table_offsets, *rec, template; - size_t size, i, nmemb, j; + size_t i, nmemb, j; off_t offset; struct sfnt_uvs_context *context; - if (ckd_mul (&size, cmap->num_var_selector_records, - sizeof *table_offsets) - || ckd_mul (&size, size, 2)) - return NULL; - context = NULL; /* First, record and sort the UVS and nondefault UVS table offsets in ascending order. */ - table_offsets = xmalloc (size); - memset (table_offsets, 0, size); + table_offsets = xcalloc (cmap->num_var_selector_records, + 2 * sizeof *table_offsets); nmemb = cmap->num_var_selector_records * 2; j = 0; @@ -14196,13 +14227,12 @@ sfnt_read_gvar_table (int fd, struct sfnt_offset_subtable *subtable) goto bail; /* Figure out how big gvar needs to be. */ - if (ckd_add (&min_bytes, coordinate_size, sizeof *gvar) - || ckd_add (&min_bytes, min_bytes, off_size) + if (ckd_add (&min_bytes, coordinate_size, off_size) || ckd_add (&min_bytes, min_bytes, data_size)) goto bail; /* Now allocate enough for all of this extra data. */ - gvar = xrealloc (gvar, min_bytes); + gvar = xaddrealloc (gvar, sizeof *gvar, min_bytes); /* Start reading offsets. */ @@ -14534,7 +14564,7 @@ sfnt_read_packed_deltas (unsigned char *restrict data, if (data >= end) return NULL; - deltas = xmalloc (sizeof *deltas * n); + deltas = xnmalloc (n, sizeof *deltas); i = 0; while (i < n) @@ -15326,7 +15356,7 @@ sfnt_infer_deltas_1 (struct sfnt_glyph *glyph, size_t start, { size_t i, pair_start, pair_end, pair_first; - pair_start = pair_first = -1; + pair_start = pair_first = SIZE_MAX; /* Look for pairs of touched points. */ @@ -15335,7 +15365,7 @@ sfnt_infer_deltas_1 (struct sfnt_glyph *glyph, size_t start, if (!touched[i]) continue; - if (pair_start == -1) + if (pair_start == SIZE_MAX) { pair_first = i; goto next; @@ -15538,10 +15568,11 @@ sfnt_vary_simple_glyph (struct sfnt_blend *blend, sfnt_glyph id, /* Start reading each tuple. */ tuple = gvar->glyph_variation_data + offset + sizeof header; - if (gvar->axis_count * sizeof *coords * 3 >= 1024 * 16) - coords = xmalloc (gvar->axis_count * sizeof *coords * 3); - else + void *coords_alloc = NULL; + if (gvar->axis_count < 1024 * 16 / (3 * sizeof *coords)) coords = alloca (gvar->axis_count * sizeof *coords * 3); + else + coords = coords_alloc = xnmalloc (gvar->axis_count, 3 * sizeof *coords); intermediate_start = coords + gvar->axis_count; intermediate_end = intermediate_start + gvar->axis_count; @@ -15551,6 +15582,8 @@ sfnt_vary_simple_glyph (struct sfnt_blend *blend, sfnt_glyph id, touched = NULL; original_x = NULL; original_y = NULL; + void *touched_alloc = NULL; + void *original_x_alloc = NULL; while (ntuples--) { @@ -15702,21 +15735,23 @@ sfnt_vary_simple_glyph (struct sfnt_blend *blend, sfnt_glyph id, if (!original_x) { - if ((glyph->simple->number_of_points - * sizeof *touched) >= 1024 * 16) - touched = xmalloc (sizeof *touched - * glyph->simple->number_of_points); - else + if (glyph->simple->number_of_points + < 1024 * 16 / sizeof *touched) touched = alloca (sizeof *touched * glyph->simple->number_of_points); - - if ((sizeof *original_x * 2 - * glyph->simple->number_of_points) >= 1024 * 16) - original_x = xmalloc (sizeof *original_x * 2 - * glyph->simple->number_of_points); else + touched = touched_alloc + = xnmalloc (glyph->simple->number_of_points, + sizeof *touched); + + if (glyph->simple->number_of_points + < 1024 * 16 / (2 * sizeof *original_x)) original_x = alloca (sizeof *original_x * 2 * glyph->simple->number_of_points); + else + original_x = original_x_alloc + = xnmalloc (glyph->simple->number_of_points, + 2 * sizeof *original_x); original_y = original_x + glyph->simple->number_of_points; } @@ -15777,16 +15812,9 @@ sfnt_vary_simple_glyph (struct sfnt_blend *blend, sfnt_glyph id, /* Return success. */ - if ((glyph->simple->number_of_points - * sizeof *touched) >= 1024 * 16) - xfree (touched); - - if (gvar->axis_count * sizeof *coords * 3 >= 1024 * 16) - xfree (coords); - - if ((sizeof *original_x * 2 - * glyph->simple->number_of_points) >= 1024 * 16) - xfree (original_x); + xfree (touched_alloc); + xfree (coords_alloc); + xfree (original_x_alloc); if (points != (uint16_t *) -1) xfree (points); @@ -15803,16 +15831,9 @@ sfnt_vary_simple_glyph (struct sfnt_blend *blend, sfnt_glyph id, xfree (local_points); fail1: - if ((glyph->simple->number_of_points - * sizeof *touched) >= 1024 * 16) - xfree (touched); - - if (gvar->axis_count * sizeof *coords * 3 >= 1024 * 16) - xfree (coords); - - if ((sizeof *original_x * 2 - * glyph->simple->number_of_points) >= 1024 * 16) - xfree (original_x); + xfree (touched_alloc); + xfree (coords_alloc); + xfree (original_x_alloc); if (points != (uint16_t *) -1) xfree (points); @@ -15916,10 +15937,11 @@ sfnt_vary_compound_glyph (struct sfnt_blend *blend, sfnt_glyph id, /* Start reading each tuple. */ tuple = gvar->glyph_variation_data + offset + sizeof header; - if (gvar->axis_count * sizeof *coords * 3 >= 1024 * 16) - coords = xmalloc (gvar->axis_count * sizeof *coords * 3); - else + void *coords_alloc = NULL; + if (gvar->axis_count < 1024 * 16 / (3 * sizeof *coords)) coords = alloca (gvar->axis_count * sizeof *coords * 3); + else + coords = coords_alloc = xnmalloc (gvar->axis_count, 3 * sizeof *coords); intermediate_start = coords + gvar->axis_count; intermediate_end = intermediate_start + gvar->axis_count; @@ -16157,9 +16179,7 @@ sfnt_vary_compound_glyph (struct sfnt_blend *blend, sfnt_glyph id, /* Return success. */ - if (gvar->axis_count * sizeof *coords * 3 >= 1024 * 16) - xfree (coords); - + xfree (coords_alloc); if (points != (uint16_t *) -1) xfree (points); @@ -16175,9 +16195,7 @@ sfnt_vary_compound_glyph (struct sfnt_blend *blend, sfnt_glyph id, xfree (local_points); fail1: - if (gvar->axis_count * sizeof *coords * 3 >= 1024 * 16) - xfree (coords); - + xfree (coords_alloc); if (points != (uint16_t *) -1) xfree (points); From 7bfde4d50b5e188211e5154a735619905e2a734d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 23 May 2026 17:59:14 -0700 Subject: [PATCH 091/112] sfnt.c eassert vs assert Use eassert uniformly, instead of assert. * src/sfnt.c [!TEST]: Do not include or use assert. (eassert) [TEST]: New macro. --- src/sfnt.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sfnt.c b/src/sfnt.c index 5c3c2c4b972..4900daee6f6 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -21,7 +21,6 @@ along with GNU Emacs. If not, see . */ #include "sfnt.h" -#include #include #include #include @@ -48,6 +47,7 @@ along with GNU Emacs. If not, see . */ #ifdef TEST +#include #include #include #include @@ -129,6 +129,8 @@ xfree (void *ptr) /* Needed for tests. */ #define ARRAYELTS(arr) (sizeof (arr) / sizeof (arr)[0]) +#define eassert(expr) assert (expr) + /* Also necessary. */ #define AVOID _Noreturn ATTRIBUTE_COLD void @@ -4362,7 +4364,7 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, if ((left & ~SFNT_POLY_MASK) == (right & ~SFNT_POLY_MASK)) { /* Assert that start does not exceed the end of the row. */ - assert (start <= row_end); + eassert (start <= row_end); w = coverage[right - left]; a = *start + w; @@ -4378,7 +4380,7 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, if (left & SFNT_POLY_MASK) { /* Assert that start does not exceed the end of the row. */ - assert (start <= row_end); + eassert (start <= row_end); /* Compute the coverage for the first pixel, and move left past it. The coverage is a number from 1 to 7 describing how @@ -4405,7 +4407,7 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, while (left + SFNT_POLY_MASK < right) { /* Assert that start does not exceed the end of the row. */ - assert (start <= row_end); + eassert (start <= row_end); a = *start + w; *start++ = sfnt_saturate_short (a); @@ -4417,7 +4419,7 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, if (right & SFNT_POLY_MASK) { /* Assert that start does not exceed the end of the row. */ - assert (start <= row_end); + eassert (start <= row_end); w = coverage[right - left]; a = *start + w; @@ -12598,7 +12600,7 @@ sfnt_interpret_compound_glyph_2 (struct sfnt_glyph *glyph, advance phantom points. */ num_points = context->num_points - base_index; num_contours = context->num_end_points - base_contour; - assert (num_points >= 2); + eassert (num_points >= 2); /* Nothing to instruct! */ if (!num_points && !num_contours) @@ -12669,7 +12671,7 @@ sfnt_interpret_compound_glyph_2 (struct sfnt_glyph *glyph, } /* Copy S1 and S2 into the glyph zone. */ - assert (num_points >= 2); + eassert (num_points >= 2); zone->x_points[num_points - 1] = s2; zone->x_points[num_points - 2] = s1; @@ -12960,7 +12962,7 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph, the outline ultimately produced, they are temporarily appended to the outline here, so as to enable defer_offsets below to refer to them. */ - assert (value->num_points >= 2); + eassert (value->num_points >= 2); last_point = value->num_points - 2; number_of_contours = value->num_contours; @@ -13015,7 +13017,7 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph, /* Assert the child anchor is within the confines of the zone. */ - assert (point2 < value->num_points); + eassert (point2 < value->num_points); /* Get the points and use them to compute the offsets. */ @@ -13137,7 +13139,7 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph, /* Subtract the two phantom points from context->num_points. This behavior is correct, as only the subglyph's phantom points may be provided as anchor points. */ - assert (context->num_points - contour_start >= 2); + eassert (context->num_points - contour_start >= 2); context->num_points -= 2; sfnt_transform_f26dot6 (component, From e7a333f18e96fc88d98e574be5c8e355efa96c36 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 23 May 2026 18:48:45 -0700 Subject: [PATCH 092/112] EVENT_INIT via a compound literal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pacifies GCC 16.1.1 x86-64 -Warray-bounds when compiling with -fsanitize=address. It’s also cleaner on more-typical platforms. * src/termhooks.h (EVENT_INIT): Define via a compound literal rather than via a memset plus an assignment. This evaluates the argument lvalue only once, and is more likely to catch type errors. --- src/termhooks.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/termhooks.h b/src/termhooks.h index 38c9df9cad2..ebac777ab4c 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -411,8 +411,7 @@ struct input_event Lisp_Object device; }; -#define EVENT_INIT(event) (memset (&(event), 0, sizeof (struct input_event)), \ - (event).device = Qt) +#define EVENT_INIT(event) ((event) = (struct input_event) {.device = Qt}) /* Bits in the modifiers member of the input_event structure. Note that reorder_modifiers assumes that the bits are in canonical From 6932c940fda848422cb6c66c81c9d7a108e8320b Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 23 May 2026 22:40:11 -0700 Subject: [PATCH 093/112] Fold calls to fix_position into treesit_check_position (bug#80830) * src/treesit.c (treesit_check_position): Return the validated value. (Ftreesit_node_first_child_for_pos): (Ftreesit_node_descendant_for_range): (Ftreesit_query_capture): (Ftreesit__linecol_at): Fold calls to fix_position into treesit_check_position in treesit.c. --- src/treesit.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/treesit.c b/src/treesit.c index 00b97da2c5c..4b1bce4fe2c 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -2917,13 +2917,15 @@ treesit_check_node (Lisp_Object obj) } /* Check that OBJ is a positive integer/marker and it is within the - visible portion of BUF. */ -static void + visible portion of BUF. Signal if invalid, return the value if + valid. */ +static ptrdiff_t treesit_check_position (Lisp_Object obj, struct buffer *buf) { ptrdiff_t pos = fix_position (obj); if (pos < BUF_BEGV (buf) || pos > BUF_ZV (buf)) xsignal1 (Qargs_out_of_range, obj); + return pos; } bool @@ -3346,10 +3348,10 @@ Note that this function returns an immediate child, not the smallest struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer); ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; - treesit_check_position (pos, buf); + ptrdiff_t fixpos = treesit_check_position (pos, buf); treesit_initialize (); - ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, fix_position (pos)); + ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, fixpos); TSNode treesit_node = XTS_NODE (node)->node; TSTreeCursor cursor = ts_tree_cursor_new (treesit_node); @@ -3382,13 +3384,13 @@ If NODE is nil, return nil. */) struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer); ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; - treesit_check_position (beg, buf); - treesit_check_position (end, buf); + ptrdiff_t fixpos_beg = treesit_check_position (beg, buf); + ptrdiff_t fixpos_end = treesit_check_position (end, buf); treesit_initialize (); - ptrdiff_t byte_beg = buf_charpos_to_bytepos (buf, fix_position (beg)); - ptrdiff_t byte_end = buf_charpos_to_bytepos (buf, fix_position (end)); + ptrdiff_t byte_beg = buf_charpos_to_bytepos (buf, fixpos_beg); + ptrdiff_t byte_end = buf_charpos_to_bytepos (buf, fixpos_end); TSNode treesit_node = XTS_NODE (node)->node; TSNode child; if (NILP (named)) @@ -4060,10 +4062,12 @@ the query. */) /* Check BEG and END. */ struct buffer *buf = XBUFFER (XTS_PARSER (lisp_parser)->buffer); + ptrdiff_t fixpos_beg = 0; + ptrdiff_t fixpos_end = 0; if (!NILP (beg)) - treesit_check_position (beg, buf); + fixpos_beg = treesit_check_position (beg, buf); if (!NILP (end)) - treesit_check_position (end, buf); + fixpos_end = treesit_check_position (end, buf); /* Initialize query objects. At the end of this block, we should have a working TSQuery and a TSQueryCursor. */ @@ -4085,8 +4089,8 @@ the query. */) { ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (lisp_node)->parser)->visible_beg; - ptrdiff_t beg_byte = CHAR_TO_BYTE (fix_position (beg)); - ptrdiff_t end_byte = CHAR_TO_BYTE (fix_position (end)); + ptrdiff_t beg_byte = CHAR_TO_BYTE (fixpos_beg); + ptrdiff_t end_byte = CHAR_TO_BYTE (fixpos_end); /* In ts_query_cursor_set_byte_range, if end_byte = 0, it's set to UINT32_MAX for some reason. But range (1, 1) shouldn't capture anything. So in this case just return Qnil. (bug#80798) */ @@ -5181,9 +5185,9 @@ return the line and column in the form of This is used for internal testing and debugging ONLY. */) (Lisp_Object pos) { - treesit_check_position (pos, current_buffer); + ptrdiff_t fixpos = treesit_check_position (pos, current_buffer); struct ts_linecol pos_linecol - = treesit_linecol_of_pos (CHAR_TO_BYTE (fix_position (pos)), + = treesit_linecol_of_pos (CHAR_TO_BYTE (fixpos), BUF_TS_LINECOL_POINT (current_buffer)); return Fcons (make_fixnum (pos_linecol.line), make_fixnum (pos_linecol.col)); } From c146e3643c4eb2fc52fa730df9388544a31feb40 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sun, 24 May 2026 09:17:44 +0000 Subject: [PATCH 094/112] Fix off-by-one error in 'styled_format' This would (rarely) result in composition properties being shared across the concatenation of two copies of a string. * src/editfns.c (styled_format): Include the first argument in the range. * test/src/editfns-tests.el (editfns-tests--format-composition-property): New. --- src/editfns.c | 2 +- test/src/editfns-tests.el | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/editfns.c b/src/editfns.c index 341e241dfcb..4089edb1074 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -4398,7 +4398,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) props = extend_property_ranges (props, len, new_len); /* If successive arguments have properties, be sure that the value of `composition' property be the copy. */ - if (1 < i && info[i - 1].end) + if (1 <= i && info[i - 1].end) make_composition_value_copy (props); add_text_properties_from_list (val, props, make_fixnum (info[i].start)); diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el index 9bdd5cf5db6..e6f80d0ef48 100644 --- a/test/src/editfns-tests.el +++ b/test/src/editfns-tests.el @@ -938,4 +938,13 @@ sufficiently large to avoid truncation." (pos-bol 2) (pos-eol 2)) (should (equal (buffer-string) "toto\nEmacs forever!\n")))) +(ert-deftest editfns-tests--format-composition-property () + "Check that composition properties are un-identified by `format'." + (let* ((s (compose-chars ?a ?b ?c)) + (str (format "%s%s%s" s s s))) + (should-not (eq (get-text-property 0 'composition str) + (get-text-property 3 'composition str))) + (should-not (eq (get-text-property 3 'composition str) + (get-text-property 6 'composition str))))) + ;;; editfns-tests.el ends here From 94dbab2fe45fdcdcefc3a19ecf6c2063eecc1df2 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sun, 24 May 2026 10:11:33 +0000 Subject: [PATCH 095/112] Fix 'do_casify_natnum' for events with all flags set * src/casefiddle.c (do_casify_natnum): Extend range a little, to cover character events with all modifier flags set. * test/src/casefiddle-tests.el (casefiddle-allflags): New test. --- src/casefiddle.c | 2 +- test/src/casefiddle-tests.el | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/casefiddle.c b/src/casefiddle.c index fb44081b215..162014d4716 100644 --- a/src/casefiddle.c +++ b/src/casefiddle.c @@ -253,7 +253,7 @@ do_casify_natnum (struct casing_context *ctx, Lisp_Object obj) /* If the character has higher bits set above the flags, return it unchanged. It is not a real character. */ - if (! (0 <= ch && ch <= flagbits)) + if (! (0 <= ch && ch <= flagbits + MAX_CHAR)) return obj; int flags = ch & flagbits; diff --git a/test/src/casefiddle-tests.el b/test/src/casefiddle-tests.el index dcbe2e32c22..28895ec921e 100644 --- a/test/src/casefiddle-tests.el +++ b/test/src/casefiddle-tests.el @@ -306,4 +306,13 @@ (casefiddle-tests--check-syms "aa_bb cc_dd" "Aa_Bb Cc_Dd" "Aa_bb Cc_dd") (casefiddle-tests--check-syms "Aa_Bb Cc_Dd" "Aa_Bb Cc_Dd" "Aa_Bb Cc_Dd")) +(ert-deftest casefiddle-allflags () + "Check that all-flags events are properly handled by `upcase'." + ;; U+00FF LATIN SMALL LETTER Y WITH DIAERESIS + ;; U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS + (should (= (upcase ?\xff) + ?\x178)) + (should (= (upcase ?\A-\C-\H-\S-\s-\M-\xff) + ?\A-\C-\H-\S-\s-\M-\x178))) + ;;; casefiddle-tests.el ends here From 7f8ac8bf6f04045a676543862098c47bbf732f9e Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sun, 24 May 2026 11:51:38 +0000 Subject: [PATCH 096/112] Avoid crash in self-insert-command for peculiar arguments * src/cmds.c (internal_self_insert): Don't call auto-fill-function after inserting zero newlines. * test/src/cmds-tests.el (self-insert-zero-newlines): New. --- src/cmds.c | 3 ++- test/src/cmds-tests.el | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cmds.c b/src/cmds.c index 99e436e65c1..e9dee5ed2e3 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -477,7 +477,8 @@ internal_self_insert (int c, EMACS_INT n) if ((CHAR_TABLE_P (Vauto_fill_chars) ? !NILP (CHAR_TABLE_REF (Vauto_fill_chars, c)) : (c == ' ' || c == '\n')) - && !NILP (BVAR (current_buffer, auto_fill_function))) + && !NILP (BVAR (current_buffer, auto_fill_function)) + && n > 0) { Lisp_Object auto_fill_result; diff --git a/test/src/cmds-tests.el b/test/src/cmds-tests.el index a02c36868ca..8c0e4706e3c 100644 --- a/test/src/cmds-tests.el +++ b/test/src/cmds-tests.el @@ -40,5 +40,13 @@ (let ((shortage (forward-line (+ 2 most-positive-fixnum)))) (should (= shortage (1+ most-positive-fixnum)))))) +(ert-deftest self-insert-zero-newlines () + "Test `self-insert-command' with arguments which used to cause a crash." + (with-temp-buffer + (let* ((pt nil) + (auto-fill-function (lambda () (setq pt (point))))) + (self-insert-command 0 10) + (should-not (equal pt 0))))) + (provide 'cmds-tests) ;;; cmds-tests.el ends here From b72dcebdabfc3b7b28c9542633bd48b43bcc6365 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sun, 24 May 2026 12:05:50 +0000 Subject: [PATCH 097/112] Avoid crash in self-insert-command with non-ASCII auto-fill * src/cmds.c (internal_self_insert): If the autofill function changed the newline character we inserted, don't attempt to restore point. * test/src/cmds-tests.el (self-insert-nonascii-autofill): New. --- src/cmds.c | 2 +- test/src/cmds-tests.el | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/cmds.c b/src/cmds.c index e9dee5ed2e3..9ca9a6d28de 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -489,7 +489,7 @@ internal_self_insert (int c, EMACS_INT n) SET_PT_BOTH (PT - 1, PT_BYTE - 1); auto_fill_result = call0 (Qinternal_auto_fill); /* Test PT < ZV in case the auto-fill-function is strange. */ - if (c == '\n' && PT < ZV) + if (c == '\n' && PT < ZV && FETCH_BYTE (PT) == '\n') SET_PT_BOTH (PT + 1, PT_BYTE + 1); if (!NILP (auto_fill_result)) hairy = 2; diff --git a/test/src/cmds-tests.el b/test/src/cmds-tests.el index 8c0e4706e3c..2038c01942f 100644 --- a/test/src/cmds-tests.el +++ b/test/src/cmds-tests.el @@ -48,5 +48,22 @@ (self-insert-command 0 10) (should-not (equal pt 0))))) +(ert-deftest self-insert-nonascii-autofill () + "Test `self-insert-command' with a non-ASCII autofill function." + (with-temp-buffer + (let ((auto-fill-function + (lambda () + (delete-char 1) + (insert #x2000) + (forward-char -1)))) + (dotimes (_ 10) + (self-insert-command 1 10) + (goto-char 2) + (should (equal (point) 2)) + (should (equal (length (buffer-string)) 1)) + (should (equal (format "%S" (buffer-string)) + "\"\x2000\"")) + (delete-char -1))))) + (provide 'cmds-tests) ;;; cmds-tests.el ends here From 44013f6be751363f7c4c642ebbfd618110db8b75 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 25 May 2026 11:21:00 +0800 Subject: [PATCH 098/112] =?UTF-8?q?Revert=20"Don=E2=80=99t=20silently=20tr?= =?UTF-8?q?uncate=20file=20names=20in=20exec.c"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3461b450c5eae3ed53192aa9514e0b1ac1b1c8f2. Gnulib and intprops.h are not available from within the exec helper. --- exec/exec.c | 96 ++++++++++++++++++++++++++-------------------------- exec/trace.c | 2 +- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/exec/exec.c b/exec/exec.c index ace62dd0191..7736c0dab27 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -863,25 +863,32 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs, -/* Format PID, a nonnegative process identifier, in base 10. - Place the result in *IN. Do not null-terminate the result. - Possibly modify the bytes in IN that are after the result. - Return a pointer to the byte after the result. */ +/* Format PID, an unsigned process identifier, in base 10. Place the + result in *IN, and return a pointer to the byte after the + result. REM should be NULL. */ char * -format_pid (char in[INT_STRLEN_BOUND (pid_t)], pid_t pid) +format_pid (char *in, unsigned int pid) { - char *pend = in + INT_STRLEN_BOUND (pid_t); - char *p = pend; + unsigned int digits[32], *fill; - do - *--p = '0' + pid % 10; - while ((pid /= 10) != 0); + fill = digits; - do - *in++ = *p++; - while (p < pend); + for (; pid != 0; pid = pid / 10) + *fill++ = pid % 10; + /* Insert 0 if the number would otherwise be empty. */ + + if (fill == digits) + *fill++ = 0; + + while (fill != digits) + { + --fill; + *in++ = '0' + *fill; + } + + *in = '\0'; return in; } @@ -897,13 +904,10 @@ format_pid (char in[INT_STRLEN_BOUND (pid_t)], pid_t pid) Finally, use REGS to add the required interpreter arguments to the caller's argv. - NAME must be a null-terminated string in a buffer of size PATH_MAX. - It might be updated to be a string no longer than PATH_MAX - 1. - Value is NULL upon failure, with errno set accordingly. */ char * -exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, +exec_0 (char *name, struct exec_tracee *tracee, size_t *size, USER_REGS_STRUCT *regs) { int fd, rc, i; @@ -912,13 +916,14 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, program_header program; USER_WORD entry, program_entry, offset; USER_WORD header_offset; - ptrdiff_t nlen; USER_WORD name_len, aligned_len; struct exec_jump_command jump; /* This also encompasses !__LP64__. */ #if defined __mips__ && !defined MIPS_NABI int fpu_mode; #endif /* defined __mips__ && !defined MIPS_NABI */ + char buffer[80], buffer1[PATH_MAX + 80], *rewrite; + ssize_t link_size; size_t remaining; /* If the process is trying to run /proc/self/exe, make it run @@ -926,13 +931,8 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, if (!strcmp (name, "/proc/self/exe") && tracee->exec_file) { - nlen = strnlen (tracee->exec_file, PATH_MAX); - if (PATH_MAX <= nlen) - { - errno = ENAMETOOLONG; - return NULL; - } - memcpy (name, tracee->exec_file, nlen + 1); + strncpy (name, tracee->exec_file, PATH_MAX - 1); + name[PATH_MAX] = '\0'; } else { @@ -940,45 +940,45 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, cwd. Do not use sprintf at it is not reentrant and it mishandles results longer than INT_MAX. */ - nlen = strlen (name); - if (name[0] && name[0] != '/') { - char buffer[sizeof "/proc//cwd" + INT_STRLEN_BOUND (pid_t)]; - char buffer1[PATH_MAX]; + /* Clear both buffers. */ + memset (buffer, 0, sizeof buffer); + memset (buffer1, 0, sizeof buffer1); - /* Copy over "/proc/", the PID, and "/cwd". */ - char *rewrite = stpcpy (buffer, "/proc/"); + /* Copy over /proc, the PID, and /cwd/. */ + rewrite = stpcpy (buffer, "/proc/"); rewrite = format_pid (rewrite, tracee->pid); strcpy (rewrite, "/cwd"); /* Resolve this symbolic link. */ - ssize_t link_size = readlink (buffer, buffer1, sizeof buffer1); + link_size = readlink (buffer, buffer1, + PATH_MAX + 1); + if (link_size < 0) return NULL; - /* Check that the link is reasonable. */ + /* Check that the name is a reasonable size. */ - if (link_size == 0 || buffer1[0] != '/') - { - errno = EINVAL; - return NULL; - } - - ptrdiff_t link_len = link_size - (buffer1[link_size - 1] == '/'); - if (PATH_MAX <= link_len + 1 + nlen) + if (link_size > PATH_MAX) { + /* The name is too long. */ errno = ENAMETOOLONG; return NULL; } - /* Replace name with link contents, - then '/' if needed, then name. */ - memmove (name + link_len + 1, name, nlen + 1); - memcpy (name, buffer1, link_len); - name[link_len] = '/'; - nlen += link_len + 1; + /* Add a directory separator if necessary. */ + + if (!link_size || buffer1[link_size - 1] != '/') + buffer1[link_size] = '/', link_size++; + + rewrite = buffer1 + link_size; + remaining = buffer1 + sizeof buffer1 - rewrite - 1; + memcpy (rewrite, name, strnlen (name, remaining)); + + /* Replace name with buffer1. */ + strcpy (name, buffer1); } } @@ -1151,7 +1151,7 @@ exec_0 (char name[PATH_MAX], struct exec_tracee *tracee, loader_area_used += sizeof jump; /* Copy the length of NAME and NAME itself to the loader area. */ - name_len = nlen; + name_len = strlen (name); aligned_len = ((name_len + 1 + sizeof name_len - 1) & -sizeof name_len); if (sizeof loader_area - loader_area_used diff --git a/exec/trace.c b/exec/trace.c index d3d6f223eb8..da9ac96c6ff 100644 --- a/exec/trace.c +++ b/exec/trace.c @@ -732,7 +732,7 @@ check_signal (struct exec_tracee *tracee, int status) static int handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) { - char buffer[PATH_MAX], *area; + char buffer[PATH_MAX + 80], *area; USER_REGS_STRUCT original; size_t size, loader_size; USER_WORD loader; From 7cef36258148e2c202535b5761df8545718a27bf Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 25 May 2026 11:23:10 +0800 Subject: [PATCH 099/112] Fix the Android build * src/sfnt.c (sfnt_fill_span) [NDEBUG]: Don't access `row_end' when not defined. --- src/sfnt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sfnt.c b/src/sfnt.c index 4900daee6f6..4e4e2e121e6 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -4363,8 +4363,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, if ((left & ~SFNT_POLY_MASK) == (right & ~SFNT_POLY_MASK)) { +#ifndef NDEBUG /* Assert that start does not exceed the end of the row. */ eassert (start <= row_end); +#endif /* !NDEBUG */ w = coverage[right - left]; a = *start + w; @@ -4379,8 +4381,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, if (left & SFNT_POLY_MASK) { +#ifndef NDEBUG /* Assert that start does not exceed the end of the row. */ eassert (start <= row_end); +#endif /* !NDEBUG */ /* Compute the coverage for the first pixel, and move left past it. The coverage is a number from 1 to 7 describing how @@ -4406,8 +4410,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, /* Fill pixels between left and right. */ while (left + SFNT_POLY_MASK < right) { +#ifndef NDEBUG /* Assert that start does not exceed the end of the row. */ eassert (start <= row_end); +#endif /* !NDEBUG */ a = *start + w; *start++ = sfnt_saturate_short (a); @@ -4418,8 +4424,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y, if (right & SFNT_POLY_MASK) { +#ifndef NDEBUG /* Assert that start does not exceed the end of the row. */ eassert (start <= row_end); +#endif /* !NDEBUG */ w = coverage[right - left]; a = *start + w; From d6215451fad244c6947dc6f67c039969853e6b12 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 25 May 2026 11:29:32 +0800 Subject: [PATCH 100/112] Fix parsing of font metadata tables on Android * src/sfnt.c (sfnt_read_meta_table): Allocate `directory->length' bytes after the map rather than in place of it. --- src/sfnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfnt.c b/src/sfnt.c index 4e4e2e121e6..956b89d3efb 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -5856,7 +5856,7 @@ sfnt_read_meta_table (int fd, struct sfnt_offset_subtable *subtable) if (ckd_mul (&map_size, sizeof *meta->data_maps, meta->num_data_maps) /* Do so while checking for overflow from bad sfnt files. */ || directory->length - required < map_size - || ckd_add (&data_size, data_size, directory->length)) + || ckd_add (&data_size, map_size, directory->length)) { xfree (meta); return NULL; From 6d15d68e1f77ebb81827d792fbc67363dd5b730c Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 25 May 2026 11:50:03 +0800 Subject: [PATCH 101/112] ; * src/sfntfont-android.c (GET_SCANLINE_BUFFER): Correct commentary. --- src/sfntfont-android.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c index 30cf1876191..adf9bf74632 100644 --- a/src/sfntfont-android.c +++ b/src/sfntfont-android.c @@ -95,7 +95,7 @@ static size_t max_scanline_buffer_size; } \ else if (_size <= scanline_buffer.buffer_size) \ (buffer) = scanline_buffer.buffer_data; \ - /* This is unreachable but clang says it is. */ \ + /* This is unreachable but clang says it is isn't. */\ else \ emacs_abort (); \ \ @@ -127,7 +127,7 @@ static size_t max_scanline_buffer_size; } \ else if (_size <= scanline_buffer.buffer_size) \ (buffer) = scanline_buffer.buffer_data; \ - /* This is unreachable but clang says it is. */ \ + /* This is unreachable but clang says it isn't. */ \ else \ emacs_abort (); \ \ From 217064e9dca2b9d4b55e0fd823017b4ee07163e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20J=C3=B6rg?= Date: Mon, 25 May 2026 11:23:34 +0200 Subject: [PATCH 102/112] ;cperl-mode.el: Fix fontification edge cases These were reported by happy-barney on GitHub https://github.com/HaraldJoerg/cperl-mode/issues * lisp/progmodes/cperl-mode.el (cperl-init-faces): Don't mistake $method as a method declaration. Move matcher for "use require" higher to prevent "require" being fontified as keyword. * test/lisp/progmodes/cperl-mode-resources/sub-names.pl: Add a test case for $method * test/lisp/progmodes/cperl-mode-tests.el (cperl-test-fontify-declarations): Add a test case for a module name looking like a keyword (cperl-test-fontify-sub-names): Verify that $method does not declare a method --- lisp/progmodes/cperl-mode.el | 37 ++++++++++--------- .../cperl-mode-resources/sub-names.pl | 9 +++++ test/lisp/progmodes/cperl-mode-tests.el | 23 +++++++++--- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el index d3014fee2b7..91e2e46fdba 100644 --- a/lisp/progmodes/cperl-mode.el +++ b/lisp/progmodes/cperl-mode.el @@ -6353,7 +6353,7 @@ functions (which they are not). Inherits from `default'.") ;; facespec is evaluated depending on whether the ;; statement ends in a "{" (definition) or ";" ;; (declaration without body) - (list (concat "\\<" cperl-sub-regexp + (list (concat "\\(?:\\`\\|[^$%@*&]\\)" cperl-sub-regexp ;; group 1: optional subroutine name (rx (sequence (eval cperl--ws+-rx) @@ -6400,7 +6400,24 @@ functions (which they are not). Inherits from `default'.") (error (match-end 2)))) nil (1 font-lock-variable-name-face))) - ;; -------- flow control + ;; -------- various stuff calling for a package name + ;; (matcher (subexp facespec) (subexp facespec)) + `(,(rx (sequence + (or (sequence (or line-start space "{" ) + (group-n 1 (or "package" "require" "use" + "import" "no" "bootstrap" "class")) + (eval cperl--ws+-rx)) + (sequence (group-n 2 (sequence ":" + (eval cperl--ws*-rx) + "isa")) + "(" + (eval cperl--ws*-rx))) + (group-n 3 (eval cperl--normal-identifier-rx)) + (any " \t\n;)"))) ; require A if B; + (1 font-lock-keyword-face t t) + (2 font-lock-constant-face t t) + (3 font-lock-function-name-face)) + ;; -------- flow control ;; (matcher . subexp) font-lock-keyword-face by default ;; This highlights declarations and definitions differently. ;; We do not try to highlight in the case of attributes: @@ -6507,22 +6524,6 @@ functions (which they are not). Inherits from `default'.") ;; (matcher subexp facespec) '("-[rwxoRWXOezsfdlpSbctugkTBMAC]\\>\\([ \t]+_\\>\\)?" 0 font-lock-function-name-face keep) ; Not very good, triggers at "[a-z]" - ;; -------- various stuff calling for a package name - ;; (matcher (subexp facespec) (subexp facespec)) - `(,(rx (sequence - (or (sequence (or line-start space "{" ) - (or "package" "require" "use" "import" - "no" "bootstrap" "class") - (eval cperl--ws+-rx)) - (sequence (group-n 2 (sequence ":" - (eval cperl--ws*-rx) - "isa")) - "(" - (eval cperl--ws*-rx))) - (group-n 1 (eval cperl--normal-identifier-rx)) - (any " \t\n;)"))) ; require A if B; - (1 font-lock-function-name-face) - (2 font-lock-constant-face t t)) ;; -------- formats ;; (matcher subexp facespec) '("^[ \t]*format[ \t]+\\([a-zA-Z_][a-zA-Z_0-9:]*\\)[ \t]*=[ \t]*$" diff --git a/test/lisp/progmodes/cperl-mode-resources/sub-names.pl b/test/lisp/progmodes/cperl-mode-resources/sub-names.pl index 46d05b4dbd2..229106865a3 100644 --- a/test/lisp/progmodes/cperl-mode-resources/sub-names.pl +++ b/test/lisp/progmodes/cperl-mode-resources/sub-names.pl @@ -17,6 +17,15 @@ # This comment has a method name in it, and we don't want "method" # to be fontified as a keyword, nor "name" fontified as a name. +# Next is a variable named "$method" followed by a keyword. This +# keyword is not a subroutine name and should not be fontified +# accordingly. Reported by Branislav Zahradnik, +# https://github.com/HaraldJoerg/cperl-mode/issues/24 + +push @abstract, $method + unless defined &$method + ; + __END__ =head1 Test using the keywords POD diff --git a/test/lisp/progmodes/cperl-mode-tests.el b/test/lisp/progmodes/cperl-mode-tests.el index 117eb9fdf9a..ffb79c6e5a2 100644 --- a/test/lisp/progmodes/cperl-mode-tests.el +++ b/test/lisp/progmodes/cperl-mode-tests.el @@ -143,7 +143,8 @@ point in the distant past, and is still broken in perl-mode. " (with-temp-buffer (funcall cperl-test-mode) (insert "package Foo::Bar;\n") - (insert "use Fee::Fie::Foe::Foo\n;") + (insert "use Fee::Fie::Foe::Foo\n;\n") + (insert "use require::relative;\n") ; module name has a keyword (insert "my $xyzzy = 'PLUGH';\n") (goto-char (point-min)) (font-lock-ensure) @@ -153,9 +154,15 @@ point in the distant past, and is still broken in perl-mode. " (search-forward "use") ; This was buggy in perl-mode (should (equal (get-text-property (match-beginning 0) 'face) 'font-lock-keyword-face)) - (search-forward "my") - (should (equal (get-text-property (match-beginning 0) 'face) - 'font-lock-keyword-face)))) + (re-search-forward (rx(sequence(group-n 1 "use") + (1+ blank) + (group-n 2 "require")))) + (should (equal (get-text-property (match-beginning 1) 'face) + 'font-lock-keyword-face)) + (should (equal (get-text-property (match-beginning 2) 'face) + (if (eq cperl-test-mode #'cperl-mode) + 'font-lock-function-name-face + 'font-lock-constant-face))))) (ert-deftest cperl-test-fontify-attrs-and-signatures () "Test fontification of the various combinations of subroutine @@ -330,13 +337,17 @@ comments and POD they should be fontified as POD." (should (equal (get-text-property (match-beginning 1) 'face) (if (equal cperl-test-mode 'perl-mode) nil 'cperl-method-call))) - ;; POD + ;; comment (search-forward-regexp "\\(method\\) \\(name\\)") (should (equal (get-text-property (match-beginning 1) 'face) 'font-lock-comment-face)) (should (equal (get-text-property (match-beginning 2) 'face) 'font-lock-comment-face)) - ;; comment + ;; false positive: $method is not a method + (search-forward-regexp "\\($method\\)\\(?:\n\\|\\s-\\)+\\(unless\\)") + (should (equal (get-text-property (match-beginning 2) 'face) + 'font-lock-keyword-face)) + ;; POD (search-forward-regexp "\\(method\\) \\(name\\)") (should (equal (get-text-property (match-beginning 1) 'face) 'font-lock-comment-face)) From ea2110b6e56ea4dc8d9fbe3ee19a7f56ffafa87f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 25 May 2026 18:39:26 +0300 Subject: [PATCH 103/112] ; * src/sfntfont-android.c (GET_SCANLINE_BUFFER): Fix a typo. --- src/sfntfont-android.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c index adf9bf74632..55f9c9e9078 100644 --- a/src/sfntfont-android.c +++ b/src/sfntfont-android.c @@ -95,7 +95,7 @@ static size_t max_scanline_buffer_size; } \ else if (_size <= scanline_buffer.buffer_size) \ (buffer) = scanline_buffer.buffer_data; \ - /* This is unreachable but clang says it is isn't. */\ + /* This is unreachable but clang says it isn't. */ \ else \ emacs_abort (); \ \ From 72b50901ef95410810b4ca7ecf103f028b8ae4b4 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 25 May 2026 17:01:07 -0400 Subject: [PATCH 104/112] lisp/emacs-lisp/package.el (package-quickstart-refresh): Delete stale elc --- lisp/emacs-lisp/package.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 068b94360d4..9ff761f0157 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -4814,6 +4814,10 @@ find FILE." ;; byte-compile-warnings: (not make-local) ;; End: ")) + (with-demoted-errors "%S" + ;; The `.elc' file is now stale. Remove it so it doesn't affect + ;; its own compilation or lingers in case of compilation failure. + (delete-file (concat package-quickstart-file "c"))) ;; FIXME: Do it asynchronously in an Emacs subprocess, and ;; don't show the byte-compiler warnings. (byte-compile-file package-quickstart-file))) From 25fb3f9b467c5dccddca4afead9b1ea6e29b08fb Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Tue, 26 May 2026 14:07:11 +0000 Subject: [PATCH 105/112] Fix self-insert-command in multibyte buffers (bug#81129) * src/cmds.c (internal_self_insert): Pass PT_BYTE to FETCH_BYTE, not PT. --- src/cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmds.c b/src/cmds.c index 9ca9a6d28de..f226c7542b3 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -489,7 +489,7 @@ internal_self_insert (int c, EMACS_INT n) SET_PT_BOTH (PT - 1, PT_BYTE - 1); auto_fill_result = call0 (Qinternal_auto_fill); /* Test PT < ZV in case the auto-fill-function is strange. */ - if (c == '\n' && PT < ZV && FETCH_BYTE (PT) == '\n') + if (c == '\n' && PT < ZV && FETCH_BYTE (PT_BYTE) == '\n') SET_PT_BOTH (PT + 1, PT_BYTE + 1); if (!NILP (auto_fill_result)) hairy = 2; From 02fb01166eb5ee11473ecc2ccd5cb5a2a92528a1 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 26 May 2026 15:54:34 -0400 Subject: [PATCH 106/112] Gnus: Prefer passing functions to message-add-action Building code with code is tricky. E.g. the code in gnus-draft-setup suffered from a security issue because it forgot to quote some arguments (see commit 142b1e0d4c3). * lisp/gnus/gnus-salt.el (gnus-pick-setup-message): * lisp/gnus/gnus-msg.el (gnus-inews-add-send-actions): * lisp/gnus/gnus-draft.el (gnus-draft-setup): Prefer passing functions to message-add-action over passing it ELisp expressions. * lisp/gnus/message.el (message-do-actions): Drop errors but not silently. --- lisp/gnus/gnus-draft.el | 14 +++++++------- lisp/gnus/gnus-msg.el | 19 ++++++++++--------- lisp/gnus/gnus-salt.el | 7 ++++--- lisp/gnus/message.el | 3 ++- lisp/gnus/nndraft.el | 2 +- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/lisp/gnus/gnus-draft.el b/lisp/gnus/gnus-draft.el index 9d5b8baba3f..89b20c91fda 100644 --- a/lisp/gnus/gnus-draft.el +++ b/lisp/gnus/gnus-draft.el @@ -273,13 +273,13 @@ If DONT-POP is nil, display the buffer after setting it up." (setq message-post-method (lambda (arg) (gnus-post-method arg (car ga)))) (unless (equal (cadr ga) "") - (dolist (article (cdr ga)) - (message-add-action - `(progn - (gnus-add-mark ,(car ga) 'replied ,article) - (gnus-request-set-mark ,(car ga) (list (list (list ,article) - 'add '(reply))))) - 'send)))) + (let ((group (car ga))) + (dolist (article (cdr ga)) + (message-add-action + (lambda () + (gnus-add-mark group 'replied article) + (gnus-request-set-mark group `(((,article) add (reply))))) + 'send))))) (run-hooks 'gnus-draft-setup-hook))) (defun gnus-draft-article-sendable-p (article) diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el index a478093fc6c..4318de613b0 100644 --- a/lisp/gnus/gnus-msg.el +++ b/lisp/gnus/gnus-msg.el @@ -544,10 +544,10 @@ instead." (let ((gn gnus-newsgroup-name)) (lambda (&optional arg) (gnus-post-method arg gn)))) (message-add-action - `(progn - (setq gnus-current-window-configuration ',winconf-name) - (when (gnus-buffer-live-p ,buffer) - (set-window-configuration ,winconf))) + (lambda () + (setq gnus-current-window-configuration winconf-name) + (when (gnus-buffer-live-p buffer) + (set-window-configuration winconf))) 'exit 'postpone 'kill) (let ((to-be-marked (cond (yanked @@ -556,12 +556,13 @@ instead." (article (if (listp article) article (list article))) (t nil)))) (message-add-action - `(when (gnus-buffer-live-p ,buffer) - (with-current-buffer ,buffer - ,(when to-be-marked + (lambda () + (when (gnus-buffer-live-p buffer) + (with-current-buffer buffer + (when to-be-marked (if (eq config 'forward) - `(gnus-summary-mark-article-as-forwarded ',to-be-marked) - `(gnus-summary-mark-article-as-replied ',to-be-marked))))) + (gnus-summary-mark-article-as-forwarded to-be-marked) + (gnus-summary-mark-article-as-replied to-be-marked)))))) 'send))) ;;; Post news commands of Gnus group mode and summary mode diff --git a/lisp/gnus/gnus-salt.el b/lisp/gnus/gnus-salt.el index d70f7f8fe5c..e4b2cf99616 100644 --- a/lisp/gnus/gnus-salt.el +++ b/lisp/gnus/gnus-salt.el @@ -119,9 +119,10 @@ It accepts the same format specs that `gnus-summary-line-format' does." (when (and (gnus-buffer-live-p gnus-summary-buffer) (with-current-buffer gnus-summary-buffer gnus-pick-mode)) - (message-add-action - `(gnus-configure-windows ,gnus-current-window-configuration t) - 'send 'exit 'postpone 'kill))) + (let ((gcwc gnus-current-window-configuration)) + (message-add-action + (lambda () (gnus-configure-windows gcwc t)) + 'send 'exit 'postpone 'kill)))) (defvar gnus-pick-line-number 1) (defun gnus-pick-line-number () diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index 671c3fdc1bc..6531669087b 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el @@ -4762,10 +4762,11 @@ Valid types are `send', `return', `exit', `kill' and `postpone'." (delq action (symbol-value var)))))) (defun message-do-actions (actions) + ;; FIXME: Replace it with `run-hooks'? "Perform all actions in ACTIONS." ;; Now perform actions on successful sending. (dolist (action actions) - (ignore-errors + (with-demoted-errors "message-do-actions: %S" (cond ;; A simple function. ((functionp action) diff --git a/lisp/gnus/nndraft.el b/lisp/gnus/nndraft.el index 133ebe734eb..e59d680e92d 100644 --- a/lisp/gnus/nndraft.el +++ b/lisp/gnus/nndraft.el @@ -207,7 +207,7 @@ are generated if and only if they are also in `message-draft-headers'." (clear-visited-file-modtime) (add-hook 'write-contents-functions #'nndraft-generate-headers nil t) (add-hook 'after-save-hook #'nndraft-update-unread-articles nil t) - (message-add-action '(nndraft-update-unread-articles) + (message-add-action #'nndraft-update-unread-articles 'exit 'postpone 'kill) article)) From ca5e9976b1498dd6244c8c9d138375d3bcf4569a Mon Sep 17 00:00:00 2001 From: Andrea Alberti Date: Mon, 25 May 2026 04:33:22 +0200 Subject: [PATCH 107/112] Pixel-direct alignment in visual-wrap-prefix-mode (bug#81039) `visual-wrap--content-prefix' previously returned a column count computed as (max (string-width prefix) (ceiling (string-pixel-width prefix) avg-space-width)) with two problems: * `string-width' ignores `buffer-invisibility-spec', so an invisible prefix (hidden ATX markers under `markdown-ts-hide-markup', for example) still reserved its character count on line 1 via a `min-width' display property, shifting the visible heading right. * With variable-pitch fonts, rounding the prefix width up to whole columns added visible padding whenever the natural width did not fall on an exact column boundary. Return the prefix's natural pixel width via `string-pixel-width' instead, which accounts for any display transformation applied to the prefix (invisibility, `display' replacements, text scaling, proportional fonts). Drop the `min-width' property from `visual-wrap--apply-to-line' so line 1 renders at its natural width. Switch the continuation `wrap-prefix' to a mixed-unit `:align-to' sum form: (space :align-to (+ (PIX) (EXTRA-INDENT . width))) where PIX is the prefix's pixel width and EXTRA-INDENT is `visual-wrap-extra-indent' in canonical character widths. The display engine resolves each term per the active frame and sums them, so no Lisp-level unit conversion is needed. Since `min-width' is no longer installed, the accumulation cycle that commit 81a5beb8af0 (bug#73882) worked around cannot recur. Drop the `min-width' strip from `visual-wrap--content-prefix' and the `min-width' removal from `visual-wrap--remove-properties'. Keep `min-width' in `visual-wrap--safe-display-specs' so that lines where other modes install it are not skipped. * lisp/visual-wrap.el (visual-wrap--content-prefix): Return pixel width instead of column count; drop the `min-width' strip. (visual-wrap--apply-to-line): Drop `min-width' on line 1; use mixed-unit `:align-to' sum form for the continuation wrap-prefix. (visual-wrap--adjust-prefix): Handle only string prefixes; the numeric (pixel) case is now handled inline in `--apply-to-line' via the mixed-unit `:align-to' sum form. (visual-wrap--remove-properties): Drop `min-width' removal. (visual-wrap--safe-display-specs): Add note about `min-width'. * test/lisp/visual-wrap-tests.el: Update expected `wrap-prefix' values to the new sum form. (visual-wrap-tests/invisible-prefix): New test motivated by bug#81039. (visual-wrap-tests/negative-extra-indent): New test; verify that a large negative `visual-wrap-extra-indent' produces a valid wrap-prefix (the display engine clamps the stretch to zero). * test/manual/visual-wrap-test.el: New file. Manual test suite for visual-eyeball verification of prefix alignment behavior. Reported-by: Andrea Alberti Co-authored-by: Stefan Monnier --- lisp/visual-wrap.el | 98 ++++---- test/lisp/visual-wrap-tests.el | 69 ++++-- test/manual/visual-wrap-test.el | 421 ++++++++++++++++++++++++++++++++ 3 files changed, 517 insertions(+), 71 deletions(-) create mode 100644 test/manual/visual-wrap-test.el diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el index dd2df9a40b3..733f059ca85 100644 --- a/lisp/visual-wrap.el +++ b/lisp/visual-wrap.el @@ -34,12 +34,21 @@ ;;; Code: (defcustom visual-wrap-extra-indent 0 - "Number of extra spaces to indent in `visual-wrap-prefix-mode'. + "Number of extra columns to indent in `visual-wrap-prefix-mode'. `visual-wrap-prefix-mode' indents the visual lines to the level of the actual line plus `visual-wrap-extra-indent'. A negative value will do a relative de-indent. +When the prefix is a repeated string (e.g. `> ' or `;;; '), the extra +indent is applied by appending or trimming space characters. When the +prefix is whitespace-only indentation, the extra indent is measured in +canonical character widths (the default font's average character width), +which may differ from the width of a space character in some fonts; the +canonical width is used because variable-pitch fonts often have +particularly narrow spaces, and the average character width produces +more predictable indentation. + Examples: actual indent = 2 @@ -58,7 +67,7 @@ extra indent = 2 aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." :type 'integer - :safe 'integerp + :safe #'integerp :version "30.1" :group 'visual-line) @@ -128,49 +137,47 @@ members of `visual-wrap--safe-display-specs' (which see)." eol-face))))))) (defun visual-wrap--adjust-prefix (prefix) - "Adjust PREFIX with `visual-wrap-extra-indent'." - (if (numberp prefix) - (+ visual-wrap-extra-indent prefix) - (let ((prefix-len (string-width prefix))) - (cond - ((= 0 visual-wrap-extra-indent) - prefix) - ((< 0 visual-wrap-extra-indent) - (concat prefix (make-string visual-wrap-extra-indent ?\s))) - ((< 0 (+ visual-wrap-extra-indent prefix-len)) - (substring prefix - 0 (+ visual-wrap-extra-indent prefix-len))) - (t - ""))))) + "Adjust the string PREFIX with `visual-wrap-extra-indent'." + (let ((prefix-len (string-width prefix))) + (cond + ((= 0 visual-wrap-extra-indent) + prefix) + ((< 0 visual-wrap-extra-indent) + (concat prefix (make-string visual-wrap-extra-indent ?\s))) + ((< 0 (+ visual-wrap-extra-indent prefix-len)) + (substring prefix + 0 (+ visual-wrap-extra-indent prefix-len))) + (t + "")))) (defun visual-wrap--apply-to-line () "Apply visual-wrapping properties to the logical line starting at point." (when-let* ((first-line-prefix (fill-match-adaptive-prefix)) (next-line-prefix (visual-wrap--content-prefix - first-line-prefix (point)))) - (when (numberp next-line-prefix) - ;; Set a minimum width for the prefix so it lines up correctly - ;; with subsequent lines. Make sure not to do this past the end - ;; of the line though! (`fill-match-adaptive-prefix' could - ;; potentially return a prefix longer than the current line in the - ;; buffer.) - (add-display-text-property - (point) (min (+ (point) (length first-line-prefix)) - (pos-eol)) - 'min-width `((,next-line-prefix . width)))) - (setq next-line-prefix (visual-wrap--adjust-prefix next-line-prefix)) + first-line-prefix))) (put-text-property (point) (pos-eol) 'wrap-prefix (if (numberp next-line-prefix) - `(space :align-to (,next-line-prefix . width)) - next-line-prefix)))) + ;; Whitespace continuation: use a mixed-unit `:align-to' that + ;; combines the pixel width from `visual-wrap--content-prefix' + ;; with `visual-wrap-extra-indent' specified by the user in + ;; canonical character widths. The display engine resolves + ;; each unit per the active frame and sums them. If a large + ;; negative `visual-wrap-extra-indent' makes the sum negative, + ;; the display engine clamps the stretch width to zero + ;; (xdisp.c), so the continuation starts at the left margin. + `(space :align-to (+ (,next-line-prefix) + (,visual-wrap-extra-indent . width))) + ;; String prefix (e.g. `> ', `;;; '): adjust for extra + ;; indent in characters, then use the string directly. + (visual-wrap--adjust-prefix next-line-prefix))))) -(defun visual-wrap--content-prefix (prefix position) +(defun visual-wrap--content-prefix (prefix) "Get the next-line prefix for the specified first-line PREFIX. POSITION is the position in the buffer where PREFIX is located. -This returns a string prefix to use for subsequent lines; an integer, -indicating the number of canonical-width spaces to use; or nil, if +This returns a string prefix to use for subsequent lines; a number, +indicating the pixel width to use for whitespace alignment; or nil if PREFIX was empty." (cond ((string= prefix "") @@ -187,18 +194,13 @@ PREFIX was empty." (remove-text-properties 0 (length prefix) '(wrap-prefix) prefix) prefix) (t - ;; Otherwise, we want the prefix to be whitespace of the same width - ;; as the first-line prefix. We want to return an integer width (in - ;; units of the font's average-width) large enough to fit the - ;; first-line prefix. - (let ((avg-space (propertize (buffer-substring position (1+ position)) - 'display '(space :width (1 . width))))) - ;; Remove any `min-width' display specs since we'll replace with - ;; our own later in `visual-wrap--apply-to-line' (bug#73882). - (add-display-text-property 0 (length prefix) 'min-width nil prefix) - (max (string-width prefix) - (ceiling (string-pixel-width prefix (current-buffer)) - (string-pixel-width avg-space (current-buffer)))))))) + ;; Whitespace continuation: return the natural pixel width of the + ;; first-line prefix. Using `string-pixel-width' (rather than a + ;; character count) accounts for any display transformation applied + ;; to the prefix: invisibility, `display' replacements (e.g. icons, + ;; `display ""'), text scaling, proportional fonts. Continuation + ;; lines then align with whatever line 1 actually renders. + (string-pixel-width prefix (current-buffer))))) (defun visual-wrap-fill-context-prefix (beg end) "Compute visual wrap prefix from text between BEG and END. @@ -215,8 +217,8 @@ by `visual-wrap-extra-indent'." ;; taskpaper-mode where paragraph-start matches everything). (or (let ((paragraph-start regexp-unmatchable)) (fill-context-prefix beg end)) - ;; Note: fill-context-prefix may return nil; See: - ;; http://article.gmane.org/gmane.emacs.devel/156285 + ;; Note: fill-context-prefix may return nil; See: + ;; http://article.gmane.org/gmane.emacs.devel/156285 "")) (prefix (visual-wrap--adjust-prefix fcp)) (face (visual-wrap--prefix-face fcp beg end))) @@ -226,8 +228,6 @@ by `visual-wrap-extra-indent'." (defun visual-wrap--remove-properties (start end) "Remove visual wrapping text properties from START to END." - ;; Remove `min-width' from any prefixes we detected. - (remove-display-text-property start end 'min-width) ;; Remove `wrap-prefix' related properties from any lines with ;; prefixes we detected. (remove-text-properties start end '(wrap-prefix nil))) diff --git a/test/lisp/visual-wrap-tests.el b/test/lisp/visual-wrap-tests.el index 4fc033ec69e..a1f286cf96a 100644 --- a/test/lisp/visual-wrap-tests.el +++ b/test/lisp/visual-wrap-tests.el @@ -20,6 +20,9 @@ ;;; Commentary: ;; Tests for `visual-wrap-prefix-mode'. +;; +;; Pixel values in these tests assume the batch-mode metric of one +;; pixel per canonical character column (`string-pixel-width " "' = 1). ;;; Code: @@ -36,12 +39,8 @@ (should (equal-including-properties (buffer-string) #("greetings\n* hello\n* hi" - 10 12 ( wrap-prefix (space :align-to (2 . width)) - display (min-width ((2 . width)))) - 12 17 ( wrap-prefix (space :align-to (2 . width))) - 18 20 ( wrap-prefix (space :align-to (2 . width)) - display (min-width ((2 . width)))) - 20 22 ( wrap-prefix (space :align-to (2 . width)))))))) + 10 17 (wrap-prefix (space :align-to (+ (2) (0 . width)))) + 18 22 (wrap-prefix (space :align-to (+ (2) (0 . width))))))))) (ert-deftest visual-wrap-tests/safe-display () "Test adding wrapping properties to text with safe display properties." @@ -51,10 +50,9 @@ (should (equal-including-properties (buffer-string) #("* hello" - 0 2 ( wrap-prefix (space :align-to (2 . width)) - display (min-width ((2 . width)))) - 2 7 ( wrap-prefix (space :align-to (2 . width)) - display (raise 1))))))) + 0 2 (wrap-prefix (space :align-to (+ (2) (0 . width)))) + 2 7 (wrap-prefix (space :align-to (+ (2) (0 . width))) + display (raise 1))))))) (ert-deftest visual-wrap-tests/unsafe-display/within-line () "Test adding wrapping properties to text with unsafe display properties. @@ -66,10 +64,9 @@ When these properties don't extend across multiple lines, (should (equal-including-properties (buffer-string) #("* [img]" - 0 2 ( wrap-prefix (space :align-to (2 . width)) - display (min-width ((2 . width)))) - 2 7 ( wrap-prefix (space :align-to (2 . width)) - display (image :type bmp))))))) + 0 2 (wrap-prefix (space :align-to (+ (2) (0 . width)))) + 2 7 (wrap-prefix (space :align-to (+ (2) (0 . width))) + display (image :type bmp))))))) (ert-deftest visual-wrap-tests/unsafe-display/spanning-lines () "Test adding wrapping properties to text with unsafe display properties. @@ -126,18 +123,14 @@ See bug#76018." (should (equal-including-properties (buffer-string) #("* this zoo contains goats" - 0 2 ( wrap-prefix (space :align-to (2 . width)) - display (min-width ((2 . width)))) - 2 25 ( wrap-prefix (space :align-to (2 . width)))))) + 0 25 (wrap-prefix (space :align-to (+ (2) (0 . width))))))) (let ((start (point))) (insert-and-inherit "\n\nit also contains pandas") (visual-wrap-prefix-function start (point-max))) (should (equal-including-properties (buffer-string) #("* this zoo contains goats\n\nit also contains pandas" - 0 2 ( wrap-prefix (space :align-to (2 . width)) - display (min-width ((2 . width)))) - 2 25 ( wrap-prefix (space :align-to (2 . width)))))))) + 0 25 (wrap-prefix (space :align-to (+ (2) (0 . width))))))))) (ert-deftest visual-wrap-tests/cleanup () "Test that deactivating `visual-wrap-prefix-mode' cleans up text properties." @@ -146,11 +139,43 @@ See bug#76018." (visual-wrap-prefix-function (point-min) (point-max)) ;; Make sure we've added the visual-wrapping properties. (should (equal (text-properties-at (point-min)) - '( wrap-prefix (space :align-to (2 . width)) - display (min-width ((2 . width)))))) + '(wrap-prefix (space :align-to (+ (2) (0 . width)))))) (visual-wrap-prefix-mode -1) (should (equal-including-properties (buffer-string) "* hello\n* hi")))) +(ert-deftest visual-wrap-tests/negative-extra-indent () + "A large negative `visual-wrap-extra-indent' does not break alignment. +The mixed-unit `:align-to' sum may go negative, but the display engine +clamps the stretch width to zero (xdisp.c), so the continuation starts +at the left margin." + (with-temp-buffer + (setq-local visual-wrap-extra-indent -20) + (insert "* hello") + (visual-wrap-prefix-function (point-min) (point-max)) + ;; The sum (+ (2) (-20 . width)) is negative in batch mode + ;; (2 - 20 = -18), but the display engine clamps to zero. + (should (equal (get-text-property (point-min) 'wrap-prefix) + '(space :align-to (+ (2) (-20 . width))))))) + +(ert-deftest visual-wrap-tests/invisible-prefix () + "Invisible prefix characters do not reserve column space. +The natural pixel width of a fully invisible prefix is zero, so the +continuation `wrap-prefix' aligns to pixel 0 and no `min-width' display +property is installed on line 1. See bug#81039." + (with-temp-buffer + (insert (propertize "### " 'invisible t)) + (insert "Heading") + (visual-wrap-prefix-function (point-min) (point-max)) + (should (equal (get-text-property (point-min) 'wrap-prefix) + '(space :align-to (+ (0) (0 . width))))) + ;; The original bug was that `min-width' got installed on the + ;; invisible prefix region, padding line 1 even though the prefix + ;; rendered at zero pixels. The redesign installs no `min-width' + ;; at all. + (should-not (memq 'min-width + (ensure-list + (get-text-property (point-min) 'display)))))) + ;; visual-wrap-tests.el ends here diff --git a/test/manual/visual-wrap-test.el b/test/manual/visual-wrap-test.el new file mode 100644 index 00000000000..6cd617253da --- /dev/null +++ b/test/manual/visual-wrap-test.el @@ -0,0 +1,421 @@ +;;; visual-wrap-test.el --- Manual tests for visual-wrap-prefix-mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; Manual test suite for `visual-wrap-prefix-mode'. Each test opens a +;; buffer named *visual-wrap-test-NNN* with an explanatory banner at +;; the top, followed by sample lines. The banner describes what to +;; look for; the code below carries no parallel documentation. +;; +;; Run from `emacs -Q': +;; +;; emacs -Q -l test/manual/visual-wrap-test.el \ +;; --eval "(visual-wrap-test-001)" +;; +;; Append `-nw' to the same invocation to repeat each test in a TTY +;; frame. `string-pixel-width' adapts to the frame, so GUI and TTY +;; runs share the same expectations modulo test 004 (variable-pitch), +;; which degrades silently on a TTY. +;; +;; Tests: +;; 001 Visible fixed-pitch prefix (baseline / regression check). +;; 002 Fully invisible prefix (the original bug). +;; 003 Partially invisible prefix. +;; 004a Variable-pitch narrow prefix `;;; ' (GUI only). +;; 004b Variable-pitch wide prefix `%%% ' (GUI only). +;; 005 Non-zero `visual-wrap-extra-indent'. +;; 006 markdown-ts-mode + `markdown-ts-hide-markup' (real-world repro). +;; 007 org-table-style `|' prefix (regression check for bug#73882). + +;;; Code: + +(defconst visual-wrap-test--long + "The quick brown fox jumps over the lazy dog, repeatedly, with great enthusiasm, again and again, until the moon comes up and the cows come home, and then some more for good measure." + "A line long enough to overflow any reasonable window.") + +(defun visual-wrap-test--prepare (name) + "Create or reset buffer NAME, plain `text-mode', return it." + (let ((buf (get-buffer-create name))) + (with-current-buffer buf + (read-only-mode -1) + (erase-buffer) + (kill-all-local-variables) + (text-mode)) + buf)) + +(defun visual-wrap-test--show (buf) + "Enable `visual-wrap-prefix-mode' in BUF and switch to it." + (with-current-buffer buf + (goto-char (point-min)) + (visual-wrap-prefix-mode 1)) + (switch-to-buffer buf)) + +(defun visual-wrap-test--insert-invisible (text) + "Insert TEXT and mark its character range invisible via text properties. +Uses `invisible t', which is matched by the default +`buffer-invisibility-spec'." + (let ((start (point))) + (insert text) + (put-text-property start (point) 'invisible t))) + +(defun visual-wrap-test-001 () + "Baseline: visible fixed-pitch prefix. See banner in the test buffer." + (interactive) + (let ((buf (visual-wrap-test--prepare "*visual-wrap-test-001*"))) + (with-current-buffer buf + (insert "\ +visual-wrap-test-001 — visible fixed-pitch prefix (baseline) +============================================================ + +Mode: `text-mode'. The paragraph below starts with `> ', which +the default `adaptive-fill-regexp' matches as a paragraph prefix. + +`visual-wrap-prefix-mode' is enabled in this buffer. Narrow the +window until the long paragraph wraps onto several visual lines. + +Expected: + * Line 1 is not shifted; `> ' renders at its natural width. + * Continuation visual lines align horizontally with the first + character that follows `> ' on line 1. + +This case worked correctly before the patch (bug#81039). The test confirms +the redesign (bug#81039) has not broken the common fixed-pitch fixed-width +case while fixing the invisible-prefix and variable-pitch cases. + +Sample line: + +> ") + (insert visual-wrap-test--long "\n")) + (visual-wrap-test--show buf))) + +(defun visual-wrap-test-002 () + "Fully invisible prefix. See banner in the test buffer." + (interactive) + (let ((buf (visual-wrap-test--prepare "*visual-wrap-test-002*"))) + (with-current-buffer buf + (insert "\ +visual-wrap-test-002 — fully invisible prefix +============================================= + +Mode: `text-mode'. The paragraph below starts with `### ', and +all four of those characters carry `invisible t' as a text +property. The default `buffer-invisibility-spec' includes t, so +the display engine renders them at zero pixels. + +The original bug reported in bug#81039: `visual-wrap--content-prefix' +used `string-width' to derive a column count, which ignores +invisibility. It therefore reserved four columns of `min-width' on +line 1 and shifted the visible content rightward. + +`visual-wrap-prefix-mode' is enabled. Narrow the window so the +paragraph wraps. + +Expected with the redesign (bug#81039): + * Line 1 is NOT shifted; the visible content starts at column 0 + (the `### ' has zero rendered width). + * Continuation visual lines also start at column 0, since the + natural pixel width of the prefix is zero. + +Sample line: + +") + (visual-wrap-test--insert-invisible "### ") + (insert visual-wrap-test--long "\n")) + (visual-wrap-test--show buf))) + +(defun visual-wrap-test-003 () + "Partially invisible prefix. See banner in the test buffer." + (interactive) + (let ((buf (visual-wrap-test--prepare "*visual-wrap-test-003*"))) + (with-current-buffer buf + (insert "\ +visual-wrap-test-003 — partially invisible prefix +================================================= + +Mode: `text-mode'. The paragraph below begins with `### ' +\(four characters: three hashes and a space). The first two +hashes carry `invisible t'; the third hash and the space remain +visible. The visible portion of the prefix is therefore `# ', +two columns wide. + +`visual-wrap-prefix-mode' is enabled. Narrow the window so the +paragraph wraps. + +Expected with the redesign (bug#81039): + * Line 1 shows `# ' at column 0, followed by the paragraph + text — no extra padding to compensate for the hidden hashes. + * Continuation visual lines align with the first character + after the visible `# ' on line 1 (i.e. two columns in). + +If line 1's content begins past column 2, or continuations land +elsewhere than two columns in, the natural-width computation is +not honoring per-character invisibility. + +Sample line: + +") + (visual-wrap-test--insert-invisible "##") + (insert "# ") + (insert visual-wrap-test--long "\n")) + (visual-wrap-test--show buf))) + +(defun visual-wrap-test--variable-pitch (name prefix narrow-or-wide) + "Set up a variable-pitch test buffer named NAME with PREFIX. +NARROW-OR-WIDE is the string \"narrow\" or \"wide\", used only in +the banner." + (let ((buf (visual-wrap-test--prepare name))) + (with-current-buffer buf + (when (display-graphic-p) + (variable-pitch-mode 1)) + (unless (display-graphic-p) + (insert "\ +NOTE: this Emacs frame is a TTY. `variable-pitch-mode' has no +effect; every glyph is exactly one column wide. The test below +therefore degenerates to a visible fixed-pitch prefix (similar to +test 001). Re-run inside a GUI frame to actually test the +variable-pitch path. + +")) + (insert (format "\ +visual-wrap-test — variable-pitch %s prefix `%s' +================================================= + +Mode: `text-mode' + `variable-pitch-mode' (GUI only). The +paragraph below starts with `%s', whose natural pixel width in +a proportional font is %s than the same number of monospace +columns. + +This is the case Jim Porter's 2024 commit was designed to handle: +under the old `(max string-width (ceiling pixel/avg-space))' +formula, the column-rounded `min-width' on line 1 over-padded the +prefix. Under the redesign (bug#81039), the continuation `wrap-prefix' uses +the prefix's pixel width directly, so no rounding occurs. + +`visual-wrap-prefix-mode' is enabled. Narrow the window so the +paragraph wraps. + +Expected with the redesign (bug#81039): + * Line 1 renders `%s' at its natural pixel width. + * Continuation visual lines align with the first character that + follows `%s' on line 1, in pixels — no visible jitter + between line 1 and the wrapped lines. + +To compare against the pre-bug#81039 behavior, re-run this test +without `--load'ing the patched `visual-wrap.el' (bug#81039) (i.e. let +the built-in version handle the buffer). You should see a small +but real horizontal gap between the prefix end on line 1 and the +start of continuation lines. + +Sample line: + +%s" narrow-or-wide prefix prefix narrow-or-wide prefix prefix prefix)) + (insert visual-wrap-test--long "\n\n" + (format "\ + +=== Appendix: artifact in banner text (out of scope of bug#81039) === + +On close inspection in GUI, the bullet-prefix line + + * Continuation... + +above sits a few pixels right of its follow-on buffer lines that start +with four spaces + + follows `%s' on... + +This is an artifact due to the specific content in the banner. Because +the prefix width is computed for each physical line separately, in the +case of a variable-pitch font we end up having slightly different widths +(in this example, the differences are barely visible by human eye). In +fact, ` * ' and ` ' are separate adaptive-fill prefixes on independent +buffer lines, and `visual-wrap.el' processes them independently: it has +no notion of \"these lines belong to one logical bullet\". Under the +old code the step was an estimated ~17 pixels (column-rounded +`min-width' on ` * ' line, no processing on ` ' lines). The +redesign (bug#81039) drops it to an estimated ~2 pixels (natural pixel +width of ` * ' is slightly larger than that of ` ' in a proportional +font), small enough to look aligned. +" prefix))) + (visual-wrap-test--show buf))) + +(defun visual-wrap-test-004a () + "Variable-pitch narrow prefix `;;; '. See banner in the test buffer." + (interactive) + (visual-wrap-test--variable-pitch + "*visual-wrap-test-004a*" ";;; " "narrower")) + +(defun visual-wrap-test-004b () + "Variable-pitch wide prefix `%%% '. See banner in the test buffer." + (interactive) + (visual-wrap-test--variable-pitch + "*visual-wrap-test-004b*" "%%% " "wider")) + +(defun visual-wrap-test-005 () + "Non-zero `visual-wrap-extra-indent'. See banner in the test buffer." + (interactive) + (let ((buf (visual-wrap-test--prepare "*visual-wrap-test-005*"))) + (with-current-buffer buf + (setq-local visual-wrap-extra-indent 4) + (insert "\ +visual-wrap-test-005 — non-zero `visual-wrap-extra-indent' +========================================================= + +Mode: `text-mode'. `visual-wrap-extra-indent' is set buffer-local +to 4. + +`visual-wrap--adjust-prefix' must now convert four canonical-char +columns to pixels before adding them to the prefix's pixel width +(since `visual-wrap--content-prefix' returns a pixel count under +the redesign (bug#81039)). + +`visual-wrap-prefix-mode' is enabled. Narrow the window so the +paragraph wraps. + +Expected: + * Continuation visual lines start four canonical-character + columns to the right of the `> ' prefix on line 1. + * Line 1 itself is not shifted. + +If continuations land at zero columns past the prefix end, the +column-to-pixel conversion in `visual-wrap--adjust-prefix' is not +firing. If they land somewhere fractional or wrong, the unit +conversion is wrong. + +Sample line: + +> ") + (insert visual-wrap-test--long "\n")) + (visual-wrap-test--show buf))) + +(defun visual-wrap-test-006 () + "markdown-ts-mode + `markdown-ts-hide-markup'. See banner in the test buffer." + (interactive) + (let ((have-mode (fboundp 'markdown-ts-mode)) + (buf (get-buffer-create "*visual-wrap-test-006*"))) + (with-current-buffer buf + (read-only-mode -1) + (erase-buffer) + (kill-all-local-variables) + (unless have-mode + (insert "\ +WARNING: this Emacs build does not expose `markdown-ts-mode`. +Test 006 cannot run. Use Emacs 31 or newer. + +")) + (insert "\ +visual-wrap-test-006 — markdown-ts-mode + hide-markup (real-world repro) +======================================================================= + +Mode: `markdown-ts-mode` with `markdown-ts-hide-markup` enabled. This +is the case that originally exposed the bug reported in bug#81039. The +ATX heading marker `### ` carries `invisible markdown-ts--markup`, which +is in `buffer-invisibility-spec` while hide-markup is on. + +Default `adaptive-fill-regexp` matches `### ` as a paragraph +prefix. Under the old code, hidden hashes were still counted by +`string-width`, so the heading text shifted right by four columns +the moment `visual-wrap-prefix-mode` came on — visible even +without any wrapping happening. + +Two cases are demonstrated below: a short heading (no wrap +needed, but the shift was visible) and a long heading (wraps, +and the continuation must align with the visible heading text). + +Expected with the redesign (bug#81039): +* Short heading: not shifted; reads as `A short heading`. +* Long heading: line 1 not shifted; continuation visual lines + align with the start of the visible heading text. + +To compare, revert the patch (bug#81039), restart, and re-run; you +should see the heading text on line 1 shift right by four columns. + +Case 1 — short heading (no wrap; the shift was visible without +wrapping under the old code): + +### A short heading + +Case 2 — long heading (wraps; continuation visual lines must +align with the start of the visible heading text): + +### ") + (insert visual-wrap-test--long "\n") + (when have-mode + (markdown-ts-mode) + ;; Enable hide-markup directly. `markdown-ts-toggle-hide-markup' + ;; is not autoloaded, so it is not yet bound at the time the + ;; enclosing `let' captures `fboundp' on entry. + (setq markdown-ts-hide-markup t) + (add-to-invisibility-spec 'markdown-ts--markup) + (font-lock-flush)) + (goto-char (point-min)) + (visual-wrap-prefix-mode 1)) + (switch-to-buffer buf))) + +(defun visual-wrap-test-007 () + "Org-table-style `|' prefix. See banner in the test buffer." + (interactive) + (let ((buf (visual-wrap-test--prepare "*visual-wrap-test-007*"))) + (with-current-buffer buf + (insert "\ +visual-wrap-test-007 — org-table-style `|' prefix (bug#73882 regression) +======================================================================== + +Mode: `text-mode'. The buffer below contains a pre-aligned org-style +table. `|' is in the default `adaptive-fill-regexp', so each table +row is treated as a logical line with `| ' as its first-line prefix. + +Original bug: with `global-visual-wrap-prefix-mode' enabled, the table +cells in the first column got misaligned because `min-width' from a +prior fontification of the same `|' character accumulated on each +pass, inflating the width past one space. Reporter: +Arthur Elsenaar, 2024-10-19. Fixed by Jim Porter as 81a5beb8af0 +\(strip prior `min-width' before measuring the prefix). + +The redesign (bug#81039) supersedes that fix at a lower level: no +`min-width' display property is installed at all, so there is nothing +that can accumulate across fontification passes. + +`visual-wrap-prefix-mode' is enabled in this buffer. + +Expected: + * The table cells stay aligned. Each `|' character in every column + sits at the same horizontal position from row to row. + * No `min-width' property appears anywhere on the table text. + +To compare against the pre-Jim-Porter behavior, you would need to +revert his commit and ours; this is purely a regression check today. + +You may also want to run `M-x org-mode' in this buffer and verify +that the table remains properly aligned. + +Sample table: + +| head | 1 | 2 | 3 | 4 | +|--------+---+---+---+---| +| apple | | | | | +| orange | | | | | +| pear | | | | | +| banana | | | | | +")) + (visual-wrap-test--show buf))) + +(provide 'visual-wrap-test) + +;;; visual-wrap-test.el ends here From 5d8bb14d3b90513ed1a849ebbafb82a7734d9c8c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 26 May 2026 17:51:44 -0700 Subject: [PATCH 108/112] Omit useless casts found by GCC 16 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC 16’s -Wuseless-cast warning can be useful. Fix the useless casts it identifies, and also fix false positives by using compound literals, which are safer anyway than casts. * src/composite.c (composition_adjust_point) (Ffind_composition_internal): * lwlib/xlwmenu.c (xlwMenuResources, xlwMenuClassRec) (resource_widget_value, XlwMenuDestroy, Select): * src/alloc.c (process_mark_stack): * src/data.c (Faref): * src/emacs-module.c (module_extract_big_integer): * src/fileio.c (Finsert_file_contents): * src/frame.h (FRAME_MESSAGE_BUF_SIZE): * src/gtkutil.c (xg_tool_item_stale_p, update_frame_tool_bar): * src/image.c (pbm_load, png_load_body, jpeg_load_body) (tiff_load, gif_load): * src/pdumper.c (ptrdiff_t_to_dump_off, dump_queue_dequeue) (field_relpos, dump_field_emacs_ptr) (dump_object_start_pseudovector, pdumper_remember_scalar_impl) (pdumper_load, syms_of_pdumper): * src/regex-emacs.c (BUF_PUSH, BUF_PUSH_2, POINTER_TO_OFFSET): * src/xdisp.c (remember_mouse_glyph, pint2str): * src/xterm.c (cvt_string_to_pixel, handle_one_xevent): Omit useless casts. Perhaps they were formerly needed, but they should not be needed now. * src/alloc.c (Fmemory_info): * src/category.c (Fdefine_category, Fmodify_category_entry): * src/data.c (Fash): * src/dispextern.h (GLYPH_CODE_P): * src/emacs.c (load_seccomp): * src/fns.c (Flocale_info, maybe_resize_hash_table): * src/indent.c (check_display_width): * src/json.c (symset_size): * src/lisp.h (XUNTAG, BOOL_VECTOR_LENGTH_MAX, obarray_size) (hash_table_index_size): * src/lread.c (make_obarray, grow_obarray, Fobarray_clear): * src/menu.c (digest_single_submenu, x_popup_menu_1): * src/term.c (init_tty): * src/widget.c (update_wm_hints): * src/xdisp.c (truncate_echo_area): * src/xfns.c (x_set_border_pixel): * src/xfont.c (xfont_match, xfont_open): * src/xmenu.c (set_frame_menubar): * test/src/emacs-module-resources/mod-test.c (emacs_module_init): Use compound literal instead of a cast that is useless in some platforms but not others. * src/dispextern.h, src/haikugui.h, src/w32gui.h: (WINDOW_HANDLE_UINTPTR): New macro. * src/frame.c (gui_report_frame_params): * src/xterm.c (x_try_cr_xlib_drawable): Use it. * src/lisp.h (XUNTAG): And tag with UINTPTR_MAX to pacify gcc warning about a constant out of range. (hash_idx_t): Make it int_least32_t, as it need not be exactly 32 bits. (PRIdHASH_IDX): New macro. * src/pdumper.c (dump_queue_dequeue): Use it. * src/profiler.c (setup_cpu_timer): Make a local EMACS_INT rather than int, to avoid need for casting later. * src/syntax.c (uninitialized_interval): Use 1u rather than 1 so the cast is always useful. A compound literal wouldn’t do here, as this macro needs to be an integer constant expression. * src/xfns.c (XICCallback, XICProc): Remove macros. (Xxic_preedit_start_callback): Use a cleaner way to specify it, avoiding the need for type macros, and for a cast if HAVE_XICCALLBACK_CALLBACK. * src/xterm.c (handle_one_xevent): 2nd arg is now XEvent * on all platforms, as there is no need to diverge, and diverging meant we needed lots of unnecessary casts. --- lwlib/xlwmenu.c | 22 ++++++------ src/alloc.c | 26 +++++++------- src/category.c | 4 +-- src/composite.c | 7 ++-- src/data.c | 4 +-- src/dispextern.h | 10 +++++- src/emacs-module.c | 2 +- src/emacs.c | 2 +- src/fileio.c | 2 +- src/fns.c | 10 +++--- src/frame.c | 7 ++-- src/frame.h | 2 +- src/gtkutil.c | 5 ++- src/haikugui.h | 2 ++ src/image.c | 21 +++++------ src/indent.c | 2 +- src/json.c | 2 +- src/lisp.h | 16 +++++---- src/lread.c | 6 ++-- src/menu.c | 8 ++--- src/pdumper.c | 20 +++++------ src/profiler.c | 5 ++- src/regex-emacs.c | 10 +++--- src/syntax.c | 2 +- src/term.c | 12 +++---- src/w32gui.h | 2 ++ src/widget.c | 12 +++---- src/xdisp.c | 8 ++--- src/xfns.c | 17 +++++---- src/xfont.c | 4 +-- src/xmenu.c | 2 +- src/xterm.c | 41 +++++++++------------- test/src/emacs-module-resources/mod-test.c | 4 +-- 33 files changed, 150 insertions(+), 149 deletions(-) diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c index 12aeac8b16f..9dc27929517 100644 --- a/lwlib/xlwmenu.c +++ b/lwlib/xlwmenu.c @@ -118,7 +118,7 @@ xlwMenuResources[] = {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(menu.foreground), XtRString, "XtDefaultForeground"}, {XtNdisabledForeground, XtCDisabledForeground, XtRPixel, sizeof(Pixel), - offset(menu.disabled_foreground), XtRString, (XtPointer)NULL}, + offset(menu.disabled_foreground), XtRString, NULL}, {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel), offset(menu.button_foreground), XtRString, "XtDefaultForeground"}, {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel), @@ -147,17 +147,17 @@ xlwMenuResources[] = offset (menu.bottom_shadow_pixmap), XtRImmediate, (XtPointer)None}, {XtNopen, XtCCallback, XtRCallback, sizeof(XtPointer), - offset(menu.open), XtRCallback, (XtPointer)NULL}, + offset(menu.open), XtRCallback, NULL}, {XtNselect, XtCCallback, XtRCallback, sizeof(XtPointer), - offset(menu.select), XtRCallback, (XtPointer)NULL}, + offset(menu.select), XtRCallback, NULL}, {XtNhighlightCallback, XtCCallback, XtRCallback, sizeof(XtPointer), - offset(menu.highlight), XtRCallback, (XtPointer)NULL}, + offset(menu.highlight), XtRCallback, NULL}, {XtNenterCallback, XtCCallback, XtRCallback, sizeof(XtPointer), - offset(menu.enter), XtRCallback, (XtPointer)NULL}, + offset(menu.enter), XtRCallback, NULL}, {XtNleaveCallback, XtCCallback, XtRCallback, sizeof(XtPointer), - offset(menu.leave), XtRCallback, (XtPointer)NULL}, + offset(menu.leave), XtRCallback, NULL}, {XtNmenu, XtCMenu, XtRPointer, sizeof(XtPointer), - offset(menu.contents), XtRImmediate, (XtPointer)NULL}, + offset(menu.contents), XtRImmediate, NULL}, {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), offset(menu.cursor_shape), XtRString, (XtPointer)"right_ptr"}, {XtNhorizontal, XtCHorizontal, XtRInt, sizeof(int), @@ -208,7 +208,7 @@ xlwMenuActionsList [] = XlwMenuClassRec xlwMenuClassRec = { { /* CoreClass fields initialization */ - (WidgetClass) SuperClass, /* superclass */ + SuperClass, /* superclass */ "XlwMenu", /* class_name */ sizeof(XlwMenuRec), /* size */ XlwMenuClassInitialize, /* class_initialize */ @@ -430,7 +430,7 @@ resource_widget_value (XlwMenuWidget mw, widget_value *val) resourced_name = val->name; if (!val->value) { - complete_name = (char *) XtMalloc (strlen (resourced_name) + 1); + complete_name = XtMalloc (strlen (resourced_name) + 1); strcpy (complete_name, resourced_name); } else @@ -2259,7 +2259,7 @@ XlwMenuDestroy (Widget w) XlwMenuWidget mw = (XlwMenuWidget) w; if (pointer_grabbed) - ungrab_all ((Widget)w, CurrentTime); + ungrab_all (w, CurrentTime); pointer_grabbed = 0; keyboard_grabbed = 0; @@ -2773,7 +2773,7 @@ Select (Widget w, XEvent *ev, String *params, Cardinal *num_params) after the initial down-click that brought the menu up, do nothing. */ if ((selected_item == 0 - || ((widget_value *) selected_item)->call_data == 0) + || selected_item->call_data == 0) && !next_release_must_exit && (ev->xbutton.time - menu_post_event.xbutton.time < XtGetMultiClickTime (XtDisplay (w)))) diff --git a/src/alloc.c b/src/alloc.c index ed0d6f4976d..395cca304c6 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -6609,7 +6609,7 @@ process_mark_stack (ptrdiff_t base_sp) case PVEC_CHAR_TABLE: case PVEC_SUB_CHAR_TABLE: - mark_char_table (ptr, (enum pvec_type) pvectype); + mark_char_table (ptr, pvectype); break; case PVEC_BOOL_VECTOR: @@ -7177,28 +7177,28 @@ respective remote host. */) #else units = 1; #endif - return list4i ((uintmax_t) si.totalram * units / 1024, - (uintmax_t) si.freeram * units / 1024, - (uintmax_t) si.totalswap * units / 1024, - (uintmax_t) si.freeswap * units / 1024); + return list4i ((uintmax_t) {si.totalram} * units / 1024, + (uintmax_t) {si.freeram} * units / 1024, + (uintmax_t) {si.totalswap} * units / 1024, + (uintmax_t) {si.freeswap} * units / 1024); #elif defined WINDOWSNT unsigned long long totalram, freeram, totalswap, freeswap; if (w32_memory_info (&totalram, &freeram, &totalswap, &freeswap) == 0) - return list4i ((uintmax_t) totalram / 1024, - (uintmax_t) freeram / 1024, - (uintmax_t) totalswap / 1024, - (uintmax_t) freeswap / 1024); + return list4i ((uintmax_t) {totalram} / 1024, + (uintmax_t) {freeram} / 1024, + (uintmax_t) {totalswap} / 1024, + (uintmax_t) {freeswap} / 1024); else return Qnil; #elif defined MSDOS unsigned long totalram, freeram, totalswap, freeswap; if (dos_memory_info (&totalram, &freeram, &totalswap, &freeswap) == 0) - return list4i ((uintmax_t) totalram / 1024, - (uintmax_t) freeram / 1024, - (uintmax_t) totalswap / 1024, - (uintmax_t) freeswap / 1024); + return list4i ((uintmax_t) {totalram} / 1024, + (uintmax_t) {freeram} / 1024, + (uintmax_t) {totalswap} / 1024, + (uintmax_t) {freeswap} / 1024); else return Qnil; #else /* not HAVE_LINUX_SYSINFO, not WINDOWSNT, not MSDOS */ diff --git a/src/category.c b/src/category.c index c5956a46cdf..6261b5a1e25 100644 --- a/src/category.c +++ b/src/category.c @@ -117,7 +117,7 @@ the current buffer's category table. */) table = check_category_table (table); if (!NILP (CATEGORY_DOCSTRING (table, XFIXNAT (category)))) - error ("Category `%c' is already defined", (int) XFIXNAT (category)); + error ("Category `%c' is already defined", (int) {XFIXNAT (category)}); SET_CATEGORY_DOCSTRING (table, XFIXNAT (category), docstring); return Qnil; @@ -347,7 +347,7 @@ then delete CATEGORY from the category set instead of adding it. */) table = check_category_table (table); if (NILP (CATEGORY_DOCSTRING (table, XFIXNAT (category)))) - error ("Undefined category: %c", (int) XFIXNAT (category)); + error ("Undefined category: %c", (int) {XFIXNAT (category)}); set_value = NILP (reset); diff --git a/src/composite.c b/src/composite.c index 2898ea9651e..55841d08cb5 100644 --- a/src/composite.c +++ b/src/composite.c @@ -1873,8 +1873,7 @@ composition_adjust_point (ptrdiff_t last_pt, ptrdiff_t new_pt) return new_pt; /* Next check the automatic composition. */ - if (! find_automatic_composition (new_pt, (ptrdiff_t) -1, (ptrdiff_t) -1, - &beg, &end, &val, Qnil) + if (! find_automatic_composition (new_pt, -1, -1, &beg, &end, &val, Qnil) || beg == new_pt) return new_pt; for (i = 0; i < LGSTRING_GLYPH_LEN (val); i++) @@ -2074,7 +2073,7 @@ See `find-composition' for more details. */) && !NILP (BVAR (current_buffer, enable_multibyte_characters))) || (!NILP (string) && STRING_MULTIBYTE (string))) && ! inhibit_auto_composition () - && find_automatic_composition (from, to, (ptrdiff_t) -1, + && find_automatic_composition (from, to, -1, &start, &end, &gstring, string)) return list3 (make_fixnum (start), make_fixnum (end), gstring); return Qnil; @@ -2083,7 +2082,7 @@ See `find-composition' for more details. */) { ptrdiff_t s, e; - if (find_automatic_composition (from, to, (ptrdiff_t) -1, + if (find_automatic_composition (from, to, -1, &s, &e, &gstring, string) && (e <= fixed_pos ? e > end : s < start)) return list3 (make_fixnum (s), make_fixnum (e), gstring); diff --git a/src/data.c b/src/data.c index 2f245ce8061..92926eca89a 100644 --- a/src/data.c +++ b/src/data.c @@ -2583,7 +2583,7 @@ or a byte-code object. IDX starts at 0. */) if (idxval < 0 || idxval >= SCHARS (array)) args_out_of_range (array, idx); if (! STRING_MULTIBYTE (array)) - return make_fixnum ((unsigned char) SREF (array, idxval)); + return make_fixnum (SREF (array, idxval)); idxval_byte = string_char_to_byte (array, idxval); c = STRING_CHAR (SDATA (array) + idxval_byte); @@ -3587,7 +3587,7 @@ discarding bits. */) if (c == 0) return value; - if ((EMACS_INT) -1 >> 1 == -1 && FIXNUMP (value)) + if ((EMACS_INT) {-1} >> 1 == -1 && FIXNUMP (value)) { EMACS_INT shift = -c; EMACS_INT result diff --git a/src/dispextern.h b/src/dispextern.h index d08bd7ee7a9..4071ca57f72 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -185,6 +185,14 @@ typedef void *Emacs_Cursor; #ifdef HAVE_WINDOW_SYSTEM +/* Convert a window handle to uintptr_t. This default uses a compound literal, + which is good for platforms where handles are integers, as it checks + types better than a cast would. Platforms where handles are pointers + should override the default with a more-powerful cast. */ +# ifndef WINDOW_HANDLE_UINTPTR +# define WINDOW_HANDLE_UINTPTR(h) ((uintptr_t) {(h)}) +# endif + /* ``box'' structure similar to that found in the X sample server, meaning that X2 and Y2 are not actually the end of the box, but one pixel past the end of the box, which makes checking for overlaps @@ -2045,7 +2053,7 @@ GLYPH_CODE_P (Lisp_Object gc) : (RANGED_FIXNUMP (0, gc, (MAX_FACE_ID < EMACS_INT_MAX >> CHARACTERBITS - ? ((EMACS_INT) MAX_FACE_ID << CHARACTERBITS) | MAX_CHAR + ? ((EMACS_INT) {MAX_FACE_ID} << CHARACTERBITS) | MAX_CHAR : EMACS_INT_MAX)))); } diff --git a/src/emacs-module.c b/src/emacs-module.c index 3c49490e5c4..ce6c292dbb5 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -1120,7 +1120,7 @@ module_extract_big_integer (emacs_env *env, emacs_value arg, int *sign, u = -(EMACS_UINT) x; static_assert (required * bits < PTRDIFF_MAX); for (ptrdiff_t i = 0; i < required; ++i) - magnitude[i] = (emacs_limb_t) (u >> (i * bits)); + magnitude[i] = u >> (i * bits); MODULE_INTERNAL_CLEANUP (); return true; } diff --git a/src/emacs.c b/src/emacs.c index d50f817cefc..0827101da2f 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1232,7 +1232,7 @@ load_seccomp (const char *file) || stat.st_size % sizeof *program.filter != 0) { fprintf (stderr, "seccomp filter %s has invalid size %ld\n", - file, (long) stat.st_size); + file, (long) {stat.st_size}); goto out; } if (ckd_add (&program.len, stat.st_size / sizeof *program.filter, 0)) diff --git a/src/fileio.c b/src/fileio.c index e6a6670ff9d..28adb6dd5f9 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -4396,7 +4396,7 @@ by calling `format-decode', which see. */) Ferase_buffer (); bset_enable_multibyte_characters (buf, Qnil); - insert_1_both ((char *) read_buf, nread, nread, 0, 0, 0); + insert_1_both (read_buf, nread, nread, 0, 0, 0); TEMP_SET_PT_BOTH (BEG, BEG_BYTE); coding_system = calln (Vset_auto_coding_function, filename, make_fixnum (nread)); diff --git a/src/fns.c b/src/fns.c index e3d297102ca..687f0303aae 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3959,14 +3959,14 @@ The data read from the system are decoded using `locale-coding-system'. */) # endif # ifdef HAVE_LANGINFO__NL_PAPER_WIDTH if (EQ (item, Qpaper)) - /* We have to cast twice here: first to a correctly-sized integer, + /* We have to convert twice here: first to a correctly-sized integer, then to int, because that's what nl_langinfo is documented to - return for _NO_PAPER_{WIDTH,HEIGHT}. The first cast doesn't + return for _NO_PAPER_{WIDTH,HEIGHT}. The cast doesn't suffice because it could overflow an Emacs fixnum. This can happen when running under ASan, which fills allocated but uninitialized memory with 0xBE bytes. */ - return list2i ((int) (intptr_t) nl_langinfo (_NL_PAPER_WIDTH), - (int) (intptr_t) nl_langinfo (_NL_PAPER_HEIGHT)); + return list2i ((int) {(intptr_t) nl_langinfo (_NL_PAPER_WIDTH)}, + (int) {(intptr_t) nl_langinfo (_NL_PAPER_HEIGHT)}); # endif #endif /* HAVE_LANGINFO_CODESET*/ return Qnil; @@ -4987,7 +4987,7 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) ptrdiff_t old_index_size = hash_table_index_size (h); ptrdiff_t index_bits = compute_hash_index_bits (new_size); - ptrdiff_t index_size = (ptrdiff_t)1 << index_bits; + ptrdiff_t index_size = (ptrdiff_t) {1} << index_bits; hash_idx_t *index = hash_table_alloc_bytes (index_size * sizeof *index); for (ptrdiff_t i = 0; i < index_size; i++) index[i] = -1; diff --git a/src/frame.c b/src/frame.c index 2c0a27cf47c..489ecbc7187 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5458,7 +5458,7 @@ gui_report_frame_params (struct frame *f, Lisp_Object *alistptr) E.g., on MS-Windows it returns a value whose type is HANDLE, which is actually a pointer. Explicit casting avoids compiler warnings. */ - w = (uintptr_t) FRAME_NATIVE_WINDOW (f); + w = WINDOW_HANDLE_UINTPTR (FRAME_NATIVE_WINDOW (f)); store_in_alist (alistptr, Qwindow_id, make_formatted_string ("%"PRIuMAX, w)); #ifdef HAVE_X_WINDOWS @@ -5466,7 +5466,7 @@ gui_report_frame_params (struct frame *f, Lisp_Object *alistptr) /* Tooltip frame may not have this widget. */ if (FRAME_X_OUTPUT (f)->widget) #endif - w = (uintptr_t) FRAME_OUTER_WINDOW (f); + w = WINDOW_HANDLE_UINTPTR (FRAME_OUTER_WINDOW (f)); store_in_alist (alistptr, Qouter_window_id, make_formatted_string ("%"PRIuMAX, w)); #endif @@ -5480,7 +5480,8 @@ gui_report_frame_params (struct frame *f, Lisp_Object *alistptr) if (FRAME_OUTPUT_DATA (f)->parent_desc == FRAME_DISPLAY_INFO (f)->root_window) tem = Qnil; else - tem = make_fixed_natnum ((uintptr_t) FRAME_OUTPUT_DATA (f)->parent_desc); + tem = make_fixed_natnum (WINDOW_HANDLE_UINTPTR + (FRAME_OUTPUT_DATA (f)->parent_desc)); store_in_alist (alistptr, Qexplicit_name, (f->explicit_name ? Qt : Qnil)); store_in_alist (alistptr, Qparent_id, tem); store_in_alist (alistptr, Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)); diff --git a/src/frame.h b/src/frame.h index 091b112e8b9..64d8a74f36e 100644 --- a/src/frame.h +++ b/src/frame.h @@ -1382,7 +1382,7 @@ FRAME_PARENT_FRAME (struct frame *f) width of the frame by 4 because multi-byte form may require at most 4-byte for a character. */ -#define FRAME_MESSAGE_BUF_SIZE(f) (((int) FRAME_COLS (f)) * 4) +#define FRAME_MESSAGE_BUF_SIZE(f) (4 * FRAME_COLS (f)) #define CHECK_FRAME(x) \ CHECK_TYPE (FRAMEP (x), Qframep, x) diff --git a/src/gtkutil.c b/src/gtkutil.c index df41fb91110..6b67a978cfe 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -5738,8 +5738,7 @@ xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name, gpointer gold_img = g_object_get_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA); #ifdef USE_CAIRO - void *old_img = (void *) gold_img; - if (old_img != img->cr_data) + if (gold_img != img->cr_data) return 1; #else Pixmap old_img = (Pixmap) gold_img; @@ -6106,7 +6105,7 @@ update_frame_tool_bar (struct frame *f) w = xg_get_image_for_pixmap (f, img, x->widget, NULL); g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA, #ifdef USE_CAIRO - (gpointer)img->cr_data + img->cr_data #else (gpointer)img->pixmap #endif diff --git a/src/haikugui.h b/src/haikugui.h index 50dba6e8061..afe677c487a 100644 --- a/src/haikugui.h +++ b/src/haikugui.h @@ -36,6 +36,8 @@ struct haiku_rect typedef void *haiku; +#define WINDOW_HANDLE_UINTPTR(h) ((uintptr_t) (h)) + typedef haiku Emacs_Pixmap; typedef haiku Emacs_Window; typedef haiku Emacs_Cursor; diff --git a/src/image.c b/src/image.c index f41a08eb1a8..723443193c0 100644 --- a/src/image.c +++ b/src/image.c @@ -7840,8 +7840,7 @@ pbm_load (struct frame *f, struct image *img) /* Maybe fill in the background field while we have ximg handy. */ if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - /* Casting avoids a GCC warning. */ - IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg); + IMAGE_BACKGROUND (img, f, ximg); /* Put ximg into the image. */ image_put_x_image (f, img, ximg, 0); @@ -8586,9 +8585,8 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c) img->width = width; img->height = height; - /* Maybe fill in the background field while we have ximg handy. - Casting avoids a GCC warning. */ - IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg); + /* Maybe fill in the background field while we have ximg handy. */ + IMAGE_BACKGROUND (img, f, ximg); /* Put ximg into the image. */ image_put_x_image (f, img, ximg, 0); @@ -8597,8 +8595,8 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c) if (mask_img) { /* Fill in the background_transparent field while we have the - mask handy. Casting avoids a GCC warning. */ - image_background_transparent (img, f, (Emacs_Pix_Context)mask_img); + mask handy. */ + image_background_transparent (img, f, mask_img); image_put_x_image (f, img, mask_img, 1); } @@ -9165,8 +9163,7 @@ jpeg_load_body (struct frame *f, struct image *img, /* Maybe fill in the background field while we have ximg handy. */ if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - /* Casting avoids a GCC warning. */ - IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg); + IMAGE_BACKGROUND (img, f, ximg); /* Put ximg into the image. */ image_put_x_image (f, img, ximg, 0); @@ -9606,8 +9603,7 @@ tiff_load (struct frame *f, struct image *img) /* Maybe fill in the background field while we have ximg handy. */ if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - /* Casting avoids a GCC warning on W32. */ - IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg); + IMAGE_BACKGROUND (img, f, ximg); /* Put ximg into the image. */ image_put_x_image (f, img, ximg, 0); @@ -10329,8 +10325,7 @@ gif_load (struct frame *f, struct image *img) /* Maybe fill in the background field while we have ximg handy. */ if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - /* Casting avoids a GCC warning. */ - IMAGE_BACKGROUND (img, f, (Emacs_Pix_Context)ximg); + IMAGE_BACKGROUND (img, f, ximg); /* Put ximg into the image. */ image_put_x_image (f, img, ximg, 0); diff --git a/src/indent.c b/src/indent.c index e8513fbf6f2..8f0648743bd 100644 --- a/src/indent.c +++ b/src/indent.c @@ -500,7 +500,7 @@ check_display_width (Lisp_Object window, Lisp_Object prop; EMACS_INT align_to_max = (col < MOST_POSITIVE_FIXNUM - INT_MAX - ? (EMACS_INT) INT_MAX + col + ? (EMACS_INT) {INT_MAX} + col : MOST_POSITIVE_FIXNUM); plist = XCDR (val); diff --git a/src/json.c b/src/json.c index 5186667a9d2..7174367873b 100644 --- a/src/json.c +++ b/src/json.c @@ -134,7 +134,7 @@ struct symset_tbl static inline ptrdiff_t symset_size (int bits) { - return (ptrdiff_t) 1 << bits; + return (ptrdiff_t) {1} << bits; } static struct symset_tbl * diff --git a/src/lisp.h b/src/lisp.h index d4978460f68..dd780e90c1d 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -747,10 +747,11 @@ INLINE void /* Extract A's pointer value, assuming A's Lisp type is TYPE and the extracted pointer's type is CTYPE *. When !USE_LSB_TAG this simply - extracts A's low-order bits, as (uintptr_t) LISP_WORD_TAG (type) is + extracts A's low-order bits, as LISP_WORD_TAG (type) & UINTPTR_MAX is always zero then. */ #define XUNTAG(a, type, ctype) \ - ((ctype *) ((uintptr_t) XLP (a) - (uintptr_t) LISP_WORD_TAG (type))) + ((ctype *) ((uintptr_t) XLP (a) \ + - (uintptr_t) {LISP_WORD_TAG (type) & UINTPTR_MAX})) /* A forwarding pointer to a value. It uses a generic pointer to avoid alignment bugs that could occur if it used a pointer to a @@ -1841,10 +1842,10 @@ enum #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) {BOOL_VECTOR_BITS_PER_CHAR}) \ ? EMACS_INT_MAX \ : ((min (PTRDIFF_MAX, SIZE_MAX) - bool_header_size) \ - * (EMACS_INT) BOOL_VECTOR_BITS_PER_CHAR)) \ + * (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. */ @@ -2437,7 +2438,7 @@ make_lisp_obarray (struct Lisp_Obarray *o) INLINE ptrdiff_t obarray_size (const struct Lisp_Obarray *o) { - return (ptrdiff_t)1 << o->size_bits; + return (ptrdiff_t) {1} << o->size_bits; } Lisp_Object check_obarray_slow (Lisp_Object); @@ -2557,7 +2558,8 @@ typedef enum hash_table_weakness_t { /* The type of a hash table index, both for table indices and index (hash) indices. It's signed and a subtype of ptrdiff_t. */ -typedef int32_t hash_idx_t; +typedef int_least32_t hash_idx_t; +#define PRIdHASH_IDX PRIdLEAST32 struct Lisp_Hash_Table { @@ -2715,7 +2717,7 @@ HASH_TABLE_SIZE (const struct Lisp_Hash_Table *h) INLINE ptrdiff_t hash_table_index_size (const struct Lisp_Hash_Table *h) { - return (ptrdiff_t)1 << h->index_bits; + return (ptrdiff_t) {1} << h->index_bits; } /* Hash value for KEY in hash table H. */ diff --git a/src/lread.c b/src/lread.c index 219d64d0282..00f85114ac7 100644 --- a/src/lread.c +++ b/src/lread.c @@ -5029,7 +5029,7 @@ make_obarray (unsigned bits) struct Lisp_Obarray *o = allocate_obarray (); o->count = 0; o->size_bits = bits; - ptrdiff_t size = (ptrdiff_t)1 << bits; + ptrdiff_t size = (ptrdiff_t) {1} << bits; o->buckets = hash_table_alloc_bytes (size * sizeof *o->buckets); for (ptrdiff_t i = 0; i < size; i++) o->buckets[i] = make_fixnum (0); @@ -5053,7 +5053,7 @@ grow_obarray (struct Lisp_Obarray *o) int new_bits = o->size_bits + 1; if (new_bits > obarray_max_bits) error ("Obarray too big"); - ptrdiff_t new_size = (ptrdiff_t)1 << new_bits; + ptrdiff_t new_size = (ptrdiff_t) {1} << new_bits; o->buckets = hash_table_alloc_bytes (new_size * sizeof *o->buckets); for (ptrdiff_t i = 0; i < new_size; i++) o->buckets[i] = make_fixnum (0); @@ -5123,7 +5123,7 @@ DEFUN ("obarray-clear", Fobarray_clear, Sobarray_clear, 1, 1, 0, /* This function does not bother setting the status of its contained symbols to uninterned. It doesn't matter very much. */ int new_bits = obarray_default_bits; - int new_size = (ptrdiff_t)1 << new_bits; + int new_size = (ptrdiff_t) {1} << new_bits; Lisp_Object *new_buckets = hash_table_alloc_bytes (new_size * sizeof *new_buckets); for (ptrdiff_t i = 0; i < new_size; i++) diff --git a/src/menu.c b/src/menu.c index ff4721d35f7..6f014581939 100644 --- a/src/menu.c +++ b/src/menu.c @@ -803,9 +803,9 @@ digest_single_submenu (int start, int end, bool top_level_items) wv->lname = item_name; if (!NILP (descrip)) wv->lkey = descrip; - /* The intptr_t cast avoids a warning. There's no problem + /* The intptr_t avoids a warning. There's no problem as long as pointers have enough bits to hold small integers. */ - wv->call_data = (!NILP (def) ? (void *) (intptr_t) i : 0); + wv->call_data = (!NILP (def) ? (void *) (intptr_t) {i} : 0); if (NILP (type)) wv->button_type = BUTTON_TYPE_NONE; @@ -1272,12 +1272,12 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu) xpos += check_integer_range (x, (xpos < INT_MIN - MOST_NEGATIVE_FIXNUM - ? (EMACS_INT) INT_MIN - xpos + ? (EMACS_INT) {INT_MIN} - xpos : MOST_NEGATIVE_FIXNUM), INT_MAX - xpos); ypos += check_integer_range (y, (ypos < INT_MIN - MOST_NEGATIVE_FIXNUM - ? (EMACS_INT) INT_MIN - ypos + ? (EMACS_INT) {INT_MIN} - ypos : MOST_NEGATIVE_FIXNUM), INT_MAX - ypos); diff --git a/src/pdumper.c b/src/pdumper.c index 259ecf7301d..066058d2078 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -159,7 +159,7 @@ ptrdiff_t_to_dump_off (ptrdiff_t value) { eassert (DUMP_OFF_MIN <= value); eassert (value <= DUMP_OFF_MAX); - return (dump_off) value; + return value; } /* Worst-case allocation granularity on any system that might load @@ -1234,13 +1234,14 @@ dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis) dump_trace (("dump_queue_dequeue basis=%"PRIdDUMP_OFF" fancy=%"PRIdPTR - " zero=%"PRIdPTR" normal=%"PRIdPTR" strong=%"PRIdPTR" hash=%td\n"), + " zero=%"PRIdPTR" normal=%"PRIdPTR" strong=%"PRIdPTR + " hash=%"PRIdHASH_IDX"\n"), basis, dump_tailq_length (&dump_queue->fancy_weight_objects), dump_tailq_length (&dump_queue->zero_weight_objects), dump_tailq_length (&dump_queue->one_weight_normal_objects), dump_tailq_length (&dump_queue->one_weight_strong_objects), - (ptrdiff_t) XHASH_TABLE (dump_queue->link_weights)->count); + XHASH_TABLE (dump_queue->link_weights)->count); #define nr_candidates 3 struct candidate @@ -1773,7 +1774,7 @@ field_relpos (const void *in_start, const void *in_field) ever violated, make sure the two pointers indeed point into the same object, and if so, enlarge the value of PDUMPER_MAX_OBJECT_SIZE. */ eassert (relpos < PDUMPER_MAX_OBJECT_SIZE); - return (dump_off) relpos; + return relpos; } static void @@ -1967,7 +1968,7 @@ dump_field_emacs_ptr (struct dump_context *ctx, intptr_t rel_emacs_ptr = 0; if (abs_emacs_ptr) { - rel_emacs_ptr = emacs_offset ((void *)abs_emacs_ptr); + rel_emacs_ptr = emacs_offset (abs_emacs_ptr); dump_reloc_dump_to_emacs_ptr_raw (ctx, ctx->obj_offset + relpos); } cpyptr ((char *) out + relpos, &rel_emacs_ptr); @@ -1980,7 +1981,7 @@ dump_object_start_pseudovector (struct dump_context *ctx, { eassert (in_hdr->size & PSEUDOVECTOR_FLAG); ptrdiff_t vec_size = vectorlike_nbytes (in_hdr); - dump_object_start (ctx, out_hdr, (dump_off) vec_size); + dump_object_start (ctx, out_hdr, vec_size); *out_hdr = *in_hdr; } @@ -4416,7 +4417,7 @@ pdumper_remember_scalar_impl (void *mem, ptrdiff_t nbytes) { eassert (0 <= nbytes && nbytes <= INT_MAX); if (nbytes > 0) - pdumper_remember_user_data_1 (mem, (int) nbytes); + pdumper_remember_user_data_1 (mem, nbytes); } void @@ -5655,7 +5656,7 @@ pdumper_load (const char *dump_filename, char *argv0) err = PDUMPER_LOAD_BAD_FILE_TYPE; if (stat.st_size > INTPTR_MAX) goto out; - dump_size = (intptr_t) stat.st_size; + dump_size = stat.st_size; err = PDUMPER_LOAD_BAD_FILE_TYPE; if (dump_size < sizeof (*header)) @@ -5910,7 +5911,6 @@ syms_of_pdumper (void) doc: /* The fingerprint of this Emacs binary. It is a string that is supposed to be unique to each build of Emacs. */); - Vpdumper_fingerprint = make_unibyte_string ((char *) hexbuf, - sizeof hexbuf); + Vpdumper_fingerprint = make_unibyte_string (hexbuf, sizeof hexbuf); #endif /* HAVE_PDUMPER */ } diff --git a/src/profiler.c b/src/profiler.c index b8339a3c544..c9cc3f118ad 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -392,12 +392,11 @@ deliver_profiler_signal (int signal) static int setup_cpu_timer (Lisp_Object sampling_interval) { - int billion = 1000000000; + EMACS_INT billion = 1000000000; if (! RANGED_FIXNUMP (1, sampling_interval, (TYPE_MAXIMUM (time_t) < EMACS_INT_MAX / billion - ? ((EMACS_INT) TYPE_MAXIMUM (time_t) * billion - + (billion - 1)) + ? TYPE_MAXIMUM (time_t) * billion + (billion - 1) : EMACS_INT_MAX))) return -1; diff --git a/src/regex-emacs.c b/src/regex-emacs.c index 03c4ba3e4e9..d8ed8a462a1 100644 --- a/src/regex-emacs.c +++ b/src/regex-emacs.c @@ -175,7 +175,7 @@ ptrdiff_t emacs_re_safe_alloca = MAX_ALLOCA; (destination = SAFE_ALLOCA (nsize), \ memcpy (destination, source, osize)) -/* True if 'size1' is non-NULL and PTR is pointing anywhere inside +/* True if 'size1' is nonzero and PTR is pointing anywhere inside 'string1' or just past its end. This works if PTR is NULL, which is a good thing. */ #define FIRST_STRING_P(ptr) \ @@ -1210,7 +1210,7 @@ static bool analyze_first (struct re_pattern_buffer *bufp, #define BUF_PUSH(c) \ do { \ GET_BUFFER_SPACE (1); \ - *b++ = (unsigned char) (c); \ + *b++ = (c); \ } while (false) @@ -1218,8 +1218,8 @@ static bool analyze_first (struct re_pattern_buffer *bufp, #define BUF_PUSH_2(c1, c2) \ do { \ GET_BUFFER_SPACE (2); \ - *b++ = (unsigned char) (c1); \ - *b++ = (unsigned char) (c2); \ + *b++ = (c1); \ + *b++ = (c2); \ } while (false) @@ -3637,7 +3637,7 @@ static bool bcmp_translate (re_char *, re_char *, ptrdiff_t, #define POINTER_TO_OFFSET(ptr) \ (FIRST_STRING_P (ptr) \ ? (ptr) - string1 \ - : (ptr) - string2 + (ptrdiff_t) size1) + : (ptr) - string2 + size1) /* Call before fetching a character with *d. This switches over to string2 if necessary. diff --git a/src/syntax.c b/src/syntax.c index 7649abb1aa0..38ae2f90572 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -236,7 +236,7 @@ SYNTAX_MATCH (int c) } /* A "dummy" value we never dereference, distinct from NULL. */ -#define uninitialized_interval ((INTERVAL) (intptr_t) 1) +#define uninitialized_interval ((INTERVAL) (intptr_t) 1u) /* This should be called with FROM at the start of forward search, or after the last position of the backward search. It diff --git a/src/term.c b/src/term.c index 8047e4102a1..cd8c9717640 100644 --- a/src/term.c +++ b/src/term.c @@ -4585,7 +4585,7 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ tty->TS_exit_attribute_mode = tgetstr ("me", address); #ifdef TERMINFO tty->TS_enter_strike_through_mode = tigetstr ("smxx"); - if (tty->TS_enter_strike_through_mode == (char *) (intptr_t) -1) + if (tty->TS_enter_strike_through_mode == (char *) (intptr_t) {-1}) tty->TS_enter_strike_through_mode = NULL; #else /* FIXME: Is calling tgetstr here for non-terminfo case correct, @@ -4621,8 +4621,8 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ const char *bg; /* Our own non-standard support for 24-bit colors. */ if ((fg = tigetstr ("setf24")) && (bg = tigetstr ("setb24")) - && fg != (char *) (intptr_t) -1 - && bg != (char *) (intptr_t) -1) + && fg != (char *) (intptr_t) {-1} + && bg != (char *) (intptr_t) {-1}) { tty->TS_set_foreground = fg; tty->TS_set_background = bg; @@ -4630,8 +4630,8 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ } /* Other non-standard support for 24-bit colors. */ else if ((fg = tigetstr ("setrgbf")) && (bg = tigetstr ("setrgbb")) - && fg != (char *) (intptr_t) -1 - && bg != (char *) (intptr_t) -1) + && fg != (char *) (intptr_t) {-1} + && bg != (char *) (intptr_t) {-1}) { tty->TS_set_foreground = fg; tty->TS_set_background = bg; @@ -4692,7 +4692,7 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ common default escape sequence and is not recommended. */ #ifdef TERMINFO tty->TF_set_underline_style = tigetstr ("Smulx"); - if (tty->TF_set_underline_style == (char *) (intptr_t) -1) + if (tty->TF_set_underline_style == (char *) (intptr_t) {-1}) tty->TF_set_underline_style = NULL; #else tty->TF_set_underline_style = tgetstr ("Smulx", address); diff --git a/src/w32gui.h b/src/w32gui.h index a0e2763462b..40bc786bf06 100644 --- a/src/w32gui.h +++ b/src/w32gui.h @@ -33,6 +33,8 @@ typedef HWND Window; typedef HDC Display; /* HDC so it doesn't conflict with xpm lib. */ typedef HCURSOR Emacs_Cursor; +#define WINDOW_HANDLE_UINTPTR(h) ((uintptr_t) (h)) + /* Windows equivalent of XImage. */ typedef struct _XImage { diff --git a/src/widget.c b/src/widget.c index f05818fcc76..8aa67885047 100644 --- a/src/widget.c +++ b/src/widget.c @@ -299,12 +299,12 @@ update_wm_hints (WMShellWidget wmshell, EmacsFrame ew) + (rounded_height - (char_height * ch))); XtVaSetValues ((Widget) wmshell, - XtNbaseWidth, (XtArgVal) base_width, - XtNbaseHeight, (XtArgVal) base_height, - XtNwidthInc, (XtArgVal) (frame_resize_pixelwise ? 1 : cw), - XtNheightInc, (XtArgVal) (frame_resize_pixelwise ? 1 : ch), - XtNminWidth, (XtArgVal) base_width, - XtNminHeight, (XtArgVal) base_height, + XtNbaseWidth, (XtArgVal) {base_width}, + XtNbaseHeight, (XtArgVal) {base_height}, + XtNwidthInc, (XtArgVal) {frame_resize_pixelwise ? 1 : cw}, + XtNheightInc, (XtArgVal) {frame_resize_pixelwise ? 1 : ch}, + XtNminWidth, (XtArgVal) {base_width}, + XtNminHeight, (XtArgVal) {base_height}, NULL); /* Return if size hints really changed. If they did not, then Xt diff --git a/src/xdisp.c b/src/xdisp.c index b00a4b2e1e7..2b4af7d877e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -2848,7 +2848,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) text_glyph: gr = 0; gy = 0; for (; r <= end_row && r->enabled_p; ++r) - if (r->y + (int) r->height > y) + if (r->y + r->height > y) { gr = r; gy = r->y; break; @@ -2948,7 +2948,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) row_glyph: gr = 0, gy = 0; for (; r <= end_row && r->enabled_p; ++r) - if (r->y + (int) r->height > y) + if (r->y + r->height > y) { gr = r; gy = r->y; break; @@ -13509,7 +13509,7 @@ truncate_echo_area (ptrdiff_t nchars) initialized yet, just toss it. */ if (sf->glyphs_initialized_p) with_echo_area_buffer (0, 0, truncate_message_1, - (void *) (intptr_t) nchars, Qnil); + (void *) (intptr_t) {nchars}, Qnil); } } @@ -29092,7 +29092,7 @@ pint2str (register char *buf, register int width, register ptrdiff_t d) } } - for (width -= (int) (p - buf); width > 0; --width) + for (width -= p - buf; width > 0; --width) *p++ = ' '; *p-- = '\0'; while (p > buf) diff --git a/src/xfns.c b/src/xfns.c index 976218819dd..2a1d3f5860e 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1559,7 +1559,7 @@ x_set_border_pixel (struct frame *f, unsigned long pix) { block_input (); XtVaSetValues (f->output_data.x->widget, XtNborderColor, - (Pixel) pix, NULL); + (Pixel) {pix}, NULL); unblock_input (); if (FRAME_VISIBLE_P (f)) @@ -2736,11 +2736,6 @@ static int xic_preedit_start_callback (XIC, XPointer, XPointer); static void xic_string_conversion_callback (XIC, XPointer, XIMStringConversionCallbackStruct *); -#ifndef HAVE_XICCALLBACK_CALLBACK -#define XICCallback XIMCallback -#define XICProc XIMProc -#endif - static XIMCallback Xxic_preedit_draw_callback = { NULL, @@ -2759,11 +2754,19 @@ static XIMCallback Xxic_preedit_done_callback = (XIMProc) xic_preedit_done_callback, }; +#ifdef HAVE_XICCALLBACK_CALLBACK static XICCallback Xxic_preedit_start_callback = { NULL, - (XICProc) xic_preedit_start_callback, + xic_preedit_start_callback, }; +#else +static XIMCallback Xxic_preedit_start_callback = + { + NULL, + (XIMProc) xic_preedit_start_callback, + }; +#endif static XIMCallback Xxic_string_conversion_callback = { diff --git a/src/xfont.c b/src/xfont.c index f237badcf27..441ec15fe4d 100644 --- a/src/xfont.c +++ b/src/xfont.c @@ -565,7 +565,7 @@ xfont_match (struct frame *f, Lisp_Object spec) { if (XGetFontProperty (xfont, XA_FONT, &value)) { - char *s = XGetAtomName (display, (Atom) value); + char *s = XGetAtomName (display, (Atom) {value}); /* If DXPC (a Differential X Protocol Compressor) Ver.3.7 is running, XGetAtomName will return null @@ -733,7 +733,7 @@ xfont_open (struct frame *f, Lisp_Object entity, int pixel_size) char *p0, *p; int dashes = 0; - p0 = p = XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value); + p0 = p = XGetAtomName (FRAME_X_DISPLAY (f), (Atom) {value}); /* Count the number of dashes in the "full name". If it is too few, this isn't really the font's full name, so don't use it. diff --git a/src/xmenu.c b/src/xmenu.c index 924db3f0a45..35473f2db0e 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -1131,7 +1131,7 @@ set_frame_menubar (struct frame *f, bool deep_p) menu item is really supposed to be empty. */ /* The intptr_t cast avoids a warning. This value just has to be different from small integers. */ - wv->call_data = (void *) (intptr_t) (-1); + wv->call_data = (void *) (intptr_t) {-1}; if (prev_wv) prev_wv->next = wv; diff --git a/src/xterm.c b/src/xterm.c index 06fe480646e..358e01c776a 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1182,15 +1182,9 @@ static bool x_handle_net_wm_state (struct frame *, const XPropertyEvent *); static void x_check_fullscreen (struct frame *); static void x_check_expected_move (struct frame *, int, int); static void x_sync_with_move (struct frame *, int, int, bool); -#ifndef HAVE_XINPUT2 -static int handle_one_xevent (struct x_display_info *, - const XEvent *, int *, - struct input_event *); -#else static int handle_one_xevent (struct x_display_info *, XEvent *, int *, struct input_event *); -#endif #if ! (defined USE_X_TOOLKIT || defined USE_MOTIF) && defined USE_GTK static int x_dispatch_event (XEvent *, Display *); #endif @@ -6187,7 +6181,9 @@ x_try_cr_xlib_drawable (struct frame *f, GC gc) cairo_destroy (buf); cairo_set_user_data (cr, &saved_drawable_key, - (void *) (uintptr_t) FRAME_X_RAW_DRAWABLE (f), NULL); + ((void *) + WINDOW_HANDLE_UINTPTR (FRAME_X_RAW_DRAWABLE (f))), + NULL); FRAME_X_RAW_DRAWABLE (f) = pixmap; cairo_surface_flush (xlib_surface); @@ -9010,7 +9006,7 @@ cvt_string_to_pixel (Display *dpy, XrmValue *args, Cardinal *nargs, screen = *(Screen **) args[0].addr; cmap = *(Colormap *) args[1].addr; - color_name = (String) from->addr; + color_name = from->addr; if (strcmp (color_name, XtDefaultBackground) == 0) { @@ -18868,11 +18864,7 @@ x_find_selection_owner (struct x_display_info *dpyinfo, Atom selection) static int handle_one_xevent (struct x_display_info *dpyinfo, -#ifndef HAVE_XINPUT2 - const XEvent *event, -#else XEvent *event, -#endif int *finish, struct input_event *hold_quit) { union buffered_input_event inev; @@ -19363,7 +19355,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (f) { _XEditResCheckMessages (f->output_data.x->widget, - NULL, (XEvent *) event, NULL); + NULL, event, NULL); goto done; } @@ -19437,7 +19429,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, == dpyinfo->Xatom_net_wm_frame_drawn) { if (any) - x_sync_handle_frame_drawn (dpyinfo, (XEvent *) event, any); + x_sync_handle_frame_drawn (dpyinfo, event, any); goto done; } @@ -19460,8 +19452,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dx = 0; dy = 0; - rc = x_coords_from_dnd_message (dpyinfo, (XEvent *) event, - &dx, &dy); + rc = x_coords_from_dnd_message (dpyinfo, event, &dx, &dy); if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie, rc, dx, dy)) @@ -19938,12 +19929,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, expose_frame (f, event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height); #ifndef USE_TOOLKIT_SCROLL_BARS - x_scroll_bar_handle_exposure (f, (XEvent *) event); + x_scroll_bar_handle_exposure (f, event); #endif } #ifndef USE_TOOLKIT_SCROLL_BARS else - x_scroll_bar_handle_exposure (f, (XEvent *) event); + x_scroll_bar_handle_exposure (f, event); #endif #ifdef HAVE_XDBE @@ -19980,7 +19971,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, event->xgraphicsexpose.width, event->xgraphicsexpose.height); #ifndef USE_TOOLKIT_SCROLL_BARS - x_scroll_bar_handle_exposure (f, (XEvent *) event); + x_scroll_bar_handle_exposure (f, event); #endif #ifdef USE_GTK x_clear_under_internal_border (f); @@ -22215,7 +22206,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_find_modifier_meanings (dpyinfo); FALLTHROUGH; case MappingKeyboard: - XRefreshKeyboardMapping ((XMappingEvent *) &event->xmapping); + XRefreshKeyboardMapping (&event->xmapping); } goto OTHER; @@ -24251,7 +24242,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { Status status_return; nbytes = XmbLookupString (FRAME_XIC (f), - &xkey, (char *) copy_bufptr, + &xkey, copy_bufptr, copy_bufsiz, &keysym, &status_return); coding = FRAME_X_XIM_CODING (f); @@ -24261,7 +24252,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, copy_bufsiz = nbytes + 1; copy_bufptr = SAFE_ALLOCA (copy_bufsiz); nbytes = XmbLookupString (FRAME_XIC (f), - &xkey, (char *) copy_bufptr, + &xkey, copy_bufptr, copy_bufsiz, &keysym, &status_return); } @@ -25494,7 +25485,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (event->type == (dpyinfo->xrandr_event_base + RRScreenChangeNotify)) - XRRUpdateConfiguration ((XEvent *) event); + XRRUpdateConfiguration (event); if (event->type == (dpyinfo->xrandr_event_base + RRScreenChangeNotify)) @@ -25566,9 +25557,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, && event->xconfigure.height != 0)) { #if defined USE_X_TOOLKIT && defined HAVE_XINPUT2 - XtDispatchEvent (use_copy ? © : (XEvent *) event); + XtDispatchEvent (use_copy ? © : event); #else - XtDispatchEvent ((XEvent *) event); + XtDispatchEvent (event); #endif } } diff --git a/test/src/emacs-module-resources/mod-test.c b/test/src/emacs-module-resources/mod-test.c index a5aeda0a666..3dabca1aa43 100644 --- a/test/src/emacs-module-resources/mod-test.c +++ b/test/src/emacs-module-resources/mod-test.c @@ -794,7 +794,7 @@ emacs_module_init (struct emacs_runtime *ert) { fprintf (stderr, "Runtime size of runtime structure (%"pT" bytes) " "smaller than compile-time size (%"pZ" bytes)", - (T_TYPE) ert->size, (Z_TYPE) sizeof (*ert)); + (T_TYPE) {ert->size}, (Z_TYPE) {sizeof (*ert)}); return 1; } @@ -804,7 +804,7 @@ emacs_module_init (struct emacs_runtime *ert) { fprintf (stderr, "Runtime size of environment structure (%"pT" bytes) " "smaller than compile-time size (%"pZ" bytes)", - (T_TYPE) env->size, (Z_TYPE) sizeof (*env)); + (T_TYPE) {env->size}, (Z_TYPE) {sizeof (*env)}); return 2; } From 6fb6a4f76ddc5dcbb4f6c4693f59ee498a02baca Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 26 May 2026 17:51:44 -0700 Subject: [PATCH 109/112] Pacify GCC better when building the test module * test/Makefile.in ($(test_module)): Compile mini-gmp-gnulib.c, not mini-gmp.c, so that we get its pragmas to pacify GCC. --- test/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile.in b/test/Makefile.in index 21f31f4c2d0..a1d33b98d2b 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -309,7 +309,7 @@ $(test_module): $(test_module:${SO}=.c) ../src/emacs-module.h \ $(AM_V_CCLD)${MKDIR_P} $(dir $@) $(AM_V_at)$(CC) -shared $(CPPFLAGS) $(MODULE_CFLAGS) $(LDFLAGS) \ -o $@ $< $(LIBGMP) \ - $(and $(GMP_H),$(srcdir)/../lib/mini-gmp.c) \ + $(and $(GMP_H),$(srcdir)/../lib/mini-gmp-gnulib.c) \ $(CLOCK_TIME_LIB) $(NANOSLEEP_LIB) endif From 834ff524f98024cbf30771df3849a5d9241ab2e2 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 26 May 2026 17:51:44 -0700 Subject: [PATCH 110/112] Update from Gnulib by running admin/merge-gnulib In addition to the automatic changes, also do the following, needed due to recent Gnulib changes. * admin/merge-gnulib (AVOIDED_MODULES): Add btoc32, c32_apply_type_test, c32_get_type_test, c32isalnum, c32rtomb, c32tolower, c32toupper, localeinfo, mbrtoc32-regular. Remove btowc, iswctype, mbrtowc, wcrtomb, wctype, wctype-h. Also remove iswblank, iswdigit, iswxdigit, locale-h, raise, stdarg-h, some of which perhaps could have been removed earlier. * configure.ac (_REGEX_AVOID_UCHAR_H): New macro. --- admin/merge-gnulib | 18 +- build-aux/config.guess | 17 +- build-aux/config.sub | 11 +- configure.ac | 4 + doc/misc/texinfo.tex | 310 ++++-- lib/acl-internal.h | 12 +- lib/acl.h | 4 +- lib/attribute.h | 17 +- lib/binary-io.c | 2 +- lib/binary-io.h | 8 +- lib/boot-time-aux.h | 8 +- lib/boot-time.c | 4 +- lib/boot-time.h | 2 +- lib/byteswap.in.h | 59 +- lib/careadlinkat.c | 19 +- lib/cdefs.h | 3 +- lib/diffseq.h | 5 +- lib/dynarray.h | 10 +- lib/endian.in.h | 214 ++-- lib/file-has-acl.c | 12 +- lib/fsusage.c | 2 +- lib/gettext.h | 139 ++- lib/gnulib.mk.in | 170 ++- lib/idx.h | 22 +- lib/intprops-internal.h | 51 +- lib/intprops.h | 56 +- lib/nproc.c | 7 +- lib/pthread_sigmask.c | 41 +- lib/readutmp.h | 2 +- lib/regcomp.c | 63 +- lib/regex.c | 1 + lib/regex.h | 10 +- lib/regex_internal.c | 18 +- lib/regex_internal.h | 62 +- lib/regexec.c | 125 ++- lib/scratch_buffer.h | 6 +- lib/set-permissions.c | 8 +- lib/sha1.c | 2 +- lib/sig2str.c | 7 +- lib/signal.in.h | 11 +- lib/stat-time.h | 3 +- lib/stdbit.in.h | 2243 +++++++++++++++++++++++++++++---------- lib/stdc_count_ones.c | 2 +- lib/stdc_memreverse8u.c | 19 + lib/stdcountof.in.h | 124 +++ lib/stdio-consolesafe.c | 12 +- lib/stdio.in.h | 98 +- lib/stdlib.in.h | 6 +- lib/strftime.c | 7 +- lib/string.in.h | 79 +- lib/strnul.c | 2 +- lib/tempname.c | 4 +- lib/time_r.c | 2 +- lib/time_rz.c | 5 +- lib/u64.h | 8 +- m4/free.m4 | 10 +- m4/gettext_h.m4 | 2 +- m4/gnulib-common.m4 | 38 +- m4/gnulib-comp.m4 | 38 +- m4/manywarnings.m4 | 31 +- m4/pthread_sigmask.m4 | 27 +- m4/regex.m4 | 35 +- m4/stdbit_h.m4 | 89 +- m4/stdckdint_h.m4 | 6 +- m4/stdcountof_h.m4 | 53 + m4/stdio_h.m4 | 5 +- 66 files changed, 3317 insertions(+), 1173 deletions(-) create mode 100644 lib/stdc_memreverse8u.c create mode 100644 lib/stdcountof.in.h create mode 100644 m4/stdcountof_h.m4 diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 532a9a46931..20cea5b41e4 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -58,14 +58,18 @@ GNULIB_MODULES=' ' AVOIDED_MODULES=' - access btowc chmod close crypto/af_alg dup fchdir fstat gnulib-i18n - iswblank iswctype iswdigit iswxdigit langinfo-h libgmp-mpq - localcharset locale-h localename-unsafe-limited lock - mbrtowc mbsinit memchr mkdir msvc-inval msvc-nothrow nl_langinfo - openat-die opendir pthread-h raise - save-cwd select setenv sigprocmask stat std-gnu11 stdarg-h strncpy + access btoc32 + c32_apply_type_test c32_get_type_test + c32isalnum c32rtomb c32tolower c32toupper + chmod close crypto/af_alg dup fchdir fstat gnulib-i18n + langinfo-h libgmp-mpq + localcharset localeinfo localename-unsafe-limited lock + mbrtoc32-regular mbsinit memchr mkdir + msvc-inval msvc-nothrow nl_langinfo + openat-die opendir pthread-h + save-cwd select setenv sigprocmask stat std-gnu11 strncpy threadlib tzset unsetenv utime utime-h - wchar-h wcrtomb wctype wctype-h + wchar-h uchar-h ' GNULIB_TOOL_FLAGS=' diff --git a/build-aux/config.guess b/build-aux/config.guess index a9d01fde461..c7f4c3294a6 100755 --- a/build-aux/config.guess +++ b/build-aux/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2025 Free Software Foundation, Inc. +# Copyright 1992-2026 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2025-07-10' +timestamp='2026-05-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2025 Free Software Foundation, Inc. +Copyright 1992-2026 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -150,7 +150,7 @@ UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in -Linux|GNU|GNU/*) +Ironclad|Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build @@ -167,6 +167,8 @@ Linux|GNU|GNU/*) LIBC=gnu #elif defined(__LLVM_LIBC__) LIBC=llvm + #elif defined(__mlibc__) + LIBC=mlibc #else #include /* First heuristic to detect musl libc. */ @@ -1186,6 +1188,9 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; + sw_64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; @@ -1598,10 +1603,10 @@ EOF GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; x86_64:[Ii]ronclad:*:*|i?86:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-pc-ironclad-mlibc + GUESS=$UNAME_MACHINE-pc-ironclad-$LIBC ;; *:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-unknown-ironclad-mlibc + GUESS=$UNAME_MACHINE-unknown-ironclad-$LIBC ;; esac diff --git a/build-aux/config.sub b/build-aux/config.sub index 3d35cde174d..404aa082444 100755 --- a/build-aux/config.sub +++ b/build-aux/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2025 Free Software Foundation, Inc. +# Copyright 1992-2026 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale -timestamp='2025-07-10' +timestamp='2026-05-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -76,7 +76,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2025 Free Software Foundation, Inc. +Copyright 1992-2026 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -1432,6 +1432,7 @@ case $cpu-$vendor in | sparcv9v \ | spu \ | sv1 \ + | sw_64 \ | sx* \ | tahoe \ | thumbv7* \ @@ -1525,7 +1526,7 @@ EOF ;; ironclad*) kernel=ironclad - os=`echo "$basic_os" | sed -e 's|ironclad|mlibc|'` + os=`echo "$basic_os" | sed -e 's|ironclad|gnu|'` ;; linux*) kernel=linux @@ -2220,7 +2221,7 @@ case $kernel-$os-$obj in ;; uclinux-uclibc*- | uclinux-gnu*- ) ;; - ironclad-mlibc*-) + ironclad-gnu*- | ironclad-mlibc*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; diff --git a/configure.ac b/configure.ac index 9832ef2f7ba..ef64ef5918d 100644 --- a/configure.ac +++ b/configure.ac @@ -1615,6 +1615,10 @@ AC_DEFUN([gt_TYPE_WINT_T], AC_DEFUN([gl_TYPE_OFF64_T], [HAVE_OFF64_T=1 AC_SUBST([HAVE_OFF64_T])]) +# Emacs does not want Gnulib's fixes for glibc bug 20381 or for +# Unicode-compatible case matching, as that brings in too many Gnulib files. +AC_DEFINE([_REGEX_AVOID_UCHAR_H], [1], + [Define to 1 so that the Gnulib regex module does not use Gnulib uchar-h.]) # Initialize gnulib right after choosing the compiler. dnl Amongst other things, this sets AR and ARFLAGS. diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex index 260bf4a9f80..54c2f3e7831 100644 --- a/doc/misc/texinfo.tex +++ b/doc/misc/texinfo.tex @@ -3,7 +3,7 @@ % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % -\def\texinfoversion{2025-12-23.13} +\def\texinfoversion{2026-04-26.12} % % Copyright 1985, 1986, 1988, 1990-2025 Free Software Foundation, Inc. % @@ -348,7 +348,6 @@ % before the \shipout runs. % \atdummies % don't expand commands in the output. - \turnoffactive \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi @@ -5321,14 +5320,13 @@ \def\indexisfl{fl} % Definition for writing index entry sort key. -{ -\catcode`\-=13 -\gdef\indexwritesortas{% +\def\indexwritesortas{% \begingroup \indexnonalnumreappear - \indexwritesortasxxx} -\gdef\indexwritesortasxxx#1{% - \xdef\indexsortkey{#1}\endgroup} + \indexwritesortasxxx +} +\def\indexwritesortasxxx#1{% + \xdef\indexsortkey{#1}\endgroup } \def\indexwriteseealso#1{ @@ -5359,6 +5357,51 @@ \expandafter\doindexsegment#1\subentry\finish\subentry } +% \checksortas\segment +% Call \indexwritesortas if a @sortas command appears in the segment +\def\checksortas#1{ + \let\sortas\relax + \expandafter\checksortasx#1\relax\sortas{}\sortas +} +\def\checksortasx#1\sortas#2#3\sortas{% + \def\tmp{#3}% + \ifx\tmp\empty\else + \indexwritesortas{#2}% + \fi +} + +% \checkseealso\segment +% Call \indexwriteseealso if a @seealso command appears in the segment +\def\checkseealso#1{ + \let\seealso\relax + \expandafter\checkseealsox#1\relax\seealso{}\seealso +} +\def\checkseealsox#1\seealso#2#3\seealso{% + \def\tmp{#3}% + \ifx\tmp\empty\else + \indexwriteseealso{#2}% + \fi +} + +% \checkseeentry\segment +% Call \indexwriteseeentry if a @seeentry command appears in the segment +\def\checkseeentry#1{ + \let\seeentry\relax + \expandafter\checkseeentryx#1\relax\seeentry{}\seeentry +} +\def\checkseeentryx#1\seeentry#2#3\seeentry{% + \def\tmp{#3}% + \ifx\tmp\empty\else + \indexwriteseeentry{#2}% + \fi +} + +\def\extractindexcommands#1{% + \checksortas#1% + \checkseealso#1% + \checkseeentry#1% +} + % append the results from the next segment \def\doindexsegment#1\subentry{% \def\segment{#1}% @@ -5378,9 +5421,6 @@ % Get the string to sort by. Process the segment with all % font commands turned off. \bgroup - \let\sortas\indexwritesortas - \let\seealso\indexwriteseealso - \let\seeentry\indexwriteseeentry \indexnofonts % The braces around the commands are recognized by texindex. \def\lbracechar{{\string\indexlbrace}}% @@ -5394,11 +5434,10 @@ % \let\indexsortkey\empty \global\let\pagenumbertext\empty - % Execute the segment and throw away the typeset output. This executes - % any @sortas or @seealso commands in this segment. - \setbox\dummybox = \hbox{\segment}% + \extractindexcommands\segment \ifx\indexsortkey\empty{% \indexnonalnumdisappear + \inindexsortkeytrue \xdef\trimmed{\segment}% \xdef\trimmed{\expandafter\eatspaces\expandafter{\trimmed}}% \xdef\indexsortkey{\trimmed}% @@ -5419,7 +5458,6 @@ \fi } \def\isfinish{\finish}% -\newbox\dummybox % used above \let\subentry\relax @@ -7007,6 +7045,7 @@ \newdimen\curchapmax \newdimen\cursecmax \newdimen\curssecmax +\newbox\dummybox % used above % set #1 to the maximum section width for #2 @@ -10231,6 +10270,15 @@ \global\righthyphenmin = #3\relax } +% @documentlanguagevariant - do nothing +\parseargdef\documentlanguagevariant{} + +% @documentscript - do nothing +% This command would only become relevant if we had translations in +% multiple "scripts", e.g. Sebian in both Latin and Cyrillic alphabets. +% However, we do not even support loading Cyrillic fonts. +\parseargdef\documentscript{} + % XeTeX and LuaTeX can handle Unicode natively. % Their default I/O uses UTF-8 sequences instead of a byte-wise operation. % Other TeX engines' I/O (pdfTeX, etc.) is byte-wise. @@ -10673,6 +10721,38 @@ \newif\ifutfviiidefinedwarning \utfviiidefinedwarningtrue +% Macros to output a string to sort a multibyte UTF-8 sequence by. +% Check if there is a special definition to be used in the index +% sort key for a character. +% Output the sequence as-is, surrounded by curly braces. The braces are +% to help texindex find the first character regardless of locale character +% encoding or version of awk used to run texindex. +\gdef\UTFviiiSortkeyTwo#1#2{% + \expandafter\ifx\csname sort:#1#2\endcsname\relax + {\string #1\string #2}% + \else + \csname sort:#1#2\endcsname + \fi +} +\gdef\UTFviiiSortkeyThree#1#2#3{% + \expandafter\ifx\csname sort:#1#2#3\endcsname\relax + {\string #1\string #2\string #3}% + \else + \csname sort:#1#2#3\endcsname + \fi +} +\gdef\UTFviiiSortkeyFour#1#2#3#4{% + \expandafter\ifx\csname sort:#1#2#3#4\endcsname\relax + {\string #1\string #2\string #3\string #4}% + \else + \csname sort:#1#2#3#4\endcsname + \fi +} + +% We use this with the \ifindexsortkey condition to expand and discard +% an \else block in the containing conditional. +\def\swapnestedfi#1\fi{\fi\expandafter#1\expandafter} + % Give non-ASCII bytes the active definitions for processing UTF-8 sequences \begingroup \catcode`\~13 @@ -10691,8 +10771,8 @@ \expandafter\UTFviiiLoop \fi} % - % For bytes other than the first in a UTF-8 sequence. Not expected to - % be expanded except when writing to auxiliary files. + % UTF-8 continuation bytes (10XX XXXX) or unused (hex C1, C2). + % Not expected to be expanded except when writing to auxiliary files. \countUTFx = "80 \countUTFy = "C2 \def\UTFviiiTmp{% @@ -10704,7 +10784,9 @@ \countUTFy = "E0 \def\UTFviiiTmp{% \gdef~{% - \ifpassthroughchars $% + \ifpassthroughchars + \ifinindexsortkey\swapnestedfi\UTFviiiSortkeyTwo\fi + $% \else\expandafter\UTFviiiTwoOctets\expandafter$\fi}}% \UTFviiiLoop @@ -10712,7 +10794,9 @@ \countUTFy = "F0 \def\UTFviiiTmp{% \gdef~{% - \ifpassthroughchars $% + \ifpassthroughchars + \ifinindexsortkey\swapnestedfi\UTFviiiSortkeyThree\fi + $% \else\expandafter\UTFviiiThreeOctets\expandafter$\fi}}% \UTFviiiLoop @@ -10720,7 +10804,9 @@ \countUTFy = "F4 \def\UTFviiiTmp{% \gdef~{% - \ifpassthroughchars $% + \ifpassthroughchars + \ifinindexsortkey\swapnestedfi\UTFviiiSortkeyFour\fi + $% \else\expandafter\UTFviiiFourOctets\expandafter$\fi }}% \UTFviiiLoop @@ -10814,7 +10900,7 @@ \parseXMLCharref % % Completely expand \UTFviiiTmp, which looks like: - % 1. \UTFviiTwoOctetsName B1 B2 + % 1. \UTFviiiTwoOctetsName B1 B2 % 2. \csname u8:B1 \string B2 \endcsname % 3. \u8: B1 B2 (a single control sequence token) \xdef\UTFviiiTmp{\UTFviiiTmp}% @@ -10891,6 +10977,55 @@ \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup +% Used in \DefineSortKey as temporary definitions of \UTFviiiTwoOctetsName etc. +% Use \expandafter\noexpand to prevent excessive expansion if \DefineSortKey is +% called more than once for the same codepoint. +\def\UTFviiiSortTwoOctetsName#1#2{% + \expandafter\noexpand\csname sort:#1\string #2\endcsname}% +\def\UTFviiiSortThreeOctetsName#1#2#3{% + \expandafter\noexpand\csname sort:#1\string #2\string #3\endcsname}% +\def\UTFviiiSortFourOctetsName#1#2#3#4{% + \expandafter\noexpand\csname sort:#1\string #2\string #3\string #4\endcsname}% + +% To be used in translation files to provide strings to be output +% in the index sort key where a character occurs. +\def\DefineSortKey#1#2{% + \countUTFz = "#1\relax + \parseXMLCharref + \def\tmp{#2}% + \expandafter\let\csname usort:#1\endcsname\tmp + \bgroup + \let\UTFviiiTwoOctetsName\UTFviiiSortTwoOctetsName + \let\UTFviiiThreeOctetsName\UTFviiiSortThreeOctetsName + \let\UTFviiiFourOctetsName\UTFviiiSortFourOctetsName + % + % Expand \UTFviiiTmp fully, which looks like: + % 1. \UTFviiiTwoOctetsName B1 B2 + % 2. \expandafter\noexpand\csname sort:B1 \string B2 \endcsname + % 3. \noexpand\sort: B1 B2 + % 4. \sort: B1 B2 (a single control sequence token) + % + \xdef\UTFviiiTmp{\UTFviiiTmp}% + \egroup + \expandafter\gdef\UTFviiiTmp{#2}% +} + +% this could be used as follows +%\DefineSortKey{00F1}{nzzz} % n tilde - sort between n and o +%\DefineSortKey{00D1}{Nzzz} % N tilde - sort between n and o + +% Can be used in place of \DeclareUnicodeCharacter where the value for +% the character is completely expandable when writing to indices: +% Good: \DeclareUnicodeCharacterSK{00C9}{\'E} +% (\' expands to empty string) +% Bad: \DeclareUnicodeCharacterSK{03BB}{\ensuremath\lambda}% +% (\ensuremath expands to junk) +\def\DeclareUnicodeCharacterSK#1#2{% + \DeclareUnicodeCharacter{#1}{#2}% + \DefineSortKey{#1}{#2}% +} + + % For native Unicode handling (XeTeX and LuaTeX), % provide a definition macro that sets a catcode to `other' non-globally % @@ -11054,73 +11189,73 @@ \DeclareUnicodeCharacter{00BE}{$3\over4$}% \DeclareUnicodeCharacter{00BF}{\questiondown}% % - \DeclareUnicodeCharacter{00C0}{\`A}% - \DeclareUnicodeCharacter{00C1}{\'A}% - \DeclareUnicodeCharacter{00C2}{\^A}% - \DeclareUnicodeCharacter{00C3}{\~A}% - \DeclareUnicodeCharacter{00C4}{\"A}% - \DeclareUnicodeCharacter{00C5}{\AA}% - \DeclareUnicodeCharacter{00C6}{\AE}% - \DeclareUnicodeCharacter{00C7}{\cedilla{C}}% - \DeclareUnicodeCharacter{00C8}{\`E}% - \DeclareUnicodeCharacter{00C9}{\'E}% - \DeclareUnicodeCharacter{00CA}{\^E}% - \DeclareUnicodeCharacter{00CB}{\"E}% - \DeclareUnicodeCharacter{00CC}{\`I}% - \DeclareUnicodeCharacter{00CD}{\'I}% - \DeclareUnicodeCharacter{00CE}{\^I}% - \DeclareUnicodeCharacter{00CF}{\"I}% + \DeclareUnicodeCharacterSK{00C0}{\`A}% + \DeclareUnicodeCharacterSK{00C1}{\'A}% + \DeclareUnicodeCharacterSK{00C2}{\^A}% + \DeclareUnicodeCharacterSK{00C3}{\~A}% + \DeclareUnicodeCharacterSK{00C4}{\"A}% + \DeclareUnicodeCharacterSK{00C5}{\AA}% + \DeclareUnicodeCharacterSK{00C6}{\AE}% + \DeclareUnicodeCharacterSK{00C7}{\cedilla{C}}% + \DeclareUnicodeCharacterSK{00C8}{\`E}% + \DeclareUnicodeCharacterSK{00C9}{\'E}% + \DeclareUnicodeCharacterSK{00CA}{\^E}% + \DeclareUnicodeCharacterSK{00CB}{\"E}% + \DeclareUnicodeCharacterSK{00CC}{\`I}% + \DeclareUnicodeCharacterSK{00CD}{\'I}% + \DeclareUnicodeCharacterSK{00CE}{\^I}% + \DeclareUnicodeCharacterSK{00CF}{\"I}% % - \DeclareUnicodeCharacter{00D0}{\DH}% - \DeclareUnicodeCharacter{00D1}{\~N}% - \DeclareUnicodeCharacter{00D2}{\`O}% - \DeclareUnicodeCharacter{00D3}{\'O}% - \DeclareUnicodeCharacter{00D4}{\^O}% - \DeclareUnicodeCharacter{00D5}{\~O}% - \DeclareUnicodeCharacter{00D6}{\"O}% + \DeclareUnicodeCharacterSK{00D0}{\DH}% + \DeclareUnicodeCharacterSK{00D1}{\~N}% + \DeclareUnicodeCharacterSK{00D2}{\`O}% + \DeclareUnicodeCharacterSK{00D3}{\'O}% + \DeclareUnicodeCharacterSK{00D4}{\^O}% + \DeclareUnicodeCharacterSK{00D5}{\~O}% + \DeclareUnicodeCharacterSK{00D6}{\"O}% \DeclareUnicodeCharacter{00D7}{\ensuremath\times}% - \DeclareUnicodeCharacter{00D8}{\O}% - \DeclareUnicodeCharacter{00D9}{\`U}% - \DeclareUnicodeCharacter{00DA}{\'U}% - \DeclareUnicodeCharacter{00DB}{\^U}% - \DeclareUnicodeCharacter{00DC}{\"U}% - \DeclareUnicodeCharacter{00DD}{\'Y}% + \DeclareUnicodeCharacterSK{00D8}{\O}% + \DeclareUnicodeCharacterSK{00D9}{\`U}% + \DeclareUnicodeCharacterSK{00DA}{\'U}% + \DeclareUnicodeCharacterSK{00DB}{\^U}% + \DeclareUnicodeCharacterSK{00DC}{\"U}% + \DeclareUnicodeCharacterSK{00DD}{\'Y}% \DeclareUnicodeCharacter{00DE}{\TH}% - \DeclareUnicodeCharacter{00DF}{\ss}% + \DeclareUnicodeCharacterSK{00DF}{\ss}% % - \DeclareUnicodeCharacter{00E0}{\`a}% - \DeclareUnicodeCharacter{00E1}{\'a}% - \DeclareUnicodeCharacter{00E2}{\^a}% - \DeclareUnicodeCharacter{00E3}{\~a}% - \DeclareUnicodeCharacter{00E4}{\"a}% - \DeclareUnicodeCharacter{00E5}{\aa}% - \DeclareUnicodeCharacter{00E6}{\ae}% - \DeclareUnicodeCharacter{00E7}{\cedilla{c}}% - \DeclareUnicodeCharacter{00E8}{\`e}% - \DeclareUnicodeCharacter{00E9}{\'e}% - \DeclareUnicodeCharacter{00EA}{\^e}% - \DeclareUnicodeCharacter{00EB}{\"e}% - \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}% - \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}% - \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}% - \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}% + \DeclareUnicodeCharacterSK{00E0}{\`a}% + \DeclareUnicodeCharacterSK{00E1}{\'a}% + \DeclareUnicodeCharacterSK{00E2}{\^a}% + \DeclareUnicodeCharacterSK{00E3}{\~a}% + \DeclareUnicodeCharacterSK{00E4}{\"a}% + \DeclareUnicodeCharacterSK{00E5}{\aa}% + \DeclareUnicodeCharacterSK{00E6}{\ae}% + \DeclareUnicodeCharacterSK{00E7}{\cedilla{c}}% + \DeclareUnicodeCharacterSK{00E8}{\`e}% + \DeclareUnicodeCharacterSK{00E9}{\'e}% + \DeclareUnicodeCharacterSK{00EA}{\^e}% + \DeclareUnicodeCharacterSK{00EB}{\"e}% + \DeclareUnicodeCharacterSK{00EC}{\`{\dotless{i}}}% + \DeclareUnicodeCharacterSK{00ED}{\'{\dotless{i}}}% + \DeclareUnicodeCharacterSK{00EE}{\^{\dotless{i}}}% + \DeclareUnicodeCharacterSK{00EF}{\"{\dotless{i}}}% % - \DeclareUnicodeCharacter{00F0}{\dh}% - \DeclareUnicodeCharacter{00F1}{\~n}% - \DeclareUnicodeCharacter{00F2}{\`o}% - \DeclareUnicodeCharacter{00F3}{\'o}% - \DeclareUnicodeCharacter{00F4}{\^o}% - \DeclareUnicodeCharacter{00F5}{\~o}% - \DeclareUnicodeCharacter{00F6}{\"o}% + \DeclareUnicodeCharacterSK{00F0}{\dh}% + \DeclareUnicodeCharacterSK{00F1}{\~n}% + \DeclareUnicodeCharacterSK{00F2}{\`o}% + \DeclareUnicodeCharacterSK{00F3}{\'o}% + \DeclareUnicodeCharacterSK{00F4}{\^o}% + \DeclareUnicodeCharacterSK{00F5}{\~o}% + \DeclareUnicodeCharacterSK{00F6}{\"o}% \DeclareUnicodeCharacter{00F7}{\ensuremath\div}% - \DeclareUnicodeCharacter{00F8}{\o}% - \DeclareUnicodeCharacter{00F9}{\`u}% - \DeclareUnicodeCharacter{00FA}{\'u}% - \DeclareUnicodeCharacter{00FB}{\^u}% - \DeclareUnicodeCharacter{00FC}{\"u}% - \DeclareUnicodeCharacter{00FD}{\'y}% + \DeclareUnicodeCharacterSK{00F8}{\o}% + \DeclareUnicodeCharacterSK{00F9}{\`u}% + \DeclareUnicodeCharacterSK{00FA}{\'u}% + \DeclareUnicodeCharacterSK{00FB}{\^u}% + \DeclareUnicodeCharacterSK{00FC}{\"u}% + \DeclareUnicodeCharacterSK{00FD}{\'y}% \DeclareUnicodeCharacter{00FE}{\th}% - \DeclareUnicodeCharacter{00FF}{\"y}% + \DeclareUnicodeCharacterSK{00FF}{\"y}% % \DeclareUnicodeCharacter{0100}{\=A}% \DeclareUnicodeCharacter{0101}{\=a}% @@ -11719,6 +11854,9 @@ \newif\ifpassthroughchars \passthroughcharsfalse +\newif\ifinindexsortkey +\inindexsortkeyfalse + % For native Unicode handling (XeTeX and LuaTeX), % provide a definition macro to replace/pass-through a Unicode character % @@ -11730,7 +11868,15 @@ \uccode`\~="##2\relax \uppercase{\gdef~}{% \ifpassthroughchars - ##1% + \ifinindexsortkey + \expandafter\ifx\csname usort:#1\endcsname\relax + {##1}% + \else + \csname usort:#1\endcsname + \fi + \else + ##1% + \fi \else ##3% \fi diff --git a/lib/acl-internal.h b/lib/acl-internal.h index 855005bb756..eafb4d027fb 100644 --- a/lib/acl-internal.h +++ b/lib/acl-internal.h @@ -249,17 +249,19 @@ struct permission_context { # elif defined GETACL /* Solaris, Cygwin < 2.5 */ int count; - aclent_t *entries; + aclent_t *entries + _GL_ATTRIBUTE_COUNTED_BY (count); # ifdef ACE_GETACL int ace_count; - ace_t *ace_entries; + ace_t *ace_entries + _GL_ATTRIBUTE_COUNTED_BY (ace_count); # endif # elif HAVE_GETACL /* HP-UX */ - struct acl_entry entries[NACLENTRIES]; + struct acl_entry entries[NACLENTRIES] /* COUNTED_BY (count) */; int count; # if HAVE_ACLV_H - struct acl aclv_entries[NACLVENTRIES]; + struct acl aclv_entries[NACLVENTRIES] /* COUNTED_BY (aclv_count) */; int aclv_count; # endif @@ -268,7 +270,7 @@ struct permission_context { bool have_u; # elif HAVE_ACLSORT /* NonStop Kernel */ - struct acl entries[NACLENTRIES]; + struct acl entries[NACLENTRIES] /* COUNTED_BY (count) */; int count; # endif diff --git a/lib/acl.h b/lib/acl.h index 85453217c63..4ac25fe226d 100644 --- a/lib/acl.h +++ b/lib/acl.h @@ -48,7 +48,7 @@ struct aclinfo { /* If 'size' is nonnegative, a buffer holding the concatenation of extended attribute names, each terminated by NUL - (either u.__gl_acl_ch, or heap-allocated). */ + (either u._gl_acl_ch, or heap-allocated). */ char *buf; /* The number of useful bytes at the start of buf, counting trailing NULs. @@ -72,7 +72,7 @@ struct aclinfo trivial NFSv4 ACL (a size used by file-has-acl.c in 2023-2024 but no longer relevant now), and a different value might be better once experience is gained. For internal use only. */ - char __gl_acl_ch[152]; + char _gl_acl_ch[152]; } u; }; diff --git a/lib/attribute.h b/lib/attribute.h index c50befdfdd2..10de47516f3 100644 --- a/lib/attribute.h +++ b/lib/attribute.h @@ -81,8 +81,8 @@ /* This file uses _GL_ATTRIBUTE_ALLOC_SIZE, _GL_ATTRIBUTE_ALWAYS_INLINE, _GL_ATTRIBUTE_ARTIFICIAL, _GL_ATTRIBUTE_COLD, _GL_ATTRIBUTE_CONST, - _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_DEPRECATED, _GL_ATTRIBUTE_ERROR, - _GL_ATTRIBUTE_WARNING, _GL_ATTRIBUTE_EXTERNALLY_VISIBLE, + _GL_ATTRIBUTE_COUNTED_BY, _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_DEPRECATED, + _GL_ATTRIBUTE_ERROR, _GL_ATTRIBUTE_WARNING, _GL_ATTRIBUTE_EXTERNALLY_VISIBLE, _GL_ATTRIBUTE_FALLTHROUGH, _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_LEAF, _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_MAY_ALIAS, _GL_ATTRIBUTE_MAYBE_UNUSED, _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOINLINE, _GL_ATTRIBUTE_NONNULL, @@ -210,6 +210,19 @@ #define FALLTHROUGH _GL_ATTRIBUTE_FALLTHROUGH +/* =================== Attributes for runtime diagnostics =================== */ + +/* Attributes that provide information to the undefined-behaviour sanitizer + (UBSAN). */ + +/* COUNTED_BY (C) declares that the number of elements of the field is given + by C, which must be another field in the same struct. + The programmer is responsible for guaranteeing some invariants; see + for details. */ +/* Applies to struct fields of type array or pointer (to data). */ +#define COUNTED_BY(c) _GL_ATTRIBUTE_COUNTED_BY (c) + + /* ================== Attributes for debugging information ================== */ /* Attributes regarding debugging information emitted by the compiler. */ diff --git a/lib/binary-io.c b/lib/binary-io.c index 45060f689c6..d465eb47075 100644 --- a/lib/binary-io.c +++ b/lib/binary-io.c @@ -32,7 +32,7 @@ set_binary_mode (int fd, int mode) with console input or console output. */ return O_TEXT; else - return __gl_setmode (fd, mode); + return _gl_set_fd_mode (fd, mode); } #endif diff --git a/lib/binary-io.h b/lib/binary-io.h index 37eb3c4bb18..bc001a71c0f 100644 --- a/lib/binary-io.h +++ b/lib/binary-io.h @@ -38,9 +38,9 @@ _GL_INLINE_HEADER_BEGIN #if O_BINARY # if defined __EMX__ || defined __DJGPP__ || defined __CYGWIN__ # include /* declares setmode() */ -# define __gl_setmode setmode +# define _gl_set_fd_mode setmode # else -# define __gl_setmode _setmode +# define _gl_set_fd_mode _setmode # undef fileno # define fileno _fileno # endif @@ -49,7 +49,7 @@ _GL_INLINE_HEADER_BEGIN /* Use a function rather than a macro, to avoid gcc warnings "warning: statement with no effect". */ BINARY_IO_INLINE int -__gl_setmode (_GL_UNUSED int fd, _GL_UNUSED int mode) +_gl_set_fd_mode (_GL_UNUSED int fd, _GL_UNUSED int mode) { return O_BINARY; } @@ -72,7 +72,7 @@ extern int set_binary_mode (int fd, int mode); BINARY_IO_INLINE int set_binary_mode (int fd, int mode) { - return __gl_setmode (fd, mode); + return _gl_set_fd_mode (fd, mode); } #endif diff --git a/lib/boot-time-aux.h b/lib/boot-time-aux.h index adafb8c8182..e09d84b67a2 100644 --- a/lib/boot-time-aux.h +++ b/lib/boot-time-aux.h @@ -16,8 +16,6 @@ /* Written by Bruno Haible . */ -#define SIZEOF(a) (sizeof(a)/sizeof(a[0])) - #if defined __linux__ || defined __ANDROID__ /* Store the uptime counter, as managed by the Linux kernel, in *P_UPTIME. @@ -102,7 +100,7 @@ get_linux_boot_time_fallback (struct timespec *p_boot_time) modified when a user logs in, i.e. long after boot. */ "/var/run/utmp" /* seen on Alpine Linux with OpenRC */ }; - for (idx_t i = 0; i < SIZEOF (boot_touched_files); i++) + for (idx_t i = 0; i < countof (boot_touched_files); i++) { const char *filename = boot_touched_files[i]; struct stat statbuf; @@ -214,7 +212,7 @@ get_openbsd_boot_time (struct timespec *p_boot_time) "/var/db/host.random", "/var/run/utmp" }; - for (idx_t i = 0; i < SIZEOF (boot_touched_files); i++) + for (idx_t i = 0; i < countof (boot_touched_files); i++) { const char *filename = boot_touched_files[i]; struct stat statbuf; @@ -325,7 +323,7 @@ get_windows_boot_time (struct timespec *p_boot_time) "C:\\pagefile.sys" #endif }; - for (idx_t i = 0; i < SIZEOF (boot_touched_files); i++) + for (idx_t i = 0; i < countof (boot_touched_files); i++) { const char *filename = boot_touched_files[i]; struct stat statbuf; diff --git a/lib/boot-time.c b/lib/boot-time.c index e8d8811da26..ae305a18067 100644 --- a/lib/boot-time.c +++ b/lib/boot-time.c @@ -21,6 +21,7 @@ /* Specification. */ #include "boot-time.h" +#include #include #include #include @@ -94,7 +95,8 @@ get_boot_time_uncached (struct timespec *p_boot_time) Solaris' utmpname returns 1 upon success -- which is contrary to what the GNU libc version does. In addition, older GNU libc versions are actually void. */ - UTMP_NAME_FUNCTION ((char *) UTMP_FILE); + static char const utmp_file[] = UTMP_FILE; + UTMP_NAME_FUNCTION ((char *) utmp_file); SET_UTMP_ENT (); diff --git a/lib/boot-time.h b/lib/boot-time.h index 82969272ffe..79129924884 100644 --- a/lib/boot-time.h +++ b/lib/boot-time.h @@ -34,7 +34,7 @@ extern "C" { The difference can matter in GNU/Linux, where times in /proc/stat might be relative to boot time of the host, not the container. - This function is not multithread-safe, since on many platforms it + This function is not thread-safe, since on many platforms it invokes the functions setutxent, getutxent, endutxent. These functions may lock a file like /var/log/wtmp (so that we don't read garbage when a concurrent process writes to that file), diff --git a/lib/byteswap.in.h b/lib/byteswap.in.h index b2b26af8b03..02433d30da4 100644 --- a/lib/byteswap.in.h +++ b/lib/byteswap.in.h @@ -23,13 +23,14 @@ #error "Please include config.h first." #endif -/* Define this now, rather than after including stdint.h, in case - stdint.h recursively includes us. This is for Gnulib endian.h. */ +/* Define this now, rather than after including stdbit.h, in case stdbit.h + recursively includes us via stdint.h. This is for Gnulib endian.h. */ #ifndef _GL_BYTESWAP_INLINE # define _GL_BYTESWAP_INLINE _GL_INLINE #endif -#include +#include /* for stdc_memreverse8u* */ +#include /* for UINT_LEAST64_MAX */ _GL_INLINE_HEADER_BEGIN @@ -37,38 +38,12 @@ _GL_INLINE_HEADER_BEGIN extern "C" { #endif -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) -# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 true -#elif defined __has_builtin -# if __has_builtin (__builtin_bswap16) -# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 true -# endif -#endif - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) -# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 true -# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 true -#elif defined __has_builtin -# if __has_builtin (__builtin_bswap32) -# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 true -# endif -# if __has_builtin (__builtin_bswap64) -# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 true -# endif -#endif - /* Given an unsigned 16-bit argument X, return the value corresponding to X with reversed byte order. */ _GL_BYTESWAP_INLINE uint_least16_t bswap_16 (uint_least16_t x) { -#ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 - return __builtin_bswap16 (x); -#else - uint_fast16_t mask = 0xff; - return ( (x & mask << 8 * 1) >> 8 * 1 - | (x & mask << 8 * 0) << 8 * 1); -#endif + return stdc_memreverse8u16 (x); } /* Given an unsigned 32-bit argument X, return the value corresponding to @@ -76,15 +51,7 @@ bswap_16 (uint_least16_t x) _GL_BYTESWAP_INLINE uint_least32_t bswap_32 (uint_least32_t x) { -#ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 - return __builtin_bswap32 (x); -#else - uint_fast32_t mask = 0xff; - return ( (x & mask << 8 * 3) >> 8 * 3 - | (x & mask << 8 * 2) >> 8 * 1 - | (x & mask << 8 * 1) << 8 * 1 - | (x & mask << 8 * 0) << 8 * 3); -#endif + return stdc_memreverse8u32 (x); } #ifdef UINT_LEAST64_MAX @@ -93,19 +60,7 @@ bswap_32 (uint_least32_t x) _GL_BYTESWAP_INLINE uint_least64_t bswap_64 (uint_least64_t x) { -# ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 - return __builtin_bswap64 (x); -# else - uint_fast64_t mask = 0xff; - return ( (x & mask << 8 * 7) >> 8 * 7 - | (x & mask << 8 * 6) >> 8 * 5 - | (x & mask << 8 * 5) >> 8 * 3 - | (x & mask << 8 * 4) >> 8 * 1 - | (x & mask << 8 * 3) << 8 * 1 - | (x & mask << 8 * 2) << 8 * 3 - | (x & mask << 8 * 1) << 8 * 5 - | (x & mask << 8 * 0) << 8 * 7); -# endif + return stdc_memreverse8u64 (x); } #endif diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c index fa19e09986c..c5e8addc660 100644 --- a/lib/careadlinkat.c +++ b/lib/careadlinkat.c @@ -42,22 +42,17 @@ enum { STACK_BUF_SIZE = 1024 }; /* Act like careadlinkat (see below), with an additional argument STACK_BUF that can be used as temporary storage. - If GCC_LINT is defined, do not inline this function with GCC 10.1 - and later, to avoid creating a pointer to the stack that GCC + In GCC 10+, do not inline this function + to avoid creating a pointer to the stack that -Wreturn-local-addr incorrectly complains about. See: https://gcc.gnu.org/PR93644 Although the noinline attribute can hurt performance a bit, no better way - to pacify GCC is known; even an explicit #pragma does not pacify GCC. - When the GCC bug is fixed this workaround should be limited to the + to pacify GCC is known; even an explicit #pragma does not pacify GCC + 10 or 11, or GCC 12+ with -flto. + If the GCC bug is fixed this workaround should be limited to the broken GCC versions. */ #if _GL_GNUC_PREREQ (10, 1) -# if _GL_GNUC_PREREQ (12, 1) -# pragma GCC diagnostic ignored "-Wreturn-local-addr" -# elif defined GCC_LINT || defined lint __attribute__ ((__noinline__)) -# elif __OPTIMIZE__ && !__NO_INLINE__ -# define GCC_BOGUS_WRETURN_LOCAL_ADDR -# endif #endif static char * readlink_stk (int fd, char const *filename, @@ -172,10 +167,6 @@ careadlinkat (int fd, char const *filename, common case of a symlink of small size, we get away with a single small malloc instead of a big malloc followed by a shrinking realloc. */ - #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR - #warning "GCC might issue a bogus -Wreturn-local-addr warning here." - #warning "See ." - #endif char stack_buf[STACK_BUF_SIZE]; return readlink_stk (fd, filename, buffer, buffer_size, alloc, preadlinkat, stack_buf); diff --git a/lib/cdefs.h b/lib/cdefs.h index 42024b20e11..2800057cb7d 100644 --- a/lib/cdefs.h +++ b/lib/cdefs.h @@ -669,7 +669,8 @@ # ifdef __GNUC__ # define __restrict_arr /* Not supported in old GCC. */ # else -# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L \ + && !defined _MSC_VER) # define __restrict_arr restrict # else /* Some other non-C99 compiler. */ diff --git a/lib/diffseq.h b/lib/diffseq.h index cf710a316f8..73fa47b42e1 100644 --- a/lib/diffseq.h +++ b/lib/diffseq.h @@ -82,10 +82,11 @@ #error "Please include config.h first." #endif -/* Maximum value of type OFFSET. */ +/* Maximum value of type OFFSET. The 1u pacifies -Wuseless-cast, and + unlike a compound literal can appear in an integer constant expression. */ #ifndef OFFSET_MAX # define OFFSET_MAX \ - ((((OFFSET) 1 << (sizeof (OFFSET) * CHAR_BIT - 2)) - 1) * 2 + 1) + ((((OFFSET) 1u << (sizeof (OFFSET) * CHAR_BIT - 2)) - 1) * 2 + 1) #endif /* Default to no early abort. */ diff --git a/lib/dynarray.h b/lib/dynarray.h index a5cdf630e55..256340462d6 100644 --- a/lib/dynarray.h +++ b/lib/dynarray.h @@ -249,11 +249,11 @@ static DYNARRAY_ELEMENT * /* The implementation is imported from glibc. */ /* Avoid possible conflicts with symbols exported by the GNU libc. */ -#define __libc_dynarray_at_failure gl_dynarray_at_failure -#define __libc_dynarray_emplace_enlarge gl_dynarray_emplace_enlarge -#define __libc_dynarray_finalize gl_dynarray_finalize -#define __libc_dynarray_resize_clear gl_dynarray_resize_clear -#define __libc_dynarray_resize gl_dynarray_resize +#define __libc_dynarray_at_failure _gl_dynarray_at_failure +#define __libc_dynarray_emplace_enlarge _gl_dynarray_emplace_enlarge +#define __libc_dynarray_finalize _gl_dynarray_finalize +#define __libc_dynarray_resize_clear _gl_dynarray_resize_clear +#define __libc_dynarray_resize _gl_dynarray_resize #if defined DYNARRAY_STRUCT || defined DYNARRAY_ELEMENT || defined DYNARRAY_PREFIX diff --git a/lib/endian.in.h b/lib/endian.in.h index 8e0c2f23840..6fa0678f939 100644 --- a/lib/endian.in.h +++ b/lib/endian.in.h @@ -109,7 +109,7 @@ _GL_INLINE_HEADER_BEGIN extern "C" { #endif -/* These declarations are needed if Gnulib byteswap.h -> stdint.h -> +/* These declarations are needed if Gnulib byteswap.h -> stdbit.h -> stdint.h -> sys/types.h -> endian.h -> Gnulib byteswap.h, the last of which is blocked by its include guard so the functions are not yet declared. */ #ifdef _GL_BYTESWAP_INLINE @@ -120,138 +120,174 @@ _GL_BYTESWAP_INLINE uint_least64_t bswap_64 (uint_least64_t); /* Big endian to host. */ +#if !GNULIB_defined_be16toh _GL_ENDIAN_INLINE uint16_t be16toh (uint16_t x) { -#if BYTE_ORDER == BIG_ENDIAN - return x; -#else - return bswap_16 (x); -#endif -} - -_GL_ENDIAN_INLINE uint32_t -be32toh (uint32_t x) -{ -#if BYTE_ORDER == BIG_ENDIAN - return x; -#else - return bswap_32 (x); -#endif -} - -#ifdef UINT64_MAX -_GL_ENDIAN_INLINE uint64_t -be64toh (uint64_t x) -{ # if BYTE_ORDER == BIG_ENDIAN return x; # else - return bswap_64 (x); + return bswap_16 (x); # endif } +# define GNULIB_defined_be16toh 1 +#endif + +#if !GNULIB_defined_be32toh +_GL_ENDIAN_INLINE uint32_t +be32toh (uint32_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return x; +# else + return bswap_32 (x); +# endif +} +# define GNULIB_defined_be32toh 1 +#endif + +#ifdef UINT64_MAX +# if !GNULIB_defined_be64toh +_GL_ENDIAN_INLINE uint64_t +be64toh (uint64_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return x; +# else + return bswap_64 (x); +# endif +} +# define GNULIB_defined_be64toh 1 +# endif #endif /* Host to big endian. */ +#if !GNULIB_defined_htobe16 _GL_ENDIAN_INLINE uint16_t htobe16 (uint16_t x) { -#if BYTE_ORDER == BIG_ENDIAN - return x; -#else - return bswap_16 (x); -#endif -} - -_GL_ENDIAN_INLINE uint32_t -htobe32 (uint32_t x) -{ -#if BYTE_ORDER == BIG_ENDIAN - return x; -#else - return bswap_32 (x); -#endif -} - -#ifdef UINT64_MAX -_GL_ENDIAN_INLINE uint64_t -htobe64 (uint64_t x) -{ # if BYTE_ORDER == BIG_ENDIAN return x; # else - return bswap_64 (x); + return bswap_16 (x); # endif } +# define GNULIB_defined_htobe16 1 +#endif + +#if !GNULIB_defined_htobe32 +_GL_ENDIAN_INLINE uint32_t +htobe32 (uint32_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return x; +# else + return bswap_32 (x); +# endif +} +# define GNULIB_defined_htobe32 1 +#endif + +#ifdef UINT64_MAX +# if !GNULIB_defined_htobe64 +_GL_ENDIAN_INLINE uint64_t +htobe64 (uint64_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return x; +# else + return bswap_64 (x); +# endif +} +# define GNULIB_defined_htobe64 1 +# endif #endif /* Little endian to host. */ +#if !GNULIB_defined_le16toh _GL_ENDIAN_INLINE uint16_t le16toh (uint16_t x) { -#if BYTE_ORDER == BIG_ENDIAN - return bswap_16 (x); -#else - return x; -#endif -} - -_GL_ENDIAN_INLINE uint32_t -le32toh (uint32_t x) -{ -#if BYTE_ORDER == BIG_ENDIAN - return bswap_32 (x); -#else - return x; -#endif -} - -#ifdef UINT64_MAX -_GL_ENDIAN_INLINE uint64_t -le64toh (uint64_t x) -{ # if BYTE_ORDER == BIG_ENDIAN - return bswap_64 (x); + return bswap_16 (x); # else return x; # endif } +# define GNULIB_defined_le16toh 1 +#endif + +#if !GNULIB_defined_le32toh +_GL_ENDIAN_INLINE uint32_t +le32toh (uint32_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return bswap_32 (x); +# else + return x; +# endif +} +# define GNULIB_defined_le32toh 1 +#endif + +#ifdef UINT64_MAX +# if !GNULIB_defined_le64toh +_GL_ENDIAN_INLINE uint64_t +le64toh (uint64_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return bswap_64 (x); +# else + return x; +# endif +} +# define GNULIB_defined_le64toh 1 +# endif #endif /* Host to little endian. */ +#if !GNULIB_defined_htole16 _GL_ENDIAN_INLINE uint16_t htole16 (uint16_t x) { -#if BYTE_ORDER == BIG_ENDIAN - return bswap_16 (x); -#else - return x; -#endif -} - -_GL_ENDIAN_INLINE uint32_t -htole32 (uint32_t x) -{ -#if BYTE_ORDER == BIG_ENDIAN - return bswap_32 (x); -#else - return x; -#endif -} - -#ifdef UINT64_MAX -_GL_ENDIAN_INLINE uint64_t -htole64 (uint64_t x) -{ # if BYTE_ORDER == BIG_ENDIAN - return bswap_64 (x); + return bswap_16 (x); # else return x; # endif } +# define GNULIB_defined_htole16 1 +#endif + +#if !GNULIB_defined_htole32 +_GL_ENDIAN_INLINE uint32_t +htole32 (uint32_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return bswap_32 (x); +# else + return x; +# endif +} +# define GNULIB_defined_htole32 1 +#endif + +#ifdef UINT64_MAX +# if !GNULIB_defined_htole64 +_GL_ENDIAN_INLINE uint64_t +htole64 (uint64_t x) +{ +# if BYTE_ORDER == BIG_ENDIAN + return bswap_64 (x); +# else + return x; +# endif +} +# define GNULIB_defined_htole64 1 +# endif #endif #ifdef __cplusplus diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 3269d7f71b7..8b9bb0468fe 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -160,8 +160,8 @@ aclinfo_has_xattr (struct aclinfo const *ai, char const *xattr) static void get_aclinfo (int fd, char const *name, struct aclinfo *ai, int flags) { - ai->buf = ai->u.__gl_acl_ch; - ssize_t acl_alloc = sizeof ai->u.__gl_acl_ch; + ai->buf = ai->u._gl_acl_ch; + ssize_t acl_alloc = sizeof ai->u._gl_acl_ch; if (! (USE_ACL || flags & ACL_GET_SCONTEXT)) ai->size = 0; @@ -194,10 +194,10 @@ get_aclinfo (int fd, char const *name, struct aclinfo *ai, int flags) /* Grow allocation to at least 'size'. Grow it by a nontrivial amount, to defend against denial of service by an adversary that fiddles with ACLs. */ - if (ai->buf != ai->u.__gl_acl_ch) + if (ai->buf != ai->u._gl_acl_ch) { free (ai->buf); - ai->buf = ai->u.__gl_acl_ch; + ai->buf = ai->u._gl_acl_ch; } if (ckd_add (&acl_alloc, acl_alloc, acl_alloc >> 1)) acl_alloc = SSIZE_MAX; @@ -297,7 +297,7 @@ aclinfo_scontext_free (char *scontext) void aclinfo_free (struct aclinfo *ai) { - if (ai->buf != ai->u.__gl_acl_ch) + if (ai->buf != ai->u._gl_acl_ch) free (ai->buf); aclinfo_scontext_free (ai->scontext); } @@ -510,7 +510,7 @@ fdfile_has_aclinfo (MAYBE_UNUSED int fd, #else /* !USE_LINUX_XATTR */ - ai->buf = ai->u.__gl_acl_ch; + ai->buf = ai->u._gl_acl_ch; ai->size = -1; ai->u.err = ENOTSUP; ai->scontext = (char *) UNKNOWN_SECURITY_CONTEXT; diff --git a/lib/fsusage.c b/lib/fsusage.c index 1700a19c996..fbb38d7ab08 100644 --- a/lib/fsusage.c +++ b/lib/fsusage.c @@ -57,7 +57,7 @@ && (~ (x) == (sizeof (x) < sizeof (int) \ ? - (1 << (sizeof (x) * CHAR_BIT)) \ : 0))) \ - ? UINTMAX_MAX : (uintmax_t) (x)) + ? UINTMAX_MAX : (uintmax_t) {(x)}) /* Extract the top bit of X as an uintmax_t value. */ #define EXTRACT_TOP_BIT(x) ((x) \ diff --git a/lib/gettext.h b/lib/gettext.h index 0291cf09c5f..02b8b7b8de4 100644 --- a/lib/gettext.h +++ b/lib/gettext.h @@ -60,10 +60,40 @@ # endif /* Disabled NLS. */ +/* When gcc is used with option -Wformat=2, we need to silence + "warning: format not a string literal, argument types not checked [-Wformat-nonliteral]" + warnings that would occur at every invocation of a *gettext function + in a *printf format string position. + Do this with inline functions when possible, namely for gettext, dgettext, + dcgettext, which are known to gcc as "external built-ins". + It is not ideal to ignore the possible side effects done in the + Domainname and Category arguments, but it's better than to have a + warning at every invocation in a format string position. */ +/* When clang is used with option -Wformat=2, we need to silence + "warning: format string is not a string literal [-Wformat-nonliteral]" + warnings that would occur at every invocation of a *gettext function + in a *printf format string position. + It is not ideal to ignore the possible side effects done in the + Domainname and Category arguments, but it's better than to have a + warning at every invocation in a format string position. */ +/* These warnings would not occur with enabled NLS. */ +/* A test case: + ================================ foo.c ================================ + #include + #include "gettext.h" + void foo (int n) + { + printf (gettext ("foo %d"), n); + printf (dgettext ("toto", "foo %d"), n); + printf (dcgettext ("toto", "foo %d", LC_MESSAGES), n); + printf (ngettext ("foo %d", "bar %d", n), n); + printf (dngettext ("toto", "foo %d", "bar %d", n), n); + printf (dcngettext ("toto", "foo %d", "bar %d", n, LC_MESSAGES), n); + } + ======================================================================= + $CC -Wformat=2 -S foo.c + */ # if defined __GNUC__ && !defined __clang__ && !defined __cplusplus -/* Use inline functions, to avoid warnings - warning: format not a string literal and no format arguments - that don't occur with enabled NLS. */ /* The return type 'const char *' serves the purpose of producing warnings for invalid uses of the value returned from these functions. */ # if __GNUC__ >= 9 @@ -118,36 +148,80 @@ dcgettext (const char *domain, const char *msgid, int category) # if __GNUC__ >= 9 # pragma GCC diagnostic pop # endif -# else -/* The casts to 'const char *' serve the purpose of producing warnings - for invalid uses of the value returned from these functions. */ +# elif defined __clang__ # undef gettext # define gettext(Msgid) ((const char *) (Msgid)) # undef dgettext -# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) +# define dgettext(Domainname, Msgid) gettext (Msgid) +# undef dcgettext +# define dcgettext(Domainname, Msgid, Category) dgettext (Domainname, Msgid) +# else +/* The conversions to 'const char *' via compound literals serve the purpose + of producing warnings for invalid uses of the value returned from these + functions and for invalid-typed Msgid arguments. */ +# undef gettext +# define gettext(Msgid) ((const char *) {(Msgid)}) +/* The conversions via compound literals serve the purpose of producing warnings + for invalid-typed arguments. */ +# undef dgettext +# define dgettext(Domainname, Msgid) \ + ((void) (const char *) {(Domainname)}, gettext (Msgid)) # undef dcgettext # define dcgettext(Domainname, Msgid, Category) \ - ((void) (Category), dgettext (Domainname, Msgid)) + ((void) (int) {(Category)}, dgettext (Domainname, Msgid)) # endif -# undef ngettext -# define ngettext(Msgid1, Msgid2, N) \ - ((N) == 1 \ - ? ((void) (Msgid2), (const char *) (Msgid1)) \ - : ((void) (Msgid1), (const char *) (Msgid2))) -# undef dngettext -# define dngettext(Domainname, Msgid1, Msgid2, N) \ - ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) -# undef dcngettext -# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ - ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) + +# if (defined __GNUC__ && defined __cplusplus) || defined __clang__ +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ngettext (Msgid1, Msgid2, N) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + dngettext (Domainname, Msgid1, Msgid2, N) +# elif defined __GNUC__ && !defined __cplusplus +/* Silence -Wuseless-cast warnings. */ +# if __GNUC__ >= 14 +# pragma GCC diagnostic ignored "-Wuseless-cast" +# endif +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void) (const char *) (Domainname), ngettext (Msgid1, Msgid2, N)) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void) (int) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) +# else +/* The conversions to 'const char *' via compound literals serve the purpose + of producing warnings for invalid uses of the value returned from these + functions and for invalid-typed Msgid1 and Msgid2 arguments. */ +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 \ + ? ((void) (Msgid2), (const char *) {(Msgid1)}) \ + : ((void) (Msgid1), (const char *) {(Msgid2)})) +/* The conversions via compound literals serve the purpose of producing warnings + for invalid-typed arguments. */ +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void) (const char *) {(Domainname)}, ngettext (Msgid1, Msgid2, N)) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void) (int) {(Category)}, dngettext (Domainname, Msgid1, Msgid2, N)) +# endif + # undef textdomain -# define textdomain(Domainname) ((const char *) (Domainname)) +# define textdomain(Domainname) ((const char *) {(Domainname)}) # undef bindtextdomain # define bindtextdomain(Domainname, Dirname) \ - ((void) (Domainname), (const char *) (Dirname)) + ((void) (const char *) {(Domainname)}, (const char *) {(Dirname)}) # undef bind_textdomain_codeset # define bind_textdomain_codeset(Domainname, Codeset) \ - ((void) (Domainname), (const char *) (Codeset)) + ((void) (const char *) {(Domainname)}, (const char *) {(Codeset)}) #endif @@ -178,6 +252,11 @@ dcgettext (const char *domain, const char *msgid, int category) The letter 'p' stands for 'particular' or 'special'. */ #include /* for LC_MESSAGES */ +/* The LC_MESSAGES locale category is specified in POSIX, but not in ISO C. + On systems that don't define it, use the same value as GNU libintl. */ +#if !defined LC_MESSAGES +# define LC_MESSAGES 1729 +#endif #ifdef DEFAULT_TEXT_DOMAIN # define pgettext(Msgctxt, Msgid) \ @@ -204,11 +283,9 @@ dcgettext (const char *domain, const char *msgid, int category) #if defined __GNUC__ || defined __clang__ __inline -#else -#ifdef __cplusplus +#elif defined __cplusplus inline #endif -#endif static const char * pgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, @@ -223,11 +300,9 @@ pgettext_aux (const char *domain, #if defined __GNUC__ || defined __clang__ __inline -#else -#ifdef __cplusplus +#elif defined __cplusplus inline #endif -#endif static const char * npgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, @@ -274,11 +349,9 @@ npgettext_aux (const char *domain, #if defined __GNUC__ || defined __clang__ __inline -#else -#ifdef __cplusplus +#elif defined __cplusplus inline #endif -#endif static const char * dcpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, @@ -320,11 +393,9 @@ dcpgettext_expr (const char *domain, #if defined __GNUC__ || defined __clang__ __inline -#else -#ifdef __cplusplus +#elif defined __cplusplus inline #endif -#endif static const char * dcnpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 824931caf90..2a18a330fa1 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -35,7 +35,13 @@ # --macro-prefix=gl \ # --no-vc-files \ # --avoid=access \ -# --avoid=btowc \ +# --avoid=btoc32 \ +# --avoid=c32_apply_type_test \ +# --avoid=c32_get_type_test \ +# --avoid=c32isalnum \ +# --avoid=c32rtomb \ +# --avoid=c32tolower \ +# --avoid=c32toupper \ # --avoid=chmod \ # --avoid=close \ # --avoid=crypto/af_alg \ @@ -43,17 +49,13 @@ # --avoid=fchdir \ # --avoid=fstat \ # --avoid=gnulib-i18n \ -# --avoid=iswblank \ -# --avoid=iswctype \ -# --avoid=iswdigit \ -# --avoid=iswxdigit \ # --avoid=langinfo-h \ # --avoid=libgmp-mpq \ # --avoid=localcharset \ -# --avoid=locale-h \ +# --avoid=localeinfo \ # --avoid=localename-unsafe-limited \ # --avoid=lock \ -# --avoid=mbrtowc \ +# --avoid=mbrtoc32-regular \ # --avoid=mbsinit \ # --avoid=memchr \ # --avoid=mkdir \ @@ -63,14 +65,12 @@ # --avoid=openat-die \ # --avoid=opendir \ # --avoid=pthread-h \ -# --avoid=raise \ # --avoid=save-cwd \ # --avoid=select \ # --avoid=setenv \ # --avoid=sigprocmask \ # --avoid=stat \ # --avoid=std-gnu11 \ -# --avoid=stdarg-h \ # --avoid=strncpy \ # --avoid=threadlib \ # --avoid=tzset \ @@ -78,9 +78,7 @@ # --avoid=utime \ # --avoid=utime-h \ # --avoid=wchar-h \ -# --avoid=wcrtomb \ -# --avoid=wctype \ -# --avoid=wctype-h \ +# --avoid=uchar-h \ # alignasof \ # alloca-opt \ # attribute \ @@ -254,6 +252,7 @@ CPPFLAGS = @CPPFLAGS@ CRYPTOLIB = @CRYPTOLIB@ CXX = @CXX@ CXXFLAGS = @CXXFLAGS@ +CXX_HAVE_STDCOUNTOF_H = @CXX_HAVE_STDCOUNTOF_H@ CYGWIN_OBJ = @CYGWIN_OBJ@ C_SWITCH_MACHINE = @C_SWITCH_MACHINE@ C_SWITCH_SYSTEM = @C_SWITCH_SYSTEM@ @@ -372,6 +371,7 @@ GL_GENERATE_LIMITS_H_CONDITION = @GL_GENERATE_LIMITS_H_CONDITION@ GL_GENERATE_MINI_GMP_H_CONDITION = @GL_GENERATE_MINI_GMP_H_CONDITION@ GL_GENERATE_STDBIT_H_CONDITION = @GL_GENERATE_STDBIT_H_CONDITION@ GL_GENERATE_STDCKDINT_H_CONDITION = @GL_GENERATE_STDCKDINT_H_CONDITION@ +GL_GENERATE_STDCOUNTOF_H_CONDITION = @GL_GENERATE_STDCOUNTOF_H_CONDITION@ GL_GENERATE_STDDEF_H_CONDITION = @GL_GENERATE_STDDEF_H_CONDITION@ GL_GENERATE_STDINT_H_CONDITION = @GL_GENERATE_STDINT_H_CONDITION@ GL_GNULIB_ABORT_DEBUG = @GL_GNULIB_ABORT_DEBUG@ @@ -621,6 +621,28 @@ GL_GNULIB_SNZPRINTF = @GL_GNULIB_SNZPRINTF@ GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@ GL_GNULIB_STACK_TRACE = @GL_GNULIB_STACK_TRACE@ GL_GNULIB_STAT = @GL_GNULIB_STAT@ +GL_GNULIB_STDC_BIT_CEIL = @GL_GNULIB_STDC_BIT_CEIL@ +GL_GNULIB_STDC_BIT_FLOOR = @GL_GNULIB_STDC_BIT_FLOOR@ +GL_GNULIB_STDC_BIT_WIDTH = @GL_GNULIB_STDC_BIT_WIDTH@ +GL_GNULIB_STDC_COUNT_ONES = @GL_GNULIB_STDC_COUNT_ONES@ +GL_GNULIB_STDC_COUNT_ZEROS = @GL_GNULIB_STDC_COUNT_ZEROS@ +GL_GNULIB_STDC_FIRST_LEADING_ONE = @GL_GNULIB_STDC_FIRST_LEADING_ONE@ +GL_GNULIB_STDC_FIRST_LEADING_ZERO = @GL_GNULIB_STDC_FIRST_LEADING_ZERO@ +GL_GNULIB_STDC_FIRST_TRAILING_ONE = @GL_GNULIB_STDC_FIRST_TRAILING_ONE@ +GL_GNULIB_STDC_FIRST_TRAILING_ZERO = @GL_GNULIB_STDC_FIRST_TRAILING_ZERO@ +GL_GNULIB_STDC_HAS_SINGLE_BIT = @GL_GNULIB_STDC_HAS_SINGLE_BIT@ +GL_GNULIB_STDC_LEADING_ONES = @GL_GNULIB_STDC_LEADING_ONES@ +GL_GNULIB_STDC_LEADING_ZEROS = @GL_GNULIB_STDC_LEADING_ZEROS@ +GL_GNULIB_STDC_LOAD8 = @GL_GNULIB_STDC_LOAD8@ +GL_GNULIB_STDC_LOAD8_ALIGNED = @GL_GNULIB_STDC_LOAD8_ALIGNED@ +GL_GNULIB_STDC_MEMREVERSE8 = @GL_GNULIB_STDC_MEMREVERSE8@ +GL_GNULIB_STDC_MEMREVERSE8U = @GL_GNULIB_STDC_MEMREVERSE8U@ +GL_GNULIB_STDC_ROTATE_LEFT = @GL_GNULIB_STDC_ROTATE_LEFT@ +GL_GNULIB_STDC_ROTATE_RIGHT = @GL_GNULIB_STDC_ROTATE_RIGHT@ +GL_GNULIB_STDC_STORE8 = @GL_GNULIB_STDC_STORE8@ +GL_GNULIB_STDC_STORE8_ALIGNED = @GL_GNULIB_STDC_STORE8_ALIGNED@ +GL_GNULIB_STDC_TRAILING_ONES = @GL_GNULIB_STDC_TRAILING_ONES@ +GL_GNULIB_STDC_TRAILING_ZEROS = @GL_GNULIB_STDC_TRAILING_ZEROS@ GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@ GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@ GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@ @@ -681,6 +703,7 @@ GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@ GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@ GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@ GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@ +GL_GNULIB_VAPRINTF = @GL_GNULIB_VAPRINTF@ GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@ GL_GNULIB_VASZPRINTF = @GL_GNULIB_VASZPRINTF@ GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@ @@ -701,20 +724,7 @@ GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@ GL_GNULIB_WRITE = @GL_GNULIB_WRITE@ 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@ -GL_STDC_BIT_WIDTH = @GL_STDC_BIT_WIDTH@ -GL_STDC_COUNT_ONES = @GL_STDC_COUNT_ONES@ -GL_STDC_COUNT_ZEROS = @GL_STDC_COUNT_ZEROS@ -GL_STDC_FIRST_LEADING_ONE = @GL_STDC_FIRST_LEADING_ONE@ -GL_STDC_FIRST_LEADING_ZERO = @GL_STDC_FIRST_LEADING_ZERO@ -GL_STDC_FIRST_TRAILING_ONE = @GL_STDC_FIRST_TRAILING_ONE@ -GL_STDC_FIRST_TRAILING_ZERO = @GL_STDC_FIRST_TRAILING_ZERO@ -GL_STDC_HAS_SINGLE_BIT = @GL_STDC_HAS_SINGLE_BIT@ -GL_STDC_LEADING_ONES = @GL_STDC_LEADING_ONES@ -GL_STDC_LEADING_ZEROS = @GL_STDC_LEADING_ZEROS@ -GL_STDC_TRAILING_ONES = @GL_STDC_TRAILING_ONES@ -GL_STDC_TRAILING_ZEROS = @GL_STDC_TRAILING_ZEROS@ +GL_HAVE_STDBIT_H_CONDITION = @GL_HAVE_STDBIT_H_CONDITION@ GMALLOC_OBJ = @GMALLOC_OBJ@ GMP_H = @GMP_H@ GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@ @@ -924,7 +934,9 @@ HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@ HAVE_SIGSET_T = @HAVE_SIGSET_T@ HAVE_SLEEP = @HAVE_SLEEP@ HAVE_SPAWN_H = @HAVE_SPAWN_H@ +HAVE_STDBIT_H = @HAVE_STDBIT_H@ HAVE_STDCKDINT_H = @HAVE_STDCKDINT_H@ +HAVE_STDCOUNTOF_H = @HAVE_STDCOUNTOF_H@ HAVE_STDINT_H = @HAVE_STDINT_H@ HAVE_STPCPY = @HAVE_STPCPY@ HAVE_STPNCPY = @HAVE_STPNCPY@ @@ -1104,7 +1116,9 @@ NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@ NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@ NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@ NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@ +NEXT_AS_FIRST_DIRECTIVE_STDBIT_H = @NEXT_AS_FIRST_DIRECTIVE_STDBIT_H@ NEXT_AS_FIRST_DIRECTIVE_STDCKDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDCKDINT_H@ +NEXT_AS_FIRST_DIRECTIVE_STDCOUNTOF_H = @NEXT_AS_FIRST_DIRECTIVE_STDCOUNTOF_H@ NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@ NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@ NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@ @@ -1125,7 +1139,9 @@ NEXT_GETOPT_H = @NEXT_GETOPT_H@ NEXT_INTTYPES_H = @NEXT_INTTYPES_H@ NEXT_LIMITS_H = @NEXT_LIMITS_H@ NEXT_SIGNAL_H = @NEXT_SIGNAL_H@ +NEXT_STDBIT_H = @NEXT_STDBIT_H@ NEXT_STDCKDINT_H = @NEXT_STDCKDINT_H@ +NEXT_STDCOUNTOF_H = @NEXT_STDCOUNTOF_H@ NEXT_STDDEF_H = @NEXT_STDDEF_H@ NEXT_STDINT_H = @NEXT_STDINT_H@ NEXT_STDIO_H = @NEXT_STDIO_H@ @@ -1391,6 +1407,7 @@ SQLITE3_CFLAGS = @SQLITE3_CFLAGS@ SQLITE3_LIBS = @SQLITE3_LIBS@ STDBIT_H = @STDBIT_H@ STDCKDINT_H = @STDCKDINT_H@ +STDCOUNTOF_H = @STDCOUNTOF_H@ STDDEF_H = @STDDEF_H@ STDDEF_NOT_IDEMPOTENT = @STDDEF_NOT_IDEMPOTENT@ STDINT_H = @STDINT_H@ @@ -1516,6 +1533,7 @@ gl_GNULIB_ENABLED_issymlinkat_CONDITION = @gl_GNULIB_ENABLED_issymlinkat_CONDITI gl_GNULIB_ENABLED_lchmod_CONDITION = @gl_GNULIB_ENABLED_lchmod_CONDITION@ gl_GNULIB_ENABLED_open_CONDITION = @gl_GNULIB_ENABLED_open_CONDITION@ gl_GNULIB_ENABLED_rawmemchr_CONDITION = @gl_GNULIB_ENABLED_rawmemchr_CONDITION@ +gl_GNULIB_ENABLED_stdc_memreverse8u_CONDITION = @gl_GNULIB_ENABLED_stdc_memreverse8u_CONDITION@ gl_GNULIB_ENABLED_strtoll_CONDITION = @gl_GNULIB_ENABLED_strtoll_CONDITION@ gl_GNULIB_ENABLED_utimens_CONDITION = @gl_GNULIB_ENABLED_utimens_CONDITION@ gl_GNULIB_ENABLED_verify_CONDITION = @gl_GNULIB_ENABLED_verify_CONDITION@ @@ -3199,23 +3217,36 @@ BUILT_SOURCES += $(STDBIT_H) ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) stdbit.h: stdbit.in.h $(top_builddir)/config.status $(gl_V_at)$(SED_HEADER_STDOUT) \ - -e 's/@''GL_STDC_LEADING_ZEROS''@/$(GL_STDC_LEADING_ZEROS)/g' \ - -e 's/@''GL_STDC_LEADING_ONES''@/$(GL_STDC_LEADING_ONES)/g' \ - -e 's/@''GL_STDC_TRAILING_ZEROS''@/$(GL_STDC_TRAILING_ZEROS)/g' \ - -e 's/@''GL_STDC_TRAILING_ONES''@/$(GL_STDC_TRAILING_ONES)/g' \ - -e 's/@''GL_STDC_FIRST_LEADING_ZERO''@/$(GL_STDC_FIRST_LEADING_ZERO)/g' \ - -e 's/@''GL_STDC_FIRST_LEADING_ONE''@/$(GL_STDC_FIRST_LEADING_ONE)/g' \ - -e 's/@''GL_STDC_FIRST_TRAILING_ZERO''@/$(GL_STDC_FIRST_TRAILING_ZERO)/g' \ - -e 's/@''GL_STDC_FIRST_TRAILING_ONE''@/$(GL_STDC_FIRST_TRAILING_ONE)/g' \ - -e 's/@''GL_STDC_COUNT_ZEROS''@/$(GL_STDC_COUNT_ZEROS)/g' \ - -e 's/@''GL_STDC_COUNT_ONES''@/$(GL_STDC_COUNT_ONES)/g' \ - -e 's/@''GL_STDC_HAS_SINGLE_BIT''@/$(GL_STDC_HAS_SINGLE_BIT)/g' \ - -e 's/@''GL_STDC_BIT_WIDTH''@/$(GL_STDC_BIT_WIDTH)/g' \ - -e 's/@''GL_STDC_BIT_FLOOR''@/$(GL_STDC_BIT_FLOOR)/g' \ - -e 's/@''GL_STDC_BIT_CEIL''@/$(GL_STDC_BIT_CEIL)/g' \ + -e 's/@''HAVE_STDBIT_H''@/$(HAVE_STDBIT_H)/g' \ + -e 's/@''GUARD_PREFIX''@/$(GUARD_PREFIX)/g' \ + -e 's/@''PRAGMA_SYSTEM_HEADER''@/$(PRAGMA_SYSTEM_HEADER)/g' \ + -e 's/@''PRAGMA_COLUMNS''@/$(PRAGMA_COLUMNS)/g' \ + -e 's/@''INCLUDE_NEXT''@/$(INCLUDE_NEXT)/g' \ + -e 's/@''NEXT_STDBIT_H''@/$(NEXT_STDBIT_H)/g' \ + -e 's/@''GNULIB_STDC_LEADING_ZEROS''@/$(GL_GNULIB_STDC_LEADING_ZEROS)/g' \ + -e 's/@''GNULIB_STDC_LEADING_ONES''@/$(GL_GNULIB_STDC_LEADING_ONES)/g' \ + -e 's/@''GNULIB_STDC_TRAILING_ZEROS''@/$(GL_GNULIB_STDC_TRAILING_ZEROS)/g' \ + -e 's/@''GNULIB_STDC_TRAILING_ONES''@/$(GL_GNULIB_STDC_TRAILING_ONES)/g' \ + -e 's/@''GNULIB_STDC_FIRST_LEADING_ZERO''@/$(GL_GNULIB_STDC_FIRST_LEADING_ZERO)/g' \ + -e 's/@''GNULIB_STDC_FIRST_LEADING_ONE''@/$(GL_GNULIB_STDC_FIRST_LEADING_ONE)/g' \ + -e 's/@''GNULIB_STDC_FIRST_TRAILING_ZERO''@/$(GL_GNULIB_STDC_FIRST_TRAILING_ZERO)/g' \ + -e 's/@''GNULIB_STDC_FIRST_TRAILING_ONE''@/$(GL_GNULIB_STDC_FIRST_TRAILING_ONE)/g' \ + -e 's/@''GNULIB_STDC_COUNT_ZEROS''@/$(GL_GNULIB_STDC_COUNT_ZEROS)/g' \ + -e 's/@''GNULIB_STDC_COUNT_ONES''@/$(GL_GNULIB_STDC_COUNT_ONES)/g' \ + -e 's/@''GNULIB_STDC_HAS_SINGLE_BIT''@/$(GL_GNULIB_STDC_HAS_SINGLE_BIT)/g' \ + -e 's/@''GNULIB_STDC_BIT_WIDTH''@/$(GL_GNULIB_STDC_BIT_WIDTH)/g' \ + -e 's/@''GNULIB_STDC_BIT_FLOOR''@/$(GL_GNULIB_STDC_BIT_FLOOR)/g' \ + -e 's/@''GNULIB_STDC_BIT_CEIL''@/$(GL_GNULIB_STDC_BIT_CEIL)/g' \ + -e 's/@''GNULIB_STDC_ROTATE_LEFT''@/$(GL_GNULIB_STDC_ROTATE_LEFT)/g' \ + -e 's/@''GNULIB_STDC_ROTATE_RIGHT''@/$(GL_GNULIB_STDC_ROTATE_RIGHT)/g' \ + -e 's/@''GNULIB_STDC_MEMREVERSE8''@/$(GL_GNULIB_STDC_MEMREVERSE8)/g' \ + -e 's/@''GNULIB_STDC_MEMREVERSE8U''@/$(GL_GNULIB_STDC_MEMREVERSE8U)/g' \ + -e 's/@''GNULIB_STDC_LOAD8_ALIGNED''@/$(GL_GNULIB_STDC_LOAD8_ALIGNED)/g' \ + -e 's/@''GNULIB_STDC_LOAD8''@/$(GL_GNULIB_STDC_LOAD8)/g' \ + -e 's/@''GNULIB_STDC_STORE8_ALIGNED''@/$(GL_GNULIB_STDC_STORE8_ALIGNED)/g' \ + -e 's/@''GNULIB_STDC_STORE8''@/$(GL_GNULIB_STDC_STORE8)/g' \ $(srcdir)/stdbit.in.h > $@-t $(AM_V_at)mv $@-t $@ -libgnu_a_SOURCES += stdbit.c else stdbit.h: $(top_builddir)/config.status rm -f $@ @@ -3230,7 +3261,8 @@ endif ## begin gnulib module stdc_bit_width ifeq (,$(OMIT_GNULIB_MODULE_stdc_bit_width)) -ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +ifneq (,$(GL_HAVE_STDBIT_H_CONDITION)) +else libgnu_a_SOURCES += stdc_bit_width.c endif @@ -3240,7 +3272,8 @@ endif ## begin gnulib module stdc_count_ones ifeq (,$(OMIT_GNULIB_MODULE_stdc_count_ones)) -ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +ifneq (,$(GL_HAVE_STDBIT_H_CONDITION)) +else libgnu_a_SOURCES += stdc_count_ones.c endif @@ -3250,17 +3283,31 @@ endif ## begin gnulib module stdc_leading_zeros ifeq (,$(OMIT_GNULIB_MODULE_stdc_leading_zeros)) -ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +ifneq (,$(GL_HAVE_STDBIT_H_CONDITION)) +else libgnu_a_SOURCES += stdc_leading_zeros.c endif endif ## end gnulib module stdc_leading_zeros +## begin gnulib module stdc_memreverse8u +ifeq (,$(OMIT_GNULIB_MODULE_stdc_memreverse8u)) + +ifneq (,$(gl_GNULIB_ENABLED_stdc_memreverse8u_CONDITION)) +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_memreverse8u.c +endif + +endif +endif +## end gnulib module stdc_memreverse8u + ## begin gnulib module stdc_trailing_zeros ifeq (,$(OMIT_GNULIB_MODULE_stdc_trailing_zeros)) -ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +ifneq (,$(GL_HAVE_STDBIT_H_CONDITION)) +else libgnu_a_SOURCES += stdc_trailing_zeros.c endif @@ -3299,6 +3346,36 @@ EXTRA_DIST += intprops-internal.h stdckdint.in.h endif ## end gnulib module stdckdint-h +## begin gnulib module stdcountof-h +ifeq (,$(OMIT_GNULIB_MODULE_stdcountof-h)) + +BUILT_SOURCES += $(STDCOUNTOF_H) + +# We need the following in order to create when the system +# doesn't have one that works with the given compiler. +ifneq (,$(GL_GENERATE_STDCOUNTOF_H_CONDITION)) +stdcountof.h: stdcountof.in.h $(top_builddir)/config.status + $(gl_V_at)$(SED_HEADER_STDOUT) \ + -e 's|@''GUARD_PREFIX''@|GL|g' \ + -e 's/@''HAVE_STDCOUNTOF_H''@/$(HAVE_STDCOUNTOF_H)/g' \ + -e 's/@''CXX_HAVE_STDCOUNTOF_H''@/$(CXX_HAVE_STDCOUNTOF_H)/g' \ + -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ + -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ + -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ + -e 's|@''NEXT_STDCOUNTOF_H''@|$(NEXT_STDCOUNTOF_H)|g' \ + $(srcdir)/stdcountof.in.h > $@-t + $(AM_V_at)mv $@-t $@ +else +stdcountof.h: $(top_builddir)/config.status + rm -f $@ +endif +MOSTLYCLEANFILES += stdcountof.h stdcountof.h-t + +EXTRA_DIST += stdcountof.in.h + +endif +## end gnulib module stdcountof-h + ## begin gnulib module stddef-h ifeq (,$(OMIT_GNULIB_MODULE_stddef-h)) @@ -3445,6 +3522,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -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_VAPRINTF''@/$(GL_GNULIB_VAPRINTF)/g' \ -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \ -e 's/@''GNULIB_VASZPRINTF''@/$(GL_GNULIB_VASZPRINTF)/g' \ -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \ @@ -3468,6 +3546,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's/@''GNULIB_MDA_GETW''@/$(GL_GNULIB_MDA_GETW)/g' \ -e 's/@''GNULIB_MDA_PUTW''@/$(GL_GNULIB_MDA_PUTW)/g' \ -e 's/@''GNULIB_MDA_TEMPNAM''@/$(GL_GNULIB_MDA_TEMPNAM)/g' \ + -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \ < $(srcdir)/stdio.in.h > $@-t1 $(AM_V_at)sed \ -e 's|@''HAVE_DECL_FCLOSEALL''@|$(HAVE_DECL_FCLOSEALL)|g' \ @@ -3499,6 +3578,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's|@''REPLACE_FOPEN_FOR_FOPEN_GNU''@|$(REPLACE_FOPEN_FOR_FOPEN_GNU)|g' \ -e 's|@''REPLACE_FPRINTF''@|$(REPLACE_FPRINTF)|g' \ -e 's|@''REPLACE_FPURGE''@|$(REPLACE_FPURGE)|g' \ + -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \ -e 's|@''REPLACE_FREOPEN''@|$(REPLACE_FREOPEN)|g' \ -e 's|@''REPLACE_FSEEK''@|$(REPLACE_FSEEK)|g' \ -e 's|@''REPLACE_FSEEKO''@|$(REPLACE_FSEEKO)|g' \ diff --git a/lib/idx.h b/lib/idx.h index deb7dc4cb13..b6d304dbbd8 100644 --- a/lib/idx.h +++ b/lib/idx.h @@ -19,11 +19,17 @@ #ifndef _IDX_H #define _IDX_H -/* Get ptrdiff_t. */ -#include +#ifndef __PTRDIFF_TYPE__ +# include +#endif -/* Get PTRDIFF_MAX. */ -#include +/* IDX_MAX is the maximum value of an idx_t. */ +#ifdef __PTRDIFF_MAX__ +# define IDX_MAX __PTRDIFF_MAX__ +#else +# include +# define IDX_MAX PTRDIFF_MAX +#endif /* The type 'idx_t' holds an (array) index or an (object) size. Its implementation promotes to a signed integer type, @@ -127,10 +133,12 @@ extern "C" { /* Use the signed type 'ptrdiff_t'. */ /* Note: ISO C does not mandate that 'size_t' and 'ptrdiff_t' have the same size, but it is so on all platforms we have seen since 1990. */ +#ifdef __PTRDIFF_TYPE__ +typedef __PTRDIFF_TYPE__ idx_t; +#else +/* already included above. */ typedef ptrdiff_t idx_t; - -/* IDX_MAX is the maximum value of an idx_t. */ -#define IDX_MAX PTRDIFF_MAX +#endif /* So far no need has been found for an IDX_WIDTH macro. Perhaps there should be another macro IDX_VALUE_BITS that does not diff --git a/lib/intprops-internal.h b/lib/intprops-internal.h index 0df385b9bf3..1fb3b799011 100644 --- a/lib/intprops-internal.h +++ b/lib/intprops-internal.h @@ -25,6 +25,23 @@ # pragma GCC diagnostic ignored "-Wtype-limits" #endif +/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25764. See: + https://gcc.gnu.org/PR68193 + https://github.com/llvm/llvm-project/issues/25764 + For now, assume GCC < 14 and all Clang versions generate bogus + warnings for _Generic. This matters only for compilers that + lack relevant builtins. */ +#if (__GNUC__ && __GNUC__ < 14) || defined __clang__ +# define _GL__GENERIC_BOGUS 1 +#else +# define _GL__GENERIC_BOGUS 0 +#endif + +/* Suppress -Wuseless-cast for, e.g., gcc-14 -std=gnu99. */ +#if __STDC_VERSION__ < 201112 && 14 <= __GNUC__ +# pragma GCC diagnostic ignored "-Wuseless-cast" +#endif + /* Return a value with the common real type of E and V and the value of V. Do not evaluate E. */ #define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) @@ -32,8 +49,20 @@ /* The extra casts in the following macros work around compiler bugs, e.g., in Cray C 5.0.3.0. */ -/* True if the real type T is signed. */ -#define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* True if the standard integer or standard real type T is signed. */ +#if (__STDC_VERSION__ < 201112 || (defined _MSC_VER && _MSC_VER < 1944) \ + || _GL__GENERIC_BOGUS) +# define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +#else +/* Pacify -Wuseless-cast, but do not default to the simpler expression; + see . */ +# define _GL_TYPE_SIGNED(t) \ + (_Generic ((t) {0}, \ + bool: 0, char: CHAR_MIN < 0, signed char: 1, unsigned char: 0, \ + short int: 1, unsigned short int: 0, int: 1, unsigned int: 0, \ + long int: 1, unsigned long int: 0, long long int: 1, unsigned long long int: 0, \ + float: 1, double: 1, long double: 1)) +#endif /* Return 1 if the real expression E, after promotion, has a signed or floating type. Do not evaluate E. */ @@ -179,18 +208,6 @@ _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW) #endif -/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25764. See: - https://gcc.gnu.org/PR68193 - https://github.com/llvm/llvm-project/issues/25764 - For now, assume GCC < 14 and all Clang versions generate bogus - warnings for _Generic. This matters only for compilers that - lack relevant builtins. */ -#if (__GNUC__ && __GNUC__ < 14) || defined __clang__ -# define _GL__GENERIC_BOGUS 1 -#else -# define _GL__GENERIC_BOGUS 0 -#endif - /* Store the low-order bits of A B into *R, where OP specifies the operation and OVERFLOW the overflow predicate. Return 1 if the result overflows. Arguments should not have side effects, @@ -304,15 +321,15 @@ ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) -/* Return 1 if the integer expressions A - B and -A would overflow, - respectively. Arguments should not have side effects, +/* Return 1 if the integer expression -A would overflow. + Arguments should not have side effects, and can be any signed integer type other than char, bool, a bit-precise integer type, or an enumeration type. These macros are tuned for their last input argument being a constant. */ #if _GL_HAS_BUILTIN_OVERFLOW_P # define _GL_INT_NEGATE_OVERFLOW(a) \ - __builtin_sub_overflow_p (0, a, (__typeof__ (- (a))) 0) + __builtin_sub_overflow_p (0, a, _GL_INT_CONVERT (- (a), 0)) #else # define _GL_INT_NEGATE_OVERFLOW(a) \ _GL_INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) diff --git a/lib/intprops.h b/lib/intprops.h index 924b6f9a466..8279cd73e34 100644 --- a/lib/intprops.h +++ b/lib/intprops.h @@ -25,9 +25,21 @@ /* True if the arithmetic type T is an integer type. bool counts as an integer. */ -#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) +#if (__STDC_VERSION__ < 201112 || (defined _MSC_VER && _MSC_VER < 1944) \ + || _GL__GENERIC_BOGUS) +# define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) +#else +/* Pacify -Wuseless-cast and do not default to the simpler expression; + see . */ +# define TYPE_IS_INTEGER(t) \ + (_Generic ((t) {0}, \ + bool: 1, char: 1, signed char: 1, unsigned char: 1, \ + short int: 1, unsigned short int: 1, int: 1, unsigned int: 1, \ + long int: 1, unsigned long int: 1, long long int: 1, unsigned long long int: 1, \ + float: 0, double: 0, long double: 0)) +#endif -/* True if the real type T is signed. */ +/* True if the standard integer or standard real type T is signed. */ #define TYPE_SIGNED(t) _GL_TYPE_SIGNED (t) /* Return 1 if the real expression E, after promotion, has a @@ -50,12 +62,34 @@ Padding bits are not supported; this is checked at compile-time below. */ #define TYPE_WIDTH(t) _GL_TYPE_WIDTH (t) -/* The maximum and minimum values for the integer type T. */ -#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) -#define TYPE_MAXIMUM(t) \ - ((t) (! TYPE_SIGNED (t) \ - ? (t) -1 \ - : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) +/* The maximum and minimum values for the standard integer type T. */ +#if (__STDC_VERSION__ < 201112 || (defined _MSC_VER && _MSC_VER < 1944) \ + || _GL__GENERIC_BOGUS) +# define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) +# define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) +#else +/* Pacify -Wuseless-cast and do not default to the simpler expressions; + see . */ +# define TYPE_MINIMUM(t) \ + (_Generic ((t) {0}, \ + bool: (bool) 0, char: (char) CHAR_MIN, \ + signed char: (signed char) SCHAR_MIN, unsigned char: (unsigned char) 0, \ + short int: (short int) SHRT_MIN, unsigned short int: (unsigned short int) 0, \ + int: INT_MIN, unsigned int: 0u, \ + long int: LONG_MIN, unsigned long int: 0ul, \ + long long int: LLONG_MIN, unsigned long long int: 0ull)) +# define TYPE_MAXIMUM(t) \ + (_Generic ((t) {0}, \ + bool: (bool) 1, char: (char) CHAR_MAX, \ + signed char: (signed char) SCHAR_MAX, unsigned char: (unsigned char) -1, \ + short int: (short int) SHRT_MAX, unsigned short int: (unsigned short int) -1, \ + int: INT_MAX, unsigned int: -1u, \ + long int: LONG_MAX, unsigned long int: -1ul, \ + long long int: LLONG_MAX, unsigned long long int: -1ull)) +#endif /* Bound on length of the string representing an unsigned integer value representable in B bits. log10 (2.0) < 146/485. The @@ -184,11 +218,11 @@ that the result (e.g., A + B) has that type. */ #if _GL_HAS_BUILTIN_OVERFLOW_P # define _GL_ADD_OVERFLOW(a, b, min, max) \ - __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0) + __builtin_add_overflow_p (a, b, _GL_INT_CONVERT ((a) + (b), 0)) # define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ - __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0) + __builtin_sub_overflow_p (a, b, _GL_INT_CONVERT ((a) - (b), 0)) # define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ - __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0) + __builtin_mul_overflow_p (a, b, _GL_INT_CONVERT ((a) * (b), 0)) #else # define _GL_ADD_OVERFLOW(a, b, min, max) \ ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \ diff --git a/lib/nproc.c b/lib/nproc.c index b0c9514115b..ef86975fb1f 100644 --- a/lib/nproc.c +++ b/lib/nproc.c @@ -25,6 +25,7 @@ #if HAVE_SETMNTENT # include #endif +#include #include #include #include @@ -61,8 +62,6 @@ #include "minmax.h" -#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) - #define NPROC_MINIMUM 1 /* Return the number of processors available to the current process, based @@ -335,9 +334,9 @@ num_processors_available (enum nproc_query query) # endif { CTL_HW, HW_NCPU } }; - for (int i = 0; i < ARRAY_SIZE (mib); i++) + for (int i = 0; i < countof (mib); i++) { - if (sysctl (mib[i], ARRAY_SIZE (mib[i]), &nprocs, &len, NULL, 0) == 0 + if (sysctl (mib[i], countof (mib[i]), &nprocs, &len, NULL, 0) == 0 && len == sizeof (nprocs) && 0 < nprocs) return nprocs; diff --git a/lib/pthread_sigmask.c b/lib/pthread_sigmask.c index 95600d6098b..7a21ec76a25 100644 --- a/lib/pthread_sigmask.c +++ b/lib/pthread_sigmask.c @@ -19,19 +19,22 @@ /* Specification. */ #include -#include -#include +/* The native Windows implementation is defined in sigprocmask.c. */ +#if !(defined _WIN32 && !defined __CYGWIN__) -#if PTHREAD_SIGMASK_INEFFECTIVE -# include -#endif +# include +# include + +# if PTHREAD_SIGMASK_INEFFECTIVE +# include +# endif int pthread_sigmask (int how, const sigset_t *new_mask, sigset_t *old_mask) -#undef pthread_sigmask +# undef pthread_sigmask { -#if HAVE_PTHREAD_SIGMASK -# if PTHREAD_SIGMASK_INEFFECTIVE +# if HAVE_PTHREAD_SIGMASK && !PTHREAD_SIGMASK_NOT_IN_LIBC +# if PTHREAD_SIGMASK_INEFFECTIVE sigset_t omask; sigset_t *old_mask_ptr = &omask; sigemptyset (&omask); @@ -40,13 +43,13 @@ pthread_sigmask (int how, const sigset_t *new_mask, sigset_t *old_mask) sigaddset (&omask, SIGILL); sigset_t omask_copy; memcpy (&omask_copy, &omask, sizeof omask); -# else +# else sigset_t *old_mask_ptr = old_mask; -# endif +# endif int ret = pthread_sigmask (how, new_mask, old_mask_ptr); -# if PTHREAD_SIGMASK_INEFFECTIVE +# if PTHREAD_SIGMASK_INEFFECTIVE if (ret == 0) { /* Detect whether pthread_sigmask is currently ineffective. @@ -64,14 +67,18 @@ pthread_sigmask (int how, const sigset_t *new_mask, sigset_t *old_mask) if (old_mask) memcpy (old_mask, &omask, sizeof omask); } -# endif -# if PTHREAD_SIGMASK_FAILS_WITH_ERRNO +# endif +# if PTHREAD_SIGMASK_FAILS_WITH_ERRNO if (ret == -1) return errno; -# endif +# endif return ret; -#else +# else int ret = sigprocmask (how, new_mask, old_mask); - return (ret < 0 ? errno : 0); -#endif + /* Test for ret != 0, not ret < 0, as a workaround against NetBSD bug + . */ + return (ret != 0 ? errno : 0); +# endif } + +#endif diff --git a/lib/readutmp.h b/lib/readutmp.h index 7b6af7eb554..badbbc4331e 100644 --- a/lib/readutmp.h +++ b/lib/readutmp.h @@ -330,7 +330,7 @@ char *extract_trimmed_name (const STRUCT_UTMP *ut) If OPTIONS & READ_UTMP_NO_BOOT_TIME is nonzero, omit the boot time entries. - This function is not multithread-safe, since on many platforms it + This function is not thread-safe, since on many platforms it invokes the functions setutxent, getutxent, endutxent. These functions are needed because they may lock FILE (so that we don't read garbage when a concurrent process writes to FILE), but their diff --git a/lib/regcomp.c b/lib/regcomp.c index aa2f6800886..ab3783f94ce 100644 --- a/lib/regcomp.c +++ b/lib/regcomp.c @@ -21,6 +21,12 @@ # include #endif +/* The localeinfo-related code fixes glibc bug 20381. + Someday this fix should be merged into glibc. */ +#if !defined _LIBC && !defined _REGEX_AVOID_UCHAR_H +# include "localeinfo.h" +#endif + static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, size_t length, reg_syntax_t syntax); static void re_compile_fastmap_iter (regex_t *bufp, @@ -267,11 +273,31 @@ re_compile_fastmap (struct re_pattern_buffer *bufp) weak_alias (__re_compile_fastmap, re_compile_fastmap) static __always_inline void -re_set_fastmap (char *fastmap, bool icase, int ch) +re_set_fastmap (char *fastmap, unsigned char ch) { fastmap[ch] = 1; - if (icase) - fastmap[tolower (ch)] = 1; +} + +/* Record in FASTMAP the initial byte of the representations of all + characters that match WC ignoring case, other than WC itself. + Use MBS as a scratch state. */ + +static void +re_set_fastmap_icase (char *fastmap, wchar_t wc, mbstate_t *mbs) +{ +#if defined _LIBC || defined _REGEX_AVOID_UCHAR_H + wchar_t folded[1] = {__towlower (wc)}; + int nfolded = folded[0] != wc; +#else + wchar_t folded[CASE_FOLDED_BUFSIZE]; + int nfolded = case_folded_counterparts (wc, folded); +#endif + for (int i = 0; i < nfolded; i++) + { + char buf[MB_LEN_MAX]; + if (__wcrtomb (buf, folded[i], mbs) != (size_t) -1) + re_set_fastmap (fastmap, buf[0]); + } } /* Helper function for re_compile_fastmap. @@ -283,7 +309,6 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, { re_dfa_t *dfa = bufp->buffer; Idx node_cnt; - bool icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) { Idx node = init_state->nodes.elems[node_cnt]; @@ -291,8 +316,8 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, if (type == CHARACTER) { - re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); - if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) + re_set_fastmap (fastmap, dfa->nodes[node].opr.c); + if (bufp->syntax & RE_ICASE) { unsigned char buf[MB_LEN_MAX]; unsigned char *p; @@ -307,10 +332,8 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, *p++ = dfa->nodes[node].opr.c; memset (&state, '\0', sizeof (state)); if (__mbrtowc (&wc, (const char *) buf, p - buf, - &state) == p - buf - && (__wcrtomb ((char *) buf, __towlower (wc), &state) - != (size_t) -1)) - re_set_fastmap (fastmap, false, buf[0]); + &state) == p - buf) + re_set_fastmap_icase (fastmap, wc, &state); } } else if (type == SIMPLE_BRACKET) @@ -322,7 +345,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) if (w & ((bitset_word_t) 1 << j)) - re_set_fastmap (fastmap, icase, ch); + re_set_fastmap (fastmap, ch); } } else if (type == COMPLEX_BRACKET) @@ -344,7 +367,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); for (i = 0; i < SBC_MAX; ++i) if (table[i] < 0) - re_set_fastmap (fastmap, icase, i); + re_set_fastmap (fastmap, i); } #endif /* _LIBC */ @@ -365,7 +388,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, mbstate_t mbs; memset (&mbs, 0, sizeof (mbs)); if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2) - re_set_fastmap (fastmap, false, (int) c); + re_set_fastmap (fastmap, c); } while (++c != 0); } @@ -375,17 +398,13 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, /* ... Else catch all bytes which can start the mbchars. */ for (i = 0; i < cset->nmbchars; ++i) { - char buf[256]; + char buf[MB_LEN_MAX]; mbstate_t state; memset (&state, '\0', sizeof (state)); if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) - re_set_fastmap (fastmap, icase, *(unsigned char *) buf); - if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) - { - if (__wcrtomb (buf, __towlower (cset->mbchars[i]), &state) - != (size_t) -1) - re_set_fastmap (fastmap, false, *(unsigned char *) buf); - } + re_set_fastmap (fastmap, buf[0]); + if (bufp->syntax & RE_ICASE) + re_set_fastmap_icase (fastmap, cset->mbchars[i], &state); } } } @@ -499,7 +518,7 @@ regerror (int errcode, const regex_t *__restrict preg, char *__restrict errbuf, { const char *msg; size_t msg_size; - int nerrcodes = sizeof __re_error_msgid_idx / sizeof __re_error_msgid_idx[0]; + int nerrcodes = countof (__re_error_msgid_idx); if (__glibc_unlikely (errcode < 0 || errcode >= nerrcodes)) /* Only error codes returned by the rest of the code should be passed diff --git a/lib/regex.c b/lib/regex.c index f9f333d237d..d0c7af90186 100644 --- a/lib/regex.c +++ b/lib/regex.c @@ -20,6 +20,7 @@ #define __STDC_WANT_IEC_60559_BFP_EXT__ #ifndef _LIBC +# define _GL_USE_STDLIB_ALLOC 1 # include # if __GNUC_PREREQ (4, 6) diff --git a/lib/regex.h b/lib/regex.h index df35c93e5ae..152a157c2f7 100644 --- a/lib/regex.h +++ b/lib/regex.h @@ -645,15 +645,15 @@ extern int re_exec (const char *); array_name[restrict] use glibc's __restrict_arr if available. Otherwise, GCC 3.1 and clang support this syntax (but not in C++ mode). - Other ISO C99 compilers support it as well. */ + Other ISO C99 compilers support it as well, except for MSVC. */ #ifndef _Restrict_arr_ # ifdef __restrict_arr # define _Restrict_arr_ __restrict_arr # else -# if ((199901L <= __STDC_VERSION__ \ - || 3 < __GNUC__ + (1 <= __GNUC_MINOR__) \ - || __clang_major__ >= 3) \ - && !defined __cplusplus) +# if (((199901L <= __STDC_VERSION__ && !defined _MSC_VER) \ + || 3 < __GNUC__ + (1 <= __GNUC_MINOR__) \ + || __clang_major__ >= 3) \ + && !defined __cplusplus) # define _Restrict_arr_ _Restrict_ # else # define _Restrict_arr_ diff --git a/lib/regex_internal.c b/lib/regex_internal.c index 4b9b80f6b95..e5e5be84bd4 100644 --- a/lib/regex_internal.c +++ b/lib/regex_internal.c @@ -387,7 +387,7 @@ build_wcs_upper_buffer (re_string_t *pstr) { size_t mbcdlen; - mbcdlen = __wcrtomb ((char *) buf, wcu, &prev_st); + mbcdlen = __wcrtomb (buf, wcu, &prev_st); if (__glibc_likely (mbclen == mbcdlen)) memcpy (pstr->mbs + byte_idx, buf, mbclen); else if (mbcdlen != (size_t) -1) @@ -1241,8 +1241,8 @@ re_node_set_merge (re_node_set *dest, const re_node_set *src) } /* Insert the new element ELEM to the re_node_set* SET. - SET should not already have ELEM. - Return true if successful. */ + SET is not expected to already contain ELEM, but tolerate + duplicates as a no-op. Return true if successful. */ static bool __attribute_warn_unused_result__ @@ -1285,8 +1285,16 @@ re_node_set_insert (re_node_set *set, Idx elem) else { for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) - set->elems[idx] = set->elems[idx - 1]; - DEBUG_ASSERT (set->elems[idx - 1] < elem); + { + set->elems[idx] = set->elems[idx - 1]; + /* Although we already guaranteed that idx is at least 2 here, + add an assertion to pacify GCC 16.1.1 -Wanalyzer-out-of-bounds + when _REGEX_AVOID_UCHAR_H is defined. */ + DEBUG_ASSERT (1 < idx); + } + /* Already in set. Return early. */ + if (__glibc_unlikely (set->elems[idx - 1] == elem)) + return true; } /* Insert the new element. */ diff --git a/lib/regex_internal.h b/lib/regex_internal.h index 11b745ef28c..bf6c9ba3b84 100644 --- a/lib/regex_internal.h +++ b/lib/regex_internal.h @@ -27,9 +27,8 @@ #include #include -#include -#include #include +#include #include #ifndef _LIBC @@ -120,22 +119,47 @@ #define NEWLINE_CHAR '\n' #define WIDE_NEWLINE_CHAR L'\n' -/* Rename to standard API for using out of glibc. */ +/* Use Gnulib if outside glibc and not avoided by the app. */ +#if defined _LIBC || defined _REGEX_AVOID_UCHAR_H +# include +# include +#else +# include +# undef wctype_t +# define wchar_t char32_t +# define wctype_t c32_type_test_t +#endif + #ifndef _LIBC # undef __wctype # undef __iswalnum # undef __iswctype # undef __towlower # undef __towupper -# define __wctype wctype -# define __iswalnum iswalnum -# define __iswctype iswctype -# define __towlower towlower -# define __towupper towupper -# define __btowc btowc -# define __mbrtowc mbrtowc -# define __wcrtomb wcrtomb +# undef __btowc +# undef __mbrtowc +# undef __wcrtomb +# undef __regfree # define __regfree regfree +# ifdef _REGEX_AVOID_UCHAR_H +# define __wctype wctype +# define __iswalnum iswalnum +# define __iswctype iswctype +# define __towlower towlower +# define __towupper towupper +# define __btowc btowc +# define __mbrtowc mbrtowc +# define __wcrtomb wcrtomb +# else +# define __wctype c32_get_type_test +# define __iswalnum c32isalnum +# define __iswctype c32_apply_type_test +# define __towlower c32tolower +# define __towupper c32toupper +# define __btowc btoc32 +# define __mbrtowc mbrtoc32 +# define __wcrtomb c32rtomb +# endif #endif /* not _LIBC */ /* Types related to integers. Unless protected by #ifdef _LIBC, the @@ -171,7 +195,11 @@ reindenting a lot of regex code that formerly used 'int'. */ typedef regoff_t Idx; #ifdef _REGEX_LARGE_OFFSETS -# define IDX_MAX SSIZE_MAX +# ifdef SSIZE_MAX +# define IDX_MAX SSIZE_MAX +# else +# define IDX_MAX ((Idx) ((size_t) -1 / 2)) +# endif #else # define IDX_MAX INT_MAX #endif @@ -435,7 +463,11 @@ typedef struct re_dfa_t re_dfa_t; # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif -#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) +#if defined _LIBC || HAVE_MALLOC_0_NONNULL +# define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) +#else +# define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t) + ((n) == 0))) +#endif #define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) #define re_free(p) free (p) @@ -772,8 +804,8 @@ __attribute__ ((pure, unused)) re_string_wchar_at (const re_string_t *pstr, Idx idx) { if (pstr->mb_cur_max == 1) - return (wint_t) pstr->mbs[idx]; - return (wint_t) pstr->wcs[idx]; + return pstr->mbs[idx]; + return pstr->wcs[idx]; } #ifdef _LIBC diff --git a/lib/regexec.c b/lib/regexec.c index c84ce1ef339..ff62ac08ef1 100644 --- a/lib/regexec.c +++ b/lib/regexec.c @@ -627,6 +627,8 @@ re_search_internal (const regex_t *preg, const char *string, Idx length, /* We must check the longest matching, if nmatch > 0. */ fl_longest_match = (nmatch != 0 || dfa->nbackref); + re_dfastate_t **save_state_log = NULL; + err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1, preg->translate, (preg->syntax & RE_ICASE) != 0, dfa); @@ -802,11 +804,32 @@ re_search_internal (const regex_t *preg, const char *string, Idx length, if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) || dfa->nbackref) { + /* Save state_log before pruning, in case set_regs + later fails and we need to retry with a shorter + match. */ + re_free (save_state_log); + save_state_log = NULL; + if (!preg->no_sub && nmatch > 1 && dfa->nbackref) + { + save_state_log + = re_malloc (re_dfastate_t *, + mctx.match_last + 1); + if (__glibc_unlikely (save_state_log == NULL)) + { + err = REG_ESPACE; + goto free_return; + } + memcpy (save_state_log, mctx.state_log, + sizeof (re_dfastate_t *) + * (mctx.match_last + 1)); + } err = prune_impossible_nodes (&mctx); if (err == REG_NOERROR) break; if (__glibc_unlikely (err != REG_NOMATCH)) goto free_return; + re_free (save_state_log); + save_state_log = NULL; match_last = -1; } else @@ -825,24 +848,79 @@ re_search_internal (const regex_t *preg, const char *string, Idx length, { Idx reg_idx; - /* Initialize registers. */ - for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) - pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; - - /* Set the points where matching start/end. */ - pmatch[0].rm_so = 0; - pmatch[0].rm_eo = mctx.match_last; - /* FIXME: This function should fail if mctx.match_last exceeds - the maximum possible regoff_t value. We need a new error - code REG_OVERFLOW. */ - - if (!preg->no_sub && nmatch > 1) + /* When set_regs fails for a backref pattern, the structural + match at match_last has no valid register assignment. Try + shorter match lengths, since a valid shorter match may + exist (e.g., all groups matching empty). */ + for (;;) { + /* Initialize registers. */ + for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) + pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; + pmatch[0].rm_so = 0; + pmatch[0].rm_eo = mctx.match_last; + + if (preg->no_sub || nmatch <= 1) + break; + err = set_regs (preg, &mctx, nmatch, pmatch, dfa->has_plural_match && dfa->nbackref > 0); + if (__glibc_likely (err == REG_NOERROR) + || save_state_log == NULL + || err != REG_NOMATCH) + break; + + /* set_regs failed; try a shorter match_last. */ + Idx ml = mctx.match_last; + re_free (mctx.state_log); + do + { + --ml; + if (ml < 0) + break; + } + while (save_state_log[ml] == NULL + || !save_state_log[ml]->halt + || !check_halt_state_context + (&mctx, save_state_log[ml], ml)); + if (ml < 0) + { + err = REG_NOMATCH; + mctx.state_log = save_state_log; + save_state_log = NULL; + break; + } + mctx.state_log + = re_malloc (re_dfastate_t *, ml + 1); + if (__glibc_unlikely (mctx.state_log == NULL)) + { + mctx.state_log = save_state_log; + save_state_log = NULL; + err = REG_ESPACE; + break; + } + memcpy (mctx.state_log, save_state_log, + sizeof (re_dfastate_t *) * (ml + 1)); + mctx.match_last = ml; + mctx.last_node + = check_halt_state_context + (&mctx, save_state_log[ml], ml); + err = prune_impossible_nodes (&mctx); if (__glibc_unlikely (err != REG_NOERROR)) - goto free_return; + { + if (err == REG_NOMATCH) + { + re_free (mctx.state_log); + mctx.state_log = save_state_log; + save_state_log = NULL; + } + break; + } } + re_free (save_state_log); + save_state_log = NULL; + if (__glibc_unlikely (err != REG_NOERROR)) + goto free_return; /* At last, add the offset to each register, since we slid the buffers so that we could assume that the matching starts @@ -882,6 +960,7 @@ re_search_internal (const regex_t *preg, const char *string, Idx length, } free_return: + re_free (save_state_log); re_free (mctx.state_log); if (dfa->nbackref) match_ctx_free (&mctx); @@ -934,7 +1013,7 @@ prune_impossible_nodes (re_match_context_t *mctx) goto free_return; if (sifted_states[0] != NULL || lim_states[0] != NULL) break; - do + for (;;) { --match_last; if (match_last < 0) @@ -942,11 +1021,17 @@ prune_impossible_nodes (re_match_context_t *mctx) ret = REG_NOMATCH; goto free_return; } - } while (mctx->state_log[match_last] == NULL - || !mctx->state_log[match_last]->halt); - halt_node = check_halt_state_context (mctx, - mctx->state_log[match_last], - match_last); + if (mctx->state_log[match_last] != NULL + && mctx->state_log[match_last]->halt) + { + halt_node + = check_halt_state_context (mctx, + mctx->state_log[match_last], + match_last); + if (halt_node) + break; + } + } } ret = merge_state_array (dfa, sifted_states, lim_states, match_last + 1); @@ -2256,7 +2341,7 @@ merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, mctx->state_log[cur_idx] = next_state; mctx->state_log_top = cur_idx; } - else if (mctx->state_log[cur_idx] == 0) + else if (mctx->state_log[cur_idx] == NULL) { mctx->state_log[cur_idx] = next_state; } diff --git a/lib/scratch_buffer.h b/lib/scratch_buffer.h index 1185a8e452f..5fc582fe9e6 100644 --- a/lib/scratch_buffer.h +++ b/lib/scratch_buffer.h @@ -102,9 +102,9 @@ extern bool scratch_buffer_set_array_size (struct scratch_buffer *buffer, /* The implementation is imported from glibc. */ /* Avoid possible conflicts with symbols exported by the GNU libc. */ -#define __libc_scratch_buffer_grow gl_scratch_buffer_grow -#define __libc_scratch_buffer_grow_preserve gl_scratch_buffer_grow_preserve -#define __libc_scratch_buffer_set_array_size gl_scratch_buffer_set_array_size +#define __libc_scratch_buffer_grow _gl_scratch_buffer_grow +#define __libc_scratch_buffer_grow_preserve _gl_scratch_buffer_grow_preserve +#define __libc_scratch_buffer_set_array_size _gl_scratch_buffer_set_array_size #ifndef _GL_LIKELY /* Rely on __builtin_expect, as provided by the module 'builtin-expect'. */ diff --git a/lib/set-permissions.c b/lib/set-permissions.c index 8a0eadf5c46..f6a1315e0d6 100644 --- a/lib/set-permissions.c +++ b/lib/set-permissions.c @@ -21,6 +21,8 @@ #include "acl.h" +#include + #include "acl-internal.h" #include "minmax.h" @@ -251,11 +253,9 @@ set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod) int ret; if (desc != -1) - ret = facl (desc, SETACL, - sizeof (entries) / sizeof (aclent_t), entries); + ret = facl (desc, SETACL, countof (entries), entries); else - ret = acl (name, SETACL, - sizeof (entries) / sizeof (aclent_t), entries); + ret = acl (name, SETACL, countof (entries), entries); if (ret < 0) { if (errno == ENOSYS || errno == EOPNOTSUPP) diff --git a/lib/sha1.c b/lib/sha1.c index bb7aa2af293..150e38ea47a 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -240,7 +240,7 @@ sha1_process_block (void const *restrict buffer, size_t len, ctx->total[0] += lolen; ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen); -#define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n)))) +#define rol(x, n) (((x) << (n)) | ((uint32_t) {(x)} >> (32 - (n)))) #define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ diff --git a/lib/sig2str.c b/lib/sig2str.c index da54234ac48..3141ff88066 100644 --- a/lib/sig2str.c +++ b/lib/sig2str.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -260,8 +261,6 @@ static struct numname { int num; char const name[8]; } numname_table[] = { 0, "EXIT" } }; -#define NUMNAME_ENTRIES (sizeof numname_table / sizeof numname_table[0]) - /* ISDIGIT differs from isdigit, as follows: - Its arg may be any int or unsigned int; it need not be an unsigned char or EOF. @@ -286,7 +285,7 @@ str2signum (char const *signame) } else { - for (unsigned int i = 0; i < NUMNAME_ENTRIES; i++) + for (int i = 0; i < countof (numname_table); i++) if (streq (numname_table[i].name, signame)) return numname_table[i].num; @@ -331,7 +330,7 @@ str2sig (char const *signame, int *signum) int sig2str (int signum, char *signame) { - for (unsigned int i = 0; i < NUMNAME_ENTRIES; i++) + for (int i = 0; i < countof (numname_table); i++) if (numname_table[i].num == signum) { strcpy (signame, numname_table[i].name); diff --git a/lib/signal.in.h b/lib/signal.in.h index ce844b1a9cc..9e140ca5e83 100644 --- a/lib/signal.in.h +++ b/lib/signal.in.h @@ -20,6 +20,12 @@ #endif @PRAGMA_COLUMNS@ +/* Deactivate the mingw , that provides an unusable definition + of pthread_sigmask(). We need to do this before including . */ +#ifndef WIN_PTHREADS_SIGNAL_H +#define WIN_PTHREADS_SIGNAL_H +#endif + #if defined __need_sig_atomic_t || defined __need_sigset_t || defined _@GUARD_PREFIX@_ALREADY_INCLUDING_SIGNAL_H || (defined _SIGNAL_H && !defined __SIZEOF_PTHREAD_MUTEX_T) /* Special invocation convention: - Inside glibc header files. @@ -68,12 +74,13 @@ /* Mac OS X 10.3, FreeBSD < 8.0, OpenBSD < 5.1, Solaris 2.6, Android, OS/2 kLIBC declare pthread_sigmask in , not in . - But avoid namespace pollution on glibc systems.*/ + But avoid namespace pollution on glibc systems. */ #if (@GNULIB_PTHREAD_SIGMASK@ || defined GNULIB_POSIXCHECK) \ && ((defined __APPLE__ && defined __MACH__) \ || (defined __FreeBSD__ && __FreeBSD__ < 8) \ || (defined __OpenBSD__ && OpenBSD < 201205) \ - || defined __sun || defined __ANDROID__ \ + || (defined __sun && !defined __cplusplus) \ + || defined __ANDROID__ \ || defined __KLIBC__) \ && ! defined __GLIBC__ # include diff --git a/lib/stat-time.h b/lib/stat-time.h index 45364316645..461a0c88b93 100644 --- a/lib/stat-time.h +++ b/lib/stat-time.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -232,7 +233,7 @@ stat_time_normalize (int result, _GL_UNUSED struct stat *st) short int const ts_off[] = { STAT_TIMESPEC_OFFSETOF (st_atim), STAT_TIMESPEC_OFFSETOF (st_mtim), STAT_TIMESPEC_OFFSETOF (st_ctim) }; - for (int i = 0; i < sizeof ts_off / sizeof *ts_off; i++) + for (int i = 0; i < countof (ts_off); i++) { struct timespec *ts = (struct timespec *) ((char *) st + ts_off[i]); long int q = ts->tv_nsec / timespec_hz; diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h index 88f298afb9f..92749487fa8 100644 --- a/lib/stdbit.in.h +++ b/lib/stdbit.in.h @@ -17,19 +17,92 @@ /* Written by Paul Eggert. */ -#ifndef STDBIT_H -#define STDBIT_H 1 +#ifndef _@GUARD_PREFIX@_STDBIT_H + +#if __GNUC__ >= 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +/* The include_next requires a split double-inclusion guard. */ +#if @HAVE_STDBIT_H@ +# @INCLUDE_NEXT@ @NEXT_STDBIT_H@ +#endif + +#ifndef _@GUARD_PREFIX@_STDBIT_H +#define _@GUARD_PREFIX@_STDBIT_H /* This file uses _GL_INLINE, WORDS_BIGENDIAN. */ #if !_GL_CONFIG_H_INCLUDED #error "Please include config.h first." #endif +/* If needed for APIs, get size_t, avoiding namespace pollution on GNU. */ +#if @GNULIB_STDC_MEMREVERSE8@ && !defined __STDC_VERSION_STDBIT_H__ +# define __need_size_t +# include +#endif + +/* If needed for APIs, get intN_t, uintN_t, int_leastN_t, + uint_leastN_t, and (for internal use) get equivalents of + uint_fast{16,32,64}_t. Avoid namespace pollution on GNU. */ +#if (@GNULIB_STDC_MEMREVERSE8U@ \ + || @GNULIB_STDC_LOAD8@ || @GNULIB_STDC_LOAD8_ALIGNED@ \ + || @GNULIB_STDC_STORE8@ || @GNULIB_STDC_STORE8_ALIGNED@) +# if !(defined __STDC_VERSION_STDBIT_H__ && defined __UINT_FAST64_TYPE__) +# include +# define _GL_STDBIT_UINT_FAST16 uint_fast16_t +# define _GL_STDBIT_UINT_FAST32 uint_fast32_t +# define _GL_STDBIT_UINT_FAST64 uint_fast64_t +# else +# define _GL_STDBIT_UINT_FAST16 __UINT_FAST16_TYPE__ +# define _GL_STDBIT_UINT_FAST32 __UINT_FAST32_TYPE__ +# define _GL_STDBIT_UINT_FAST64 __UINT_FAST64_TYPE__ +# endif +#endif + +#if @GNULIB_STDC_MEMREVERSE8U@ || @GNULIB_STDC_LOAD8_ALIGNED@ || @GNULIB_STDC_STORE8_ALIGNED@ + +/* Determine whether the compiler supports the __builtin_bswap{16,32,64} + builtins. */ +# if defined __GNUC__ && 4 < __GNUC__ + (8 <= __GNUC_MINOR__) +# define _GL_STDBIT_HAS_BUILTIN_BSWAP16 1 +# elif defined __has_builtin +# if __has_builtin (__builtin_bswap16) +# define _GL_STDBIT_HAS_BUILTIN_BSWAP16 1 +# endif +# endif +# if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__) +# define _GL_STDBIT_HAS_BUILTIN_BSWAP32 1 +# define _GL_STDBIT_HAS_BUILTIN_BSWAP64 1 +# elif defined __has_builtin +# if __has_builtin (__builtin_bswap32) +# define _GL_STDBIT_HAS_BUILTIN_BSWAP32 1 +# endif +# if __has_builtin (__builtin_bswap64) +# define _GL_STDBIT_HAS_BUILTIN_BSWAP64 1 +# endif +# endif + +#endif + +#if @GNULIB_STDC_LOAD8_ALIGNED@ || @GNULIB_STDC_STORE8_ALIGNED@ + +/* Get memcpy, but keep namespace clean on GNU. */ +# ifdef __has_builtin +# if __has_builtin (__builtin_memcpy) +# define _GL_STDBIT_MEMCPY(dest, src, n) __builtin_memcpy (dest, src, n) +# endif +# endif +# ifndef _GL_STDBIT_MEMCPY +# include +# define _GL_STDBIT_MEMCPY(dest, src, n) memcpy (dest, src, n) +# endif + +#endif + _GL_INLINE_HEADER_BEGIN -#ifndef _GL_STDBIT_INLINE -# define _GL_STDBIT_INLINE _GL_INLINE -#endif #ifndef _GL_STDC_LEADING_ZEROS_INLINE # define _GL_STDC_LEADING_ZEROS_INLINE _GL_INLINE #endif @@ -72,6 +145,30 @@ _GL_INLINE_HEADER_BEGIN #ifndef _GL_STDC_BIT_CEIL_INLINE # define _GL_STDC_BIT_CEIL_INLINE _GL_INLINE #endif +#ifndef _GL_STDC_ROTATE_LEFT_INLINE +# define _GL_STDC_ROTATE_LEFT_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_ROTATE_RIGHT_INLINE +# define _GL_STDC_ROTATE_RIGHT_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_MEMREVERSE8_INLINE +# define _GL_STDC_MEMREVERSE8_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_MEMREVERSE8U_INLINE +# define _GL_STDC_MEMREVERSE8U_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_LOAD8_ALIGNED_INLINE +# define _GL_STDC_LOAD8_ALIGNED_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_LOAD8_INLINE +# define _GL_STDC_LOAD8_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_STORE8_ALIGNED_INLINE +# define _GL_STDC_STORE8_ALIGNED_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_STORE8_INLINE +# define _GL_STDC_STORE8_INLINE _GL_INLINE +#endif /* An expression, preferably with the type of A, that has the value of B. */ #if ((defined __GNUC__ && 2 <= __GNUC__) \ @@ -90,10 +187,13 @@ _GL_INLINE_HEADER_BEGIN #endif -/* ISO C 23 § 7.18.1 General */ +#ifdef __cplusplus +extern "C" { +#endif -#define __STDC_VERSION_STDBIT_H__ 202311L +/* Some systems are only missing C2y features in stdbit.h. */ +#ifndef __STDC_VERSION_STDBIT_H__ /* ISO C 23 § 7.18.2 Endian */ @@ -105,88 +205,82 @@ _GL_INLINE_HEADER_BEGIN # define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__ #endif +#endif /* !__STDC_VERSION_STDBIT_H__ */ -#ifdef __cplusplus -extern "C" { -#endif -#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) || 4 <= __clang_major__ -# define _GL_STDBIT_HAS_BUILTIN_CLZ true -# define _GL_STDBIT_HAS_BUILTIN_CTZ true -# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true -#elif defined __has_builtin -# if (__has_builtin (__builtin_clz) \ - && __has_builtin (__builtin_clzl) \ - && __has_builtin (__builtin_clzll)) +/* Some systems are only missing C2y features in stdbit.h. */ +#ifndef __STDC_VERSION_STDBIT_H__ + +/* ISO C 23 § 7.18.3 Count Leading Zeros */ + +#if @GNULIB_STDC_LEADING_ZEROS@ + +# if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) || 4 <= __clang_major__ # define _GL_STDBIT_HAS_BUILTIN_CLZ true +# elif defined __has_builtin +# if (__has_builtin (__builtin_clz) \ + && __has_builtin (__builtin_clzl) \ + && __has_builtin (__builtin_clzll)) +# define _GL_STDBIT_HAS_BUILTIN_CLZ true +# endif # endif -# if (__has_builtin (__builtin_ctz) \ - && __has_builtin (__builtin_ctzl) \ - && __has_builtin (__builtin_ctzll)) -# define _GL_STDBIT_HAS_BUILTIN_CTZ true -# endif -# if (__has_builtin (__builtin_popcount) \ - && __has_builtin (__builtin_popcountl) \ - && __has_builtin (__builtin_popcountll)) -# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true -# endif -#endif /* Count leading 0 bits of N, even if N is 0. */ -#ifdef _GL_STDBIT_HAS_BUILTIN_CLZ -_GL_STDBIT_INLINE int -__gl_stdbit_clz (unsigned int n) +# if !GNULIB_defined_clz_functions +# ifdef _GL_STDBIT_HAS_BUILTIN_CLZ +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clz (unsigned int n) { return n ? __builtin_clz (n) : 8 * sizeof n; } -_GL_STDBIT_INLINE int -__gl_stdbit_clzl (unsigned long int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clzl (unsigned long int n) { return n ? __builtin_clzl (n) : 8 * sizeof n; } -_GL_STDBIT_INLINE int -__gl_stdbit_clzll (unsigned long long int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clzll (unsigned long long int n) { return n ? __builtin_clzll (n) : 8 * sizeof n; } -#elif defined _MSC_VER +# elif defined _MSC_VER /* Declare the few MSVC intrinsics that we need. We prefer not to include because it would pollute the namespace. */ extern unsigned char _BitScanReverse (unsigned long *, unsigned long); -# pragma intrinsic (_BitScanReverse) -# ifdef _M_X64 +# pragma intrinsic (_BitScanReverse) +# ifdef _M_X64 extern unsigned char _BitScanReverse64 (unsigned long *, unsigned long long); -# pragma intrinsic (_BitScanReverse64) -# endif +# pragma intrinsic (_BitScanReverse64) +# endif -_GL_STDBIT_INLINE int -__gl_stdbit_clzl (unsigned long int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clzl (unsigned long int n) { unsigned long int r; return 8 * sizeof n - (_BitScanReverse (&r, n) ? r + 1 : 0); } -_GL_STDBIT_INLINE int -__gl_stdbit_clz (unsigned int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clz (unsigned int n) { - return __gl_stdbit_clzl (n) - 8 * (sizeof 0ul - sizeof n); + return _gl_stdbit_clzl (n) - 8 * (sizeof 0ul - sizeof n); } -_GL_STDBIT_INLINE int -__gl_stdbit_clzll (unsigned long long int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clzll (unsigned long long int n) { -# ifdef _M_X64 +# ifdef _M_X64 unsigned long int r; return 8 * sizeof n - (_BitScanReverse64 (&r, n) ? r + 1 : 0); -# else +# else unsigned long int hi = n >> 32; - return __gl_stdbit_clzl (hi ? hi : n) + (hi ? 0 : 32); -# endif + return _gl_stdbit_clzl (hi ? hi : n) + (hi ? 0 : 32); +# endif } -#else /* !_MSC_VER */ +# else /* !_MSC_VER */ -_GL_STDBIT_INLINE int -__gl_stdbit_clzll (unsigned long long int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clzll (unsigned long long int n) { int r = 0; for (int i = 8 * sizeof n >> 1; 1 << 6 <= i; i >>= 1) @@ -199,97 +293,556 @@ __gl_stdbit_clzll (unsigned long long int n) int a2 = (0x000000000000000f < n) << 2; n >>= a2; r += a2; return (8 * sizeof n - (1 << 2) - r) + ((0x11112234ull >> (n << 2)) & 0xf); } -_GL_STDBIT_INLINE int -__gl_stdbit_clz (unsigned int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clz (unsigned int n) { - return __gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0u); + return _gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0u); } -_GL_STDBIT_INLINE int -__gl_stdbit_clzl (unsigned long int n) +_GL_STDC_LEADING_ZEROS_INLINE int +_gl_stdbit_clzl (unsigned long int n) { - return __gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0ul); + return _gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0ul); } +# endif + +# define GNULIB_defined_clz_functions 1 +# endif + +# if !GNULIB_defined_stdc_leading_zeros_functions + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ui (unsigned int n) +{ + return _gl_stdbit_clz (n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_uc (unsigned char n) +{ + return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_us (unsigned short int n) +{ + return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ul (unsigned long int n) +{ + return _gl_stdbit_clzl (n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ull (unsigned long long int n) +{ + return _gl_stdbit_clzll (n); +} + +# define GNULIB_defined_stdc_leading_zeros_functions 1 +# endif + +# define stdc_leading_zeros(n) \ + (sizeof (n) == 1 ? stdc_leading_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_leading_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_leading_zeros_ul (n) \ + : stdc_leading_zeros_ull (n)) + #endif + +/* ISO C 23 § 7.18.4 Count Leading Ones */ + +#if @GNULIB_STDC_LEADING_ONES@ + +# if !GNULIB_defined_stdc_leading_ones_functions + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_uc (unsigned char n) +{ + return stdc_leading_zeros_uc (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_us (unsigned short int n) +{ + return stdc_leading_zeros_us (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ui (unsigned int n) +{ + return stdc_leading_zeros_ui (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ul (unsigned long int n) +{ + return stdc_leading_zeros_ul (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ull (unsigned long long int n) +{ + return stdc_leading_zeros_ull (~n); +} + +# define GNULIB_defined_stdc_leading_ones_functions 1 +# endif + +# define stdc_leading_ones(n) \ + (sizeof (n) == 1 ? stdc_leading_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_leading_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_leading_ones_ul (n) \ + : stdc_leading_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.5 Count Trailing Zeros */ + +#if @GNULIB_STDC_TRAILING_ZEROS@ + +# if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) || 4 <= __clang_major__ +# define _GL_STDBIT_HAS_BUILTIN_CTZ true +# elif defined __has_builtin +# if (__has_builtin (__builtin_ctz) \ + && __has_builtin (__builtin_ctzl) \ + && __has_builtin (__builtin_ctzll)) +# define _GL_STDBIT_HAS_BUILTIN_CTZ true +# endif +# endif + /* Count trailing 0 bits of N, even if N is 0. */ -#ifdef _GL_STDBIT_HAS_BUILTIN_CTZ -_GL_STDBIT_INLINE int -__gl_stdbit_ctz (unsigned int n) +# if !GNULIB_defined_ctz_functions +# ifdef _GL_STDBIT_HAS_BUILTIN_CTZ +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctz (unsigned int n) { return n ? __builtin_ctz (n) : 8 * sizeof n; } -_GL_STDBIT_INLINE int -__gl_stdbit_ctzl (unsigned long int n) +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctzl (unsigned long int n) { return n ? __builtin_ctzl (n) : 8 * sizeof n; } -_GL_STDBIT_INLINE int -__gl_stdbit_ctzll (unsigned long long int n) +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctzll (unsigned long long int n) { return n ? __builtin_ctzll (n) : 8 * sizeof n; } -#elif defined _MSC_VER +# elif defined _MSC_VER /* Declare the few MSVC intrinsics that we need. We prefer not to include because it would pollute the namespace. */ extern unsigned char _BitScanForward (unsigned long *, unsigned long); -# pragma intrinsic (_BitScanForward) -# ifdef _M_X64 +# pragma intrinsic (_BitScanForward) +# ifdef _M_X64 extern unsigned char _BitScanForward64 (unsigned long *, unsigned long long); -# pragma intrinsic (_BitScanForward64) -# endif +# pragma intrinsic (_BitScanForward64) +# endif -_GL_STDBIT_INLINE int -__gl_stdbit_ctzl (unsigned long int n) +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctzl (unsigned long int n) { unsigned long int r; return _BitScanForward (&r, n) ? r : 8 * sizeof n; } -_GL_STDBIT_INLINE int -__gl_stdbit_ctz (unsigned int n) +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctz (unsigned int n) { - return __gl_stdbit_ctzl (n | (1ul << (8 * sizeof n - 1) << 1)); + return _gl_stdbit_ctzl (n | (1ul << (8 * sizeof n - 1) << 1)); } -_GL_STDBIT_INLINE int -__gl_stdbit_ctzll (unsigned long long int n) +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctzll (unsigned long long int n) { -# ifdef _M_X64 +# ifdef _M_X64 unsigned long int r; return _BitScanForward64 (&r, n) ? r : 8 * sizeof n; -# else +# else unsigned int lo = n; - return __gl_stdbit_ctzl (lo ? lo : n >> 32) + (lo ? 0 : 32); + return _gl_stdbit_ctzl (lo ? lo : n >> 32) + (lo ? 0 : 32); +# endif +} + +# else /* !_MSC_VER */ + +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctz (unsigned int n) +{ + return 8 * sizeof n - (n ? _gl_stdbit_clz (n & -n) + 1 : 0); +} +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctzl (unsigned long int n) +{ + return 8 * sizeof n - (n ? _gl_stdbit_clzl (n & -n) + 1 : 0); +} +_GL_STDC_TRAILING_ZEROS_INLINE int +_gl_stdbit_ctzll (unsigned long long int n) +{ + return 8 * sizeof n - (n ? _gl_stdbit_clzll (n & -n) + 1 : 0); +} +# endif + +# define GNULIB_defined_ctz_functions 1 # endif + +# if !GNULIB_defined_stdc_trailing_zeros_functions + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ui (unsigned int n) +{ + return _gl_stdbit_ctz (n); } -#else /* !_MSC_VER */ +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_uc (unsigned char n) +{ + return stdc_trailing_zeros_ui (n | (1 + (unsigned char) -1)); +} -_GL_STDBIT_INLINE int -__gl_stdbit_ctz (unsigned int n) +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_us (unsigned short int n) { - return 8 * sizeof n - (n ? __gl_stdbit_clz (n & -n) + 1 : 0); + return stdc_trailing_zeros_ui (n | (1 + (unsigned short int) -1)); } -_GL_STDBIT_INLINE int -__gl_stdbit_ctzl (unsigned long int n) + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ul (unsigned long int n) { - return 8 * sizeof n - (n ? __gl_stdbit_clzl (n & -n) + 1 : 0); + return _gl_stdbit_ctzl (n); } -_GL_STDBIT_INLINE int -__gl_stdbit_ctzll (unsigned long long int n) + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ull (unsigned long long int n) { - return 8 * sizeof n - (n ? __gl_stdbit_clzll (n & -n) + 1 : 0); + return _gl_stdbit_ctzll (n); } + +# define GNULIB_defined_stdc_trailing_zeros_functions 1 +# endif + +# define stdc_trailing_zeros(n) \ + (sizeof (n) == 1 ? stdc_trailing_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_trailing_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_trailing_zeros_ul (n) \ + : stdc_trailing_zeros_ull (n)) + #endif -#if @GL_STDC_COUNT_ONES@ + +/* ISO C 23 § 7.18.6 Count Trailing Ones */ + +#if @GNULIB_STDC_TRAILING_ONES@ + +# if !GNULIB_defined_stdc_trailing_ones_functions + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_uc (unsigned char n) +{ + return stdc_trailing_zeros_uc (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_us (unsigned short int n) +{ + return stdc_trailing_zeros_us (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ui (unsigned int n) +{ + return stdc_trailing_zeros_ui (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ul (unsigned long int n) +{ + return stdc_trailing_zeros_ul (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ull (unsigned long long int n) +{ + return stdc_trailing_zeros_ull (~n); +} + +# define GNULIB_defined_stdc_trailing_ones_functions 1 +# endif + +# define stdc_trailing_ones(n) \ + (sizeof (n) == 1 ? stdc_trailing_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_trailing_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_trailing_ones_ul (n) \ + : stdc_trailing_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.7 First Leading Zero */ + +#if @GNULIB_STDC_FIRST_LEADING_ZERO@ + +# if !GNULIB_defined_stdc_first_leading_zero_functions + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_uc (unsigned char n) +{ + unsigned int count = stdc_leading_ones_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_us (unsigned short int n) +{ + unsigned int count = stdc_leading_ones_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ui (unsigned int n) +{ + unsigned int count = stdc_leading_ones_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ul (unsigned long int n) +{ + unsigned int count = stdc_leading_ones_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ull (unsigned long long int n) +{ + unsigned int count = stdc_leading_ones_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define GNULIB_defined_stdc_first_leading_zero_functions 1 +# endif + +# define stdc_first_leading_zero(n) \ + (sizeof (n) == 1 ? stdc_first_leading_zero_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_zero_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_leading_zero_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_leading_zero_ul (n) \ + : stdc_first_leading_zero_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.8 First Leading One */ + +#if @GNULIB_STDC_FIRST_LEADING_ONE@ + +# if !GNULIB_defined_stdc_first_leading_one_functions + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_uc (unsigned char n) +{ + unsigned int count = stdc_leading_zeros_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_us (unsigned short int n) +{ + unsigned int count = stdc_leading_zeros_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ui (unsigned int n) +{ + unsigned int count = stdc_leading_zeros_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ul (unsigned long int n) +{ + unsigned int count = stdc_leading_zeros_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ull (unsigned long long int n) +{ + unsigned int count = stdc_leading_zeros_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define GNULIB_defined_stdc_first_leading_one_functions 1 +# endif + +# define stdc_first_leading_one(n) \ + (sizeof (n) == 1 ? stdc_first_leading_one_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_one_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_leading_one_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_leading_one_ul (n) \ + : stdc_first_leading_one_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.9 First Trailing Zero */ + +#if @GNULIB_STDC_FIRST_TRAILING_ZERO@ + +# if !GNULIB_defined_stdc_first_trailing_zero_functions + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_uc (unsigned char n) +{ + unsigned int count = stdc_trailing_ones_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_us (unsigned short int n) +{ + unsigned int count = stdc_trailing_ones_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ui (unsigned int n) +{ + unsigned int count = stdc_trailing_ones_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ul (unsigned long int n) +{ + unsigned int count = stdc_trailing_ones_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ull (unsigned long long int n) +{ + unsigned int count = stdc_trailing_ones_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define GNULIB_defined_stdc_first_trailing_zero_functions 1 +# endif + +# define stdc_first_trailing_zero(n) \ + (sizeof (n) == 1 ? stdc_first_trailing_zero_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_zero_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_trailing_zero_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_trailing_zero_ul (n) \ + : stdc_first_trailing_zero_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.10 First Trailing One */ + +#if @GNULIB_STDC_FIRST_TRAILING_ONE@ + +# if !GNULIB_defined_stdc_first_trailing_one_functions + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_uc (unsigned char n) +{ + unsigned int count = stdc_trailing_zeros_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_us (unsigned short int n) +{ + unsigned int count = stdc_trailing_zeros_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ui (unsigned int n) +{ + unsigned int count = stdc_trailing_zeros_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ul (unsigned long int n) +{ + unsigned int count = stdc_trailing_zeros_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ull (unsigned long long int n) +{ + unsigned int count = stdc_trailing_zeros_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define GNULIB_defined_stdc_first_trailing_one_functions 1 +# endif + +# define stdc_first_trailing_one(n) \ + (sizeof (n) == 1 ? stdc_first_trailing_one_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_one_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_trailing_one_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_trailing_one_ul (n) \ + : stdc_first_trailing_one_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.12 Count Ones */ + +#if @GNULIB_STDC_COUNT_ONES@ + +# if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) || 4 <= __clang_major__ +# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true +# elif defined __has_builtin +# if (__has_builtin (__builtin_popcount) \ + && __has_builtin (__builtin_popcountl) \ + && __has_builtin (__builtin_popcountll)) +# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true +# endif +# endif + /* Count 1 bits in N. */ -# ifdef _GL_STDBIT_HAS_BUILTIN_POPCOUNT -# define __gl_stdbit_popcount __builtin_popcount -# define __gl_stdbit_popcountl __builtin_popcountl -# define __gl_stdbit_popcountll __builtin_popcountll -# else +# if !GNULIB_defined_popcount_functions +# ifdef _GL_STDBIT_HAS_BUILTIN_POPCOUNT +# define _gl_stdbit_popcount __builtin_popcount +# define _gl_stdbit_popcountl __builtin_popcountl +# define _gl_stdbit_popcountll __builtin_popcountll +# else _GL_STDC_COUNT_ONES_INLINE int -__gl_stdbit_popcount_wide (unsigned long long int n) +_gl_stdbit_popcount_wide (unsigned long long int n) { if (sizeof n & (sizeof n - 1)) { @@ -335,33 +888,33 @@ __gl_stdbit_popcount_wide (unsigned long long int n) } } -# ifdef _MSC_VER -# if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) +# ifdef _MSC_VER +# if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) /* Declare the few MSVC intrinsics that we need. We prefer not to include because it would pollute the namespace. */ extern void __cpuid (int[4], int); -# pragma intrinsic (__cpuid) +# pragma intrinsic (__cpuid) extern unsigned int __popcnt (unsigned int); -# pragma intrinsic (__popcnt) -# ifdef _M_X64 +# pragma intrinsic (__popcnt) +# ifdef _M_X64 extern unsigned long long __popcnt64 (unsigned long long); -# pragma intrinsic (__popcnt64) -# else +# pragma intrinsic (__popcnt64) +# else _GL_STDC_COUNT_ONES_INLINE int __popcnt64 (unsigned long long int n) { return __popcnt (n >> 32) + __popcnt (n); } +# endif # endif -# endif /* 1 if supported, -1 if not, 0 if unknown. */ -extern signed char __gl_stdbit_popcount_support; +extern signed char _gl_stdbit_popcount_support; _GL_STDC_COUNT_ONES_INLINE bool -__gl_stdbit_popcount_supported (void) +_gl_stdbit_popcount_supported (void) { - if (!__gl_stdbit_popcount_support) + if (!_gl_stdbit_popcount_support) { /* Do as described in @@ -369,440 +922,46 @@ __gl_stdbit_popcount_supported (void) we'll be more cautious. */ int cpu_info[4]; __cpuid (cpu_info, 1); - __gl_stdbit_popcount_support = cpu_info[2] & 1 << 23 ? 1 : -1; + _gl_stdbit_popcount_support = cpu_info[2] & 1 << 23 ? 1 : -1; } - return 0 < __gl_stdbit_popcount_support; + return 0 < _gl_stdbit_popcount_support; } _GL_STDC_COUNT_ONES_INLINE int -__gl_stdbit_popcount (unsigned int n) +_gl_stdbit_popcount (unsigned int n) { - return (__gl_stdbit_popcount_supported () + return (_gl_stdbit_popcount_supported () ? __popcnt (n) - : __gl_stdbit_popcount_wide (n)); + : _gl_stdbit_popcount_wide (n)); } _GL_STDC_COUNT_ONES_INLINE int -__gl_stdbit_popcountl (unsigned long int n) +_gl_stdbit_popcountl (unsigned long int n) { - return (__gl_stdbit_popcount_supported () + return (_gl_stdbit_popcount_supported () ? __popcnt (n) - : __gl_stdbit_popcount_wide (n)); + : _gl_stdbit_popcount_wide (n)); } _GL_STDC_COUNT_ONES_INLINE int -__gl_stdbit_popcountll (unsigned long long int n) +_gl_stdbit_popcountll (unsigned long long int n) { - return (__gl_stdbit_popcount_supported () + return (_gl_stdbit_popcount_supported () ? __popcnt64 (n) - : __gl_stdbit_popcount_wide (n)); + : _gl_stdbit_popcount_wide (n)); } -# else /* !_MSC_VER */ -# define __gl_stdbit_popcount __gl_stdbit_popcount_wide -# define __gl_stdbit_popcountl __gl_stdbit_popcount_wide -# define __gl_stdbit_popcountll __gl_stdbit_popcount_wide +# else /* !_MSC_VER */ +# define _gl_stdbit_popcount _gl_stdbit_popcount_wide +# define _gl_stdbit_popcountl _gl_stdbit_popcount_wide +# define _gl_stdbit_popcountll _gl_stdbit_popcount_wide +# endif # endif +# define GNULIB_defined_popcount_functions 1 # endif -#endif - -/* ISO C 23 § 7.18.3 Count Leading Zeros */ - -#if @GL_STDC_LEADING_ZEROS@ - -_GL_STDC_LEADING_ZEROS_INLINE unsigned int -stdc_leading_zeros_ui (unsigned int n) -{ - return __gl_stdbit_clz (n); -} - -_GL_STDC_LEADING_ZEROS_INLINE unsigned int -stdc_leading_zeros_uc (unsigned char n) -{ - return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); -} - -_GL_STDC_LEADING_ZEROS_INLINE unsigned int -stdc_leading_zeros_us (unsigned short int n) -{ - return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); -} - -_GL_STDC_LEADING_ZEROS_INLINE unsigned int -stdc_leading_zeros_ul (unsigned long int n) -{ - return __gl_stdbit_clzl (n); -} - -_GL_STDC_LEADING_ZEROS_INLINE unsigned int -stdc_leading_zeros_ull (unsigned long long int n) -{ - return __gl_stdbit_clzll (n); -} - -# define stdc_leading_zeros(n) \ - (sizeof (n) == 1 ? stdc_leading_zeros_uc (n) \ - : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_zeros_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_leading_zeros_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_leading_zeros_ul (n) \ - : stdc_leading_zeros_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.4 Count Leading Ones */ - -#if @GL_STDC_LEADING_ONES@ - -_GL_STDC_LEADING_ONES_INLINE unsigned int -stdc_leading_ones_uc (unsigned char n) -{ - return stdc_leading_zeros_uc (~n); -} - -_GL_STDC_LEADING_ONES_INLINE unsigned int -stdc_leading_ones_us (unsigned short int n) -{ - return stdc_leading_zeros_us (~n); -} - -_GL_STDC_LEADING_ONES_INLINE unsigned int -stdc_leading_ones_ui (unsigned int n) -{ - return stdc_leading_zeros_ui (~n); -} - -_GL_STDC_LEADING_ONES_INLINE unsigned int -stdc_leading_ones_ul (unsigned long int n) -{ - return stdc_leading_zeros_ul (~n); -} - -_GL_STDC_LEADING_ONES_INLINE unsigned int -stdc_leading_ones_ull (unsigned long long int n) -{ - return stdc_leading_zeros_ull (~n); -} - -# define stdc_leading_ones(n) \ - (sizeof (n) == 1 ? stdc_leading_ones_uc (n) \ - : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_ones_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_leading_ones_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_leading_ones_ul (n) \ - : stdc_leading_ones_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.5 Count Trailing Zeros */ - -#if @GL_STDC_TRAILING_ZEROS@ - -_GL_STDC_TRAILING_ZEROS_INLINE unsigned int -stdc_trailing_zeros_ui (unsigned int n) -{ - return __gl_stdbit_ctz (n); -} - -_GL_STDC_TRAILING_ZEROS_INLINE unsigned int -stdc_trailing_zeros_uc (unsigned char n) -{ - return stdc_trailing_zeros_ui (n | (1 + (unsigned char) -1)); -} - -_GL_STDC_TRAILING_ZEROS_INLINE unsigned int -stdc_trailing_zeros_us (unsigned short int n) -{ - return stdc_trailing_zeros_ui (n | (1 + (unsigned short int) -1)); -} - -_GL_STDC_TRAILING_ZEROS_INLINE unsigned int -stdc_trailing_zeros_ul (unsigned long int n) -{ - return __gl_stdbit_ctzl (n); -} - -_GL_STDC_TRAILING_ZEROS_INLINE unsigned int -stdc_trailing_zeros_ull (unsigned long long int n) -{ - return __gl_stdbit_ctzll (n); -} - -# define stdc_trailing_zeros(n) \ - (sizeof (n) == 1 ? stdc_trailing_zeros_uc (n) \ - : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_zeros_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_trailing_zeros_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_trailing_zeros_ul (n) \ - : stdc_trailing_zeros_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.6 Count Trailing Ones */ - -#if @GL_STDC_TRAILING_ONES@ - -_GL_STDC_TRAILING_ONES_INLINE unsigned int -stdc_trailing_ones_uc (unsigned char n) -{ - return stdc_trailing_zeros_uc (~n); -} - -_GL_STDC_TRAILING_ONES_INLINE unsigned int -stdc_trailing_ones_us (unsigned short int n) -{ - return stdc_trailing_zeros_us (~n); -} - -_GL_STDC_TRAILING_ONES_INLINE unsigned int -stdc_trailing_ones_ui (unsigned int n) -{ - return stdc_trailing_zeros_ui (~n); -} - -_GL_STDC_TRAILING_ONES_INLINE unsigned int -stdc_trailing_ones_ul (unsigned long int n) -{ - return stdc_trailing_zeros_ul (~n); -} - -_GL_STDC_TRAILING_ONES_INLINE unsigned int -stdc_trailing_ones_ull (unsigned long long int n) -{ - return stdc_trailing_zeros_ull (~n); -} - -# define stdc_trailing_ones(n) \ - (sizeof (n) == 1 ? stdc_trailing_ones_uc (n) \ - : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_ones_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_trailing_ones_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_trailing_ones_ul (n) \ - : stdc_trailing_ones_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.7 First Leading Zero */ - -#if @GL_STDC_FIRST_LEADING_ZERO@ - -_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int -stdc_first_leading_zero_uc (unsigned char n) -{ - unsigned int count = stdc_leading_ones_uc (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int -stdc_first_leading_zero_us (unsigned short int n) -{ - unsigned int count = stdc_leading_ones_us (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int -stdc_first_leading_zero_ui (unsigned int n) -{ - unsigned int count = stdc_leading_ones_ui (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int -stdc_first_leading_zero_ul (unsigned long int n) -{ - unsigned int count = stdc_leading_ones_ul (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int -stdc_first_leading_zero_ull (unsigned long long int n) -{ - unsigned int count = stdc_leading_ones_ull (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -# define stdc_first_leading_zero(n) \ - (sizeof (n) == 1 ? stdc_first_leading_zero_uc (n) \ - : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_zero_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_first_leading_zero_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_first_leading_zero_ul (n) \ - : stdc_first_leading_zero_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.8 First Leading One */ - -#if @GL_STDC_FIRST_LEADING_ONE@ - -_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int -stdc_first_leading_one_uc (unsigned char n) -{ - unsigned int count = stdc_leading_zeros_uc (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int -stdc_first_leading_one_us (unsigned short int n) -{ - unsigned int count = stdc_leading_zeros_us (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int -stdc_first_leading_one_ui (unsigned int n) -{ - unsigned int count = stdc_leading_zeros_ui (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int -stdc_first_leading_one_ul (unsigned long int n) -{ - unsigned int count = stdc_leading_zeros_ul (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int -stdc_first_leading_one_ull (unsigned long long int n) -{ - unsigned int count = stdc_leading_zeros_ull (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -# define stdc_first_leading_one(n) \ - (sizeof (n) == 1 ? stdc_first_leading_one_uc (n) \ - : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_one_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_first_leading_one_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_first_leading_one_ul (n) \ - : stdc_first_leading_one_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.9 First Trailing Zero */ - -#if @GL_STDC_FIRST_TRAILING_ZERO@ - -_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int -stdc_first_trailing_zero_uc (unsigned char n) -{ - unsigned int count = stdc_trailing_ones_uc (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int -stdc_first_trailing_zero_us (unsigned short int n) -{ - unsigned int count = stdc_trailing_ones_us (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int -stdc_first_trailing_zero_ui (unsigned int n) -{ - unsigned int count = stdc_trailing_ones_ui (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int -stdc_first_trailing_zero_ul (unsigned long int n) -{ - unsigned int count = stdc_trailing_ones_ul (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int -stdc_first_trailing_zero_ull (unsigned long long int n) -{ - unsigned int count = stdc_trailing_ones_ull (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -# define stdc_first_trailing_zero(n) \ - (sizeof (n) == 1 ? stdc_first_trailing_zero_uc (n) \ - : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_zero_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_first_trailing_zero_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_first_trailing_zero_ul (n) \ - : stdc_first_trailing_zero_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.10 First Trailing One */ - -#if @GL_STDC_FIRST_TRAILING_ONE@ - -_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int -stdc_first_trailing_one_uc (unsigned char n) -{ - unsigned int count = stdc_trailing_zeros_uc (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int -stdc_first_trailing_one_us (unsigned short int n) -{ - unsigned int count = stdc_trailing_zeros_us (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int -stdc_first_trailing_one_ui (unsigned int n) -{ - unsigned int count = stdc_trailing_zeros_ui (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int -stdc_first_trailing_one_ul (unsigned long int n) -{ - unsigned int count = stdc_trailing_zeros_ul (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int -stdc_first_trailing_one_ull (unsigned long long int n) -{ - unsigned int count = stdc_trailing_zeros_ull (n); - unsigned int bits = 8 * sizeof n; - return count % bits + (count < bits); -} - -#define stdc_first_trailing_one(n) \ - (sizeof (n) == 1 ? stdc_first_trailing_one_uc (n) \ - : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_one_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_first_trailing_one_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_first_trailing_one_ul (n) \ - : stdc_first_trailing_one_ull (n)) - -#endif - - -/* ISO C 23 § 7.18.12 Count Ones */ - -#if @GL_STDC_COUNT_ONES@ +# if !GNULIB_defined_stdc_count_ones_functions _GL_STDC_COUNT_ONES_INLINE unsigned int stdc_count_ones_ui (unsigned int n) { - return __gl_stdbit_popcount (n); + return _gl_stdbit_popcount (n); } _GL_STDC_COUNT_ONES_INLINE unsigned int @@ -820,15 +979,18 @@ stdc_count_ones_us (unsigned short int n) _GL_STDC_COUNT_ONES_INLINE unsigned int stdc_count_ones_ul (unsigned long int n) { - return __gl_stdbit_popcountl (n); + return _gl_stdbit_popcountl (n); } _GL_STDC_COUNT_ONES_INLINE unsigned int stdc_count_ones_ull (unsigned long long int n) { - return __gl_stdbit_popcountll (n); + return _gl_stdbit_popcountll (n); } +# define GNULIB_defined_stdc_count_ones_functions 1 +# endif + # define stdc_count_ones(n) \ (sizeof (n) == 1 ? stdc_count_ones_uc (n) \ : sizeof (n) == sizeof (unsigned short int) ? stdc_count_ones_us (n) \ @@ -841,7 +1003,9 @@ stdc_count_ones_ull (unsigned long long int n) /* ISO C 23 § 7.18.11 Count Zeros */ -#if @GL_STDC_COUNT_ZEROS@ +#if @GNULIB_STDC_COUNT_ZEROS@ + +# if !GNULIB_defined_stdc_count_zeros_functions _GL_STDC_COUNT_ZEROS_INLINE unsigned int stdc_count_zeros_uc (unsigned char n) @@ -873,6 +1037,9 @@ stdc_count_zeros_ull (unsigned long long int n) return stdc_count_ones_ull (~n); } +# define GNULIB_defined_stdc_count_zeros_functions 1 +# endif + # define stdc_count_zeros(n) \ (sizeof (n) == 1 ? stdc_count_zeros_uc (n) \ : sizeof (n) == sizeof (unsigned short int) ? stdc_count_zeros_us (n) \ @@ -885,7 +1052,9 @@ stdc_count_zeros_ull (unsigned long long int n) /* ISO C 23 § 7.18.13 Single-bit Check */ -#if @GL_STDC_HAS_SINGLE_BIT@ +#if @GNULIB_STDC_HAS_SINGLE_BIT@ + +# if !GNULIB_defined_stdc_has_single_bit_functions _GL_STDC_HAS_SINGLE_BIT_INLINE bool stdc_has_single_bit_uc (unsigned char n) @@ -922,6 +1091,9 @@ stdc_has_single_bit_ull (unsigned long long int n) return n_1 < nx; } +# define GNULIB_defined_stdc_has_single_bit_functions 1 +# endif + # define stdc_has_single_bit(n) \ ((bool) \ (sizeof (n) == 1 ? stdc_has_single_bit_uc (n) \ @@ -935,7 +1107,9 @@ stdc_has_single_bit_ull (unsigned long long int n) /* ISO C 23 § 7.18.14 Bit Width */ -#if @GL_STDC_BIT_WIDTH@ +#if @GNULIB_STDC_BIT_WIDTH@ + +# if !GNULIB_defined_stdc_bit_width_functions _GL_STDC_BIT_WIDTH_INLINE unsigned int stdc_bit_width_uc (unsigned char n) @@ -967,6 +1141,9 @@ stdc_bit_width_ull (unsigned long long int n) return 8 * sizeof n - stdc_leading_zeros_ull (n); } +# define GNULIB_defined_stdc_bit_width_functions 1 +# endif + # define stdc_bit_width(n) \ (sizeof (n) == 1 ? stdc_bit_width_uc (n) \ : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_width_us (n) \ @@ -976,10 +1153,15 @@ stdc_bit_width_ull (unsigned long long int n) #endif +#endif /* !__STDC_VERSION_STDBIT_H__ */ + /* ISO C 23 § 7.18.15 Bit Floor */ -#if @GL_STDC_BIT_FLOOR@ +#if @GNULIB_STDC_BIT_FLOOR@ + +# if !defined __STDC_VERSION_STDBIT_H__ +# if !GNULIB_defined_stdc_bit_floor_functions _GL_STDC_BIT_FLOOR_INLINE unsigned char stdc_bit_floor_uc (unsigned char n) @@ -1011,21 +1193,32 @@ stdc_bit_floor_ull (unsigned long long int n) return n ? 1ull << (stdc_bit_width_ull (n) - 1) : 0; } -# define stdc_bit_floor(n) \ - (_GL_STDBIT_TYPEOF_CAST \ - (n, \ - (sizeof (n) == 1 ? stdc_bit_floor_uc (n) \ - : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_floor_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_bit_floor_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_bit_floor_ul (n) \ - : stdc_bit_floor_ull (n)))) +# define GNULIB_defined_stdc_bit_floor_functions 1 +# endif +# endif + +# if !defined __STDC_VERSION_STDBIT_H__ \ + || (defined __sun && defined _SYS_STDBIT_H) +# undef stdc_bit_floor +# define stdc_bit_floor(n) \ + (_GL_STDBIT_TYPEOF_CAST \ + (n, \ + (sizeof (n) == 1 ? stdc_bit_floor_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_floor_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_floor_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_floor_ul (n) \ + : stdc_bit_floor_ull (n)))) +# endif #endif /* ISO C 23 § 7.18.16 Bit Ceiling */ -#if @GL_STDC_BIT_CEIL@ +#if @GNULIB_STDC_BIT_CEIL@ + +# if !defined __STDC_VERSION_STDBIT_H__ +# if !GNULIB_defined_stdc_bit_ceil_functions _GL_STDC_BIT_CEIL_INLINE unsigned char stdc_bit_ceil_uc (unsigned char n) @@ -1057,14 +1250,962 @@ stdc_bit_ceil_ull (unsigned long long int n) return n <= 1 ? 1 : 2ull << (stdc_bit_width_ull (n - 1) - 1); } -# define stdc_bit_ceil(n) \ - (_GL_STDBIT_TYPEOF_CAST \ - (n, \ - (sizeof (n) == 1 ? stdc_bit_ceil_uc (n) \ - : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_ceil_us (n) \ - : sizeof (n) == sizeof 0u ? stdc_bit_ceil_ui (n) \ - : sizeof (n) == sizeof 0ul ? stdc_bit_ceil_ul (n) \ - : stdc_bit_ceil_ull (n)))) +# define GNULIB_defined_stdc_bit_ceil_functions 1 +# endif +# endif + +# if !defined __STDC_VERSION_STDBIT_H__ \ + || (defined __sun && defined _SYS_STDBIT_H) +# undef stdc_bit_ceil +# define stdc_bit_ceil(n) \ + (_GL_STDBIT_TYPEOF_CAST \ + (n, \ + (sizeof (n) == 1 ? stdc_bit_ceil_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_ceil_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_ceil_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_ceil_ul (n) \ + : stdc_bit_ceil_ull (n)))) +# endif + +#endif + + +/* ISO C2y § 7.18.17 Rotate Left */ + +#if @GNULIB_STDC_ROTATE_LEFT@ + +# ifdef __has_builtin +# if __has_builtin (__builtin_stdc_rotate_left) +# define _gl_stdc_rotate_left __builtin_stdc_rotate_left +# define stdc_rotate_left __builtin_stdc_rotate_left +# endif +# endif + +# ifndef _gl_stdc_rotate_left +# define _gl_stdc_rotate_left(v, c) \ + (((v) << ((c) & (sizeof (v) * 8 - 1))) \ + | ((v) >> (-(c) & (sizeof (v) * 8 - 1)))) +# endif + +# if !GNULIB_defined_stdc_rotate_left_functions + +_GL_STDC_ROTATE_LEFT_INLINE unsigned char +stdc_rotate_left_uc (unsigned char v, unsigned int c) +{ + return _gl_stdc_rotate_left (v, c); +} + +_GL_STDC_ROTATE_LEFT_INLINE unsigned short int +stdc_rotate_left_us (unsigned short int v, unsigned int c) +{ + return _gl_stdc_rotate_left (v, c); +} + +_GL_STDC_ROTATE_LEFT_INLINE unsigned int +stdc_rotate_left_ui (unsigned int v, unsigned int c) +{ + return _gl_stdc_rotate_left (v, c); +} + +_GL_STDC_ROTATE_LEFT_INLINE unsigned long int +stdc_rotate_left_ul (unsigned long int v, unsigned int c) +{ + return _gl_stdc_rotate_left (v, c); +} + +_GL_STDC_ROTATE_LEFT_INLINE unsigned long long int +stdc_rotate_left_ull (unsigned long long int v, unsigned int c) +{ + return _gl_stdc_rotate_left (v, c); +} + +# define GNULIB_defined_stdc_rotate_left_functions 1 +# endif + +# ifndef stdc_rotate_left +# define stdc_rotate_left(v, c) \ + (_GL_STDBIT_TYPEOF_CAST \ + (v, \ + (sizeof (v) == 1 ? stdc_rotate_left_uc (v, c) \ + : sizeof (v) == sizeof (unsigned short int) ? stdc_rotate_left_us (v, c) \ + : sizeof (v) == sizeof 0u ? stdc_rotate_left_ui (v, c) \ + : sizeof (v) == sizeof 0ul ? stdc_rotate_left_ul (v, c) \ + : stdc_rotate_left_ull (v, c)))) +# endif + +#endif + + +/* ISO C2y § 7.18.18 Rotate Right */ + +#if @GNULIB_STDC_ROTATE_RIGHT@ + +# ifdef __has_builtin +# if __has_builtin (__builtin_stdc_rotate_right) +# define _gl_stdc_rotate_right __builtin_stdc_rotate_right +# define stdc_rotate_right __builtin_stdc_rotate_right +# endif +# endif + +# ifndef _gl_stdc_rotate_right +# define _gl_stdc_rotate_right(v, c) \ + (((v) >> ((c) & (sizeof (v) * 8 - 1))) \ + | ((v) << (-(c) & (sizeof (v) * 8 - 1)))) +# endif + +# if !GNULIB_defined_stdc_rotate_right_functions + +_GL_STDC_ROTATE_RIGHT_INLINE unsigned char +stdc_rotate_right_uc (unsigned char v, unsigned int c) +{ + return _gl_stdc_rotate_right (v, c); +} + +_GL_STDC_ROTATE_RIGHT_INLINE unsigned short int +stdc_rotate_right_us (unsigned short int v, unsigned int c) +{ + return _gl_stdc_rotate_right (v, c); +} + +_GL_STDC_ROTATE_RIGHT_INLINE unsigned int +stdc_rotate_right_ui (unsigned int v, unsigned int c) +{ + return _gl_stdc_rotate_right (v, c); +} + +_GL_STDC_ROTATE_RIGHT_INLINE unsigned long int +stdc_rotate_right_ul (unsigned long int v, unsigned int c) +{ + return _gl_stdc_rotate_right (v, c); +} + +_GL_STDC_ROTATE_RIGHT_INLINE unsigned long long int +stdc_rotate_right_ull (unsigned long long int v, unsigned int c) +{ + return _gl_stdc_rotate_right (v, c); +} + +# define GNULIB_defined_stdc_rotate_right_functions 1 +# endif + +# ifndef stdc_rotate_right +# define stdc_rotate_right(v, c) \ + (_GL_STDBIT_TYPEOF_CAST \ + (v, \ + (sizeof (v) == 1 ? stdc_rotate_right_uc (v, c) \ + : sizeof (v) == sizeof (unsigned short int) ? stdc_rotate_right_us (v, c) \ + : sizeof (v) == sizeof 0u ? stdc_rotate_right_ui (v, c) \ + : sizeof (v) == sizeof 0ul ? stdc_rotate_right_ul (v, c) \ + : stdc_rotate_right_ull (v, c)))) +# endif + +#endif + + +/* ISO C2y § 7.18.19 8-bit Memory Reversal */ + +#if @GNULIB_STDC_MEMREVERSE8@ + +# if !GNULIB_defined_stdc_memreverse8 + +_GL_STDC_MEMREVERSE8_INLINE void +stdc_memreverse8 (size_t n, unsigned char *ptr) +{ + if (n > 0) + { + /* There is no need to optimize the cases N == 1, N == 2, N == 4 + specially using __builtin_constant_p, because GCC does the possible + optimizations already, taking into account the alignment of PTR: + GCC >= 3 for N == 1, GCC >= 8 for N == 2, GCC >= 13 for N == 4. + (Whereas clang >= 3, <= 22 optimizes only the case N == 1.) */ + size_t i, j; + for (i = 0, j = n-1; i < j; i++, j--) + { + unsigned char xi = ptr[i]; + unsigned char xj = ptr[j]; + ptr[j] = xi; + ptr[i] = xj; + } + } +} + +# define GNULIB_defined_stdc_memreverse8 1 +# endif + +#endif + + +/* ISO C2y § 7.18.20 Exact-width 8-bit Memory Reversal */ + +#if @GNULIB_STDC_MEMREVERSE8U@ + +/* Note: ISO C defines these functions with argument and return type uintN_t. + We do it here with argument and return type uint_leastN_t. This is a + generalization that does not contradict ISO C: When uintN_t exists, it is + known that uint_leastN_t is the same type as uintN_t. */ + +# if !GNULIB_defined_stdc_memreverse8u_functions + +_GL_STDC_MEMREVERSE8U_INLINE uint_least8_t +stdc_memreverse8u8 (uint_least8_t value) +{ + return value; +} + +_GL_STDC_MEMREVERSE8U_INLINE uint_least16_t +stdc_memreverse8u16 (uint_least16_t value) +{ +# ifdef _GL_STDBIT_HAS_BUILTIN_BSWAP16 + return __builtin_bswap16 (value); +# else + _GL_STDBIT_UINT_FAST16 mask = 0xFFU; + return ( (value & (mask << (8 * 1))) >> (8 * 1) + | (value & (mask << (8 * 0))) << (8 * 1)); +# endif +} + +_GL_STDC_MEMREVERSE8U_INLINE uint_least32_t +stdc_memreverse8u32 (uint_least32_t value) +{ +# ifdef _GL_STDBIT_HAS_BUILTIN_BSWAP32 + return __builtin_bswap32 (value); +# else + _GL_STDBIT_UINT_FAST32 mask = 0xFFU; + return ( (value & (mask << (8 * 3))) >> (8 * 3) + | (value & (mask << (8 * 2))) >> (8 * 1) + | (value & (mask << (8 * 1))) << (8 * 1) + | (value & (mask << (8 * 0))) << (8 * 3)); +# endif +} + +_GL_STDC_MEMREVERSE8U_INLINE uint_least64_t +stdc_memreverse8u64 (uint_least64_t value) +{ +# ifdef _GL_STDBIT_HAS_BUILTIN_BSWAP64 + return __builtin_bswap64 (value); +# else + _GL_STDBIT_UINT_FAST64 mask = 0xFFU; + return ( (value & (mask << (8 * 7))) >> (8 * 7) + | (value & (mask << (8 * 6))) >> (8 * 5) + | (value & (mask << (8 * 5))) >> (8 * 3) + | (value & (mask << (8 * 4))) >> (8 * 1) + | (value & (mask << (8 * 3))) << (8 * 1) + | (value & (mask << (8 * 2))) << (8 * 3) + | (value & (mask << (8 * 1))) << (8 * 5) + | (value & (mask << (8 * 0))) << (8 * 7)); +# endif +} + +# define GNULIB_defined_stdc_memreverse8u_functions 1 +# endif + +#endif + + +/* ISO C2y § 7.18.21 Endian-Aware 8-Bit Load */ + +/* On hosts where _GL_STDBIT_OPTIMIZE_VIA_MEMCPY (see below) might be useful, + we need to avoid type-punning, because the compiler's aliasing + analysis would frequently produce incorrect code, and requiring the + option '-fno-strict-aliasing' is no viable solution. + So, this definition won't work: + + uint_least16_t + load16 (const unsigned char ptr[2]) + { + return *(const uint_least16_t *)ptr; + } + + Instead, the following definitions are candidates: + + // Trick from Lasse Collin: use memcpy and __builtin_assume_aligned. + uint_least16_t + load16_a (const unsigned char ptr[2]) + { + uint_least16_t value; + memcpy (&value, __builtin_assume_aligned (ptr, 2), 2); + return value; + } + + // Use __builtin_assume_aligned, without memcpy. + uint_least16_t + load16_b (const unsigned char ptr[2]) + { + const unsigned char *aptr = + (const unsigned char *) __builtin_assume_aligned (ptr, 2); + return (_GL_STDBIT_BIGENDIAN + ? ((uint_least16_t) aptr [0] << 8) | (uint_least16_t) aptr [1] + : (uint_least16_t) aptr [0] | ((uint_least16_t) aptr [1] << 8)); + } + + // Use memcpy and __assume. + uint_least16_t + load16_c (const unsigned char ptr[2]) + { + __assume (((uintptr_t) ptr & (2 - 1)) == 0); + uint_least16_t value; + memcpy (&value, __builtin_assume_aligned (ptr, 2), 2); + return value; + } + + // Use __assume, without memcpy. + uint_least16_t + load16_d (const unsigned char ptr[2]) + { + __assume (((uintptr_t) ptr & (2 - 1)) == 0); + return (_GL_STDBIT_BIGENDIAN + ? ((uint_least16_t) ptr [0] << 8) | (uint_least16_t) ptr [1] + : (uint_least16_t) ptr [0] | ((uint_least16_t) ptr [1] << 8)); + } + + // Use memcpy, without __builtin_assume_aligned or __assume. + uint_least16_t + load16_e (const unsigned char ptr[2]) + { + uint_least16_t value; + memcpy (&value, ptr, 2); + return value; + } + + // Use the code for the unaligned case. + uint_least16_t + load16_f (const unsigned char ptr[2]) + { + return (_GL_STDBIT_BIGENDIAN + ? ((uint_least16_t) ptr [0] << 8) | (uint_least16_t) ptr [1] + : (uint_least16_t) ptr [0] | ((uint_least16_t) ptr [1] << 8)); + } + + Portability constraints: + - __builtin_assume_aligned works only in GCC >= 4.7 and clang >= 4. + - __assume works only with MSVC (_MSC_VER >= 1200). + + Which variant produces the best code? + - memcpy is inlined only in gcc >= 3.4, g++ >= 4.9, clang >= 4. + - MSVC's __assume has no effect. + - With gcc 13: + On armelhf, arm64, i686, powerpc, powerpc64, powerpc64le, s390x, x86_64: + All of a,b,e,f are equally good. + On alpha, arm, hppa, mips, mips64, riscv64, sh4, sparc64: + Only a,b are good; f medium; e worst. + - With older gcc versions on x86_64: + gcc >= 10: All of a,b,e,f are equally good. + gcc < 10: Only a,e are good; b,f medium. + - With MSVC 14: Only c,e are good; d,f medium. + + So, we use the following heuristic for getting good code: + - gcc >= 4.7, g++ >= 4.9, clang >= 4, or any other platform + with __builtin_assume_aligned: Use variant a. + - MSVC: Use variant e. + - Otherwise: Use variant f. + */ +#if (defined __clang__ ? __clang_major__ >= 4 : \ + (defined __GNUC__ \ + && (defined __cplusplus \ + ? __GNUC__ + (__GNUC_MINOR__ >= 9) > 4 \ + : __GNUC__ + (__GNUC_MINOR__ >= 7) > 4))) +# define _GL_HAS_BUILTIN_ASSUME_ALIGNED 1 +#elif defined __has_builtin +# if __has_builtin (__builtin_assume_aligned) +# define _GL_HAS_BUILTIN_ASSUME_ALIGNED 1 +# endif +#endif +#ifdef _GL_HAS_BUILTIN_ASSUME_ALIGNED +# define _GL_STDBIT_ASSUME_ALIGNED(ptr, align) \ + __builtin_assume_aligned (ptr, align) +#else +# define _GL_STDBIT_ASSUME_ALIGNED(ptr, align) (ptr) +#endif + +#if defined _GL_HAS_BUILTIN_ASSUME_ALIGNED || defined _MSC_VER +/* The _GL_STDBIT_OPTIMIZE_VIA_MEMCPY trick works on typical hosts + where CHAR_BIT == 8 and uint_leastN_t types have minimal sizes. + Check to be safe and to document the assumption. */ +# define _GL_STDBIT_OPTIMIZE_VIA_MEMCPY \ + ((unsigned char) -1 == 0xFF \ + && sizeof (uint_least16_t) == 2 \ + && sizeof (uint_least32_t) == 4 \ + && sizeof (uint_least64_t) == 8) +#endif + +#ifndef _GL_STDBIT_OPTIMIZE_VIA_MEMCPY +# define _GL_STDBIT_OPTIMIZE_VIA_MEMCPY 0 +#endif + +#define _GL_STDBIT_BIGENDIAN (__STDC_ENDIAN_NATIVE__ == __STDC_ENDIAN_BIG__) + +#if @GNULIB_STDC_LOAD8@ + +# if !GNULIB_defined_stdc_load8_functions + +_GL_STDC_LOAD8_INLINE uint_least8_t +stdc_load8_beu8 (const unsigned char ptr[1]) +{ + return ptr[0]; +} + +_GL_STDC_LOAD8_INLINE uint_least16_t +stdc_load8_beu16 (const unsigned char ptr[2]) +{ + _GL_STDBIT_UINT_FAST16 v0 = ptr[0]; + _GL_STDBIT_UINT_FAST16 v1 = ptr[1]; + return (v0 << (8 * 1)) | (v1 << (8 * 0)); +} + +_GL_STDC_LOAD8_INLINE uint_least32_t +stdc_load8_beu32 (const unsigned char ptr[4]) +{ + _GL_STDBIT_UINT_FAST32 v0 = ptr[0]; + _GL_STDBIT_UINT_FAST32 v1 = ptr[1]; + _GL_STDBIT_UINT_FAST32 v2 = ptr[2]; + _GL_STDBIT_UINT_FAST32 v3 = ptr[3]; + return (v0 << (8 * 3)) | (v1 << (8 * 2)) | (v2 << (8 * 1)) | (v3 << (8 * 0)); +} + +_GL_STDC_LOAD8_INLINE uint_least64_t +stdc_load8_beu64 (const unsigned char ptr[8]) +{ + _GL_STDBIT_UINT_FAST64 v0 = ptr[0]; + _GL_STDBIT_UINT_FAST64 v1 = ptr[1]; + _GL_STDBIT_UINT_FAST64 v2 = ptr[2]; + _GL_STDBIT_UINT_FAST64 v3 = ptr[3]; + _GL_STDBIT_UINT_FAST64 v4 = ptr[4]; + _GL_STDBIT_UINT_FAST64 v5 = ptr[5]; + _GL_STDBIT_UINT_FAST64 v6 = ptr[6]; + _GL_STDBIT_UINT_FAST64 v7 = ptr[7]; + return ((v0 << (8 * 7)) | (v1 << (8 * 6)) + | (v2 << (8 * 5)) | (v3 << (8 * 4)) + | (v4 << (8 * 3)) | (v5 << (8 * 2)) + | (v6 << (8 * 1)) | (v7 << (8 * 0))); +} + +_GL_STDC_LOAD8_INLINE uint_least8_t +stdc_load8_leu8 (const unsigned char ptr[1]) +{ + return ptr[0]; +} + +_GL_STDC_LOAD8_INLINE uint_least16_t +stdc_load8_leu16 (const unsigned char ptr[2]) +{ + _GL_STDBIT_UINT_FAST16 v0 = ptr[0]; + _GL_STDBIT_UINT_FAST16 v1 = ptr[1]; + return (v0 << (8 * 0)) | (v1 << (8 * 1)); +} + +_GL_STDC_LOAD8_INLINE uint_least32_t +stdc_load8_leu32 (const unsigned char ptr[4]) +{ + _GL_STDBIT_UINT_FAST32 v0 = ptr[0]; + _GL_STDBIT_UINT_FAST32 v1 = ptr[1]; + _GL_STDBIT_UINT_FAST32 v2 = ptr[2]; + _GL_STDBIT_UINT_FAST32 v3 = ptr[3]; + return (v0 << (8 * 0)) | (v1 << (8 * 1)) | (v2 << (8 * 2)) | (v3 << (8 * 3)); +} + +_GL_STDC_LOAD8_INLINE uint_least64_t +stdc_load8_leu64 (const unsigned char ptr[8]) +{ + _GL_STDBIT_UINT_FAST64 v0 = ptr[0]; + _GL_STDBIT_UINT_FAST64 v1 = ptr[1]; + _GL_STDBIT_UINT_FAST64 v2 = ptr[2]; + _GL_STDBIT_UINT_FAST64 v3 = ptr[3]; + _GL_STDBIT_UINT_FAST64 v4 = ptr[4]; + _GL_STDBIT_UINT_FAST64 v5 = ptr[5]; + _GL_STDBIT_UINT_FAST64 v6 = ptr[6]; + _GL_STDBIT_UINT_FAST64 v7 = ptr[7]; + return ((v0 << (8 * 0)) | (v1 << (8 * 1)) + | (v2 << (8 * 2)) | (v3 << (8 * 3)) + | (v4 << (8 * 4)) | (v5 << (8 * 5)) + | (v6 << (8 * 6)) | (v7 << (8 * 7))); +} + +_GL_STDC_LOAD8_INLINE int_least8_t +stdc_load8_bes8 (const unsigned char ptr[1]) +{ + return stdc_load8_beu8 (ptr); +} + +_GL_STDC_LOAD8_INLINE int_least16_t +stdc_load8_bes16 (const unsigned char ptr[2]) +{ + return stdc_load8_beu16 (ptr); +} + +_GL_STDC_LOAD8_INLINE int_least32_t +stdc_load8_bes32 (const unsigned char ptr[4]) +{ + return stdc_load8_beu32 (ptr); +} + +_GL_STDC_LOAD8_INLINE int_least64_t +stdc_load8_bes64 (const unsigned char ptr[8]) +{ + return stdc_load8_beu64 (ptr); +} + +_GL_STDC_LOAD8_INLINE int_least8_t +stdc_load8_les8 (const unsigned char ptr[1]) +{ + return stdc_load8_leu8 (ptr); +} + +_GL_STDC_LOAD8_INLINE int_least16_t +stdc_load8_les16 (const unsigned char ptr[2]) +{ + return stdc_load8_leu16 (ptr); +} + +_GL_STDC_LOAD8_INLINE int_least32_t +stdc_load8_les32 (const unsigned char ptr[4]) +{ + return stdc_load8_leu32 (ptr); +} + +_GL_STDC_LOAD8_INLINE int_least64_t +stdc_load8_les64 (const unsigned char ptr[8]) +{ + return stdc_load8_leu64 (ptr); +} + +# define GNULIB_defined_stdc_load8_functions 1 +# endif + +#endif + +#if @GNULIB_STDC_LOAD8_ALIGNED@ + +# if !GNULIB_defined_stdc_load8_aligned_functions + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least8_t +stdc_load8_aligned_beu8 (const unsigned char ptr[1]) +{ + return stdc_load8_beu8 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least16_t +stdc_load8_aligned_beu16 (const unsigned char ptr[2]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + uint_least16_t value; + _GL_STDBIT_MEMCPY (&value, _GL_STDBIT_ASSUME_ALIGNED (ptr, 2), 2); + if (!_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u16 (value); + return value; + } + else + return stdc_load8_beu16 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least32_t +stdc_load8_aligned_beu32 (const unsigned char ptr[4]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + uint_least32_t value; + _GL_STDBIT_MEMCPY (&value, _GL_STDBIT_ASSUME_ALIGNED (ptr, 4), 4); + if (!_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u32 (value); + return value; + } + else + return stdc_load8_beu32 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least64_t +stdc_load8_aligned_beu64 (const unsigned char ptr[8]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + uint_least64_t value; + _GL_STDBIT_MEMCPY (&value, _GL_STDBIT_ASSUME_ALIGNED (ptr, 8), 8); + if (!_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u64 (value); + return value; + } + else + return stdc_load8_beu64 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least8_t +stdc_load8_aligned_leu8 (const unsigned char ptr[1]) +{ + return stdc_load8_leu8 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least16_t +stdc_load8_aligned_leu16 (const unsigned char ptr[2]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + uint_least16_t value; + _GL_STDBIT_MEMCPY (&value, _GL_STDBIT_ASSUME_ALIGNED (ptr, 2), 2); + if (_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u16 (value); + return value; + } + else + return stdc_load8_leu16 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least32_t +stdc_load8_aligned_leu32 (const unsigned char ptr[4]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + uint_least32_t value; + _GL_STDBIT_MEMCPY (&value, _GL_STDBIT_ASSUME_ALIGNED (ptr, 4), 4); + if (_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u32 (value); + return value; + } + else + return stdc_load8_leu32 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE uint_least64_t +stdc_load8_aligned_leu64 (const unsigned char ptr[8]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + uint_least64_t value; + _GL_STDBIT_MEMCPY (&value, _GL_STDBIT_ASSUME_ALIGNED (ptr, 8), 8); + if (_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u64 (value); + return value; + } + else + return stdc_load8_leu64 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least8_t +stdc_load8_aligned_bes8 (const unsigned char ptr[1]) +{ + return stdc_load8_aligned_beu8 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least16_t +stdc_load8_aligned_bes16 (const unsigned char ptr[2]) +{ + return stdc_load8_aligned_beu16 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least32_t +stdc_load8_aligned_bes32 (const unsigned char ptr[4]) +{ + return stdc_load8_aligned_beu32 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least64_t +stdc_load8_aligned_bes64 (const unsigned char ptr[8]) +{ + return stdc_load8_aligned_beu64 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least8_t +stdc_load8_aligned_les8 (const unsigned char ptr[1]) +{ + return stdc_load8_aligned_leu8 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least16_t +stdc_load8_aligned_les16 (const unsigned char ptr[2]) +{ + return stdc_load8_aligned_leu16 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least32_t +stdc_load8_aligned_les32 (const unsigned char ptr[4]) +{ + return stdc_load8_aligned_leu32 (ptr); +} + +_GL_STDC_LOAD8_ALIGNED_INLINE int_least64_t +stdc_load8_aligned_les64 (const unsigned char ptr[8]) +{ + return stdc_load8_aligned_leu64 (ptr); +} + +# define GNULIB_defined_stdc_load8_aligned_functions 1 +# endif + +#endif + + +/* ISO C2y § 7.18.22 Endian-Aware 8-Bit Store */ + +#if @GNULIB_STDC_STORE8@ + +# if !GNULIB_defined_stdc_store8_functions + +_GL_STDC_STORE8_INLINE void +stdc_store8_beu8 (uint_least8_t value, unsigned char ptr[1]) +{ + ptr[0] = value; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_beu16 (uint_least16_t value, unsigned char ptr[2]) +{ + ptr[0] = (value >> 8) & 0xFFU; + ptr[1] = value & 0xFFU; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_beu32 (uint_least32_t value, unsigned char ptr[4]) +{ + ptr[0] = (value >> 24) & 0xFFU; + ptr[1] = (value >> 16) & 0xFFU; + ptr[2] = (value >> 8) & 0xFFU; + ptr[3] = value & 0xFFU; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_beu64 (uint_least64_t value, unsigned char ptr[8]) +{ + ptr[0] = (value >> 56) & 0xFFU; + ptr[1] = (value >> 48) & 0xFFU; + ptr[2] = (value >> 40) & 0xFFU; + ptr[3] = (value >> 32) & 0xFFU; + ptr[4] = (value >> 24) & 0xFFU; + ptr[5] = (value >> 16) & 0xFFU; + ptr[6] = (value >> 8) & 0xFFU; + ptr[7] = value & 0xFFU; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_leu8 (uint_least8_t value, unsigned char ptr[1]) +{ + ptr[0] = value; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_leu16 (uint_least16_t value, unsigned char ptr[2]) +{ + ptr[0] = value & 0xFFU; + ptr[1] = (value >> 8) & 0xFFU; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_leu32 (uint_least32_t value, unsigned char ptr[4]) +{ + ptr[0] = value & 0xFFU; + ptr[1] = (value >> 8) & 0xFFU; + ptr[2] = (value >> 16) & 0xFFU; + ptr[3] = (value >> 24) & 0xFFU; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_leu64 (uint_least64_t value, unsigned char ptr[8]) +{ + ptr[0] = value & 0xFFU; + ptr[1] = (value >> 8) & 0xFFU; + ptr[2] = (value >> 16) & 0xFFU; + ptr[3] = (value >> 24) & 0xFFU; + ptr[4] = (value >> 32) & 0xFFU; + ptr[5] = (value >> 40) & 0xFFU; + ptr[6] = (value >> 48) & 0xFFU; + ptr[7] = (value >> 56) & 0xFFU; +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_bes8 (int_least8_t value, unsigned char ptr[1]) +{ + stdc_store8_beu8 (value, ptr); +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_bes16 (int_least16_t value, unsigned char ptr[2]) +{ + stdc_store8_beu16 (value, ptr); +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_bes32 (int_least32_t value, unsigned char ptr[4]) +{ + stdc_store8_beu32 (value, ptr); +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_bes64 (int_least64_t value, unsigned char ptr[8]) +{ + stdc_store8_beu64 (value, ptr); +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_les8 (int_least8_t value, unsigned char ptr[1]) +{ + stdc_store8_leu8 (value, ptr); +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_les16 (int_least16_t value, unsigned char ptr[2]) +{ + stdc_store8_leu16 (value, ptr); +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_les32 (int_least32_t value, unsigned char ptr[4]) +{ + stdc_store8_leu32 (value, ptr); +} + +_GL_STDC_STORE8_INLINE void +stdc_store8_les64 (int_least64_t value, unsigned char ptr[8]) +{ + stdc_store8_leu64 (value, ptr); +} + +# define GNULIB_defined_stdc_store8_functions 1 +# endif + +#endif + +#if @GNULIB_STDC_STORE8_ALIGNED@ + +# if !GNULIB_defined_stdc_store8_aligned_functions + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_beu8 (uint_least8_t value, unsigned char ptr[1]) +{ + stdc_store8_beu8 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_beu16 (uint_least16_t value, unsigned char ptr[2]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + if (!_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u16 (value); + _GL_STDBIT_MEMCPY (_GL_STDBIT_ASSUME_ALIGNED (ptr, 2), &value, 2); + } + else + stdc_store8_beu16 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_beu32 (uint_least32_t value, unsigned char ptr[4]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + if (!_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u32 (value); + _GL_STDBIT_MEMCPY (_GL_STDBIT_ASSUME_ALIGNED (ptr, 4), &value, 4); + } + else + stdc_store8_beu32 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_beu64 (uint_least64_t value, unsigned char ptr[8]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + if (!_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u64 (value); + _GL_STDBIT_MEMCPY (_GL_STDBIT_ASSUME_ALIGNED (ptr, 8), &value, 8); + } + else + stdc_store8_beu64 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_leu8 (uint_least8_t value, unsigned char ptr[1]) +{ + stdc_store8_leu8 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_leu16 (uint_least16_t value, unsigned char ptr[2]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + if (_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u16 (value); + _GL_STDBIT_MEMCPY (_GL_STDBIT_ASSUME_ALIGNED (ptr, 2), &value, 2); + } + else + stdc_store8_leu16 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_leu32 (uint_least32_t value, unsigned char ptr[4]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + if (_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u32 (value); + _GL_STDBIT_MEMCPY (_GL_STDBIT_ASSUME_ALIGNED (ptr, 4), &value, 4); + } + else + stdc_store8_leu32 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_leu64 (uint_least64_t value, unsigned char ptr[8]) +{ + if (_GL_STDBIT_OPTIMIZE_VIA_MEMCPY) + { + if (_GL_STDBIT_BIGENDIAN) + value = stdc_memreverse8u64 (value); + _GL_STDBIT_MEMCPY (_GL_STDBIT_ASSUME_ALIGNED (ptr, 8), &value, 8); + } + else + stdc_store8_leu64 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_bes8 (int_least8_t value, unsigned char ptr[1]) +{ + stdc_store8_aligned_beu8 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_bes16 (int_least16_t value, unsigned char ptr[2]) +{ + stdc_store8_aligned_beu16 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_bes32 (int_least32_t value, unsigned char ptr[4]) +{ + stdc_store8_aligned_beu32 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_bes64 (int_least64_t value, unsigned char ptr[8]) +{ + stdc_store8_aligned_beu64 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_les8 (int_least8_t value, unsigned char ptr[1]) +{ + stdc_store8_aligned_leu8 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_les16 (int_least16_t value, unsigned char ptr[2]) +{ + stdc_store8_aligned_leu16 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_les32 (int_least32_t value, unsigned char ptr[4]) +{ + stdc_store8_aligned_leu32 (value, ptr); +} + +_GL_STDC_STORE8_ALIGNED_INLINE void +stdc_store8_aligned_les64 (int_least64_t value, unsigned char ptr[8]) +{ + stdc_store8_aligned_leu64 (value, ptr); +} + +# define GNULIB_defined_stdc_store8_aligned_functions 1 +# endif #endif @@ -1075,4 +2216,10 @@ stdc_bit_ceil_ull (unsigned long long int n) _GL_INLINE_HEADER_END -#endif /* STDBIT_H */ +/* ISO C 23 § 7.18.1 General */ +#ifndef __STDC_VERSION_STDBIT_H__ +# define __STDC_VERSION_STDBIT_H__ 202311L +#endif + +#endif /* _@GUARD_PREFIX@_STDBIT_H */ +#endif /* _@GUARD_PREFIX@_STDBIT_H */ diff --git a/lib/stdc_count_ones.c b/lib/stdc_count_ones.c index bcb4d6c2965..1a75445c827 100644 --- a/lib/stdc_count_ones.c +++ b/lib/stdc_count_ones.c @@ -19,5 +19,5 @@ #include #if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) -signed char __gl_stdbit_popcount_support; +signed char _gl_stdbit_popcount_support; #endif diff --git a/lib/stdc_memreverse8u.c b/lib/stdc_memreverse8u.c new file mode 100644 index 00000000000..ec83306dfff --- /dev/null +++ b/lib/stdc_memreverse8u.c @@ -0,0 +1,19 @@ +/* stdc_memreverse8u* functions. + Copyright (C) 2026 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#define _GL_STDC_MEMREVERSE8U_INLINE _GL_EXTERN_INLINE +#include +#include diff --git a/lib/stdcountof.in.h b/lib/stdcountof.in.h new file mode 100644 index 00000000000..c2de1adce8b --- /dev/null +++ b/lib/stdcountof.in.h @@ -0,0 +1,124 @@ +/* Copyright 2025-2026 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2025. */ + +#ifndef _@GUARD_PREFIX@_STDCOUNTOF_H + +#if __GNUC__ >= 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +/* The include_next requires a split double-inclusion guard. */ +#if (defined __cplusplus ? @CXX_HAVE_STDCOUNTOF_H@ : @HAVE_STDCOUNTOF_H@) +# @INCLUDE_NEXT@ @NEXT_STDCOUNTOF_H@ +#else + +#ifndef _@GUARD_PREFIX@_STDCOUNTOF_H +#define _@GUARD_PREFIX@_STDCOUNTOF_H + +/* This file uses _GL_GNUC_PREREQ. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + +/* Get size_t. */ +#include + +/* Returns the number of elements of the array A, as a value of type size_t. + + Example declarations of arrays: + extern int a[]; + extern int a[10]; + static int a[10][20]; + void func () { int a[10]; ... } + It works for arrays that are declared outside functions and for local + variables of array type. It does *not* work for function parameters + of array type, because they are actually parameters of pointer type. + In this case, i.e. if A is a pointer, e.g. in + void func (int a[10]) { ... } + this macro attempts to produce an error. + */ +#define countof(...) \ + ((size_t) (sizeof (__VA_ARGS__) / sizeof (__VA_ARGS__)[0] \ + + 0 * _gl_verify_is_array (__VA_ARGS__))) + +/* Attempts to verify that A is an array. */ +#if defined __cplusplus +/* Borrowed from verify.h. */ +# if !GNULIB_defined_struct__gl_verify_type +template + struct _gl_verify_type { + unsigned int _gl_verify_error_if_negative: w; + }; +# define GNULIB_defined_struct__gl_verify_type 1 +# endif +# if __cplusplus >= 201103L +# if 1 + /* Use decltype. */ +/* Default case. */ +template + struct _gl_array_type_test { static const int is_array = -1; }; +/* Unbounded arrays. */ +template + struct _gl_array_type_test { static const int is_array = 1; }; +/* Bounded arrays. */ +template + struct _gl_array_type_test { static const int is_array = 1; }; +/* String literals. */ +template + struct _gl_array_type_test { static const int is_array = 1; }; +# define _gl_verify_is_array(...) \ + sizeof (_gl_verify_type<_gl_array_type_test::is_array>) +# else + /* Use template argument deduction. + Use sizeof to get a constant expression from an unknown type. + Note: This approach does not work for countof (((int[]) { a, b, c })). */ +/* Default case. */ +template + struct _gl_array_type_test { double large; }; +/* Unbounded arrays. */ +template + struct _gl_array_type_test { char small; }; +/* Bounded arrays. */ +template + struct _gl_array_type_test { char small; }; +/* The T& parameter is essential here: it prevents decay (array-to-pointer + conversion). */ +template _gl_array_type_test _gl_array_type_test_helper(T&); +# define _gl_verify_is_array(...) \ + sizeof (_gl_verify_type<(sizeof (_gl_array_type_test_helper(__VA_ARGS__)) < sizeof (double) ? 1 : -1)>) +# endif +# else +/* The compiler does not have the necessary functionality. */ +# define _gl_verify_is_array(...) 0 +# endif +#else +/* In C, we can use typeof and __builtin_types_compatible_p. */ +/* Work around clang bug . */ +# if (_GL_GNUC_PREREQ (3, 1) && ! defined __clang__ /* || defined __clang__ */) \ + && !(defined __STRICT_ANSI__ && __STDC_VERSION__ < 202311L) /* but not with -std=c99 or -std=c11 */ +# define _gl_verify_is_array(...) \ + sizeof (struct { unsigned int _gl_verify_error_if_negative : __builtin_types_compatible_p (typeof (__VA_ARGS__), typeof (&*(__VA_ARGS__))) ? -1 : 1; }) +# else +/* The compiler does not have the necessary built-ins. */ +# define _gl_verify_is_array(...) 0 +# endif +#endif + +#endif /* _@GUARD_PREFIX@_STDCOUNTOF_H */ +#endif +#endif /* _@GUARD_PREFIX@_STDCOUNTOF_H */ diff --git a/lib/stdio-consolesafe.c b/lib/stdio-consolesafe.c index f634de13ef4..3d913d555e8 100644 --- a/lib/stdio-consolesafe.c +++ b/lib/stdio-consolesafe.c @@ -56,7 +56,7 @@ workaround_fwrite0 (char *s, size_t n, FILE *fp) } size_t -gl_consolesafe_fwrite (const void *ptr, size_t size, size_t nmemb, FILE *fp) +_gl_consolesafe_fwrite (const void *ptr, size_t size, size_t nmemb, FILE *fp) { size_t nbytes; if (ckd_mul (&nbytes, size, nmemb) || nbytes == 0) @@ -133,7 +133,7 @@ local_vasprintf (char **resultp, const char *format, va_list args) __mingw_*printf. */ int -gl_consolesafe_fprintf (FILE *restrict fp, const char *restrict format, ...) +_gl_consolesafe_fprintf (FILE *restrict fp, const char *restrict format, ...) { va_list args; va_start (args, format); @@ -151,7 +151,7 @@ gl_consolesafe_fprintf (FILE *restrict fp, const char *restrict format, ...) } int -gl_consolesafe_printf (const char *restrict format, ...) +_gl_consolesafe_printf (const char *restrict format, ...) { va_list args; va_start (args, format); @@ -169,8 +169,8 @@ gl_consolesafe_printf (const char *restrict format, ...) } int -gl_consolesafe_vfprintf (FILE *restrict fp, - const char *restrict format, va_list args) +_gl_consolesafe_vfprintf (FILE *restrict fp, + const char *restrict format, va_list args) { char *tmpstring; int result = vasprintf (&tmpstring, format, args); @@ -185,7 +185,7 @@ gl_consolesafe_vfprintf (FILE *restrict fp, } int -gl_consolesafe_vprintf (const char *restrict format, va_list args) +_gl_consolesafe_vprintf (const char *restrict format, va_list args) { char *tmpstring; int result = vasprintf (&tmpstring, format, args); diff --git a/lib/stdio.in.h b/lib/stdio.in.h index 33b0b8e48a5..107ebd6df13 100644 --- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -122,6 +122,20 @@ # endif #endif +/* _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that + can be freed via 'free'; it can be used only after declaring 'free'. */ +/* Applies to: functions. Cannot be used on inline functions. */ +#ifndef _GL_ATTRIBUTE_DEALLOC_FREE +# if defined __cplusplus && defined __GNUC__ && !defined __clang__ +/* Work around GCC bug */ +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC ((void (*) (void *)) free, 1) +# else +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC (free, 1) +# endif +#endif + /* The __attribute__ feature is available in gcc versions 2.5 and later. The __-protected variants of the attributes 'format' and 'printf' are accepted by gcc versions 2.6.4 (effectively 2.7) and later. @@ -231,6 +245,50 @@ /* The definition of _GL_WARN_ON_USE is copied here. */ +/* Make _GL_ATTRIBUTE_DEALLOC_FREE work, even though may not have + been included yet. */ +#if @GNULIB_FREE_POSIX@ +# if (@REPLACE_FREE@ && !defined free \ + && !(defined __cplusplus && defined GNULIB_NAMESPACE)) +/* We can't do '#define free rpl_free' here. */ +# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) +_GL_EXTERN_C void rpl_free (void *) _GL_ATTRIBUTE_NOTHROW; +# else +_GL_EXTERN_C void rpl_free (void *); +# endif +# undef _GL_ATTRIBUTE_DEALLOC_FREE +# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (rpl_free, 1) +# else +# if defined _MSC_VER && !defined free +_GL_EXTERN_C +# if defined _DLL + __declspec (dllimport) +# endif + void __cdecl free (void *); +# else +# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) +_GL_EXTERN_C void free (void *) _GL_ATTRIBUTE_NOTHROW; +# else +_GL_EXTERN_C void free (void *); +# endif +# endif +# endif +#else +# if defined _MSC_VER && !defined free +_GL_EXTERN_C +# if defined _DLL + __declspec (dllimport) +# endif + void __cdecl free (void *); +# else +# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) +_GL_EXTERN_C void free (void *) _GL_ATTRIBUTE_NOTHROW; +# else +_GL_EXTERN_C void free (void *); +# endif +# endif +#endif + /* Macros for stringification. */ #define _GL_STDIO_STRINGIZE(token) #token #define _GL_STDIO_MACROEXPAND_AND_STRINGIZE(token) _GL_STDIO_STRINGIZE(token) @@ -273,24 +331,24 @@ #if (defined _WIN32 && !defined __CYGWIN__) && !defined _UCRT /* Workarounds against msvcrt bugs. */ -_GL_FUNCDECL_SYS (gl_consolesafe_fwrite, size_t, +_GL_FUNCDECL_SYS (_gl_consolesafe_fwrite, size_t, (const void *ptr, size_t size, size_t nmemb, FILE *fp), _GL_ARG_NONNULL ((1, 4))); # if defined __MINGW32__ -_GL_FUNCDECL_SYS (gl_consolesafe_fprintf, int, +_GL_FUNCDECL_SYS (_gl_consolesafe_fprintf, int, (FILE *restrict fp, const char *restrict format, ...), _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3) _GL_ARG_NONNULL ((1, 2))); -_GL_FUNCDECL_SYS (gl_consolesafe_printf, int, +_GL_FUNCDECL_SYS (_gl_consolesafe_printf, int, (const char *restrict format, ...), _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2) _GL_ARG_NONNULL ((1))); -_GL_FUNCDECL_SYS (gl_consolesafe_vfprintf, int, +_GL_FUNCDECL_SYS (_gl_consolesafe_vfprintf, int, (FILE *restrict fp, const char *restrict format, va_list args), _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0) _GL_ARG_NONNULL ((1, 2))); -_GL_FUNCDECL_SYS (gl_consolesafe_vprintf, int, +_GL_FUNCDECL_SYS (_gl_consolesafe_vprintf, int, (const char *restrict format, va_list args), _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0) _GL_ARG_NONNULL ((1))); @@ -633,7 +691,7 @@ _GL_CXXALIASWARN (fprintf); #elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef fprintf -# define fprintf gl_consolesafe_fprintf +# define fprintf _gl_consolesafe_fprintf # endif #endif #if !@GNULIB_FPRINTF_POSIX@ && defined GNULIB_POSIXCHECK @@ -985,7 +1043,7 @@ _GL_CXXALIASWARN (fwrite); #elif (defined _WIN32 && !defined __CYGWIN__) && !defined _UCRT # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef fwrite -# define fwrite gl_consolesafe_fwrite +# define fwrite _gl_consolesafe_fwrite # endif #endif @@ -1371,7 +1429,7 @@ _GL_CXXALIASWARN (printf); #elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef printf -# define printf gl_consolesafe_printf +# define printf _gl_consolesafe_printf # endif #endif #if !@GNULIB_PRINTF_POSIX@ && defined GNULIB_POSIXCHECK @@ -1808,6 +1866,26 @@ _GL_CXXALIAS_SYS (vasprintf, int, _GL_CXXALIASWARN (vasprintf); #endif +#if @GNULIB_VAPRINTF@ +/* Write formatted output to a string dynamically allocated with malloc(). + Return the resulting string. Upon memory allocation error, or some + other error, return NULL, with errno set. */ +_GL_FUNCDECL_SYS (aprintf, char *, + (const char *format, ...), + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2) + _GL_ARG_NONNULL ((1)) + _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); +_GL_CXXALIAS_SYS (aprintf, char *, + (const char *format, ...)); +_GL_FUNCDECL_SYS (vaprintf, char *, + (const char *format, va_list args), + _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0) + _GL_ARG_NONNULL ((1)) + _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); +_GL_CXXALIAS_SYS (vaprintf, char *, + (const char *format, va_list args)); +#endif + #if @GNULIB_VDZPRINTF@ /* Prints formatted output to file descriptor FD. Returns the number of bytes written to the file descriptor. Upon @@ -1918,7 +1996,7 @@ _GL_CXXALIASWARN (vfprintf); #elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef vfprintf -# define vfprintf gl_consolesafe_vfprintf +# define vfprintf _gl_consolesafe_vfprintf # endif #endif #if !@GNULIB_VFPRINTF_POSIX@ && defined GNULIB_POSIXCHECK @@ -2001,7 +2079,7 @@ _GL_CXXALIASWARN (vprintf); #elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef vprintf -# define vprintf gl_consolesafe_vprintf +# define vprintf _gl_consolesafe_vprintf # endif #endif #if !@GNULIB_VPRINTF_POSIX@ && defined GNULIB_POSIXCHECK diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index 95237f2a5cb..3c2004611fe 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -757,7 +757,7 @@ _GL_WARN_ON_USE (malloc, "malloc is not POSIX compliant everywhere - " #if @REPLACE_MB_CUR_MAX@ # if !GNULIB_defined_MB_CUR_MAX _GL_STDLIB_INLINE size_t -gl_MB_CUR_MAX (void) +_gl_MB_CUR_MAX (void) { # if 0 < @REPLACE_MB_CUR_MAX@ return @REPLACE_MB_CUR_MAX@; @@ -768,7 +768,7 @@ gl_MB_CUR_MAX (void) # endif } # undef MB_CUR_MAX -# define MB_CUR_MAX gl_MB_CUR_MAX () +# define MB_CUR_MAX _gl_MB_CUR_MAX () # define GNULIB_defined_MB_CUR_MAX 1 # endif #endif @@ -1458,7 +1458,7 @@ _GL_WARN_ON_USE (setstate_r, "setstate_r is unportable - " #if @GNULIB_REALLOC_POSIX@ # if @REPLACE_REALLOC_FOR_REALLOC_POSIX@ -# if @REPLACE_REALLOC_FOR_REALLOC_POSIX@ == 2 +# if @REPLACE_REALLOC_FOR_REALLOC_POSIX@ == 2 && !_GL_INLINE_RPL_REALLOC # define _GL_INLINE_RPL_REALLOC 1 # ifdef __cplusplus extern "C" { diff --git a/lib/strftime.c b/lib/strftime.c index f7cf65d5413..5a3544674e2 100644 --- a/lib/strftime.c +++ b/lib/strftime.c @@ -109,6 +109,7 @@ #include #include #include +#include #include #include #include @@ -1882,7 +1883,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) #endif } - bufp = buf + sizeof (buf) / sizeof (buf[0]); + bufp = buf + countof (buf); if (negative_number) u_number_value = - u_number_value; @@ -1913,7 +1914,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) CHAR_T sign_char = (negative_number ? L_('-') : always_output_a_sign ? L_('+') : 0); - int number_bytes = buf + sizeof buf / sizeof buf[0] - bufp; + int number_bytes = buf + countof (buf) - bufp; int number_digits = number_bytes; #if SUPPORT_NON_GREG_CALENDARS_IN_STRFTIME if (digits_base >= 0x100) @@ -2098,7 +2099,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize) /* Generate string value for T using time_t arithmetic; this works even if sizeof (long) < sizeof (time_t). */ - bufp = buf + sizeof (buf) / sizeof (buf[0]); + bufp = buf + countof (buf); negative_number = t < 0; do diff --git a/lib/string.in.h b/lib/string.in.h index 0cd83c7844f..1c46c65f60d 100644 --- a/lib/string.in.h +++ b/lib/string.in.h @@ -420,16 +420,19 @@ _GL_WARN_ON_USE_CXX (memchr, /* Are S1 and S2, of size N, bytewise equal? */ #if @GNULIB_MEMEQ@ && !@HAVE_DECL_MEMEQ@ -# ifdef __cplusplus +# if !GNULIB_defined_memeq +# ifdef __cplusplus extern "C" { -# endif +# endif _GL_MEMEQ_INLINE bool memeq (void const *__s1, void const *__s2, size_t __n) { return !memcmp (__s1, __s2, __n); } -# ifdef __cplusplus +# ifdef __cplusplus } +# endif +# define GNULIB_defined_memeq 1 # endif #endif @@ -805,16 +808,19 @@ _GL_CXXALIASWARN (strdup); /* Are strings S1 and S2 equal? */ #if @GNULIB_STREQ@ && !@HAVE_DECL_STREQ@ -# ifdef __cplusplus +# if !GNULIB_defined_streq +# ifdef __cplusplus extern "C" { -# endif +# endif _GL_STREQ_INLINE bool streq (char const *__s1, char const *__s2) { return !strcmp (__s1, __s2); } -# ifdef __cplusplus +# ifdef __cplusplus } +# endif +# define GNULIB_defined_streq 1 # endif #endif @@ -1041,7 +1047,7 @@ _GL_WARN_ON_USE_CXX (strrchr, If *STRINGP was already NULL, nothing happens. Return the old value of *STRINGP. - This is a variant of strtok() that is multithread-safe and supports + This is a variant of strtok() that is thread-safe and supports empty fields. Caveat: It modifies the original string. @@ -1179,7 +1185,7 @@ _GL_WARN_ON_USE (strcasestr, "strcasestr does work correctly on character " x = strtok_r(NULL, "=", &sp); // x = NULL // s = "abc\0-def\0" - This is a variant of strtok() that is multithread-safe. + This is a variant of strtok() that is thread-safe. For the POSIX documentation for this function, see: https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok.html @@ -1245,13 +1251,14 @@ _GL_WARN_ON_USE (strtok_r, "strtok_r is unportable - " string + strlen (string) or to strchr (string, '\0'). */ -# ifdef __cplusplus +# if !GNULIB_defined_strnul +# ifdef __cplusplus extern "C" { -# endif -_GL_STRNUL_INLINE const char *gl_strnul (const char *string) +# endif +_GL_STRNUL_INLINE const char *_gl_strnul (const char *string) _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1)); -_GL_STRNUL_INLINE const char *gl_strnul (const char *string) +_GL_STRNUL_INLINE const char *_gl_strnul (const char *string) { /* In gcc >= 7 or clang >= 4, we could use the expression strchr (string, '\0') @@ -1261,22 +1268,24 @@ _GL_STRNUL_INLINE const char *gl_strnul (const char *string) option '-fno-builtin' is in use. */ return string + strlen (string); } -# ifdef __cplusplus +# ifdef __cplusplus } -# endif -# ifdef __cplusplus +# endif +# ifdef __cplusplus +extern "C++" { /* needed for AIX and Solaris 10 */ _GL_BEGIN_NAMESPACE template T strnul (T); template <> inline const char *strnul (const char *s) -{ return gl_strnul (s); } +{ return _gl_strnul (s); } template <> inline char *strnul< char *> ( char *s) -{ return const_cast(gl_strnul (s)); } +{ return const_cast(_gl_strnul (s)); } _GL_END_NAMESPACE -# else -# if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 9) > 4 && !defined __cplusplus) \ - || (defined __clang__ && __clang_major__ >= 3) \ - || (defined __SUNPRO_C && __SUNPRO_C >= 0x5150) \ - || (__STDC_VERSION__ >= 201112L && !defined __GNUC__) +} +# else +# if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 9) > 4 && !defined __cplusplus) \ + || (defined __clang__ && __clang_major__ >= 3) \ + || (defined __SUNPRO_C && __SUNPRO_C >= 0x5150) \ + || (__STDC_VERSION__ >= 201112L && !defined __GNUC__) /* The compiler supports _Generic from ISO C11. */ /* Since in C (but not in C++!), any function that accepts a '[const] char *' also accepts a '[const] void *' as argument, we make sure that the function- @@ -1284,14 +1293,16 @@ _GL_END_NAMESPACE char *, void * -> void * const char *, const void * -> const void * This mapping is done through the conditional expression. */ -# define strnul(s) \ - _Generic (1 ? (s) : (void *) 99, \ - void * : (char *) gl_strnul (s), \ - const void * : gl_strnul (s)) -# else -# define strnul(s) \ - ((char *) gl_strnul (s)) +# define strnul(s) \ + _Generic (1 ? (s) : (void *) 99, \ + void * : (char *) _gl_strnul (s), \ + const void * : _gl_strnul (s)) +# else +# define strnul(s) \ + ((char *) _gl_strnul (s)) +# endif # endif +# define GNULIB_defined_strnul 1 # endif #endif @@ -1400,7 +1411,7 @@ _GL_EXTERN_C char * mbsstr (const char *haystack, const char *needle) /* Don't silently convert a 'const char *' to a 'char *'. Programmers want compiler warnings for 'const' related mistakes. */ # ifdef __cplusplus -extern "C++" { /* needed for AIX */ +extern "C++" { /* needed for AIX and Solaris 10 */ template T * mbsstr_template (T* haystack, const char *needle); template <> @@ -1468,7 +1479,7 @@ _GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix) /* Don't silently convert a 'const char *' to a 'char *'. Programmers want compiler warnings for 'const' related mistakes. */ # ifdef __cplusplus -extern "C++" { /* needed for AIX */ +extern "C++" { /* needed for AIX and Solaris 10 */ template T * mbspcasecmp_template (T* string, const char *prefix); template <> @@ -1506,7 +1517,7 @@ _GL_EXTERN_C char * mbscasestr (const char *haystack, const char *needle) /* Don't silently convert a 'const char *' to a 'char *'. Programmers want compiler warnings for 'const' related mistakes. */ # ifdef __cplusplus -extern "C++" { /* needed for AIX */ +extern "C++" { /* needed for AIX and Solaris 10 */ template T * mbscasestr_template (T* haystack, const char *needle); template <> @@ -1655,7 +1666,7 @@ _GL_WARN_ON_USE (strerror, "strerror is unportable - " "use gnulib module strerror to guarantee non-NULL result"); #endif -/* Map any int, typically from errno, into an error message. Multithread-safe. +/* Map any int, typically from errno, into an error message. Thread-safe. Uses the POSIX declaration, not the glibc declaration. */ #if @GNULIB_STRERROR_R@ # if @REPLACE_STRERROR_R@ @@ -1711,7 +1722,7 @@ _GL_WARN_ON_USE (strerror_l, "strerror_l is unportable - " # endif #endif -/* Map any int, typically from errno, into an error message. Multithread-safe, +/* Map any int, typically from errno, into an error message. Thread-safe, with locale_t argument. Not portable! Only provided by gnulib. */ #if @GNULIB_STRERROR_L@ diff --git a/lib/strnul.c b/lib/strnul.c index a567f0722ec..e825542e550 100644 --- a/lib/strnul.c +++ b/lib/strnul.c @@ -1,4 +1,4 @@ -/* gl_strnul function. +/* _gl_strnul function. Copyright (C) 2025-2026 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify diff --git a/lib/tempname.c b/lib/tempname.c index 1edba07a02c..6b166253e82 100644 --- a/lib/tempname.c +++ b/lib/tempname.c @@ -111,9 +111,11 @@ random_bits (random_value *r, random_value s) __clock_gettime64 (CLOCK_REALTIME, &tv); v = mix_random_values (v, tv.tv_sec); v = mix_random_values (v, tv.tv_nsec); +#else + v = mix_random_values (v, clock ()); #endif - *r = mix_random_values (v, clock ()); + *r = v; return false; } diff --git a/lib/time_r.c b/lib/time_r.c index dfc427f6679..9da4ffa9297 100644 --- a/lib/time_r.c +++ b/lib/time_r.c @@ -22,7 +22,7 @@ #include /* The replacement functions in this file are only used on native Windows. - They are multithread-safe, because the gmtime() and localtime() functions + They are thread-safe, because the gmtime() and localtime() functions on native Windows — both in the ucrt and in the older MSVCRT — return a pointer to a 'struct tm' in thread-local memory. */ diff --git a/lib/time_rz.c b/lib/time_rz.c index 0e8ea47e791..03aa3e6700e 100644 --- a/lib/time_rz.c +++ b/lib/time_rz.c @@ -18,7 +18,7 @@ /* Written by Paul Eggert. */ /* Although this module is not thread-safe, any races should be fairly - rare and reasonably benign. For complete thread-safety, use a C + rare and reasonably benign. For complete thread safety, use a C library with a working timezone_t type, so that this module is not needed. */ @@ -118,7 +118,8 @@ save_abbr (timezone_t tz, struct tm *tm) { # if HAVE_STRUCT_TM_TM_ZONE char const *zone = tm->tm_zone; - char *zone_copy = (char *) ""; + static char const mt[] = ""; + char *zone_copy = (char *) mt; /* No need to replace null zones, or zones within the struct tm. */ if (!zone || ((char *) tm <= zone && zone < (char *) (tm + 1))) diff --git a/lib/u64.h b/lib/u64.h index 2f9c7918151..cde952fa316 100644 --- a/lib/u64.h +++ b/lib/u64.h @@ -46,10 +46,10 @@ extern "C" { /* Native implementations are trivial. See below for comments on what these operations do. */ typedef uint64_t u64; -# define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo))) -# define u64init(hi, lo) u64hilo (hi, lo) -# define u64lo(x) ((u64) (x)) -# define u64getlo(x) ((uint32_t) ((x) & UINT32_MAX)) +# define u64hilo(hi, lo) ((u64) {((u64) {(hi)} << 32) + (lo)}) +# define u64init(hi, lo) (((u64) (hi) << 32) + (lo)) +# define u64lo(x) ((u64) {(x)}) +# define u64getlo(x) ((uint32_t) {(x) & UINT32_MAX}) # define u64size(x) u64lo (x) # define u64not(x) (~(x)) # define u64lt(x, y) ((x) < (y)) diff --git a/m4/free.m4 b/m4/free.m4 index c7a134bab8a..e9c9d8f35c6 100644 --- a/m4/free.m4 +++ b/m4/free.m4 @@ -1,5 +1,5 @@ # free.m4 -# serial 6 +# serial 7 dnl Copyright (C) 2003-2005, 2009-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -18,6 +18,9 @@ AC_DEFUN([gl_FUNC_FREE], dnl So far, we know of three platforms that do this: dnl * glibc >= 2.33, thanks to the fix for this bug: dnl + dnl * musl >= 1.2.3, thanks to these commits: + dnl + dnl dnl * OpenBSD >= 4.5, thanks to this commit: dnl dnl * Solaris, because its malloc() implementation is based on brk(), @@ -26,11 +29,14 @@ AC_DEFUN([gl_FUNC_FREE], dnl documentation, or by code inspection of the free() implementation in libc. AC_CACHE_CHECK([whether free is known to preserve errno], [gl_cv_func_free_preserves_errno], - [AC_COMPILE_IFELSE( + [AC_REQUIRE([gl_MUSL_LIBC]) + AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include + #include ]], [[#if 2 < __GLIBC__ + (33 <= __GLIBC_MINOR__) + #elif defined MUSL_LIBC && defined SEEK_DATA /* musl >= 1.2.3 */ #elif defined __OpenBSD__ #elif defined __sun #else diff --git a/m4/gettext_h.m4 b/m4/gettext_h.m4 index 7ef89541b9f..7fa8926cae6 100644 --- a/m4/gettext_h.m4 +++ b/m4/gettext_h.m4 @@ -1,5 +1,5 @@ # gettext_h.m4 -# serial 1 +# serial 3 dnl Copyright (C) 2025-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, diff --git a/m4/gnulib-common.m4 b/m4/gnulib-common.m4 index 26eef771db1..12b0836e2a0 100644 --- a/m4/gnulib-common.m4 +++ b/m4/gnulib-common.m4 @@ -1,5 +1,5 @@ # gnulib-common.m4 -# serial 115 +# serial 122 dnl Copyright (C) 2007-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -436,6 +436,23 @@ AC_DEFUN([gl_COMMON_BODY], [ # endif #endif +/* _GL_ATTRIBUTE_COUNTED_BY (C) declares that the number of elements of + the field is given by C, which must be another field in the same struct. + The programmer is responsible for guaranteeing some invariants; see + for details. */ +/* Applies to struct fields of type array or pointer (to data). */ +#ifndef _GL_ATTRIBUTE_COUNTED_BY +/* This attributes is supported + - for fields of array type: by gcc >= 16, clang >= 18, + - for fields of pointer type: by gcc when + will be fixed, clang >= 19. */ +# if defined __clang__ && __clang_major__ >= 19 +# define _GL_ATTRIBUTE_COUNTED_BY(c) __attribute__ ((__counted_by__ (c))) +# else +# define _GL_ATTRIBUTE_COUNTED_BY(c) +# endif +#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. @@ -892,7 +909,7 @@ AC_DEFUN([gl_COMMON_BODY], [ # endif #endif -/* The following attributes enable detection of multithread-safety problems +/* The following attributes enable detection of thread safety problems and resource leaks at compile-time, by clang ≥ 15, when the warning option -Wthread-safety is enabled. For usage, see . */ @@ -1234,9 +1251,9 @@ Amsterdam ]) # AC_C_RESTRICT -# This definition is copied from post-2.70 Autoconf and overrides the -# AC_C_RESTRICT macro from autoconf 2.60..2.70. -m4_version_prereq([2.70.1], [], [ +# This definition is copied from post-2.73 Autoconf and overrides the +# AC_C_RESTRICT macro from autoconf 2.60..2.73. +m4_version_prereq([2.73.1], [], [ AC_DEFUN([AC_C_RESTRICT], [AC_CACHE_CHECK([for C/C++ restrict keyword], [ac_cv_c_restrict], [ac_cv_c_restrict=no @@ -1262,9 +1279,14 @@ AC_DEFUN([AC_C_RESTRICT], ]) AH_VERBATIM([restrict], [/* Define to the equivalent of the C99 'restrict' keyword, or to - nothing if this is not supported. Do not define if restrict is - supported only directly. */ + nothing if this is not supported. In particular it is not supported + in MSVC 14.44 and in g++ 7 on Solaris 11, although these compilers + define __STDC_VERSION__ to 199901L. + Do not define if restrict is supported directly. */ +#if ! (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__ \ + && !defined _MSC_VER && !defined __cplusplus) #undef restrict +#endif /* Work around a bug in older versions of Sun C++, which did not #define __restrict__ or support _Restrict or __restrict__ even though the corresponding Sun C compiler ended up with @@ -1425,6 +1447,7 @@ AC_DEFUN([gl_CC_GNULIB_WARNINGS], dnl -Wno-pedantic >= 4.8 >= 3.9 dnl -Wno-sign-compare >= 3 >= 3.9 dnl -Wno-sign-conversion >= 4.3 >= 3.9 + dnl -Wno-string-plus-int - >= 3.9 dnl -Wno-tautological-out-of-range-compare - >= 3.9 dnl -Wno-type-limits >= 4.3 >= 3.9 dnl -Wno-undef >= 3 >= 3.9 @@ -1453,6 +1476,7 @@ AC_DEFUN([gl_CC_GNULIB_WARNINGS], -Wno-pedantic #endif #if 3 < __clang_major__ + (9 <= __clang_minor__) + -Wno-string-plus-int -Wno-tautological-constant-out-of-range-compare #endif #if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 4 && !defined __clang__) || (__clang_major__ + (__clang_minor__ >= 9) > 3) diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 54fbf912efe..aec48742bbd 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -188,8 +188,10 @@ AC_DEFUN([gl_EARLY], # Code from module stdc_bit_width: # Code from module stdc_count_ones: # Code from module stdc_leading_zeros: + # Code from module stdc_memreverse8u: # Code from module stdc_trailing_zeros: # Code from module stdckdint-h: + # Code from module stdcountof-h: # Code from module stddef-h: # Code from module stdint-h: # Code from module stdio-h: @@ -554,16 +556,19 @@ AC_DEFUN([gl_INIT], gl_CONDITIONAL_HEADER([stdbit.h]) AC_PROG_MKDIR_P AC_REQUIRE([gl_STDBIT_H]) - GL_STDC_BIT_WIDTH=1 + gl_STDBIT_MODULE_INDICATOR([stdc_bit_width]) AC_REQUIRE([gl_STDBIT_H]) - GL_STDC_COUNT_ONES=1 + gl_STDBIT_MODULE_INDICATOR([stdc_count_ones]) AC_REQUIRE([gl_STDBIT_H]) - GL_STDC_LEADING_ZEROS=1 + gl_STDBIT_MODULE_INDICATOR([stdc_leading_zeros]) AC_REQUIRE([gl_STDBIT_H]) - GL_STDC_TRAILING_ZEROS=1 + gl_STDBIT_MODULE_INDICATOR([stdc_trailing_zeros]) gl_STDCKDINT_H gl_CONDITIONAL_HEADER([stdckdint.h]) AC_PROG_MKDIR_P + gl_STDCOUNTOF_H + gl_CONDITIONAL_HEADER([stdcountof.h]) + AC_PROG_MKDIR_P gl_STDDEF_H gl_STDDEF_H_REQUIRE_DEFAULTS gl_CONDITIONAL_HEADER([stddef.h]) @@ -614,7 +619,7 @@ AC_DEFUN([gl_INIT], ;; esac gl_CONDITIONAL([GL_COND_OBJ_STDIO_CONSOLESAFE], [test $USES_MSVCRT = 1]) - AC_CHECK_FUNCS([vasprintf]) + AC_CHECK_FUNCS_ONCE([vasprintf]) gl_STDLIB_H gl_STDLIB_H_REQUIRE_DEFAULTS AC_PROG_MKDIR_P @@ -694,10 +699,8 @@ AC_DEFUN([gl_INIT], [Define to 1 if you want the FILE stream functions getc, putc, etc. to use unlocked I/O if available, throughout the package. Unlocked I/O can improve performance, sometimes dramatically. - But unlocked I/O is safe only in single-threaded programs, - as well as in multithreaded programs for which you can guarantee that - every FILE stream, including stdin, stdout, stderr, is used only - in a single thread.]) + But unlocked I/O is safe only in processes in which two threads + never simultaneously access the same FILE stream.]) AC_DEFINE([USE_UNLOCKED_IO], [GNULIB_STDIO_SINGLE_THREAD], [An alias of GNULIB_STDIO_SINGLE_THREAD.]) gl_FUNC_GLIBC_UNLOCKED_IO @@ -727,6 +730,7 @@ AC_DEFUN([gl_INIT], gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false gl_gnulib_enabled_rawmemchr=false gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false + gl_gnulib_enabled_stdc_memreverse8u=false gl_gnulib_enabled_strtoll=false gl_gnulib_enabled_utimens=false gl_gnulib_enabled_verify=false @@ -945,6 +949,14 @@ AC_DEFUN([gl_INIT], gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=true fi } + func_gl_gnulib_m4code_stdc_memreverse8u () + { + if $gl_gnulib_enabled_stdc_memreverse8u; then :; else + AC_REQUIRE([gl_STDBIT_H]) + gl_STDBIT_MODULE_INDICATOR([stdc_memreverse8u]) + gl_gnulib_enabled_stdc_memreverse8u=true + fi + } func_gl_gnulib_m4code_strtoll () { if $gl_gnulib_enabled_strtoll; then :; else @@ -972,6 +984,9 @@ AC_DEFUN([gl_INIT], gl_gnulib_enabled_verify=true fi } + if $GL_GENERATE_BYTESWAP_H; then + func_gl_gnulib_m4code_stdc_memreverse8u + fi if test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1; then func_gl_gnulib_m4code_925677f0343de64b89a9f0c790b4104c fi @@ -1087,6 +1102,7 @@ AC_DEFUN([gl_INIT], AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7]) AM_CONDITIONAL([gl_GNULIB_ENABLED_rawmemchr], [$gl_gnulib_enabled_rawmemchr]) AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_stdc_memreverse8u], [$gl_gnulib_enabled_stdc_memreverse8u]) AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll]) AM_CONDITIONAL([gl_GNULIB_ENABLED_utimens], [$gl_gnulib_enabled_utimens]) AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify]) @@ -1463,13 +1479,14 @@ AC_DEFUN([gl_FILE_LIST], [ lib/signal.in.h lib/stat-time.c lib/stat-time.h - lib/stdbit.c lib/stdbit.in.h lib/stdc_bit_width.c lib/stdc_count_ones.c lib/stdc_leading_zeros.c + lib/stdc_memreverse8u.c lib/stdc_trailing_zeros.c lib/stdckdint.in.h + lib/stdcountof.in.h lib/stddef.in.h lib/stdint.in.h lib/stdio-consolesafe.c @@ -1633,6 +1650,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/stdalign.m4 m4/stdbit_h.m4 m4/stdckdint_h.m4 + m4/stdcountof_h.m4 m4/stddef_h.m4 m4/stdint.m4 m4/stdio_h.m4 diff --git a/m4/manywarnings.m4 b/m4/manywarnings.m4 index 0824226fa71..ea0442d0396 100644 --- a/m4/manywarnings.m4 +++ b/m4/manywarnings.m4 @@ -1,5 +1,5 @@ # manywarnings.m4 -# serial 32 +# serial 35 dnl Copyright (C) 2008-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -97,7 +97,8 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC(C)], # export LC_ALL=C && comm -3 \ # <((sed -n 's/^ *\(-[^ 0-9][^ ]*\).*/\1/p' manywarnings.m4; \ # awk '/^[^#]/ {print $1}' ../build-aux/gcc-warning.spec) | sort) \ - # <(gcc --help=warnings | sed -n 's/^ \(-[^ ]*\) .*/\1/p' | sort) + # <((gcc --help=c,warnings && gcc --help=common,warnings) \ + # | sed -n 's/^ \(-[^ ]*\) .*/\1/p' | sort) $1= for gl_manywarn_item in -fanalyzer -fstrict-flex-arrays \ @@ -112,9 +113,11 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC(C)], -Wextra \ -Wflex-array-member-not-at-end \ -Wformat-signedness \ + -Wfree-labels \ -Winit-self \ -Winline \ -Winvalid-pch \ + -Wkeyword-macro \ -Wlogical-op \ -Wmissing-declarations \ -Wmissing-include-dirs \ @@ -162,6 +165,7 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC(C)], AS_VAR_APPEND([$1], [' -Wformat-truncation=2']) AS_VAR_APPEND([$1], [' -Wimplicit-fallthrough=5']) AS_VAR_APPEND([$1], [' -Wshift-overflow=2']) + AS_VAR_APPEND([$1], [' -Wstringop-overflow=4']) AS_VAR_APPEND([$1], [' -Wuse-after-free=3']) AS_VAR_APPEND([$1], [' -Wunused-const-variable=2']) AS_VAR_APPEND([$1], [' -Wvla-larger-than=4031']) @@ -180,6 +184,15 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC(C)], AS_VAR_APPEND([$1], [' -fno-common']) ;; esac + case $gl_gcc_version in + gcc*' ('*') '?.* | gcc*' ('*') '1[[0-3]].*) + # In GCC < 14 the option either does not exist, + # or is accepted but always warns. + ;; + *) + AS_VAR_APPEND([$1], [' -Wuseless-cast']) + ;; + esac case $gl_gcc_version in gcc*' ('*') '?.* | gcc*' ('*') '1[[0-4]].*) # In GCC < 15 the option either does not exist, @@ -194,6 +207,20 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC(C)], # These options are not supported by gcc, but are useful with clang. AS_VAR_APPEND([$1], [' -Wthread-safety']) + # These options are not supported by gcc, only by clang. clang enables + # them by default, but they are never useful. So, disable them. + # Note! This applies *only* to options that are really never useful. + # When in doubt, let the package maintainer decide. The principle + # of this module is to enable *all* possible warnings and then allow + # the package maintainer to disable warnings they find not useful + # in the context of their package. + # Gnulib uses #include_next in many .h files. + AS_VAR_APPEND([$1], [' -Wno-gnu-include-next']) + # C programmers know what '+' does. These warning options are targeted + # at fresh C programmers that are used to JavaScript, Java, or C#. + AS_VAR_APPEND([$1], [' -Wno-string-plus-int']) + AS_VAR_APPEND([$1], [' -Wno-string-plus-char']) + # Disable specific options as needed. if test "$gl_cv_cc_nomfi_needed" = yes; then AS_VAR_APPEND([$1], [' -Wno-missing-field-initializers']) diff --git a/m4/pthread_sigmask.m4 b/m4/pthread_sigmask.m4 index 2984dcdcb45..b9c5414d720 100644 --- a/m4/pthread_sigmask.m4 +++ b/m4/pthread_sigmask.m4 @@ -1,5 +1,5 @@ # pthread_sigmask.m4 -# serial 24 +# serial 26 dnl Copyright (C) 2011-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -19,7 +19,7 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], [AC_EGREP_CPP([headers_define_pthread_sigmask], [ #include #include -#ifdef pthread_sigmask +#if defined _WIN32 && defined pthread_sigmask headers_define_pthread_sigmask #endif], [gl_cv_func_pthread_sigmask_macro=yes], @@ -103,6 +103,27 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], ]) fi + dnl We want to be able to use pthread_sigmask as a thread-safe + dnl replacement of sigprocmask, in both single-threaded and multithreaded + dnl processes. Therefore enforce PTHREAD_SIGMASK_LIB to be empty, whenever + dnl possible. + if test -n "$PTHREAD_SIGMASK_LIB"; then + dnl We get here on glibc ≤ 2.31, NetBSD, OpenBSD ≤ 5.8, AIX. + dnl Except on AIX, pthread_sigmask and sigprocmask are equivalent. + dnl Whereas on AIX, sigprocmask is not allowed in multithreaded processes + dnl . + AC_REQUIRE([AC_CANONICAL_HOST]) + case "$host_os" in + aix*) ;; + *) + REPLACE_PTHREAD_SIGMASK=1 + AC_DEFINE([PTHREAD_SIGMASK_NOT_IN_LIBC], [1], + [Define to 1 if pthread_sigmask requires linking with some library.]) + PTHREAD_SIGMASK_LIB= + ;; + esac + fi + AC_SUBST([PTHREAD_SIGMASK_LIB]) dnl For backward compatibility. LIB_PTHREAD_SIGMASK="$PTHREAD_SIGMASK_LIB" @@ -163,6 +184,8 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], dnl On Cygwin 1.7.5, the pthread_sigmask() has a wrong return value dnl convention: Upon failure, it returns -1 and sets errno. + dnl Likewise on NetBSD 9.3, when libpthread is not in use; see + dnl https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=57214 . AC_CACHE_CHECK([whether pthread_sigmask returns error numbers], [gl_cv_func_pthread_sigmask_return_works], [ diff --git a/m4/regex.m4 b/m4/regex.m4 index 45a10490673..4a7257d8925 100644 --- a/m4/regex.m4 +++ b/m4/regex.m4 @@ -1,5 +1,5 @@ # regex.m4 -# serial 81 +# serial 82 dnl Copyright (C) 1996-2001, 2003-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -318,6 +318,39 @@ AC_DEFUN([gl_REGEX], free (regs.end); } + /* These tests are derived from bug#68725, reported by + Ed Morton. The regex uses backrefs with optional groups + to detect palindromes. */ + { + regex_t re68725; + i = regcomp (&re68725, + "^(.?)(.?).?\\\\2\\\\1$", + REG_EXTENDED); + if (i) + result |= 64; + else + { + regmatch_t pm[3]; + /* "ab" is not a palindrome, so must not match + with $. */ + if (regexec (&re68725, "ab", 1, pm, 0) == 0) + result |= 64; + /* Without $, a shorter match (e.g., empty or "a") + is valid at position 0. Ensure set_regs retries + with a shorter match_last when the longest + structural match fails content validation. */ + regfree (&re68725); + i = regcomp (&re68725, + "^(.?)(.?).?\\\\2\\\\1", + REG_EXTENDED); + if (i) + result |= 64; + else if (regexec (&re68725, "ab", 3, pm, 0) != 0) + result |= 64; + regfree (&re68725); + } + } + #if 0 /* It would be nice to reject hosts whose regoff_t values are too narrow (including glibc on hosts with 64-bit ptrdiff_t and diff --git a/m4/stdbit_h.m4 b/m4/stdbit_h.m4 index 517a0a8cc72..1589e1bd657 100644 --- a/m4/stdbit_h.m4 +++ b/m4/stdbit_h.m4 @@ -1,5 +1,5 @@ # stdbit_h.m4 -# serial 2 +# serial 14 dnl Copyright 2024-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -12,27 +12,74 @@ AC_DEFUN_ONCE([gl_STDBIT_H], [ AC_REQUIRE([gl_BIGENDIAN]) - AC_CHECK_HEADERS_ONCE([stdbit.h]) - if test $ac_cv_header_stdbit_h = yes; then - GL_GENERATE_STDBIT_H=false + gl_CHECK_NEXT_HEADERS([stdbit.h]) + if test "$ac_cv_header_stdbit_h" = yes; then + HAVE_STDBIT_H=1 + else + HAVE_STDBIT_H=0 + fi + AC_SUBST([HAVE_STDBIT_H]) + AM_CONDITIONAL([GL_HAVE_STDBIT_H], [test "$ac_cv_header_stdbit_h" = yes]) + + if test "$ac_cv_header_stdbit_h" = yes; then + dnl We may have a stdbit.h without C2y features. + AC_CHECK_DECLS([stdc_rotate_left_uc], , , [[#include ]]) + if test "$ac_cv_have_decl_stdc_rotate_left_uc" = no; then + GL_GENERATE_STDBIT_H=true + else + GL_GENERATE_STDBIT_H=false + fi else GL_GENERATE_STDBIT_H=true fi - - dnl We don't use gl_MODULE_INDICATOR_INIT_VARIABLE here, because stdbit.in.h - dnl does not use #include_next. - GL_STDC_LEADING_ZEROS=0; AC_SUBST([GL_STDC_LEADING_ZEROS]) - GL_STDC_LEADING_ONES=0; AC_SUBST([GL_STDC_LEADING_ONES]) - GL_STDC_TRAILING_ZEROS=0; AC_SUBST([GL_STDC_TRAILING_ZEROS]) - GL_STDC_TRAILING_ONES=0; AC_SUBST([GL_STDC_TRAILING_ONES]) - GL_STDC_FIRST_LEADING_ZERO=0; AC_SUBST([GL_STDC_FIRST_LEADING_ZERO]) - GL_STDC_FIRST_LEADING_ONE=0; AC_SUBST([GL_STDC_FIRST_LEADING_ONE]) - GL_STDC_FIRST_TRAILING_ZERO=0; AC_SUBST([GL_STDC_FIRST_TRAILING_ZERO]) - GL_STDC_FIRST_TRAILING_ONE=0; AC_SUBST([GL_STDC_FIRST_TRAILING_ONE]) - GL_STDC_COUNT_ZEROS=0; AC_SUBST([GL_STDC_COUNT_ZEROS]) - GL_STDC_COUNT_ONES=0; AC_SUBST([GL_STDC_COUNT_ONES]) - GL_STDC_HAS_SINGLE_BIT=0; AC_SUBST([GL_STDC_HAS_SINGLE_BIT]) - GL_STDC_BIT_WIDTH=0; AC_SUBST([GL_STDC_BIT_WIDTH]) - GL_STDC_BIT_FLOOR=0; AC_SUBST([GL_STDC_BIT_FLOOR]) - GL_STDC_BIT_CEIL=0; AC_SUBST([GL_STDC_BIT_CEIL]) +]) + +# gl_STDBIT_MODULE_INDICATOR([modulename]) +# sets the shell variable that indicates the presence of the given module +# to a C preprocessor expression that will evaluate to 1. +# This macro invocation must not occur in macros that are AC_REQUIREd. +AC_DEFUN([gl_STDBIT_MODULE_INDICATOR], +[ + dnl Ensure to expand the default settings once only. + gl_STDBIT_H_REQUIRE_DEFAULTS + gl_MODULE_INDICATOR_SET_VARIABLE([$1]) + dnl Define it also as a C macro, for the benefit of the unit tests. + gl_MODULE_INDICATOR_FOR_TESTS([$1]) +]) + +# Initializes the default values for AC_SUBSTed shell variables. +# This macro must not be AC_REQUIREd. It must only be invoked, and only +# outside of macros or in macros that are not AC_REQUIREd. +AC_DEFUN([gl_STDBIT_H_REQUIRE_DEFAULTS], +[ + m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDBIT_H_MODULE_INDICATOR_DEFAULTS], [ + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_LEADING_ZEROS]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_LEADING_ONES]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_TRAILING_ZEROS]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_TRAILING_ONES]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_FIRST_LEADING_ZERO]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_FIRST_LEADING_ONE]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_FIRST_TRAILING_ZERO]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_FIRST_TRAILING_ONE]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_COUNT_ZEROS]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_COUNT_ONES]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_HAS_SINGLE_BIT]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_BIT_WIDTH]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_BIT_FLOOR]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_BIT_CEIL]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_ROTATE_LEFT]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_ROTATE_RIGHT]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_MEMREVERSE8]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_MEMREVERSE8U]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_LOAD8_ALIGNED]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_LOAD8]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_STORE8_ALIGNED]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDC_STORE8]) + ]) + m4_require(GL_MODULE_INDICATOR_PREFIX[_STDBIT_H_MODULE_INDICATOR_DEFAULTS]) + AC_REQUIRE([gl_STDBIT_H_DEFAULTS]) +]) + +AC_DEFUN([gl_STDBIT_H_DEFAULTS], +[ ]) diff --git a/m4/stdckdint_h.m4 b/m4/stdckdint_h.m4 index eb8c858a2dc..0abeb982b4c 100644 --- a/m4/stdckdint_h.m4 +++ b/m4/stdckdint_h.m4 @@ -1,5 +1,5 @@ # stdckdint_h.m4 -# serial 1 +# serial 2 dnl Copyright 2025-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -52,7 +52,7 @@ AC_DEFUN_ONCE([gl_STDCKDINT_H], HAVE_C_STDCKDINT_H=0 HAVE_WORKING_C_STDCKDINT_H=0 fi - if test "$CXX" != no; then + if test -n "$CXX" && test "$CXX" != no; then AC_CACHE_CHECK([whether stdckdint.h can be included in C++], [gl_cv_header_cxx_stdckdint_h], [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to @@ -114,7 +114,7 @@ EOF AC_SUBST([HAVE_CXX_STDCKDINT_H]) AC_SUBST([HAVE_WORKING_CXX_STDCKDINT_H]) - if test "$CXX" != no; then + if test -n "$CXX" && test "$CXX" != no; then dnl We might need the header for C or C++. if test $HAVE_C_STDCKDINT_H = 1 \ && test $HAVE_WORKING_C_STDCKDINT_H = 1 \ diff --git a/m4/stdcountof_h.m4 b/m4/stdcountof_h.m4 new file mode 100644 index 00000000000..6a888e2d97c --- /dev/null +++ b/m4/stdcountof_h.m4 @@ -0,0 +1,53 @@ +# stdcountof_h.m4 +# serial 3 +dnl Copyright 2025-2026 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl This file is offered as-is, without any warranty. + +AC_DEFUN_ONCE([gl_STDCOUNTOF_H], +[ + AC_CHECK_HEADERS_ONCE([stdcountof.h]) + gl_CHECK_NEXT_HEADERS([stdcountof.h]) + if test $ac_cv_header_stdcountof_h = yes; then + HAVE_STDCOUNTOF_H=1 + else + HAVE_STDCOUNTOF_H=0 + fi + AC_SUBST([HAVE_STDCOUNTOF_H]) + + dnl In clang 21, exists but does not work in C++ mode, because + dnl it uses _Countof, which is not a compiler built-in in C++ mode. + m4_ifdef([gl_ANSI_CXX], [AC_REQUIRE([gl_ANSI_CXX])]) + CXX_HAVE_STDCOUNTOF_H=1 + if test -n "$CXX" && test "$CXX" != no; then + AC_CACHE_CHECK([whether the C++ compiler has ], + [gl_cv_cxx_have_stdcountof_h], + [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to + dnl an autoconf bug . + cat > conftest.cpp <<\EOF +#include +int a[] = { 86, 47 }; +unsigned int a_n = countof (a); +EOF + gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp" + if AC_TRY_EVAL([gl_command]); then + gl_cv_cxx_have_stdcountof_h=yes + else + gl_cv_cxx_have_stdcountof_h=no + fi + rm -fr conftest* + ]) + if test $gl_cv_cxx_have_stdcountof_h != yes; then + CXX_HAVE_STDCOUNTOF_H=0 + fi + fi + AC_SUBST([CXX_HAVE_STDCOUNTOF_H]) + + if test $HAVE_STDCOUNTOF_H = 1 && test $CXX_HAVE_STDCOUNTOF_H = 1; then + GL_GENERATE_STDCOUNTOF_H=false + else + GL_GENERATE_STDCOUNTOF_H=true + fi +]) diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4 index 9d4126f586f..0be1fd98eab 100644 --- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,5 +1,5 @@ # stdio_h.m4 -# serial 75 +# serial 76 dnl Copyright (C) 2007-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -182,6 +182,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], 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_VAPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASZPRINTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF]) @@ -208,6 +209,8 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TEMPNAM], [1]) ]) m4_require(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS]) + dnl Make sure the shell variable for GNULIB_FREE_POSIX is initialized. + gl_STDLIB_H_REQUIRE_DEFAULTS AC_REQUIRE([gl_STDIO_H_DEFAULTS]) ]) From 225876e97999664a075eb6f1489b4b4c8e515ded Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 26 May 2026 17:51:44 -0700 Subject: [PATCH 111/112] =?UTF-8?q?ARRAYELTS=20=E2=86=92=20countof?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C2y will standardize countof as the macro that Emacs uses the name ARRAYELTS for. Switch to the standard name, which is supported by GCC 16+, by Clang 21, and by the Gnulib stdcountof-h module already in use for compilers that do not support countof. Also, use countof in a few places where we missed using ARRAYELTS. * admin/coccinelle/arrayelts.cocci: Suggest countof, not ARRAYELTS. * admin/merge-gnulib (GNULIB_MODULES): Add stdcountof-h, as it is now a direct rather than an indirect dependency. * exec/trace.c, src/lisp.h, src/sfnt.c: Include . (ARRAYELTS): Remove. All uses replaced by countof. * lib-src/ebrowse.c, lib-src/etags.c, lib-src/make-docfile.c: * lib-src/seccomp-filter.c, lwlib/lwlib-Xaw.c: Prefer and countof to doing things by hand. --- admin/coccinelle/arrayelts.cocci | 8 ++++---- admin/merge-gnulib | 2 +- exec/trace.c | 18 ++++++++--------- lib-src/ebrowse.c | 4 +++- lib-src/etags.c | 3 ++- lib-src/make-docfile.c | 3 ++- lib-src/seccomp-filter.c | 3 ++- lib/gnulib.mk.in | 1 + lwlib/lwlib-Xaw.c | 7 +++---- src/alloc.c | 12 +++++------ src/androidvfs.c | 10 +++++----- src/bignum.c | 2 +- src/chartab.c | 4 ++-- src/comp.c | 34 ++++++++++++++++---------------- src/data.c | 2 +- src/doc.c | 2 +- src/dosfns.c | 4 ++-- src/editfns.c | 2 +- src/emacs.c | 6 +++--- src/eval.c | 2 +- src/fileio.c | 2 +- src/fns.c | 4 ++-- src/font.c | 4 ++-- src/frame.c | 6 +++--- src/fringe.c | 2 +- src/haiku.c | 2 +- src/haikufns.c | 6 +++--- src/image.c | 8 ++++---- src/keyboard.c | 24 +++++++++++----------- src/keymap.c | 2 +- src/lisp.h | 8 +++----- src/lread.c | 8 ++++---- src/macfont.m | 12 +++++------ src/msdos.c | 8 ++++---- src/nsfns.m | 2 +- src/nsmenu.m | 2 +- src/nsterm.m | 2 +- src/pdumper.c | 12 +++++------ src/profiler.c | 2 +- src/sfnt.c | 17 ++++++++-------- src/sfntfont-android.c | 2 +- src/sfntfont.c | 8 ++++---- src/sound.c | 2 +- src/sysdep.c | 6 +++--- src/term.c | 2 +- src/w32.c | 6 +++--- src/w32console.c | 2 +- src/w32fns.c | 10 +++++----- src/w32proc.c | 2 +- src/w32term.c | 8 ++++---- src/w32uniscribe.c | 2 +- src/xdisp.c | 6 +++--- src/xfaces.c | 12 +++++------ src/xfns.c | 2 +- src/xgselect.c | 2 +- src/xterm.c | 10 +++++----- 56 files changed, 172 insertions(+), 172 deletions(-) diff --git a/admin/coccinelle/arrayelts.cocci b/admin/coccinelle/arrayelts.cocci index 5376a94bd85..9e1e0e64a9d 100644 --- a/admin/coccinelle/arrayelts.cocci +++ b/admin/coccinelle/arrayelts.cocci @@ -1,21 +1,21 @@ -// Use the ARRAYELTS macro where possible. +// Use the countof macro where possible. @@ type T; T[] E; @@ - (sizeof (E) / sizeof (E[...])) -+ ARRAYELTS (E) ++ countof (E) @@ type T; T[] E; @@ - (sizeof (E) / sizeof (T)) -+ ARRAYELTS (E) ++ countof (E) @@ type T; T[] E; @@ - (sizeof (E) / sizeof (*E)) -+ ARRAYELTS (E) ++ countof (E) diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 20cea5b41e4..8c906d34cef 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -50,7 +50,7 @@ GNULIB_MODULES=' qcopy-acl readlink readlinkat realloc-posix regex sig2str sigdescr_np socklen stat-time std-gnu23 stdc_bit_width stdc_count_ones stdc_trailing_zeros - stdckdint-h stddef-h stdio-h stdio-windows + stdckdint-h stdcountof-h stddef-h stdio-h stdio-windows stpcpy streq strnlen strtoimax symlink sys_stat-h sys_time-h tempname time-h time_r time_rz timegm timer-time timespec-add timespec-sub unlocked-io update-copyright utimensat diff --git a/exec/trace.c b/exec/trace.c index da9ac96c6ff..a194b87ca84 100644 --- a/exec/trace.c +++ b/exec/trace.c @@ -28,6 +28,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include #include #include @@ -1538,9 +1539,6 @@ static int interesting_syscalls[] = READLINKAT_SYSCALL, }; -/* Number of elements in an array. */ -#define ARRAYELTS(arr) (sizeof (arr) / sizeof (arr)[0]) - /* Install a secure computing filter that will notify attached tracers when a system call of interest to this module is received. Value is 0 if successful, 1 otherwise. */ @@ -1548,7 +1546,7 @@ static int interesting_syscalls[] = static int establish_seccomp_filter (void) { - struct sock_filter statements[1 + ARRAYELTS (interesting_syscalls) + 2]; + struct sock_filter statements[1 + countof (interesting_syscalls) + 2]; struct sock_fprog program; int index, rc; @@ -1567,27 +1565,27 @@ establish_seccomp_filter (void) statements[index] = ((struct sock_filter) BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, EXEC_SYSCALL, - ARRAYELTS (interesting_syscalls), 0)); index++; + countof (interesting_syscalls), 0)); index++; #ifdef OPEN_SYSCALL statements[index] = ((struct sock_filter) BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, OPEN_SYSCALL, - ARRAYELTS (interesting_syscalls) - index + 1, 0)); index++; + countof (interesting_syscalls) - index + 1, 0)); index++; #endif /* OPEN_SYSCALL */ statements[index] = ((struct sock_filter) BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, OPENAT_SYSCALL, - ARRAYELTS (interesting_syscalls) - index + 1, 0)); index++; + countof (interesting_syscalls) - index + 1, 0)); index++; #ifdef READLINK_SYSCALL statements[index] = ((struct sock_filter) BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, READLINK_SYSCALL, - ARRAYELTS (interesting_syscalls) - index + 1, 0)); index++; + countof (interesting_syscalls) - index + 1, 0)); index++; #endif /* READLINK_SYSCALL */ statements[index] = ((struct sock_filter) BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, READLINKAT_SYSCALL, - ARRAYELTS (interesting_syscalls) - index + 1, 0)); index++; + countof (interesting_syscalls) - index + 1, 0)); index++; /* If not intercepted above, permit this system call to execute as normal. */ @@ -1600,7 +1598,7 @@ establish_seccomp_filter (void) if (rc) return 1; - program.len = ARRAYELTS (statements); + program.len = countof (statements); program.filter = statements; rc = prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &program); if (rc) diff --git a/lib-src/ebrowse.c b/lib-src/ebrowse.c index 3bb6bd88d79..93c0b52b950 100644 --- a/lib-src/ebrowse.c +++ b/lib-src/ebrowse.c @@ -19,6 +19,8 @@ along with GNU Emacs. If not, see . */ #include + +#include #include #include #include @@ -3612,7 +3614,7 @@ static _Noreturn void usage (int error) { int i; - for (i = 0; i < sizeof usage_message / sizeof *usage_message; i++) + for (i = 0; i < countof (usage_message); i++) fputs (usage_message[i], stdout); exit (error ? EXIT_FAILURE : EXIT_SUCCESS); } diff --git a/lib-src/etags.c b/lib-src/etags.c index 4114ba6b655..977484e4a67 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -110,6 +110,7 @@ University of California, as described above. */ #include #include #include +#include #include #include #include @@ -6693,7 +6694,7 @@ mercury_decl (char *s, size_t pos) } else { - for (int j = 0; j < sizeof (Mercury_decl_tags) / sizeof (char*); ++j) + for (int j = 0; j < countof (Mercury_decl_tags); ++j) { if (memstreq (decl_type, decl_type_length, Mercury_decl_tags[j])) { diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index f6e321d876a..f13ade84244 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -37,6 +37,7 @@ along with GNU Emacs. If not, see . */ #include #include +#include #include #include #include @@ -651,7 +652,7 @@ compare_globals (const void *a, const void *b) /* Common symbols in decreasing popularity order. */ static char const commonsym[][8] = { "nil", "t", "unbound", "error", "lambda" }; - int ncommonsym = sizeof commonsym / sizeof *commonsym; + int ncommonsym = countof (commonsym); int ai = ncommonsym, bi = ncommonsym; for (int i = 0; i < ncommonsym; i++) { diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c index a8cdc6e06f9..f58afbf272d 100644 --- a/lib-src/seccomp-filter.c +++ b/lib-src/seccomp-filter.c @@ -39,6 +39,7 @@ variants of those files that can be used to sandbox Emacs before #include #include #include +#include #include #include #include @@ -119,7 +120,7 @@ set_attribute (enum scmp_filter_attr attr, uint32_t value) do \ { \ const struct scmp_arg_cmp arg_array[] = {__VA_ARGS__}; \ - enum { arg_cnt = sizeof arg_array / sizeof *arg_array }; \ + enum { arg_cnt = countof (arg_array) }; \ int status = seccomp_rule_add_array (ctx, action, syscall, \ arg_cnt, arg_array); \ if (status < 0) \ diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 2a18a330fa1..0605164636d 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -167,6 +167,7 @@ # stdc_count_ones \ # stdc_trailing_zeros \ # stdckdint-h \ +# stdcountof-h \ # stddef-h \ # stdio-h \ # stdio-windows \ diff --git a/lwlib/lwlib-Xaw.c b/lwlib/lwlib-Xaw.c index 0699410cc82..72e7b23c654 100644 --- a/lwlib/lwlib-Xaw.c +++ b/lwlib/lwlib-Xaw.c @@ -20,6 +20,7 @@ along with GNU Emacs. If not, see . */ #include +#include #include #include @@ -527,11 +528,9 @@ make_dialog (char* name, if (! actions_initted) { XtAppContext app = XtWidgetToApplicationContext (parent); - XtAppAddActions (app, xaw_actions, - sizeof (xaw_actions) / sizeof (xaw_actions[0])); + XtAppAddActions (app, xaw_actions, countof (xaw_actions)); #if defined USE_CAIRO || defined HAVE_XFT - XtAppAddActions (app, button_actions, - sizeof (button_actions) / sizeof (button_actions[0])); + XtAppAddActions (app, button_actions, countof (button_actions)); #endif actions_initted = True; } diff --git a/src/alloc.c b/src/alloc.c index 395cca304c6..5fc166dbc24 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -4150,7 +4150,7 @@ memory_full (size_t nbytes) consing_until_gc = min (consing_until_gc, memory_full_cons_threshold); /* The first time we get here, free the spare memory. */ - for (int i = 0; i < ARRAYELTS (spare_memory); i++) + for (int i = 0; i < countof (spare_memory); i++) if (spare_memory[i]) { if (i == 0) @@ -5679,7 +5679,7 @@ visit_static_gc_roots (struct gc_root_visitor visitor) &buffer_local_symbols, GC_ROOT_BUFFER_LOCAL_NAME); - for (int i = 0; i < ARRAYELTS (lispsym); i++) + for (int i = 0; i < countof (lispsym); i++) { Lisp_Object sptr = builtin_lisp_symbol (i); visitor.visit (&sptr, GC_ROOT_C_SYMBOL, visitor.data); @@ -7035,11 +7035,11 @@ sweep_symbols (void) struct symbol_block *sblk; struct symbol_block **sprev = &symbol_block; int lim = symbol_block_index; - object_ct num_free = 0, num_used = ARRAYELTS (lispsym); + object_ct num_free = 0, num_used = countof (lispsym); symbol_free_list = NULL; - for (int i = 0; i < ARRAYELTS (lispsym); i++) + for (int i = 0; i < countof (lispsym); i++) lispsym[i].u.s.gcmarkbit = 0; for (sblk = symbol_block; sblk; sblk = *sprev) @@ -7305,7 +7305,7 @@ which_symbols (Lisp_Object obj, EMACS_INT find_max) if (! deadp (obj)) { - for (int i = 0; i < ARRAYELTS (lispsym); i++) + for (int i = 0; i < countof (lispsym); i++) { Lisp_Object sym = builtin_lisp_symbol (i); if (symbol_uses_obj (sym, obj)) @@ -7473,7 +7473,7 @@ If this portion is smaller than `gc-cons-threshold', this is ignored. */); DEFVAR_INT ("symbols-consed", symbols_consed, doc: /* Number of symbols that have been consed so far. */); - symbols_consed += ARRAYELTS (lispsym); + symbols_consed += countof (lispsym); DEFVAR_INT ("string-chars-consed", string_chars_consed, doc: /* Number of string characters that have been consed so far. */); diff --git a/src/androidvfs.c b/src/androidvfs.c index 311ea31cda6..50a48acdd63 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -1068,7 +1068,7 @@ android_scan_directory_tree (const char *file, size_t *limit_return) copy = NULL; /* Make sure ntokens is within bounds. */ - if (ntokens == ARRAYELTS (tokens)) + if (ntokens == countof (tokens)) goto fail; len = strlen (token) + 1; @@ -2609,7 +2609,7 @@ android_content_name (struct android_vnode *vnode, char *name, else i = 0; - for (; i < ARRAYELTS (content_vnodes); ++i) + for (; i < countof (content_vnodes); ++i) { special = &content_vnodes[i]; @@ -2769,7 +2769,7 @@ android_content_readdir (struct android_vdir *vdir) /* There are no more files to be read. */ if (dir->next_name == (content_directory_contents - + ARRAYELTS (content_directory_contents))) + + countof (content_directory_contents))) return NULL; /* Get the next child. */ @@ -6688,7 +6688,7 @@ android_root_name (struct android_vnode *vnode, char *name, /* Now, find out if the first component is a special vnode; if so, call its root lookup function with the rest of NAME there. */ - for (i = 0; i < ARRAYELTS (special_vnodes); ++i) + for (i = 0; i < countof (special_vnodes); ++i) { special = &special_vnodes[i]; @@ -6774,7 +6774,7 @@ android_root_readdir (struct android_vdir *vdir) dir = (struct android_root_vdir *) vdir; p = dir->directory ? readdir (dir->directory) : NULL; - if (p || dir->index >= ARRAYELTS (special_vnodes)) + if (p || dir->index >= countof (special_vnodes)) return p; dirent.d_ino = 0; diff --git a/src/bignum.c b/src/bignum.c index 89145f2a9c0..405f1796e93 100644 --- a/src/bignum.c +++ b/src/bignum.c @@ -64,7 +64,7 @@ init_bignum (void) 'longjmp'. */ mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp); - for (int i = 0; i < ARRAYELTS (mpz); i++) + for (int i = 0; i < countof (mpz); i++) mpz_init (mpz[i]); } diff --git a/src/chartab.c b/src/chartab.c index 7d2710f20a3..758aec36929 100644 --- a/src/chartab.c +++ b/src/chartab.c @@ -1163,7 +1163,7 @@ uniprop_decode_value_run_length (Lisp_Object table, Lisp_Object value) static uniprop_decoder_t uniprop_decoder [] = { uniprop_decode_value_run_length }; -static const int uniprop_decoder_count = ARRAYELTS (uniprop_decoder); +static const int uniprop_decoder_count = countof (uniprop_decoder); /* Return the decoder of char-table TABLE or nil if none. */ @@ -1238,7 +1238,7 @@ static uniprop_encoder_t uniprop_encoder[] = uniprop_encode_value_run_length, uniprop_encode_value_numeric }; -static const int uniprop_encoder_count = ARRAYELTS (uniprop_encoder); +static const int uniprop_encoder_count = countof (uniprop_encoder); /* Return the encoder of char-table TABLE or nil if none. */ diff --git a/src/comp.c b/src/comp.c index 545d13b6bfd..b2b4fb6f222 100644 --- a/src/comp.c +++ b/src/comp.c @@ -827,10 +827,10 @@ freloc_check_fill (void) eassert (!NILP (Vcomp_subr_list)); - if (ARRAYELTS (helper_link_table) > F_RELOC_MAX_SIZE) + if (countof (helper_link_table) > F_RELOC_MAX_SIZE) goto overflow; memcpy (freloc.link_table, helper_link_table, sizeof (helper_link_table)); - freloc.size = ARRAYELTS (helper_link_table); + freloc.size = countof (helper_link_table); Lisp_Object subr_l = Vcomp_subr_list; FOR_EACH_TAIL (subr_l) @@ -1510,7 +1510,7 @@ emit_slow_eq (gcc_jit_rvalue *x, gcc_jit_rvalue *y) return emit_call (intern_c_string ("slow_eq"), comp.bool_type, - ARRAYELTS (args), + countof (args), args, false); } @@ -2154,7 +2154,7 @@ emit_setjmp (gcc_jit_rvalue *buf) gcc_jit_context_new_function (comp.ctxt, NULL, GCC_JIT_FUNCTION_IMPORTED, comp.int_type, STR (SETJMP_NAME), - ARRAYELTS (params), params, + countof (params), params, false); return gcc_jit_context_new_call (comp.ctxt, NULL, f, 1, args); @@ -2182,7 +2182,7 @@ emit_setjmp (gcc_jit_rvalue *buf) gcc_jit_context_new_function (comp.ctxt, NULL, GCC_JIT_FUNCTION_IMPORTED, comp.int_type, STR (SETJMP_NAME), - ARRAYELTS (params), params, + countof (params), params, false); return gcc_jit_context_new_call (comp.ctxt, NULL, f, 2, args); @@ -2231,7 +2231,7 @@ emit_limple_insn (Lisp_Object insn) ptrdiff_t i = 0; FOR_EACH_TAIL (p) { - if (i == ARRAYELTS (arg)) + if (i == countof (arg)) break; arg[i++] = XCAR (p); } @@ -2732,7 +2732,7 @@ emit_static_object (const char *name, Lisp_Object obj) gcc_jit_context_new_struct_type (comp.ctxt, NULL, format_string ("%s_struct", name), - ARRAYELTS (fields), fields)); + countof (fields), fields)); gcc_jit_lvalue *data_struct = gcc_jit_context_new_global (comp.ctxt, @@ -2807,7 +2807,7 @@ emit_static_object (const char *name, Lisp_Object obj) gcc_jit_block_add_eval (block, NULL, gcc_jit_context_new_call (comp.ctxt, NULL, comp.memcpy, - ARRAYELTS (args), + countof (args), args)); gcc_jit_block_add_assignment (block, NULL, ptrvar, gcc_jit_lvalue_get_address ( @@ -2975,7 +2975,7 @@ emit_ctxt_code (void) Fcons (Qnative_comp_debug, make_fixnum (comp.debug)), Fcons (Qgccjit, Fcomp_libgccjit_version ()) }; - emit_static_object (TEXT_OPTIM_QLY_SYM, Flist (ARRAYELTS (opt_qly), opt_qly)); + emit_static_object (TEXT_OPTIM_QLY_SYM, Flist (countof (opt_qly), opt_qly)); emit_static_object (TEXT_FDOC_SYM, CALLNI (comp-ctxt-function-docs, Vcomp_ctxt)); @@ -3113,7 +3113,7 @@ define_lisp_cons (void) gcc_jit_context_new_union_type (comp.ctxt, NULL, "comp_cdr_u", - ARRAYELTS (cdr_u_fields), + countof (cdr_u_fields), cdr_u_fields); comp.lisp_cons_u_s_car = gcc_jit_context_new_field (comp.ctxt, @@ -3132,7 +3132,7 @@ define_lisp_cons (void) gcc_jit_context_new_struct_type (comp.ctxt, NULL, "comp_cons_s", - ARRAYELTS (cons_s_fields), + countof (cons_s_fields), cons_s_fields); comp.lisp_cons_u_s = gcc_jit_context_new_field (comp.ctxt, @@ -3155,7 +3155,7 @@ define_lisp_cons (void) gcc_jit_context_new_union_type (comp.ctxt, NULL, "comp_cons_u", - ARRAYELTS (cons_u_fields), + countof (cons_u_fields), cons_u_fields); comp.lisp_cons_u = @@ -3234,7 +3234,7 @@ define_memcpy (void) comp.memcpy = gcc_jit_context_new_function (comp.ctxt, NULL, GCC_JIT_FUNCTION_IMPORTED, comp.void_ptr_type, "memcpy", - ARRAYELTS (params), params, false); + countof (params), params, false); } /* struct handler definition */ @@ -3294,7 +3294,7 @@ define_handler_struct (void) "pad2") }; gcc_jit_struct_set_fields (comp.handler_s, NULL, - ARRAYELTS (fields), + countof (fields), fields); } @@ -3338,7 +3338,7 @@ define_thread_state_struct (void) gcc_jit_context_new_struct_type (comp.ctxt, NULL, "comp_thread_state", - ARRAYELTS (fields), + countof (fields), fields); comp.thread_state_ptr_type = gcc_jit_type_get_pointer (gcc_jit_struct_as_type (comp.thread_state_s)); @@ -4141,7 +4141,7 @@ declare_lex_function (Lisp_Object func) GCC_JIT_FUNCTION_EXPORTED, comp.lisp_obj_type, SSDATA (c_name), - ARRAYELTS (params), params, 0); + countof (params), params, 0); } SAFE_FREE (); return res; @@ -4471,7 +4471,7 @@ DEFUN ("comp--install-trampoline", Fcomp__install_trampoline, subr_name); Lisp_Object subr_l = Vcomp_subr_list; - ptrdiff_t i = ARRAYELTS (helper_link_table); + ptrdiff_t i = countof (helper_link_table); FOR_EACH_TAIL (subr_l) { Lisp_Object subr = XCAR (subr_l); diff --git a/src/data.c b/src/data.c index 92926eca89a..bbc4b34c6b8 100644 --- a/src/data.c +++ b/src/data.c @@ -1943,7 +1943,7 @@ notify_variable_watchers (Lisp_Object symbol, if (SUBRP (watcher)) { Lisp_Object args[] = { symbol, newval, operation, where }; - funcall_subr (XSUBR (watcher), ARRAYELTS (args), args); + funcall_subr (XSUBR (watcher), countof (args), args); } else calln (watcher, symbol, newval, operation, where); diff --git a/src/doc.c b/src/doc.c index 069c0294914..99d1ab292f0 100644 --- a/src/doc.c +++ b/src/doc.c @@ -546,7 +546,7 @@ the same file name is found in the `doc-directory'. */) { #include "buildobj.h" }; - int i = ARRAYELTS (buildobj); + int i = countof (buildobj); while (0 <= --i) Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files); } diff --git a/src/dosfns.c b/src/dosfns.c index 07d553b0d78..189eaec408b 100644 --- a/src/dosfns.c +++ b/src/dosfns.c @@ -395,7 +395,7 @@ msdos_stdcolor_idx (const char *name) { int i; - for (i = 0; i < ARRAYELTS (vga_colors); i++) + for (i = 0; i < countof (vga_colors); i++) if (xstrcasecmp (name, vga_colors[i]) == 0) return i; @@ -413,7 +413,7 @@ msdos_stdcolor_name (int idx) return build_string (unspecified_fg); else if (idx == FACE_TTY_DEFAULT_BG_COLOR) return build_string (unspecified_bg); - else if (idx >= 0 && idx < ARRAYELTS (vga_colors)) + else if (idx >= 0 && idx < countof (vga_colors)) return build_string (vga_colors[idx]); else return Qunspecified; /* meaning the default */ diff --git a/src/editfns.c b/src/editfns.c index 4089edb1074..84f1e5cef03 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -2450,7 +2450,7 @@ check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end, { int initial_buf[16]; int *buf = initial_buf; - ptrdiff_t buf_size = ARRAYELTS (initial_buf); + ptrdiff_t buf_size = countof (initial_buf); int *bufalloc = 0; ptrdiff_t buf_used = 0; Lisp_Object result = Qnil; diff --git a/src/emacs.c b/src/emacs.c index 0827101da2f..3a9c7458e49 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1718,7 +1718,7 @@ android_emacs_init (int argc, char **argv, char *dump_file) { int i; printf ("Usage: %s [OPTION-OR-FILENAME]...\n", argv[0]); - for (i = 0; i < ARRAYELTS (usage_message); i++) + for (i = 0; i < countof (usage_message); i++) fputs (usage_message[i], stdout); exit (0); } @@ -2836,7 +2836,7 @@ sort_args (int argc, char **argv) } /* Look for a match with a known old-fashioned option. */ - for (i = 0; i < ARRAYELTS (standard_args); i++) + for (i = 0; i < countof (standard_args); i++) if (!strcmp (argv[from], standard_args[i].name)) { options[from] = standard_args[i].nargs; @@ -2858,7 +2858,7 @@ sort_args (int argc, char **argv) match = -1; - for (i = 0; i < ARRAYELTS (standard_args); i++) + for (i = 0; i < countof (standard_args); i++) if (standard_args[i].longname && !strncmp (argv[from], standard_args[i].longname, thislen)) diff --git a/src/eval.c b/src/eval.c index 1fdc6653cfc..699dcde2e0b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3245,7 +3245,7 @@ funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *args) Lisp_Object *a; if (numargs < maxargs) { - eassume (maxargs <= ARRAYELTS (argbuf)); + eassume (maxargs <= countof (argbuf)); a = argbuf; memcpy (a, args, numargs * word_size); memclear (a + numargs, (maxargs - numargs) * word_size); diff --git a/src/fileio.c b/src/fileio.c index 28adb6dd5f9..0b11b7bdf65 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -1962,7 +1962,7 @@ get_homedir (void) { static char const *userenv[] = {"LOGNAME", "USER"}; struct passwd *pw = NULL; - for (int i = 0; i < ARRAYELTS (userenv); i++) + for (int i = 0; i < countof (userenv); i++) { char *user = egetenv (userenv[i]); if (user) diff --git a/src/fns.c b/src/fns.c index 687f0303aae..d692a92580a 100644 --- a/src/fns.c +++ b/src/fns.c @@ -4759,7 +4759,7 @@ cmpfn_user_defined (Lisp_Object key1, Lisp_Object key2, struct Lisp_Hash_Table *h) { Lisp_Object args[] = { h->test->user_cmp_function, key1, key2 }; - return hash_table_user_defined_call (ARRAYELTS (args), args, h); + return hash_table_user_defined_call (countof (args), args, h); } static EMACS_INT @@ -4805,7 +4805,7 @@ static hash_hash_t hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) { Lisp_Object args[] = { h->test->user_hash_function, key }; - Lisp_Object hash = hash_table_user_defined_call (ARRAYELTS (args), args, h); + Lisp_Object hash = hash_table_user_defined_call (countof (args), args, h); return reduce_emacs_uint_to_hash_hash (FIXNUMP (hash) ? XUFIXNUM(hash) : sxhash (hash)); } diff --git a/src/font.c b/src/font.c index fed90084219..ad46fb1904d 100644 --- a/src/font.c +++ b/src/font.c @@ -734,7 +734,7 @@ get_font_prop_index (Lisp_Object key) { int i; - for (i = 0; i < ARRAYELTS (font_property_table); i++) + for (i = 0; i < countof (font_property_table); i++) if (EQ (key, builtin_lisp_symbol (font_property_table[i].key))) return i; return -1; @@ -5700,7 +5700,7 @@ If the named font cannot be opened and loaded, return nil. */) #endif -#define BUILD_STYLE_TABLE(TBL) build_style_table (TBL, ARRAYELTS (TBL)) +#define BUILD_STYLE_TABLE(TBL) build_style_table (TBL, countof (TBL)) static Lisp_Object build_style_table (const struct table_entry *entry, int nelement) diff --git a/src/frame.c b/src/frame.c index 489ecbc7187..d17af6198be 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5081,7 +5081,7 @@ handle_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val, Lisp_Object old_value) { Lisp_Object param_index = Fget (prop, Qx_frame_parameter); - if (FIXNATP (param_index) && XFIXNAT (param_index) < ARRAYELTS (frame_parms)) + if (FIXNATP (param_index) && XFIXNAT (param_index) < countof (frame_parms)) { if (FRAME_RIF (f)) { @@ -7384,10 +7384,10 @@ syms_of_frame (void) DEFSYM (Qcloned_from, "cloned-from"); DEFSYM (Qundeleted, "undeleted"); - for (int i = 0; i < ARRAYELTS (frame_parms); i++) + for (int i = 0; i < countof (frame_parms); i++) { int sym = frame_parms[i].sym; - eassert (sym >= 0 && sym < ARRAYELTS (lispsym)); + eassert (sym >= 0 && sym < countof (lispsym)); Lisp_Object v = builtin_lisp_symbol (sym); Fput (v, Qx_frame_parameter, make_fixnum (i)); } diff --git a/src/fringe.c b/src/fringe.c index 5187325f281..b390246576b 100644 --- a/src/fringe.c +++ b/src/fringe.c @@ -488,7 +488,7 @@ static struct fringe_bitmap standard_bitmaps[] = #define NO_FRINGE_BITMAP 0 #define UNDEF_FRINGE_BITMAP 1 -#define MAX_STANDARD_FRINGE_BITMAPS ARRAYELTS (standard_bitmaps) +#define MAX_STANDARD_FRINGE_BITMAPS countof (standard_bitmaps) static struct fringe_bitmap **fringe_bitmaps; static Lisp_Object *fringe_faces; diff --git a/src/haiku.c b/src/haiku.c index 68a1d238add..d8615562c93 100644 --- a/src/haiku.c +++ b/src/haiku.c @@ -133,7 +133,7 @@ struct load_sample /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */ static struct load_sample samples[16*60]; static int first_idx = -1, last_idx = -1; -static int max_idx = ARRAYELTS (samples); +static int max_idx = countof (samples); static unsigned num_of_processors = 0; static int diff --git a/src/haikufns.c b/src/haikufns.c index 3568c1bc0bc..32813833874 100644 --- a/src/haikufns.c +++ b/src/haikufns.c @@ -85,7 +85,7 @@ get_geometry_from_preferences (struct haiku_display_info *dpyinfo, }; int i; - for (i = 0; i < ARRAYELTS (r); ++i) + for (i = 0; i < countof (r); ++i) { if (NILP (Fassq (r[i].tem, parms))) { @@ -2065,7 +2065,7 @@ haiku_free_custom_cursors (struct frame *f) output = FRAME_OUTPUT_DATA (f); dpyinfo = FRAME_DISPLAY_INFO (f); - for (i = 0; i < ARRAYELTS (custom_cursors); ++i) + for (i = 0; i < countof (custom_cursors); ++i) { cursor = &custom_cursors[i]; frame_cursor = (Emacs_Cursor *) ((char *) output @@ -2111,7 +2111,7 @@ haiku_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) values. */ haiku_free_custom_cursors (f); - for (i = 0; i < ARRAYELTS (custom_cursors); ++i) + for (i = 0; i < countof (custom_cursors); ++i) { frame_cursor = (Emacs_Cursor *) ((char *) output + custom_cursors[i].output_offset); diff --git a/src/image.c b/src/image.c index 723443193c0..640e3736b08 100644 --- a/src/image.c +++ b/src/image.c @@ -4971,7 +4971,7 @@ Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data, { #ifdef USE_CAIRO Emacs_Color fgbg[] = {{.pixel = fg}, {.pixel = bg}}; - FRAME_TERMINAL (f)->query_colors (f, fgbg, ARRAYELTS (fgbg)); + FRAME_TERMINAL (f)->query_colors (f, fgbg, countof (fgbg)); fg = lookup_rgb_color (f, fgbg[0].red, fgbg[0].green, fgbg[0].blue); bg = lookup_rgb_color (f, fgbg[1].red, fgbg[1].green, fgbg[1].blue); img->pixmap @@ -6298,7 +6298,7 @@ static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"}; static int xpm_str_to_color_key (const char *s) { - for (int i = 0; i < ARRAYELTS (xpm_color_key_strings); i++) + for (int i = 0; i < countof (xpm_color_key_strings); i++) if (strcmp (xpm_color_key_strings[i], s) == 0) return i; return -1; @@ -7731,7 +7731,7 @@ pbm_load (struct frame *f, struct image *img) #ifdef USE_CAIRO { Emacs_Color fgbg[] = {{.pixel = fg}, {.pixel = bg}}; - FRAME_TERMINAL (f)->query_colors (f, fgbg, ARRAYELTS (fgbg)); + FRAME_TERMINAL (f)->query_colors (f, fgbg, countof (fgbg)); fg = lookup_rgb_color (f, fgbg[0].red, fgbg[0].green, fgbg[0].blue); bg = lookup_rgb_color (f, fgbg[1].red, fgbg[1].green, fgbg[1].blue); } @@ -12992,7 +12992,7 @@ lookup_image_type (Lisp_Object type) return &native_image_type; #endif - for (int i = 0; i < ARRAYELTS (image_types); i++) + for (int i = 0; i < countof (image_types); i++) { struct image_type const *r = &image_types[i]; if (EQ (type, builtin_lisp_symbol (r->type))) diff --git a/src/keyboard.c b/src/keyboard.c index 6f0b5fbb2ec..4cfb2de07f2 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -6360,13 +6360,13 @@ make_lispy_event (struct input_event *event) case NON_ASCII_KEYSTROKE_EVENT: button_down_time = 0; - for (i = 0; i < ARRAYELTS (lispy_accent_codes); i++) + for (i = 0; i < countof (lispy_accent_codes); i++) if (event->code == lispy_accent_codes[i]) return modify_event_symbol (i, event->modifiers, Qfunction_key, Qnil, lispy_accent_keys, &accent_key_syms, - ARRAYELTS (lispy_accent_keys)); + countof (lispy_accent_keys)); #if 0 #ifdef XK_kana_A @@ -6375,7 +6375,7 @@ make_lispy_event (struct input_event *event) event->modifiers & ~shift_modifier, Qfunction_key, Qnil, lispy_kana_keys, &func_key_syms, - ARRAYELTS (lispy_kana_keys)); + countof (lispy_kana_keys)); #endif /* XK_kana_A */ #endif /* 0 */ @@ -6386,18 +6386,18 @@ make_lispy_event (struct input_event *event) event->modifiers, Qfunction_key, Qnil, iso_lispy_function_keys, &func_key_syms, - ARRAYELTS (iso_lispy_function_keys)); + countof (iso_lispy_function_keys)); #endif if ((FUNCTION_KEY_OFFSET <= event->code && (event->code - < FUNCTION_KEY_OFFSET + ARRAYELTS (lispy_function_keys))) + < FUNCTION_KEY_OFFSET + countof (lispy_function_keys))) && lispy_function_keys[event->code - FUNCTION_KEY_OFFSET]) return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET, event->modifiers, Qfunction_key, Qnil, lispy_function_keys, &func_key_syms, - ARRAYELTS (lispy_function_keys)); + countof (lispy_function_keys)); /* Handle system-specific or unknown keysyms. We need to use an alist rather than a vector as the cache @@ -6424,13 +6424,13 @@ make_lispy_event (struct input_event *event) make_fixnum (event->modifiers)); case MULTIMEDIA_KEY_EVENT: - if (event->code < ARRAYELTS (lispy_multimedia_keys) + if (event->code < countof (lispy_multimedia_keys) && event->code > 0 && lispy_multimedia_keys[event->code]) { return modify_event_symbol (event->code, event->modifiers, Qfunction_key, Qnil, lispy_multimedia_keys, &func_key_syms, - ARRAYELTS (lispy_multimedia_keys)); + countof (lispy_multimedia_keys)); } return Qnil; #endif @@ -7529,7 +7529,7 @@ static const char *const modifier_names[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "alt", "super", "hyper", "shift", "control", "meta" }; -#define NUM_MOD_NAMES ARRAYELTS (modifier_names) +#define NUM_MOD_NAMES countof (modifier_names) static Lisp_Object modifier_symbols; @@ -13607,7 +13607,7 @@ This is effective only in `noninteractive' sessions. */); { int i; - for (i = 0; i < ARRAYELTS (head_table); i++) + for (i = 0; i < countof (head_table); i++) { const struct event_head *p = &head_table[i]; Lisp_Object var = builtin_lisp_symbol (p->var); @@ -13626,12 +13626,12 @@ This is effective only in `noninteractive' sessions. */); staticpro (&frame_relative_event_pos); mouse_syms = make_nil_vector (5); staticpro (&mouse_syms); - wheel_syms = make_nil_vector (ARRAYELTS (lispy_wheel_names)); + wheel_syms = make_nil_vector (countof (lispy_wheel_names)); staticpro (&wheel_syms); { int i; - int len = ARRAYELTS (modifier_names); + int len = countof (modifier_names); modifier_symbols = make_nil_vector (len); for (i = 0; i < len; i++) diff --git a/src/keymap.c b/src/keymap.c index dc40d68089a..a42cec854dd 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -2118,7 +2118,7 @@ For an approximate inverse of this, see `kbd'. */) Lisp_Object lists[2] = { prefix, keys }; ptrdiff_t listlens[2] = { nprefix, nkeys }; - for (int li = 0; li < ARRAYELTS (lists); li++) + for (int li = 0; li < countof (lists); li++) { Lisp_Object list = lists[li]; ptrdiff_t listlen = listlens[li], i_byte = 0; diff --git a/src/lisp.h b/src/lisp.h index dd780e90c1d..764205dcf90 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -25,6 +25,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include #include #include @@ -70,9 +71,6 @@ INLINE_HEADER_BEGIN #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) -/* Number of elements in an array. */ -#define ARRAYELTS(arr) (sizeof (arr) / sizeof (arr)[0]) - /* Number of bits in a Lisp_Object tag. */ DEFINE_GDB_SYMBOL_BEGIN (int, GCTYPEBITS) #define GCTYPEBITS 3 @@ -3452,7 +3450,7 @@ enum maxargs }; /* Call a function F that accepts many args, passing it ARRAY's elements. */ -#define CALLMANY(f, array) (f) (ARRAYELTS (array), array) +#define CALLMANY(f, array) (f) (countof (array), array) /* Call a function F that accepts many args, passing it the remaining args, E.g., 'return CALLN (Fformat, fmt, text);' is less error-prone than @@ -4493,7 +4491,7 @@ extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); extern Lisp_Object listn (ptrdiff_t, Lisp_Object, ...); #define list(...) \ - listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__) + listn (countof (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__) enum gc_root_type { diff --git a/src/lread.c b/src/lread.c index 00f85114ac7..b079e83dd06 100644 --- a/src/lread.c +++ b/src/lread.c @@ -1539,7 +1539,7 @@ Return t if the file exists and loads successfully. */) if (!NILP (Ffboundp (Qdo_after_load_evaluation))) calln (Qdo_after_load_evaluation, hist_file_name); - for (int i = 0; i < ARRAYELTS (saved_strings); i++) + for (int i = 0; i < countof (saved_strings); i++) { xfree (saved_strings[i].string); saved_strings[i].string = NULL; @@ -3449,7 +3449,7 @@ skip_lazy_string (source_t *source) and record where in the file it comes from. */ /* First exchange the two saved_strings. */ - static_assert (ARRAYELTS (saved_strings) == 2); + static_assert (countof (saved_strings) == 2); struct saved_string t = saved_strings[0]; saved_strings[0] = saved_strings[1]; saved_strings[1] = t; @@ -3507,7 +3507,7 @@ get_lazy_string (Lisp_Object val) compatibility. */ EMACS_INT pos = eabs (XFIXNUM (XCDR (val))); struct saved_string *ss = &saved_strings[0]; - struct saved_string *ssend = ss + ARRAYELTS (saved_strings); + struct saved_string *ssend = ss + countof (saved_strings); while (ss < ssend && !(pos >= ss->position && pos < ss->position + ss->length)) ss++; @@ -5199,7 +5199,7 @@ init_obarray_once (void) initial_obarray = Vobarray; staticpro (&initial_obarray); - for (int i = 0; i < ARRAYELTS (lispsym); i++) + for (int i = 0; i < countof (lispsym); i++) define_symbol (builtin_lisp_symbol (i), defsym_name[i]); DEFSYM (Qunbound, "unbound"); diff --git a/src/macfont.m b/src/macfont.m index 1916e5c0287..3cd3b79a346 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -224,7 +224,7 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, unichar characters[] = {0xfffd}; NSString *string = [NSString stringWithCharacters:characters - length:ARRAYELTS (characters)]; + length:countof (characters)]; NSGlyphInfo *glyphInfo = [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid collection:collection @@ -893,7 +893,7 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, }; int i; - for (i = 0; i < ARRAYELTS (numeric_traits); i++) + for (i = 0; i < countof (numeric_traits); i++) { num = CFDictionaryGetValue (dict, numeric_traits[i].trait); if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval)) @@ -2119,7 +2119,7 @@ static int macfont_variation_glyphs (struct font *, int c, if (! traits) goto err; - for (i = 0; i < ARRAYELTS (numeric_traits); i++) + for (i = 0; i < countof (numeric_traits); i++) { tmp = AREF (spec, numeric_traits[i].index); if (FIXNUMP (tmp)) @@ -3788,7 +3788,7 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no { attributes = CFDictionaryCreate (NULL, (const void **) keys, (const void **) values, - ARRAYELTS (keys), + countof (keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease (values[1]); @@ -4002,7 +4002,7 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CTLineRef ctline = NULL; string = CFStringCreateWithCharacters (NULL, characters, - ARRAYELTS (characters)); + countof (characters)); if (string) { @@ -4018,7 +4018,7 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no attributes = CFDictionaryCreate (NULL, (const void **) keys, (const void **) values, - ARRAYELTS (keys), + countof (keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease (glyph_info); diff --git a/src/msdos.c b/src/msdos.c index 4d111b30969..ddfb0451395 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -581,7 +581,7 @@ dos_set_window_size (int *rows, int *cols) }; int i = 0; - while (i < ARRAYELTS (std_dimension)) + while (i < countof (std_dimension)) { if (std_dimension[i].need_vga <= have_vga && std_dimension[i].rows >= *rows) @@ -2068,7 +2068,7 @@ dos_set_keyboard (int code, int always) keyboard_map_all = always; dos_keyboard_layout = 1; - for (i = 0; i < ARRAYELTS (keyboard_layout_list); i++) + for (i = 0; i < countof (keyboard_layout_list); i++) if (code == keyboard_layout_list[i].country_code) { keyboard = keyboard_layout_list[i].keyboard_map; @@ -2511,7 +2511,7 @@ dos_rawgetc (void) one. */ if (code == -1) { - if (sc >= ARRAYELTS (ibmpc_translate_map)) + if (sc >= countof (ibmpc_translate_map)) continue; if ((code = ibmpc_translate_map[sc]) == Ignore) continue; @@ -3479,7 +3479,7 @@ init_environment (int argc, char **argv, int skip_args) static const char * const tempdirs[] = { "$TMPDIR", "$TEMP", "$TMP", "c:/" }; - const int imax = ARRAYELTS (tempdirs); + const int imax = countof (tempdirs); /* Make sure they have a usable $TMPDIR. Many Emacs functions use temporary files and assume "/tmp" if $TMPDIR is unset, which diff --git a/src/nsfns.m b/src/nsfns.m index 045d167e6b4..3ee6315d963 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1168,7 +1168,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. }; int i; - for (i = 0; i < ARRAYELTS (r); ++i) + for (i = 0; i < countof (r); ++i) { if (NILP (Fassq (r[i].tem, parms))) { diff --git a/src/nsmenu.m b/src/nsmenu.m index 2b785a8dab8..ab6e7d7140d 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -630,7 +630,7 @@ -(void)removeAllItems int len = strlen (key); char *buf = xmalloc (len + 1); memcpy (buf, key, len + 1); - for (int i = 0; i < ARRAYELTS (key_symbols); i++) + for (int i = 0; i < countof (key_symbols); i++) { ptrdiff_t fromlen = strlen (key_symbols[i].from); char *p = buf; diff --git a/src/nsterm.m b/src/nsterm.m index 2507053f3a1..20097454444 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2645,7 +2645,7 @@ Hide the window (X11 semantics) Internal call used by NSView-keyDown. -------------------------------------------------------------------------- */ { - const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym); + const unsigned last_keysym = countof (convert_ns_to_X_keysym); unsigned keysym; /* An array would be faster, but less easy to read. */ for (keysym = 0; keysym < last_keysym; keysym += 2) diff --git a/src/pdumper.c b/src/pdumper.c index 066058d2078..039768b022b 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -4387,7 +4387,7 @@ DEFUN ("dump-emacs-portable--sort-predicate-copied", void pdumper_do_now_and_after_load_impl (pdumper_hook hook) { - if (nr_dump_hooks == ARRAYELTS (dump_hooks)) + if (nr_dump_hooks == countof (dump_hooks)) fatal ("out of dump hooks: make dump_hooks[] bigger"); dump_hooks[nr_dump_hooks++] = hook; hook (); @@ -4396,7 +4396,7 @@ pdumper_do_now_and_after_load_impl (pdumper_hook hook) void pdumper_do_now_and_after_late_load_impl (pdumper_hook hook) { - if (nr_dump_late_hooks == ARRAYELTS (dump_late_hooks)) + if (nr_dump_late_hooks == countof (dump_late_hooks)) fatal ("out of dump hooks: make dump_late_hooks[] bigger"); dump_late_hooks[nr_dump_late_hooks++] = hook; hook (); @@ -4405,7 +4405,7 @@ pdumper_do_now_and_after_late_load_impl (pdumper_hook hook) static void pdumper_remember_user_data_1 (void *mem, int nbytes) { - if (nr_remembered_data == ARRAYELTS (remembered_data)) + if (nr_remembered_data == countof (remembered_data)) fatal ("out of remembered data slots: make remembered_data[] bigger"); remembered_data[nr_remembered_data].mem = mem; remembered_data[nr_remembered_data].sz = nbytes; @@ -5731,7 +5731,7 @@ pdumper_load (const char *dump_filename, char *argv0) .protection = DUMP_MEMORY_ACCESS_READWRITE, }; - if (!dump_mmap_contiguous (sections, ARRAYELTS (sections))) + if (!dump_mmap_contiguous (sections, countof (sections))) goto out; err = PDUMPER_LOAD_ERROR; @@ -5768,7 +5768,7 @@ pdumper_load (const char *dump_filename, char *argv0) dump_do_all_emacs_relocations (header, dump_base); dump_mmap_discard_contents (§ions[DS_DISCARDABLE]); - for (int i = 0; i < ARRAYELTS (sections); ++i) + for (int i = 0; i < countof (sections); ++i) dump_mmap_reset (§ions[i]); Lisp_Object hashes = zero_vector; @@ -5807,7 +5807,7 @@ pdumper_load (const char *dump_filename, char *argv0) dump_private.dump_filename = dump_filename_copy; out: - for (int i = 0; i < ARRAYELTS (sections); ++i) + for (int i = 0; i < countof (sections); ++i) dump_mmap_release (§ions[i]); if (dump_fd >= 0) emacs_close (dump_fd); diff --git a/src/profiler.c b/src/profiler.c index c9cc3f118ad..fefc717d270 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -429,7 +429,7 @@ setup_cpu_timer (Lisp_Object sampling_interval) sigev.sigev_signo = SIGPROF; sigev.sigev_notify = SIGEV_SIGNAL; - for (int i = 0; i < ARRAYELTS (system_clock); i++) + for (int i = 0; i < countof (system_clock); i++) if (timer_create (system_clock[i], &sigev, &profiler_timer) == 0) { profiler_timer_ok = true; diff --git a/src/sfnt.c b/src/sfnt.c index 956b89d3efb..d436421c79b 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -28,6 +28,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include #include #include @@ -127,8 +128,6 @@ xfree (void *ptr) #define TEST_STATIC static /* Needed for tests. */ -#define ARRAYELTS(arr) (sizeof (arr) / sizeof (arr)[0]) - #define eassert(expr) assert (expr) /* Also necessary. */ @@ -18062,9 +18061,9 @@ static uint32_t sfnt_sround_values[] = static struct sfnt_generic_test_args sround_test_args = { sfnt_sround_values, - ARRAYELTS (sfnt_sround_values), + countof (sfnt_sround_values), false, - ARRAYELTS (sfnt_sround_instructions), + countof (sfnt_sround_instructions), }; static unsigned char sfnt_s45round_instructions[] = @@ -18084,9 +18083,9 @@ static uint32_t sfnt_s45round_values[] = static struct sfnt_generic_test_args s45round_test_args = { sfnt_s45round_values, - ARRAYELTS (sfnt_s45round_values), + countof (sfnt_s45round_values), false, - ARRAYELTS (sfnt_s45round_instructions), + countof (sfnt_s45round_instructions), }; static struct sfnt_generic_test_args rutg_test_args = @@ -19468,14 +19467,14 @@ static struct sfnt_interpreter_test all_tests[] = { "SROUND", sfnt_sround_instructions, - ARRAYELTS (sfnt_sround_instructions), + countof (sfnt_sround_instructions), &sround_test_args, sfnt_generic_check, }, { "S45ROUND", sfnt_s45round_instructions, - ARRAYELTS (sfnt_s45round_instructions), + countof (sfnt_s45round_instructions), &s45round_test_args, sfnt_generic_check, }, @@ -20369,7 +20368,7 @@ main (int argc, char **argv) interpreter->pop_hook = sfnt_pop_hook; } - for (i = 0; i < ARRAYELTS (all_tests); ++i) + for (i = 0; i < countof (all_tests); ++i) sfnt_run_interpreter_test (&all_tests[i], interpreter); exit (0); diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c index 55f9c9e9078..7a2e4cb3f8f 100644 --- a/src/sfntfont-android.c +++ b/src/sfntfont-android.c @@ -701,7 +701,7 @@ loaded before character sets are made available. */) /* Scan through each of the system font directories. Enumerate each font that looks like a TrueType font. */ - for (i = 0; i < ARRAYELTS (system_font_directories); ++i) + for (i = 0; i < countof (system_font_directories); ++i) { dir = opendir (system_font_directories[i]); diff --git a/src/sfntfont.c b/src/sfntfont.c index 858c5449ac7..39a3afadfb0 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -486,7 +486,7 @@ sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc) { /* Weight hasn't been found yet. Scan through the weight table. */ - for (i = 0; i < ARRAYELTS (sfnt_weight_descriptions); ++i) + for (i = 0; i < countof (sfnt_weight_descriptions); ++i) { if (!strcmp (sfnt_weight_descriptions[i].c_string, single)) @@ -503,7 +503,7 @@ sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc) { /* Slant hasn't been found yet. Scan through the slant table. */ - for (i = 0; i < ARRAYELTS (sfnt_slant_descriptions); ++i) + for (i = 0; i < countof (sfnt_slant_descriptions); ++i) { if (!strcmp (sfnt_slant_descriptions[i].c_string, single)) @@ -520,7 +520,7 @@ sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc) { /* Width hasn't been found yet. Scan through the width table. */ - for (i = 0; i < ARRAYELTS (sfnt_width_descriptions); ++i) + for (i = 0; i < countof (sfnt_width_descriptions); ++i) { if (!strcmp (sfnt_width_descriptions[i].c_string, single)) @@ -1998,7 +1998,7 @@ sfntfont_list (struct frame *f, Lisp_Object font_spec) for (desc = system_fonts; desc; desc = desc->next) { rc = sfntfont_list_1 (desc, font_spec, instances, - ARRAYELTS (instances)); + countof (instances)); if (rc < 0) matching = Fcons (sfntfont_desc_to_entity (desc, 0), diff --git a/src/sound.c b/src/sound.c index 5c2dfa08e21..fc68f98457e 100644 --- a/src/sound.c +++ b/src/sound.c @@ -1312,7 +1312,7 @@ do_play_sound (const char *psz_file_or_data, unsigned long ui_volume, bool in_me wcscat (sz_cmd_buf_w, fname_w); wcscat (sz_cmd_buf_w, L"\" alias GNUEmacs_PlaySound_Device wait"); mci_error = mciSendStringW (sz_cmd_buf_w, - sz_ret_buf_w, ARRAYELTS (sz_ret_buf_w) , NULL); + sz_ret_buf_w, countof (sz_ret_buf_w) , NULL); } if (mci_error != 0) { diff --git a/src/sysdep.c b/src/sysdep.c index 2f48b7c6681..069e052d3ab 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -430,7 +430,7 @@ init_baud_rate (int fd) #endif /* not DOS_NT */ } - baud_rate = (emacs_ospeed < ARRAYELTS (baud_convert) + baud_rate = (emacs_ospeed < countof (baud_convert) ? baud_convert[emacs_ospeed] : 9600); if (baud_rate == 0) baud_rate = 1200; @@ -3136,7 +3136,7 @@ static const struct speed_struct speeds[] = static speed_t convert_speed (speed_t speed) { - for (ptrdiff_t i = 0; i < ARRAYELTS (speeds); i++) + for (ptrdiff_t i = 0; i < countof (speeds); i++) { if (speed == speeds[i].internal) return speed; @@ -3356,7 +3356,7 @@ list_system_processes (void) int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PROC}; #endif size_t len; - size_t mibsize = ARRAYELTS (mib); + size_t mibsize = countof (mib); struct kinfo_proc *procs; size_t i; diff --git a/src/term.c b/src/term.c index cd8c9717640..2261293a60b 100644 --- a/src/term.c +++ b/src/term.c @@ -1427,7 +1427,7 @@ term_get_fkeys_1 (void) if (!KEYMAPP (KVAR (kboard, Vinput_decode_map))) kset_input_decode_map (kboard, Fmake_sparse_keymap (Qnil)); - for (i = 0; i < ARRAYELTS (keys); i++) + for (i = 0; i < countof (keys); i++) { char *sequence = tgetstr (keys[i].cap, address); if (sequence) diff --git a/src/w32.c b/src/w32.c index 409d4238bc9..4be30fc5ec4 100644 --- a/src/w32.c +++ b/src/w32.c @@ -1957,7 +1957,7 @@ static unsigned num_of_processors; /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */ static struct load_sample samples[16*60]; static int first_idx = -1, last_idx = -1; -static int max_idx = ARRAYELTS (samples); +static int max_idx = countof (samples); static int buf_next (int from) @@ -2870,7 +2870,7 @@ init_environment (char ** argv) int i; - const int imax = ARRAYELTS (tempdirs); + const int imax = countof (tempdirs); /* Implementation note: This function explicitly works with ANSI file names, not with UTF-8 encoded file names. This is because @@ -2943,7 +2943,7 @@ init_environment (char ** argv) {"LANG", NULL}, }; -#define N_ENV_VARS ARRAYELTS (dflt_envvars) +#define N_ENV_VARS countof (dflt_envvars) /* We need to copy dflt_envvars[] and work on the copy because we don't want the dumped Emacs to inherit the values of diff --git a/src/w32console.c b/src/w32console.c index ea62d59a787..30a1f65f43f 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -215,7 +215,7 @@ w32con_clear_frame (struct frame *f) static struct glyph glyph_base[80]; static struct glyph *glyphs = glyph_base; -static size_t glyphs_len = ARRAYELTS (glyph_base); +static size_t glyphs_len = countof (glyph_base); static BOOL ceol_initialized = FALSE; /* Clear from Cursor to end (what's "standout marker"?). */ diff --git a/src/w32fns.c b/src/w32fns.c index 1749f2ba390..726fe52affc 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -838,7 +838,7 @@ w32_default_color_map (void) cmap = Qnil; - for (i = 0; i < ARRAYELTS (w32_color_map); pc++, i++) + for (i = 0; i < countof (w32_color_map); pc++, i++) cmap = Fcons (Fcons (build_string (pc->name), make_fixnum (pc->colorref)), cmap); @@ -2834,7 +2834,7 @@ w32_createwindow (struct frame *f, int *coords) } /* Reset F's touch point array. */ - for (i = 0; i < ARRAYELTS (f->output_data.w32->touch_ids); ++i) + for (i = 0; i < countof (f->output_data.w32->touch_ids); ++i) f->output_data.w32->touch_ids[i] = -1; /* Assign an offset for touch points reported to F. */ @@ -4173,7 +4173,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, windows_msg.time = GetMessageTime (); TranslateMessage (&windows_msg); } - count = get_wm_chars (hwnd, buf, ARRAYELTS (buf), 1, + count = get_wm_chars (hwnd, buf, countof (buf), 1, /* The message may have been synthesized by who knows what; be conservative. */ modifier_set (VK_LCONTROL) @@ -8413,7 +8413,7 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, file_details_w->lStructSize = sizeof (*file_details_w); /* Set up the inout parameter for the selected file name. */ file_details_w->lpstrFile = filename_buf_w; - file_details_w->nMaxFile = ARRAYELTS (filename_buf_w); + file_details_w->nMaxFile = countof (filename_buf_w); file_details_w->hwndOwner = FRAME_W32_WINDOW (f); /* Undocumented Bug in Common File Dialog: If a filter is not specified, shell links are not resolved. */ @@ -8446,7 +8446,7 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, else file_details_a->lStructSize = sizeof (*file_details_a); file_details_a->lpstrFile = filename_buf_a; - file_details_a->nMaxFile = ARRAYELTS (filename_buf_a); + file_details_a->nMaxFile = countof (filename_buf_a); file_details_a->hwndOwner = FRAME_W32_WINDOW (f); file_details_a->lpstrFilter = filter_a; file_details_a->lpstrInitialDir = dir_a; diff --git a/src/w32proc.c b/src/w32proc.c index b89979c7314..52d7ef9b5a7 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -4220,7 +4220,7 @@ nl_langinfo (nl_item item) { 210, 297 } }; int idx = atoi (nl_langinfo_buf); - if (0 <= idx && idx < ARRAYELTS (paper_size)) + if (0 <= idx && idx < countof (paper_size)) retval = (char *)(intptr_t) (item == _NL_PAPER_WIDTH ? paper_size[idx][0] : paper_size[idx][1]); diff --git a/src/w32term.c b/src/w32term.c index ccf5d14cb10..728f6ce856d 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -276,7 +276,7 @@ int event_record_index; record_event (char *locus, int type) { - if (event_record_index == ARRAYELTS (event_record)) + if (event_record_index == countof (event_record)) event_record_index = 0; event_record[event_record_index].locus = locus; @@ -5259,7 +5259,7 @@ w32_read_socket (struct terminal *terminal, hlinfo->mouse_face_hidden = true; } - if (temp_index == ARRAYELTS (temp_buffer)) + if (temp_index == countof (temp_buffer)) temp_index = 0; temp_buffer[temp_index++] = msg.msg.wParam; inev.kind = NON_ASCII_KEYSTROKE_EVENT; @@ -5285,7 +5285,7 @@ w32_read_socket (struct terminal *terminal, hlinfo->mouse_face_hidden = true; } - if (temp_index == ARRAYELTS (temp_buffer)) + if (temp_index == countof (temp_buffer)) temp_index = 0; temp_buffer[temp_index++] = msg.msg.wParam; @@ -5400,7 +5400,7 @@ w32_read_socket (struct terminal *terminal, hlinfo->mouse_face_hidden = true; } - if (temp_index == ARRAYELTS (temp_buffer)) + if (temp_index == countof (temp_buffer)) temp_index = 0; temp_buffer[temp_index++] = msg.msg.wParam; inev.kind = MULTIMEDIA_KEY_EVENT; diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index 2266dadcac5..6f468423bb2 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c @@ -882,7 +882,7 @@ uniscribe_check_otf_1 (HDC context, Lisp_Object script, Lisp_Object lang, { SCRIPT_CACHE cache = NULL; OPENTYPE_TAG tags[128], script_tag, lang_tag; - int max_tags = ARRAYELTS (tags); + int max_tags = countof (tags); int ntags, i, ret = 0; HRESULT rslt; diff --git a/src/xdisp.c b/src/xdisp.c index 2b4af7d877e..1691bd0d80e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3145,7 +3145,7 @@ funcall_with_backtraces (ptrdiff_t nargs, Lisp_Object *args) } #define SAFE_CALLMANY(inhibit_quit, f, array) \ - dsafe__call (inhibit_quit, f, ARRAYELTS (array), array) + dsafe__call (inhibit_quit, f, countof (array), array) #define dsafe_calln(inhibit_quit, ...) \ SAFE_CALLMANY (inhibit_quit, \ backtrace_on_redisplay_error \ @@ -7093,7 +7093,7 @@ load_overlay_strings (struct it *it, ptrdiff_t charpos) { ptrdiff_t n = 0; struct overlay_entry entriesbuf[20]; - ptrdiff_t size = ARRAYELTS (entriesbuf); + ptrdiff_t size = countof (entriesbuf); struct overlay_entry *entries = entriesbuf; struct itree_node *node; @@ -12248,7 +12248,7 @@ vadd_to_log (char const *format, va_list ap) ptrdiff_t form_nargs = format_nargs (format); ptrdiff_t nargs = 1 + form_nargs; Lisp_Object args[10]; - eassert (nargs <= ARRAYELTS (args)); + eassert (nargs <= countof (args)); AUTO_STRING (args0, format); args[0] = args0; for (ptrdiff_t i = 1; i < nargs; i++) diff --git a/src/xfaces.c b/src/xfaces.c index 010b0e1847e..73d475c757f 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -458,7 +458,7 @@ DEFUN ("dump-colors", Fdump_colors, Sdump_colors, 0, 0, 0, putc ('\n', stderr); - for (i = n = 0; i < ARRAYELTS (color_count); ++i) + for (i = n = 0; i < countof (color_count); ++i) if (color_count[i]) { fprintf (stderr, "%3d: %5d", i, color_count[i]); @@ -5807,14 +5807,14 @@ Value is ORDER. */) { Lisp_Object list; int i; - int indices[ARRAYELTS (font_sort_order)]; + int indices[countof (font_sort_order)]; CHECK_LIST (order); memset (indices, 0, sizeof indices); i = 0; for (list = order; - CONSP (list) && i < ARRAYELTS (indices); + CONSP (list) && i < countof (indices); list = XCDR (list), ++i) { Lisp_Object attr = XCAR (list); @@ -5836,9 +5836,9 @@ Value is ORDER. */) indices[i] = xlfd; } - if (!NILP (list) || i != ARRAYELTS (indices)) + if (!NILP (list) || i != countof (indices)) signal_error ("Invalid font sort order", order); - for (i = 0; i < ARRAYELTS (font_sort_order); ++i) + for (i = 0; i < countof (font_sort_order); ++i) if (indices[i] == 0) signal_error ("Invalid font sort order", order); @@ -7340,7 +7340,7 @@ DEFUN ("dump-face", Fdump_face, Sdump_face, 0, 1, 0, doc: /* */) int i; fputs ("font selection order: ", stderr); - for (i = 0; i < ARRAYELTS (font_sort_order); ++i) + for (i = 0; i < countof (font_sort_order); ++i) fprintf (stderr, "%d ", font_sort_order[i]); putc ('\n', stderr); diff --git a/src/xfns.c b/src/xfns.c index 2a1d3f5860e..0750a444e81 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -3070,7 +3070,7 @@ best_xim_style (struct x_display_info *dpyinfo, XIMStyles *xim) { int i, j; - int nr_supported = ARRAYELTS (supported_xim_styles); + int nr_supported = countof (supported_xim_styles); if (dpyinfo->preferred_xim_style) return dpyinfo->preferred_xim_style; diff --git a/src/xgselect.c b/src/xgselect.c index 97f2c3391d9..0d2de12654f 100644 --- a/src/xgselect.c +++ b/src/xgselect.c @@ -112,7 +112,7 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, bool have_wfds = wfds != NULL; GPollFD gfds_buf[128]; GPollFD *gfds = gfds_buf; - int gfds_size = ARRAYELTS (gfds_buf); + int gfds_size = countof (gfds_buf); int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1; int i, nfds, tmo_in_millisec, must_free = 0; bool need_to_dispatch; diff --git a/src/xterm.c b/src/xterm.c index 358e01c776a..ddbf8e06664 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5142,7 +5142,7 @@ int event_record_index; void record_event (char *locus, int type) { - if (event_record_index == ARRAYELTS (event_record)) + if (event_record_index == countof (event_record)) event_record_index = 0; event_record[event_record_index].locus = locus; @@ -17807,7 +17807,7 @@ static int temp_index; static short temp_buffer[100]; #define STORE_KEYSYM_FOR_DEBUG(keysym) \ - if (temp_index == ARRAYELTS (temp_buffer)) \ + if (temp_index == countof (temp_buffer)) \ temp_index = 0; \ temp_buffer[temp_index++] = (keysym) @@ -29921,7 +29921,7 @@ x_intern_cached_atom (struct x_display_info *dpyinfo, && !strcmp (name, dpyinfo->motif_drag_atom_name)) return dpyinfo->motif_drag_atom; - for (i = 0; i < ARRAYELTS (x_atom_refs); ++i) + for (i = 0; i < countof (x_atom_refs); ++i) { ptr = (char *) dpyinfo; @@ -30009,7 +30009,7 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom atom, return xstrdup (buffer); } - for (i = 0; i < ARRAYELTS (x_atom_refs); ++i) + for (i = 0; i < countof (x_atom_refs); ++i) { ref_atom = *(Atom *) (dpyinfo_pointer + x_atom_refs[i].offset); @@ -31515,7 +31515,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) XScreenNumberOfScreen (dpyinfo->screen)); { - enum { atom_count = ARRAYELTS (x_atom_refs) }; + enum { atom_count = countof (x_atom_refs) }; /* 1 for _XSETTINGS_SN. */ enum { total_atom_count = 2 + atom_count }; Atom atoms_return[total_atom_count]; From b174382a2dfaf77af0709c0ad87ad8db9cc46dc7 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 26 May 2026 22:21:08 -0700 Subject: [PATCH 112/112] Also copy lib/mini-gmp-gnulib.c from Gnulib --- lib/mini-gmp-gnulib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mini-gmp-gnulib.c b/lib/mini-gmp-gnulib.c index b309d2555f9..d3bb998c4bd 100644 --- a/lib/mini-gmp-gnulib.c +++ b/lib/mini-gmp-gnulib.c @@ -39,6 +39,10 @@ # pragma GCC diagnostic ignored "-Wsuggest-attribute=malloc" #endif +#if _GL_GNUC_PREREQ (14, 0) +# pragma GCC diagnostic ignored "-Wuseless-cast" +#endif + /* Pacify GCC -Wunused-variable for variables used only in 'assert' calls. */ #if (defined NDEBUG \ && (4 < __GNUC__ + (6 <= __GNUC_MINOR__) || defined __clang__))