(DEFINE-FILE-INFO READTABLE "XCL" PACKAGE "XCL") (il:filecreated " 2-Nov-87 15:12:49" il:|{POGO:AISNORTH:XEROX}<CUTTING>LISP>NEW-WHERE-IS.;4| 18589 il:|changes| il:|to:| (il:functions get-where-is-entries del-where-is-database) il:|previous| il:|date:| "26-Oct-87 12:42:24" il:|{POGO:AISNORTH:XEROX}<CUTTING>LISP>NEW-WHERE-IS.;3|) ; Copyright (c) 1987 by Xerox Corporation. All rights reserved. (il:prettycomprint il:new-where-iscoms) (il:rpaqq il:new-where-iscoms ((il:prop (il:makefile-environment il:filetype) il:new-where-is) (il:p (provide "WHERE-IS") (require "HASH-FILE" "HASH-FILE.DFASL") (require "CASH-FILE" "CASH-FILE.DFASL") (case il:makesysname (:lyric (il:filesload (il:sysload) il:filepkg-patch)))) (il:coms (il:* il:|;;| "run time code") (il:functions hash-file-where-is hash-file-types-of get-where-is-entries add-where-is-databases add-where-is-database del-where-is-database same-where-is-database close-where-is-files) (il:addvars (il:aroundexitfns close-where-is-files)) (il:variables *where-is-cash-files* *where-is-cash-size*)) (il:coms (il:* il:|;;| "notice time code") (il:functions where-is-notice where-is-notice-internal where-is-files where-is-default-define-types where-is-namestring where-is-read-coms where-is-set-write-date where-is-get-write-date) (il:variables *where-is-hash-file-size* *where-is-ignore-define-types*) (il:prop il:argnames where-is-notice)))) (il:putprops il:new-where-is il:makefile-environment (:readtable "XCL" :package "XCL")) (il:putprops il:new-where-is il:filetype :compile-file) (provide "WHERE-IS") (require "HASH-FILE" "HASH-FILE.DFASL") (require "CASH-FILE" "CASH-FILE.DFASL") (case il:makesysname (:lyric (il:filesload (il:sysload) il:filepkg-patch))) (il:* il:|;;| "run time code") (defun hash-file-where-is (name type) (il:* il:|;;| "return a list of file names containing NAME of TYPE ") (remove-duplicates (mapcan #'(lambda (entry) (cdr (assoc type entry))) (get-where-is-entries name)) :test 'string=)) (defun hash-file-types-of (name &optional (possible-types (where-is-default-define-types))) (let ((entries (get-where-is-entries name)) (types nil)) (dolist (type possible-types) (dolist (entry entries) (when (assoc type entry) (push type types) (return)))) (remove-duplicates types))) (defun get-where-is-entries (name) (il:* il:|;;| "return a list of all entries for name in *WHERE-IS-CASH-FILES*") (maplist #'(lambda (tail) (let ((database (car tail))) (proceed-case (cash-file:get-cash-file name (if (cash-file:cash-file-p database) database (setf (car tail) ( cash-file:open-cash-file database *where-is-cash-size*)) )) (nil nil :report "Delete from the databases known to WHERE-IS?" (del-where-is-database database) nil)))) *where-is-cash-files*)) (defun add-where-is-databases (&rest pathnames) "add each PATHNAME to the databases known to WHERE-IS" (mapcar #'add-where-is-database pathnames)) (defun add-where-is-database (pathname) "add PATHNAME to the databases known to WHERE-IS" (let ((new-pathname (pathname pathname))) (il:* il:|;;| "first delete & close the old one (if any)") (del-where-is-database new-pathname) (il:* il:|;;| "now add the new one") (push new-pathname *where-is-cash-files*) new-pathname)) (defun del-where-is-database (database) (let ((found (find-if #'(lambda (element) (same-where-is-database database element)) *where-is-cash-files*))) (when found (setq *where-is-cash-files* (delete found *where-is-cash-files* :test 'eq)) (if (cash-file:cash-file-p found) (hash-file:close-hash-file ( cash-file:cash-file-hash-file found)) found)))) (defun same-where-is-database (x y) (flet ((coerce-to-pathame (cash-file-or-file-name) (pathname (if (cash-file:cash-file-p cash-file-or-file-name) (hash-file::hash-file-stream (cash-file:cash-file-hash-file cash-file-or-file-name)) cash-file-or-file-name)))) (let ((pathname-x (coerce-to-pathame x)) (pathname-y (coerce-to-pathame y))) (il:* il:|;;| "do a case & version insensitive comparison") (and (equalp (pathname-host pathname-x) (pathname-host pathname-y)) (equalp (pathname-device pathname-x) (pathname-device pathname-y)) (equalp (pathname-directory pathname-x) (pathname-directory pathname-y)) (equalp (pathname-name pathname-x) (pathname-name pathname-y)) (equalp (pathname-type pathname-x) (pathname-type pathname-y)))))) (defun close-where-is-files (event) (case event ((nil il:beforelogout il:beforesysout il:beforemakesys) (il:nlsetq (mapc #'(lambda (cash-file:cash-file) (if (cash-file:cash-file-p cash-file:cash-file) (hash-file:close-hash-file ( cash-file:cash-file-hash-file cash-file:cash-file)))) *where-is-cash-files*))))) (il:addtovar il:aroundexitfns close-where-is-files) (defvar *where-is-cash-files* nil "list of pathnames or CASH-FILEs") (defvar *where-is-cash-size* 100 "size of the CACHE-FILE cache to use") (il:* il:|;;| "notice time code") (defun where-is-notice (database-file &key (files "*.;") (new nil) (define-types (where-is-default-define-types)) (hash-file-size *where-is-hash-file-size*) (quiet nil) (temp-file nil)) (let* ((file (if temp-file (if new temp-file (il:copyfile database-file temp-file)) database-file)) (hash-file:hash-file (if new (hash-file:make-hash-file file hash-file-size) (hash-file:open-hash-file file :direction :io))) (hash-file::*delete-old-version-on-rehash* t)) (unwind-protect (dolist (pathname (where-is-files files)) (unless quiet (format t ";;; ~A ." (namestring pathname))) (let ((namestring (where-is-namestring pathname))) (if (and (not new) (let ((old-write-date (where-is-get-write-date namestring hash-file:hash-file))) (and old-write-date (= (file-write-date pathname) old-write-date)))) (unless quiet (format t " up to date.~%")) (multiple-value-bind (file-vars values) (where-is-read-coms pathname) (when file-vars (il:* il:|;;| "bind the filevars s.t. IL:INFILECOMS? will find them") (progv file-vars values (unless quiet (princ ".")) (dolist (type define-types) (let ((names (il:infilecoms? nil type (first file-vars )))) (when (consp names) (il:* il:|;;| "IL:INFILECOMS? sometimes returns T.") (dolist (name names) (where-is-notice-internal name type namestring hash-file:hash-file)))))) (where-is-set-write-date namestring pathname hash-file:hash-file) (unless quiet (princ ". done.") (terpri))))))) (hash-file:close-hash-file hash-file:hash-file)) (let ((pathname (pathname (hash-file::hash-file-stream hash-file:hash-file)))) (cond (temp-file (unless quiet (format t ";;; Renaming ~A ... " (namestring pathname))) (multiple-value-bind (merged true-name real-true-name) (rename-file pathname database-file) (unless quiet (format t "~A~%" (namestring real-true-name))) real-true-name)) (t pathname))))) (defun where-is-notice-internal (name type file-name hash-file:hash-file) (il:* il:|;;| "note that NAME is defined as TYPE on FILE-NAME in HASH-FILE ") (il:* il:|;;| "we keep an ALIST for each name, indexed by type") (let* ((alist (hash-file:get-hash-file name hash-file:hash-file)) (old-entry (assoc type alist :test 'equal)) (old-files (cdr old-entry))) (unless (member file-name old-files) (il:* il:|;;| "this optimization helps a lot when re-noticing a file ") (setf (hash-file:get-hash-file name hash-file:hash-file) (cons (cons type (cons file-name old-files)) (delete old-entry alist :test 'eq :count 1)))))) (defun where-is-files (files) (il:* il:|;;| "expand the FILES argument to WHERE-IS-NOTICE") (il:* il:|;;| "allow: non-LIST, file names & file patterns") (mapcan #'(lambda (pattern) (let ((pathname (probe-file pattern))) (if pathname (list pathname) (case il:makesysname (:lyric (il:* il:|;;| "CL:DIRECTORY is broken in Lyric") (il:directory pattern)) (otherwise (directory pattern)))))) (if (listp files) files (list files)))) (defun where-is-default-define-types nil (mapcan #'(lambda (type) (il:* il:|;;| "ignore aliases and types on *WHERE-IS-IGNORE-DEFINE-TYPES*") (unless (or (consp type) (member type *where-is-ignore-define-types* )) (list type))) il:filepkgtypes)) (defun where-is-namestring (pathname) (il:* il:|;;| "return a namestring for PATHNAME containing only the NAME & TYPE fields ") (namestring (make-pathname :host nil :name (pathname-name pathname) :type (if (equal (pathname-type pathname) "") nil (pathname-type pathname))))) (defun where-is-read-coms (pathname) (il:* il:|;;;| "returns as first value a list of the filevars on PATHNAME, as second value a list of the values for these filevars.") (il:resetlst (il:* il:|;;| "make sure all IL:LOADVARS get undone") (il:resetsave (il:resetundo)) (do ((il:load-verbose-stream 'nil) (all-file-vars) (queue (list (il:filecoms (string-upcase (pathname-name pathname)))) (cond ((consp (il:nlsetq (il:loadvars queue pathname nil))) (mapcan #'(lambda (file-var) (if (boundp file-var) (let ((file-vars (il:infilecoms? nil 'il:filevars file-var))) (push file-var all-file-vars) (when (consp file-vars) file-vars)) (prog1 nil (warn "Couldn't find ~S on ~A." file-var (namestring pathname))))) queue)) (t (warn "Error attempting to LOADVARS ~S from ~A." queue (namestring pathname )) 'nil)))) ((null queue) (setq all-file-vars (nreverse all-file-vars)) (values all-file-vars (mapcar #'symbol-value all-file-vars))) (declare (special il:load-verbose-stream)) (dolist (file-var queue) (if (member file-var all-file-vars :test 'eq) (il:* il:|;;| "don't want to load any twice") (setf queue (delete file-var queue :test 'eq))))))) (defun where-is-set-write-date (namestring pathname hash-file:hash-file) (il:* il:|;;| "store the write date as a bogus entry on the file") (where-is-notice-internal namestring 'si::write-date (file-write-date pathname) hash-file:hash-file)) (defun where-is-get-write-date (namestring hash-file:hash-file) (il:* il:|;;| "retrieve write date stored for NAMESTRING in HASH-FILE:HASH-FILE") (cadr (assoc 'si::write-date (hash-file:get-hash-file namestring hash-file:hash-file)))) (defvar *where-is-hash-file-size* 10000 "initial size to create WHERE-IS hash files") (defvar *where-is-ignore-define-types* '(il:files il:expressions il:filevars il:alists) ) (il:putprops where-is-notice il:argnames (il:database-file &key il:files il:new il:define-types il:hash-file-size il:quiet il:temp-file)) (il:putprops il:new-where-is il:copyright ("Xerox Corporation" 1987)) (il:declare\: il:dontcopy (il:filemap (nil))) il:stop