;;; -*- Mode:Lisp; Readtable:ZL; Package:USER; Base:8; Patch-File:T -*- ;;; Patch file for System version 123.266 ;;; Reason: ;;; Fix zwei "C-sh-S" (Lisp Match Search) command. No longer loops at end ;;; of buffer if pattern not found. "#" now matches exactly one s-exp. ;;; Don't enter EH if given a string with nothing but delimiters. ;;; Written 9-May-88 14:17:38 by pld at site Gigamos Cambridge ;;; while running on Azathoth from band 3 ;;; with Experimental System 123.264, Experimental Local-File 73.5, Experimental FILE-Server 22.4, Experimental Unix-Interface 11.0, Experimental KERMIT 34.3, Experimental ZMail 71.2, Experimental Lambda-Diag 15.0, Experimental Tape 22.4, microcode 1756, SDU Boot Tape 3.14, SDU ROM 8, the old ones. ; From modified file DJ: L.ZWEI; COMH.LISP#20 at 9-May-88 14:46:38 #8R ZWEI#: (COMPILER-LET ((*PACKAGE* (PKG-FIND-PACKAGE "ZWEI"))) (COMPILER::PATCH-SOURCE-FILE "SYS: ZWEI; COMH  " (DEFUN LISP-MATCH-SEARCH (BP STRING &OPTIONAL REVERSEP FIXUP-P IGNORE LIMIT-BP &AUX (START 0) (END (LENGTH STRING)) (final-limit-bp (if reversep (interval-first-bp *interval*) (interval-last-bp *interval*)))) "Search from BP for Lisp code that matches against STRING. Matching at any given place is done with LISP-STRING-BUFFER-MATCH. Differences in whitespace characters are ignored except when quoted or inside strings. The characters # as an atom in the STRING match any sexp in the buffer. The characters ... as an atom in the STRING match any number of sexps. If a match is found, the value is a bp to the end (start, if reverse) of the matching text. A second value is a bp to the start (end, if reverse) of the matching text. REVERSEP means search backward from BP; the code matched must end before BP. Otherwise, search goes forward from BP. LIMIT-BP is a place to stop searching; the matched code cannot continue past there in forward search or begin before there in backward search. FIXUP-P says what to do if no match is found. T means return the end of the range to be searched (either LIMIT-BP or the beginning or end of the interval). NIL means return NIL. Second value is NIL in either case." ;; Ignore leading delimiter chars in STRING. (DO () ((OR (= START END) (NOT (= LIST-DELIMITER (LIST-SYNTAX (CHAR STRING START)))))) (INCF START)) ;; Strings that start with ... or # are handled specially. (COND ((= START END) (AND FIXUP-P (OR LIMIT-BP FINAL-LIMIT-BP))) ((AND (STRING-EQUAL STRING "..." :START1 START :END1 (+ START 3)) (OR (= (+ START 3) END) (NOT (MEMQ (LIST-SYNTAX (CHAR STRING (+ START 3))) '(#,LIST-ALPHABETIC #,LIST-SINGLE-QUOTE))))) (BARF "A search pattern starting with ... is not meaningful.")) ((AND (STRING-EQUAL STRING "#" :START1 START :END1 (+ START 1)) (OR (= (+ START 2) END) (NOT (MEMQ (LIST-SYNTAX (CHAR STRING (+ START 2))) '(#,LIST-ALPHABETIC #,LIST-SINGLE-QUOTE))))) (LET ((TAIL-FOUND (LISP-MATCH-SEARCH (FORWARD-SEXP BP 1 T) (SUBSTRING STRING (+ START 3))))) (OR (AND TAIL-FOUND (FORWARD-SEXP TAIL-FOUND -1 NIL 0 BP T T)) (AND FIXUP-P LIMIT-BP FINAL-LIMIT-BP)))) (REVERSEP (LET ((BP1 (COPY-BP BP)) TEM) (DO-FOREVER (SETQ BP1 (ZWEI-SEARCH BP1 (CHAR STRING START) T NIL NIL (OR LIMIT-BP FINAL-LIMIT-BP))) (UNLESS BP1 (RETURN (AND FIXUP-P (OR LIMIT-BP FINAL-LIMIT-BP)))) (IF (SETQ TEM (LISP-STRING-BUFFER-MATCH BP1 BP STRING START)) (RETURN (VALUES BP1 TEM)))))) (T (LET ((BP1 (COPY-BP BP)) TEM) (DO-FOREVER (SETQ BP1 (ZWEI-SEARCH BP1 (CHAR STRING START) NIL NIL NIL LIMIT-BP)) (UNLESS BP1 (RETURN (AND FIXUP-P (OR LIMIT-BP FINAL-LIMIT-BP)))) (DBP BP1) (IF (SETQ TEM (LISP-STRING-BUFFER-MATCH BP1 (OR LIMIT-BP FINAL-LIMIT-BP) STRING START)) (RETURN (VALUES TEM BP1))) (IF (OR (BP-= BP1 LIMIT-BP) (BP-= BP1 FINAL-LIMIT-BP)) (RETURN (IF FIXUP-P BP1))) (UNLESS (IBP BP1) (RETURN (IF FIXUP-P BP1 NIL)))))))) )) ; From modified file DJ: L.ZWEI; COMH.LISP#20 at 9-May-88 15:05:20 #8R ZWEI#: (COMPILER-LET ((*PACKAGE* (PKG-FIND-PACKAGE "ZWEI"))) (COMPILER::PATCH-SOURCE-FILE "SYS: ZWEI; COMH  " (DEFUN LISP-STRING-BUFFER-MATCH (START-BP LIMIT-BP PATTERN-STRING &OPTIONAL (START 0) END) "Match part of a string against part of an editor buffer, comparing as Lisp code. The string is PATTERN-STRING; START and END specify the range to use. The buffer text starts at START-BP. It will not match past LIMIT-BP. If there is a match, the value is a bp to the end of the buffer text matched. Otherwise, the value is NIL. Differences in whitespace characters are ignored except when quoted or inside strings. The characters # as an atom in the PATTERN-STRING match any sexp in the buffer. The characters ... as an atom in the PATTERN-STRING match any number of sexps." (UNLESS END (SETQ END (LENGTH PATTERN-STRING))) (DO-NAMED OUTER ((I START (1+ I)) (BP (COPY-BP START-BP)) IN-STRING QUOTED IN-COMMENT IN-ATOM (P-SYN -1)) ((= I END) BP) (IF (BP-= LIMIT-BP BP) (RETURN NIL)) (LET* ((S-CHAR (CHAR PATTERN-STRING I)) (S-SYN (LIST-SYNTAX S-CHAR))) ;; S-SYN is this pattern character's syntax. ;; P-SYN is the previous significant pattern character's syntax. ;; It is LIST-ALPHABETIC iff the last pattern character, not counting delimiters, ;; was such as to be part of an atom. This is the case in which ;; at least one delimiter is required in the buffer in order to match. (COND (IN-STRING ;; First update the syntactic state. (COND (QUOTED (SETQ QUOTED NIL)) ((= S-SYN LIST-DOUBLE-QUOTE) (SETQ IN-STRING NIL)) ((= S-SYN LIST-SLASH) (SETQ QUOTED T))) ;; Now always match against buffer. (UNLESS (EQ S-CHAR (BP-CH-CHARACTER BP)) (RETURN NIL)) (SETQ P-SYN -1) (IBP BP)) (IN-COMMENT (IF (EQ S-CHAR #/RETURN) (SETQ IN-COMMENT NIL)) ;; Now always match against buffer. (UNLESS (CHAR-EQUAL S-CHAR (BP-CHARACTER BP)) (RETURN NIL)) (SETQ P-SYN -1) (IBP BP)) (QUOTED (SETQ QUOTED NIL) ;; Quoted char, always match against buffer. (UNLESS (EQ S-CHAR (BP-CH-CHARACTER BP)) (RETURN NIL)) (SETQ P-SYN LIST-ALPHABETIC) (IBP BP)) ;; Not in string or comment, not slashified. ((= S-SYN LIST-DELIMITER) ;; Just skip all delimiters in the pattern. (SETQ IN-ATOM NIL)) ((AND (NOT IN-ATOM) (<= (+ I 3) END) (STRING-EQUAL PATTERN-STRING "..." :START1 I :END1 (+ I 3)) (OR (= (+ I 3) END) (NOT (MEMQ (LIST-SYNTAX (CHAR PATTERN-STRING (+ I 3))) '(#,LIST-ALPHABETIC #,LIST-SINGLE-QUOTE))))) ;; "..." has been encountered, and its an atom by itself. (DO-FOREVER ;; Try matching the rest of the pattern at one spot. (LET ((TEM (LISP-STRING-BUFFER-MATCH BP LIMIT-BP PATTERN-STRING (+ I 3) END))) (WHEN TEM (RETURN-FROM OUTER TEM))) ;; SKip one more sexp and try again. (SETQ BP (FORWARD-SEXP BP 1 NIL 0 LIMIT-BP NIL T)) (UNLESS BP (RETURN NIL)))) ((AND (NOT IN-ATOM) (<= (1+ I) END) (STRING-EQUAL PATTERN-STRING "#" :START1 I :END1 (1+ I)) (OR (= (1+ I) END) (NOT (MEMQ (LIST-SYNTAX (CHAR PATTERN-STRING (1+ I))) '(#,LIST-ALPHABETIC #,LIST-SINGLE-QUOTE))))) ;; "#" has been encountered as an atom in the pattern. ;; SKip it, and skip one sexp in the buffer, then keep matching. (SETQ BP (FORWARD-SEXP BP 1 NIL 0 LIMIT-BP NIL T)) (SETQ P-SYN -1) (UNLESS BP (RETURN NIL))) (T ;; Skip all delimiters here in the buffer, if not within an atom. (UNLESS IN-ATOM (DO ((COUNT 0 (1+ COUNT))) ;Count number of delimiters skipped. ((NOT (= LIST-DELIMITER (LIST-SYNTAX (BP-CHARACTER BP)))) (AND (ZEROP COUNT) (= S-SYN LIST-ALPHABETIC) (= P-SYN LIST-ALPHABETIC) (RETURN-FROM OUTER NIL))) (IBP BP))) ;; Set up syntax context of next pattern character. (SELECT S-SYN (LIST-DOUBLE-QUOTE (SETQ IN-STRING T)) (LIST-SLASH (SETQ QUOTED T)) (LIST-COMMENT (SETQ IN-COMMENT T)) (LIST-ALPHABETIC (SETQ IN-ATOM T))) (IF (EQ S-CHAR #/.) (SETQ IN-ATOM T)) ;; Now always match against buffer. (UNLESS (CHAR-EQUAL S-CHAR (BP-CHARACTER BP)) (RETURN NIL)) (IBP BP) (SETQ P-SYN S-SYN)))))) ))