;;; -*- Mode:LISP; Package:USER; Base:10; Readtable:ZL -*- #|| Copyright LISP Machine, Inc. 1986 See filename "Copyright.Text" for licensing and release information. ********************************************************* ********************************************************* *** NOTE: This is an EXAMPLE, not LMI supported code. *** *** information contained in this example is subject *** *** to change without notice. The ways of doing *** *** the things contained in the example may change *** *** between system releases. Some techniques which *** *** are mere examples in one release may become built *** *** in system features in the next release. Use good *** *** judgement when copying these techniques. Most *** *** examples have been motivated by specific customer *** *** requests, and may not be the best engineered *** *** or most efficient solution for someone else. *** ********************************************************* ********************************************************* Search for a set of strings in a source file. (SOMETIME CONSIDERABLY BEFORE) 27-May-86 19:03:13 -GJC ||# (defun search-files (specification strings &optional &key output-file (window 3) (version :newest) (type :lisp)) (if output-file (with-open-file (stream output-file :direction :output) (search-files-1 specification (if (atom strings) (list strings) strings) stream window version type)) (search-files-1 specification (if (atom strings) (list strings) strings) standard-output window version type))) (defun search-files-1 (specification strings output-stream window version type) (OR (FBOUNDP'MAP-ALL-FILES) (LOAD "SYS:EXAMPLES;FILE-UTILS" :SET-DEFAULT-PATHNAME NIL)) (COND ((SYMBOLP SPECIFICATION) (DOLIST (FILE (SI:SYSTEM-SOURCE-FILES SPECIFICATION)) (SEARCH-ONE-FILE (SEND (OPEN FILE :DIRECTION NIL) :TRUENAME) STRINGS OUTPUT-STREAM WINDOW))) ('ELSE (MAP-ALL-FILES #'(LAMBDA (FILE) (SEARCH-ONE-FILE FILE STRINGS OUTPUT-STREAM WINDOW)) specification :version version :type type)))) (defun multiple-string-search (strings string start end) (dolist (s strings) (if (string-search s string start end) (return-from multiple-string-search t)))) (DEFUN SEARCH-ONE-FILE (FILE STRINGS OUTPUT-STREAM WINDOW) (FORMAT OUTPUT-STREAM "~&In ~A~%" FILE) (LET ((LINE-NUMBER 0) (LAST-FOUND-LINE)) (MAP-OVER-FILE-LINES #'(LAMBDA (STRING START END) (INCF LINE-NUMBER) (COND ((MULTIPLE-STRING-SEARCH STRINGS STRING START END) (SETQ LAST-FOUND-LINE LINE-NUMBER) (FORMAT OUTPUT-STREAM "~4D* " LINE-NUMBER) (SEND OUTPUT-STREAM :LINE-OUT STRING START END)) ((AND LAST-FOUND-LINE (< (- LINE-NUMBER LAST-FOUND-LINE) WINDOW)) (FORMAT OUTPUT-STREAM "~4D> " LINE-NUMBER) (SEND OUTPUT-STREAM :LINE-OUT STRING START END)))) FILE))) (defun map-over-file-lines (f filename) "Function F gets called on STRING START END for each line in the file" ;; This is maximally bummed. Better than using :string-line-in ;; because it doesnt copy unless on boundaries. (with-open-file (s filename) (cond ((equal 8 (get s :byte-size)) (map-over-stream-lines f s)) ('else (format t "Byte size # 8, skipping"))))) (defun map-over-stream-lines (f from-stream) (prog (offset limit start end leftover leftoverp easy-lines hard-lines buf) (setq easy-lines 0 hard-lines 0) read-buffer (multiple-value (buf offset limit) (send from-stream :read-input-buffer)) (UNLESS BUF (WHEN LEFTOVERP (FUNCALL F LEFTOVER 0 (FILL-POINTER LEFTOVER)) (INCF HARD-LINES)) (return (values easy-lines hard-lines))) (setq start offset) next-line (setq end (%string-search-char #\RETURN buf start limit)) (cond ((null end) (or leftover (setq leftover (make-array 300 :element-type 'string-char :fill-pointer 0))) (UNLESS (ZEROP (setf (fill-pointer leftover) (- limit start))) (copy-array-portion buf start limit leftover 0 (- limit start))) (send from-stream :advance-input-buffer) (setq leftoverp t) (go read-buffer)) ((not leftoverp) (funcall f buf start end) (setq start (1+ end)) (incf easy-lines) (go next-line)) ('else (let* ((old-fp (fill-pointer leftover)) (new-fp (+ old-fp (- end start)))) (setf (fill-pointer leftover) new-fp) (copy-array-portion buf start end leftover old-fp new-fp) (funcall f leftover 0 new-fp) (setq leftoverp nil) (setq start (1+ end)) (incf hard-lines) (go next-line)))))) #|| ;; reference version. (defun map-over-stream-lines (f from-stream) (do ((line)(eof)) ((progn (multiple-value-setq (line eof) (send from-stream :line-in)) eof)) (funcall f line 0 (length line)))) #||