commit 04bab7bb7af3512bc8591d9b050a1ce16bbaa704 Author: Po Lu Date: Fri Oct 23 09:41:48 2026 +0800 Fix the Android build * src/fileio.c [HAVE_TREE_SITTER]: Include "treesit.h" on Android too. diff --git a/java/wrap.sh b/java/wrap.sh new file mode 100644 index 00000000000..763196c7114 --- /dev/null +++ b/java/wrap.sh @@ -0,0 +1,25 @@ +#!/system/bin/sh +HERE=$(cd "$(dirname "$0")" && pwd) +cmd=$1 +shift +# This must be called *before* `LD_PRELOAD` is set. Otherwise, if this is a 32- +# bit app running on a 64-bit device, the 64-bit getprop will fail to load +# because it will preload a 32-bit ASan runtime. +# https://github.com/android/ndk/issues/1744 +os_version=$(getprop ro.build.version.sdk) +if [ "$os_version" -eq "27" ]; then + cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@" +elif [ "$os_version" -eq "28" ]; then + cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@" +else + cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y $@" +fi +export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1 +ASAN_LIB=$(ls "$HERE"/libclang_rt.asan-*-android.so) +if [ -f "$HERE/libc++_shared.so" ]; then + # Workaround for https://github.com/android-ndk/ndk/issues/988. + export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so" +else + export LD_PRELOAD="$ASAN_LIB" +fi +exec $cmd diff --git a/src/fileio.c b/src/fileio.c index 19b8def7a45..e1b46c52854 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -113,12 +113,12 @@ along with GNU Emacs. If not, see . */ #include "commands.h" -#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY - #ifdef HAVE_TREE_SITTER #include "treesit.h" #endif +#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY + /* Type describing a file descriptor used by functions such as `insert-file-contents'. */ commit 0ed4fc46466a6deb7f42e8d410576f5ae434163e Author: Eli Zaretskii Date: Thu Oct 22 19:05:57 2026 +0300 Support quoted node references and menu items in Info * lisp/info.el (Info-find-node-2, Info-insert-dir) (Info-dir-remove-duplicates, Info-select-node) (Info-build-node-completions-1, Info-up, Info-follow-reference) (Info-complete-menu-item, Info-menu, Info-extract-menu-item) (Info-next-reference, Info-prev-reference) (Info-follow-nearest-node, Info-try-follow-nearest-node) (Info-menu-update): Adjust regular expressions to quoted node references. (Info-following-node-name, Info-toc-build): Support quoted node names with commas. (info--maybe-quoted-node): New function to quote node names. (Info-history-find-node, Info-toc-find-node) (Info-virtual-index-nodes, Info-apropos-find-node) (Info-finder-find-node): Call 'info--maybe-quoted-node' to quote node names if necessary. (Info-menu-entry-name-re): Doc fix. (Info-quoted-menu-entry-name-re, Info-quoted-node-name-re) (Info-node-spec-re): New constant regexps. (Info-extract-menu-node-name): Support quoted node names and quoted node-reference labels. Doc fix. (Info-get-token, Info-follow-nearest-node) (Info-try-follow-nearest-node): Doc fixes. (Info-fontify-node): Support quoting in cross-references and menu items. Move regexp concatenation out of the loops. Use variables with mnemonic names instead of 'match-beginning N'. (Bug#57277) diff --git a/lisp/info.el b/lisp/info.el index 1642382aa02..e7305b89f94 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -1282,11 +1282,11 @@ is non-nil)." ;; Search file for a suitable node. (let ((guesspos (point-min)) - (regexp (concat "\\(Node:\\|Ref:\\) *\\(" + (regexp (concat "\\(Node:\\|Ref:\\) *\\(?" (if (stringp nodename) (regexp-quote nodename) "") - "\\) *[,\t\n\177]"))) + "?\\) *[,\t\n\177]"))) (catch 'foo @@ -1522,7 +1522,10 @@ is non-nil)." (let ((menu-items '("top")) (end (save-excursion (search-forward "\^_" nil t) (point)))) (dolist (node nodes) - (let ((nodename (car node))) + (let* ((nodename (car node)) + (need-quoting (string-match-p "[.,:()]" nodename))) + (and need-quoting + (setq nodename (concat "" nodename ""))) (save-excursion (or (member (downcase nodename) menu-items) (re-search-forward (concat "^\\* +" @@ -1539,9 +1542,9 @@ is non-nil)." (nodename (car node))) (goto-char (point-min)) ;; Find the like-named node in the main buffer. - (if (re-search-forward (concat "^\^_.*\n.*Node: " + (if (re-search-forward (concat "^\^_.*\n.*Node: ?" (regexp-quote nodename) - "[,\n\t]") + "?[,\n\t]") nil t) (progn (search-forward "\n\^_" nil 'move) @@ -1549,7 +1552,9 @@ is non-nil)." (insert "\n")) ;; If none exists, add one. (goto-char (point-max)) - (insert "\^_\nFile: dir\tNode: " nodename "\n\n* Menu:\n\n")) + (insert "\^_\nFile: dir\tNode: " + (info--maybe-quoted-node nodename t) + "\n\n* Menu:\n\n")) ;; Merge the text from the other buffer's menu ;; into the menu in the like-named node in the main buffer. (apply #'insert-buffer-substring (cdr node)))) @@ -1624,7 +1629,10 @@ is non-nil)." (save-restriction (narrow-to-region start (point)) (goto-char (point-min)) - (while (re-search-forward "^\\* \\([^:\n]+:[^.\n]+.\\)" nil 'move) + (while (re-search-forward + ;; Non-quoted entry that ends in a ':' or a quoter entry, + ;; followed by an optional unquoted or quoted node + "^\\* \\(\\([^:\n]+:\\|[^\n]+\\)\\([^.\n]+.\\|[^\n]+\\)\\)" nil 'move) ;; Fold case straight away; `member-ignore-case' here wasteful. (let ((x (downcase (match-string 1)))) (if (member x seen) @@ -1797,11 +1805,11 @@ escaped (\\\",\\\\)." (forward-line 1) (signal 'search-failed (list "\n\^_")))) ;; Get nodename spelled as it is in the node. - (re-search-forward "Node:[ \t]*") + (re-search-forward "Node:[ \t]*?") (setq Info-current-node (buffer-substring-no-properties (point) (progn - (skip-chars-forward "^,\t\n") + (skip-chars-forward "^,\t\n") (point)))) (Info-set-mode-line) ;; Find the end of it, and narrow. @@ -2086,7 +2094,8 @@ the Top node in FILENAME." (let ((compl nil) ;; Bind this in case the user sets it to nil. (case-fold-search t) - (node-regexp "Node: *\\([^,\n]*\\) *[,\n\t]")) + (node-regexp + "Node: *\\(\\([^\n]*\\)\\|\\([^,\n]*\\) *[,\n\t]\\)")) (save-excursion (save-restriction (or Info-tag-table-marker @@ -2104,7 +2113,8 @@ the Top node in FILENAME." (goto-char (point-min)) ;; If the buffer begins with a node header, process that first. (if (Info-node-at-bob-matching node-regexp) - (setq compl (list (match-string-no-properties 1)))) + (setq compl (list (or (match-string-no-properties 2) + (match-string-no-properties 3))))) ;; Now for the rest of the nodes. (while (search-forward "\n\^_" nil t) (forward-line 1) @@ -2427,8 +2437,10 @@ End of submatch 0, 1, and 3 are the same, so you can safely concat." "\\|\\)\\)")) ;Allow empty node names. ;; For compatibility; other files have used this name. +;; Note: this is only used for node names on the node heading lines! (defun Info-following-node-name () - (and (looking-at (Info-following-node-name-re)) + (and (or (looking-at "\\([^]\\),") ; quoted node name with commas + (looking-at (Info-following-node-name-re))) (match-string-no-properties 1))) (defun Info-next () @@ -2470,8 +2482,12 @@ If SAME-FILE is non-nil, do not move to a different Info file." (re-search-forward (if (string-equal old-node "Top") (concat "\n\\*[^:]+: +(" (file-name-nondirectory old-file) ")") - (concat "\n\\* +\\(" (regexp-quote old-node) - ":\\|[^:]+: +" (regexp-quote old-node) "\\)")) + (let ((node-to-search + (if (string-match-p "[.,:()]" old-node) + (concat "" old-node "") + old-node))) + (concat "\n\\* +\\(" (regexp-quote node-to-search) + ":\\|[^:]+: +" (regexp-quote node-to-search) "\\)"))) nil t)) (progn (beginning-of-line) (if (looking-at "^\\* ") (forward-char 2))) (goto-char p) @@ -2557,10 +2573,21 @@ If SAME-FILE is non-nil, do not move to a different Info file." "History-specific implementation of `Info-find-file'." filename) +(defun info--maybe-quoted-node (node &optional heading) + "If NODE includes problematic characters, return it quoted with DEL. +NODE must not include the file name. +Optional arg HEADING means check only for commas, which cause problems +in node heading lines. Otherwise check for colons, commas and periods." + (let ((forbidden (if heading "," "[:,.]"))) + (if (string-match-p forbidden node) + (concat "" node "") + node))) + (defun Info-history-find-node (filename nodename &optional _no-going-back) "History-specific implementation of `Info-find-node-2'." (insert (format "\n\^_\nFile: %s, Node: %s, Up: (dir)\n\n" - (or filename Info-current-file) nodename)) + (or filename Info-current-file) + (info--maybe-quoted-node nodename t))) (insert "History of Visited Nodes\n") (insert "************************\n\n") (insert "* Menu:\n\n") @@ -2569,7 +2596,7 @@ If SAME-FILE is non-nil, do not move to a different Info file." (let ((file (nth 0 (car hl))) (node (nth 1 (car hl)))) (if (stringp file) - (insert "* " node ": (" + (insert "* " (info--maybe-quoted-node node) ": (" (propertize (or (file-name-directory file) "") 'invisible t) (file-name-nondirectory file) ")" node ".\n"))) @@ -2593,7 +2620,7 @@ If SAME-FILE is non-nil, do not move to a different Info file." (curr-node (substring-no-properties (or nodename Info-current-node))) (node-list (Info-toc-nodes curr-file))) (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n" - curr-file curr-node)) + curr-file (info--maybe-quoted-node curr-node t))) (insert "Table of Contents\n") (insert "*****************\n\n") (insert "*Note Top::\n") @@ -2654,10 +2681,13 @@ Table of contents is created from the tree structure of menus." (let* ((nodename (substring-no-properties (Info-following-node-name))) (bound (- (or (save-excursion (search-forward "\n\^_" nil t)) (point-max)) 2)) - (upnode (and (re-search-forward - (concat "Up:" (Info-following-node-name-re)) - bound t) - (match-string-no-properties 1))) + (upnode (or (save-excursion + (and (search-forward "Up: " bound t) + (Info-following-node-name))) + (and (re-search-forward + (concat "Up:" (Info-following-node-name-re)) + bound t) + (match-string-no-properties 1)))) (section "Top") menu-items) (when (and upnode (string-search "(" upnode)) (setq upnode nil)) @@ -2673,7 +2703,7 @@ Table of contents is created from the tree structure of menus." (while (< (point) bound) (cond ;; Menu item line - ((looking-at "^\\* +[^:]+:") + ((looking-at "^\\* +\\([^]+\\|[^:]+:\\)") (beginning-of-line) (forward-char 2) (let ((menu-node-name (substring-no-properties @@ -2745,8 +2775,10 @@ new buffer." (setq eol (line-end-position) bol (line-beginning-position)) (goto-char (point-min)) - (while (re-search-forward "\\*note[ \n\t]+\\([^:]*\\):" nil t) - (setq str (match-string-no-properties 1)) + (while (re-search-forward + "\\(\\*note[ \n\t]+\\([^:]*\\):\\)\\|\\(\\*note[ \n\t]+\\([^]*\\)\\)" nil t) + (setq str (or (match-string-no-properties 2) ; xref without quoting + (match-string-no-properties 4))) ; quoted xref ;; See if this one should be the default. (and (null default) (<= (match-beginning 0) start-point) @@ -2788,7 +2820,7 @@ new buffer." (unless footnotename (error "No reference was specified")) - (let (target i (str (concat "\\*note " (regexp-quote footnotename))) + (let (target i (str (concat "\\*note ?" (regexp-quote footnotename))) (case-fold-search t)) (while (setq i (string-search " " str i)) (setq str (concat (substring str 0 i) "[ \t\n]+" (substring str (1+ i)))) @@ -2796,13 +2828,13 @@ new buffer." (save-excursion ;; Move point to the beginning of reference if point is on reference (or (looking-at "\\*note[ \n\t]+") - (and (looking-back "\\*note[ \n\t]+" - (save-excursion (skip-chars-backward " \n\t") + (and (looking-back "\\*note[ \n\t]+?" + (save-excursion (skip-chars-backward " \n\t") (line-beginning-position))) (goto-char (match-beginning 0))) (if (and (save-excursion (goto-char (+ (point) 5)) ; skip a possible *note - (re-search-backward "\\*note[ \n\t]+" nil t) + (re-search-backward "\\*note[ \n\t]+?" nil t) (looking-at str)) (<= (point) (match-end 0))) (goto-char (match-beginning 0)))) @@ -2829,37 +2861,121 @@ new buffer." ;; We allow newline because this is also used in Info-follow-reference, ;; where the xref name might be wrapped over two lines. "Regexp that matches a menu entry name up to but not including the colon. +This is used to extract node names from menu entries and cross-references. +The match is tested starting at character after the initial \"* \" at the +beginning of a menu-entry line, or after skipping \"*note[ \n\t]+\" of +a cross-reference. That is, the match starts where the menu entry or the +label of the cross-reference should begin. Because of ambiguities, this should be concatenated with something like `:' and `Info-following-node-name-re'.") + +(defconst Info-quoted-menu-entry-name-re + "[ \t\n]*\\([^]+\\)[ \t\n]*" + "Like `Info-menu-entry-name-re', but for entries quoted by DEL.") + +(defconst Info-quoted-node-name-re + "[ \t\n]*\\(([^)]+)\\)?\\([^]+\\)" + "Quoted node name, with or without (INFOFILE).") + (defun Info-extract-menu-node-name (&optional multi-line index-node) + "Extract the node name at point in a menu entry or a cross-reference. +Optional argument MULTI-LINE, if non-nil, means the node name is allowed +2648to span multiple lines; this happens in cross-references. +Optional argument INDEX-NODE, if non-nil, is the index node as returned +by `Info-index-node'; this happens in menus in Index nodes. +This function is called where a match for `Info-menu-entry-name-re' +should begin, i.e. after getting past \"* \" of a menu line or the +cross-reference marker \"*note\" and the following whitespace. +Value is the node name, a string." (skip-chars-forward " \t\n") - (when (looking-at (concat Info-menu-entry-name-re ":\\(:\\|" - (Info-following-node-name-re - (cond - (index-node "^,\t\n") - (multi-line "^.,\t") - (t "^.,\t\n"))) - "\\)" - (if index-node - "\\.\\(?:[ \t\n]+(line +\\([0-9]+\\))\\)?" - ""))) + (cond + ;; First, try quoted menu entry and/or quoted node name. + ((looking-at (concat Info-quoted-menu-entry-name-re + ":\\(:\\|" Info-quoted-node-name-re "\\)" + (if index-node + "\\.\\(?:[ \t\n]+(line +\\([0-9]+\\))\\)?"))) (if index-node (setq Info-point-loc (if (match-beginning 5) (string-to-number (match-string 5)) - (buffer-substring-no-properties - (match-beginning 0) (1- (match-beginning 1))))) + ;; Strip whitespace, if any, from end of menu entry. + (info--node-canonicalize-whitespace + (match-string-no-properties 1)))) + ) + (if (string-equal (match-string 2) ":") + (match-string-no-properties 1) ; entry is actually a node name + ;; File (possibly empty) + node + (concat (match-string-no-properties 3) (match-string-no-properties 4)))) + + ;; Menu entry that is a file with quoted node name (cannot be in index) + ((looking-at (concat Info-quoted-node-name-re "::")) + (concat (match-string-no-properties 1) (match-string-no-properties 2))) + + ;; Quoted menu entry and unquoted node name + ((looking-at (concat Info-quoted-menu-entry-name-re ":\\(:\\|" + (Info-following-node-name-re + (cond + (index-node "^,\t\n") + (multi-line "^.,\t") + (t "^.,\t\n"))) + "\\)" + (if index-node + "\\.\\(?:[ \t\n]+(line +\\([0-9]+\\))\\)?" + ""))) + (if index-node + (setq Info-point-loc + (if (match-beginning 6) + (string-to-number (match-string 6)) + ;; Strip whitespace, if any, from end of menu entry. + (info--node-canonicalize-whitespace + (match-string-no-properties 1)))) + ) + (match-string-no-properties 2)) + + ;; Unquoted menu entry and quoted node + ((looking-at (concat Info-menu-entry-name-re ":\\(" + Info-quoted-node-name-re "\\)" + (if index-node + "\\.\\(?:[ \t\n]+(line +\\([0-9]+\\))\\)?"))) + (if index-node + (setq Info-point-loc + (if (match-beginning 4) + (string-to-number (match-string 4)) + ;; Strip whitespace, if any, from end of menu entry. + (info--node-canonicalize-whitespace + (buffer-substring-no-properties + (match-beginning 0) (1- (match-beginning 1)))))) + ) + (concat (match-string-no-properties 2) (match-string-no-properties 3))) + + ;; Both menu entry and node unquoted + ((looking-at (concat Info-menu-entry-name-re ":\\(:\\|" + (Info-following-node-name-re + (cond + (index-node "^,\t\n") + (multi-line "^.,\t") + (t "^.,\t\n"))) + "\\)" + (if index-node + "\\.\\(?:[ \t\n]+(line +\\([0-9]+\\))\\)?" + ""))) + (if index-node + (setq Info-point-loc + (if (match-beginning 5) + (string-to-number (match-string 5)) + (buffer-substring-no-properties + (match-beginning 0) (1- (match-beginning 1))))) ;;; Uncomment next line to use names of cross-references in non-index nodes: ;;; (setq Info-point-loc ;;; (buffer-substring (match-beginning 0) (1- (match-beginning 1)))) - ) - (info--node-canonicalize-whitespace - (or (and (not (equal (match-string-no-properties 2) "")) - (match-string-no-properties 2)) - ;; If the node name is the menu entry name (using `entry::'). - (buffer-substring-no-properties - (match-beginning 0) (1- (match-beginning 1))))))) + ) + (info--node-canonicalize-whitespace + (or (and (not (equal (match-string-no-properties 2) "")) + (match-string-no-properties 2)) + ;; If the node name is the menu entry name (using `entry::'). + (buffer-substring-no-properties + (match-beginning 0) (1- (match-beginning 1)))))))) (defun info--node-canonicalize-whitespace (string) (replace-regexp-in-string "[ \t\n]+" " " string)) @@ -2879,6 +2995,16 @@ Because of ambiguities, this should be concatenated with something like (concat (Info-following-node-name-re "^.,:") "[,:.]") "Regexp to match the text after a : until the terminating `.'.") +;; :: +;;