diff --git a/lispusers/COMPAREDIRECTORIES b/lispusers/COMPAREDIRECTORIES
index 1968c0af..d204ff9e 100644
--- a/lispusers/COMPAREDIRECTORIES
+++ b/lispusers/COMPAREDIRECTORIES
@@ -1 +1 @@
-(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
(FILECREATED " 4-Jan-2021 23:21:42" 
{DSK}<home>larry>ilisp>medley>lispusers>COMPAREDIRECTORIES.;278 65555  

      changes to%:  (VARS MEDLEY-FIX-DIRS COMPAREDIRECTORIESCOMS FIX-MEDLY-DIRS)
                    (FNS MEDLEY-FIX-DIRS COMPAREDIRECTORIES CDFILES COMPAREDIRECTORIES.INFOS 
                         MATCHNAME CDPRINT CDPRINT.LINE CDMAP CDENTRY CDSUBSET BINCOMP EOLTYPE 
                         FIND-UNCOMPILED-FILES FIND-UNSOURCED-FILES FIND-SOURCE-FILES 
                         FIND-COMPILED-FILES FIND-UNLOADED-FILES FIND-LOADED-FILES 
                         FIND-MULTICOMPILED-FILES CREATED-AS SOURCE-FOR-COMPILED-P 
                         COMPILE-SOURCE-DATE-DIFF FIX-DIRECTORY-DATES FIX-EQUIV-DATES 
                         COPY-COMPARED-FILES COPY-MISSING-FILES COMPILED-ON-SAME-SOURCE 
                         COMPARE-ENTRY-SOURCE-FILES)

      previous date%: "31-Oct-2020 09:13:05" 
{DSK}<home>larry>ilisp>medley>lispusers>COMPAREDIRECTORIES.;275)


(* ; "
Copyright (c) 1985, 1986, 1987, 1988, 1990, 1994, 1998, 2018, 2020, 2021 by Venue & Xerox Corporation.  All rights reserved.
")

(PRETTYCOMPRINT COMPAREDIRECTORIESCOMS)

(RPAQQ COMPAREDIRECTORIESCOMS
       (
        (* ;; "Compare the contents of two directories.")

        (FNS COMPAREDIRECTORIES CDFILES COMPAREDIRECTORIES.INFOS MATCHNAME MEDLEY-FIX-DIRS)
        (VARS MEDLEY-FIX-DIRS)
        (FNS CDPRINT CDPRINT.LINE)
        (FNS CDMAP CDENTRY CDSUBSET)
        (FNS BINCOMP EOLTYPE)
        (RECORDS CDENTRY CDINFO)
        
        (* ;; "look for compiled files older than the sources")

        (FNS FIND-UNCOMPILED-FILES FIND-UNSOURCED-FILES FIND-SOURCE-FILES FIND-COMPILED-FILES 
             FIND-UNLOADED-FILES FIND-LOADED-FILES FIND-MULTICOMPILED-FILES)
        (FNS CREATED-AS SOURCE-FOR-COMPILED-P COMPILE-SOURCE-DATE-DIFF)
        (FNS FIX-DIRECTORY-DATES FIX-EQUIV-DATES COPY-COMPARED-FILES COPY-MISSING-FILES 
             COMPILED-ON-SAME-SOURCE)
        [VARS (ONESECOND (IDIFFERENCE (IDATE "1-Jan-2020 12:00:01")
                                (IDATE "1-Jan-2020 12:00:00"]
        (INITVARS (LASTCDENTRIES NIL))
        (COMS (FNS COMPARE-ENTRY-SOURCE-FILES)
              (FILES COMPARESOURCES))))



(* ;; "Compare the contents of two directories.")

(DEFINEQ

(COMPAREDIRECTORIES
  [LAMBDA (DIR1 DIR2 SELECT FILEPATTERNS EXTENSIONSTOAVOID USEDIRECTORYDATE OUTPUTFILE ALLVERSIONS)
                                                             (* ; 
                                                           "Edited 14-Oct-2020 21:15 by rmk:")

    (* ;; "Compare the contents of two directories, e.g., for change-control purposes.  Compares files matching FILEPATTERN (or *.*;) on DIR1 and DIR2, listing which is newer, or when one is not found on the other.  If SELECT is or contains SAME/=, BEFORE/<, AFTER/>, then files where DIR1 is the same as, earlier than, or later than DIR2 are selected. SELECT= NIL is the same as (<  >), T is the same as (< > =).  Also allows selection based on file-length criteria.")

    (* ;; "")

    (* ;; "Unless USEDIRECTORYDATE, comparison is with respect to the the LISP filecreated dates if evailable.")

    (* ;; "")

    (* ;; "If OUTPUTFILE is NIL, the list of compared entries is returned.  Otherwise the selected entries are printed on OUTPUTFILE (T for the display).")

    [SETQ SELECT (SELECTQ SELECT
                     (NIL '(< > -* *-))
                     (T '(< > -* *- =))
                     (for S in (MKLIST SELECT) collect (SELECTQ S
                                                                       ((AFTER >) 
                                                                            '>)
                                                                       ((BEFORE <) 
                                                                            '<)
                                                                       ((SAME SAMEDATE =) 
                                                                            '=)
                                                                       (AUTHOR 'AUTHOR)
                                                                       (-* '-*)
                                                                       (*- '*-)
                                                                       (ERROR 
                                                                      "UNRECOGNIZED SELECT PARAMETER"
                                                                              S]
    (PROG (INFOS1 INFOS2 CANDIDATES SELECTED COMPAREDATE DEPTH1 DEPTH2)
          [SETQ COMPAREDATE (INTERSECTION SELECT '(< > =]

     (* ;; "DIRECTORYNAME here to get unrelativized specifications for header.")

     (* ;; "Allow all subdirectories if a directory ends in *, but peel it off for the resolution")

          (CL:WHEN (EQ '* (NTHCHAR DIR1 -1))
              (SETQ DEPTH1 T)
              (SETQ DIR1 (SUBSTRING DIR1 1 -2)))
          (CL:WHEN (EQ '* (NTHCHAR DIR2 -1))
              (SETQ DEPTH2 T)
              (SETQ DIR2 (SUBSTRING DIR2 1 -2)))
          (SETQ DIR1 (OR (DIRECTORYNAME (OR DIR1 T))
                         (ERROR "DIRECTORY DOES NOT EXIST" DIR1)))
          (SETQ DIR2 (OR (DIRECTORYNAME (OR DIR2 T))
                         (ERROR "DIRECTORY DOES NOT EXIST" DIR2)))
          (PRINTOUT T "Comparing " DIR1 6 "vs. " DIR2 T "as of " (DATE)
                 " selecting " SELECT " ... ")
          (SETQ INFOS1 (COMPAREDIRECTORIES.INFOS (CDFILES DIR1 FILEPATTERNS EXTENSIONSTOAVOID
                                                            ALLVERSIONS DEPTH1)
                              USEDIRECTORYDATE))
          (SETQ INFOS2 (COMPAREDIRECTORIES.INFOS (CDFILES DIR2 FILEPATTERNS EXTENSIONSTOAVOID
                                                            ALLVERSIONS DEPTH2)
                              USEDIRECTORYDATE))
          (CL:UNLESS (AND INFOS2 INFOS1)
                 (RETURN))

     (* ;; "At this point the CAR of each info is the atomic match-name. Peel it off to produce candidate entries.")

     (* ;; 
   "Look through all of the I2's because multiple versions (if VERSIONS) have the same matchname")

          [SETQ CANDIDATES (for I1 in INFOS1
                              join (if ALLVERSIONS
                                           then (OR (for I2 in INFOS2
                                                           when (EQ (CAR I2)
                                                                        (CAR I1))
                                                           collect (LIST (CAR I1)
                                                                             (CDR I1)
                                                                             (CDR I2)))
                                                        (CONS (LIST (CAR I1)
                                                                    (CDR I1)
                                                                    NIL)))
                                         else (CONS (LIST (CAR I1)
                                                              (CDR I1)
                                                              (CDR (ASSOC (CAR I1)
                                                                          INFOS2]

     (* ;; "Could be some 2's without 1's")

          (SORT [NCONC CANDIDATES (for I2 in INFOS2 unless (ASSOC (CAR I2)
                                                                              CANDIDATES)
                                     collect (LIST (CAR I2)
                                                       NIL
                                                       (CDR I2]
                T)

     (* ;; "CANDIDATES is now a sorted list of the form (matchname entry1 entry2) where an entry consists of (fullname date length author)")

     (* ;; "Do the SELECT filtering and insert the date relation.")

          [SETQ SELECTED
           (for C MATCHNAME INFO1 INFO2 IDATE1 IDATE2 DATEREL BINCOMP in CANDIDATES
              eachtime (SETQ MATCHNAME (pop C))
                    (SETQ INFO1 (pop C))
                    (SETQ INFO2 (pop C))
                    (if (AND INFO1 INFO2)
                        then (SETQ IDATE1 (IDATE (fetch DATE of INFO1)))
                              (SETQ IDATE2 (IDATE (fetch DATE of INFO2)))
                              (SETQ DATEREL (if (IGREATERP IDATE1 IDATE2)
                                                then '>
                                              elseif (ILESSP IDATE1 IDATE2)
                                                then '<
                                              else '=))
                      else 

                            (* ;; "Just for printing--no comparison")

                            (SETQ DATEREL '*))
              when (if (AND INFO1 INFO2)
                           then (OR (NULL COMPAREDATE)
                                        (SELECTQ DATEREL
                                            (> (MEMB '> SELECT))
                                            (< (MEMB '< SELECT))
                                            (= (MEMB '= SELECT))
                                            (SHOULDNT)))
                         elseif INFO1
                           then 

                                 (* ;; "OK if INFO2 is missing?")

                                 (MEMB '*- SELECT)
                         else 

                               (* ;; "OK if INFO1 is missing?")

                               (MEMB '-* SELECT))
              collect (create CDENTRY
                                 MATCHNAME _ MATCHNAME
                                 INFO1 _ INFO1
                                 DATEREL _ DATEREL
                                 INFO2 _ INFO2
                                 EQUIV _ (CL:UNLESS (EQ DATEREL '*)
                                             (BINCOMP (fetch FULLNAME of INFO1)
                                                    (fetch FULLNAME of INFO2)
                                                    T
                                                    (fetch EOL of INFO1)
                                                    (fetch EOL of INFO2)))]
          (PRINTOUT T (LENGTH SELECTED)
                 " entries" T)
          (push SELECTED (LIST DIR1 DIR2 SELECT (DATE)))
          (SETQ LASTCDENTRIES SELECTED)
          (CL:UNLESS OUTPUTFILE (RETURN SELECTED))
          (RETURN (CDPRINT SELECTED OUTPUTFILE (MEMB 'AUTHOR SELECT SELECT])

(CDFILES
  [LAMBDA (DIR FILEPATTERNS EXTENSIONSTOAVOID ALLVERSIONS DEPTH)
                                                             (* ; 
                                                           "Edited 16-Oct-2020 13:42 by rmk:")

    (* ;; "Returns a list of fullnames for files that satisfy the criteria")

    (* ;; "For each name returned by (DIRECTORY DIR), assumes that FILEPATTERNS applies to the suffix after the directory (i.e. after NAMEPOS).  That includes possibly subdirectories, dotted files in ultimate file names, and versions.")

    (* ;; "     Exclude subdirectories unless FILEPATTERNS includes *>*")

    (* ;; "     Exclude dotted files (.xxx) unless FILEPATTERNS includes .*")

    (* ;; "     Exclude files with extensions in EXTENSIONSTOAVOID (*=NIL does no filtering)")

    (* ;; "     Exclude older versions unless ALLVERSIONS=T")

    (* ;; "  DEPTH is the number of subdirectories below the ones specified in DIR (NIL top-level of DIR only, T = any depth)")

    (* ;; "Resolve relative directories, so we can suppress subdirectory matches.   ")

    (SETQ EXTENSIONSTOAVOID (MKLIST (U-CASE EXTENSIONSTOAVOID)))
    [SETQ FILEPATTERNS (MKLIST (OR FILEPATTERNS '*]
    (for FP FN FPNAME FPEXT EXCLUDEDOTTED (TOPDIR _ (DIRECTORYNAME (OR DIR T))) in 
                                                                                         FILEPATTERNS
       join [SETQ FPNAME (U-CASE (FILENAMEFIELD FP 'NAME]
             [SETQ FPEXT (U-CASE (FILENAMEFIELD FP 'EXTENSION]
             (CL:UNLESS FPNAME
                 (if FPEXT
                     then 

                           (* ;; ".XY")

                           (SETQ FPNAME (PACK* "." FPEXT))
                   else (SETQ FPNAME '*)))
             (CL:UNLESS FPEXT
                 (SETQ FPEXT '*))
             (SETQ EXCLUDEDOTTED (NEQ (CHARCODE %.)
                                      (CHCON1 FPNAME)))
             (SETQ FN (PACKFILENAME.STRING 'VERSION (CL:IF ALLVERSIONS
                                                        '*
                                                        "")
                             'DIRECTORY TOPDIR 'NAME '* 'EXTENSION '*)) 

             (* ;; "DEPTH is the number of internal %">%"")

             [if (EQ DEPTH T)
                 then (SETQ DEPTH MAX.SMALLP)
               elseif DEPTH
               else (SETQ DEPTH (bind (CNT _ 0)
                                           (POS _ 0)
                                           (FNDIR _ (FILENAMEFIELD FN 'DIRECTORY))
                                       while (SETQ POS (STRPOS ">" FNDIR (ADD1 POS)))
                                       do (add CNT 1) finally (RETURN CNT]
             (for FULLNAME NAME EXT THISDEPTH in (DIRECTORY FN)
                eachtime [SETQ NAME (U-CASE (FILENAMEFIELD FULLNAME 'NAME]
                      [SETQ EXT (U-CASE (FILENAMEFIELD FULLNAME 'EXTENSION]
                      (CL:UNLESS NAME
                          (if EXT
                              then 

                                    (* ;; ".XY")

                                    (SETQ NAME (PACK* "." EXT))
                                    (SETQ EXT NIL)))
                      (CL:WHEN (AND EXCLUDEDOTTED (EQ (CHARCODE %.)
                                                      (CHCON1 NAME)))
                             (GO $$ITERATE))
                      (SETQ THISDEPTH (bind (CNT _ 0)
                                             (POS _ 0)
                                             (FNDIR _ (FILENAMEFIELD FULLNAME 'DIRECTORY))
                                         while (SETQ POS (STRPOS ">" FNDIR (ADD1 POS)))
                                         do (add CNT 1) finally (RETURN CNT))) 

                      (* ;; "An empty subdirectory may appear without name or extensions")
 when (AND (OR NAME EXT)
               (OR (EQ FPNAME '*)
                   (EQ FPNAME NAME))
               (OR (EQ FPEXT '*)
                   (EQ FPEXT EXT))) unless [OR (IGREATERP THISDEPTH DEPTH)
                                                   (AND EXT (OR (MEMB '* EXTENSIONSTOAVOID)
                                                                (MEMB EXT EXTENSIONSTOAVOID]
                collect FULLNAME) finally (CL:UNLESS $$VAL (PRINTOUT T 
                                                                          "No relevant files in " 
                                                                          TOPDIR T])

(COMPAREDIRECTORIES.INFOS
  [LAMBDA (FILES USEDIRECTORYDATE)                           (* ; 
                                                           "Edited 13-Oct-2020 08:42 by rmk:")

    (* ;; "Value is a list of CDINFOS with the match-name consed on to the front")

    (for FULLNAME TYPE LDATE in FILES
       collect 

             (* ;; "GDATE/IDATE in case Y2K")

             (SETQ LDATE (FILEDATE FULLNAME))                (* ; "Is it a Lisp file?")
             (CONS (MATCHNAME FULLNAME)
                   (create CDINFO
                          FULLNAME _ FULLNAME
                          DATE _ [GDATE (IDATE (if USEDIRECTORYDATE
                                                   then (GETFILEINFO FULLNAME 'CREATIONDATE)
                                                 elseif (OR LDATE (GETFILEINFO FULLNAME
                                                                             'CREATIONDATE]
                          LENGTH _ (GETFILEINFO FULLNAME 'LENGTH)
                          AUTHOR _ (GETFILEINFO FULLNAME 'AUTHOR)
                          TYPE _ (if LDATE
                                     then (CL:IF (MEMB (FILENAMEFIELD FULLNAME 'EXTENSION)
                                                           *COMPILED-EXTENSIONS*)
                                                  'COMPILED
                                                  'SOURCE)
                                   else (PRINTFILETYPE FULLNAME))
                          EOL _ (EOLTYPE FULLNAME])

(MATCHNAME
  [LAMBDA (NAME)                                             (* ; 
                                                           "Edited  5-Sep-2020 13:41 by rmk:")

    (* ;; "The NAME.DIR for matching related files")

    (LET ((M (PACKFILENAME 'HOST NIL 'VERSION NIL 'DIRECTORY NIL 'BODY NAME)))

         (* ;; "Strip off the nuisance period")

         (CL:IF (EQ (CHARCODE %.)
                    (NTHCHARCODE M -1))
             (SUBATOM M 1 -2)
             M)])

(MEDLEY-FIX-DIRS
  [LAMBDA NIL                                          (* ; "Edited  4-Jan-2021 15:42 by larry")
    (for X in MEDLEY-FIX-DIRS join (FIX-DIRECTORY-DATES (MEDLEYDIR (PRINT X T])
)

(RPAQQ MEDLEY-FIX-DIRS ("sources" "library" "lispusers" "internal/library" "greetfiles" 
                                  "docs>Documentation Tools" "cltl2" "clos" "makesysout"))
(DEFINEQ

(CDPRINT
  [LAMBDA (CDENTRIES FILE PRINTAUTHOR)                       (* ; 
                                                           "Edited 13-Oct-2020 08:38 by rmk:")

    (* ;; "Typically CDENTRIES will have a header.  If not, we fake one up, at least for the directories and today's date.")

    (CL:UNLESS CDENTRIES
        (PRINTOUT T T "Note:  Using LASTCDENTRIES" T T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (RESETLST
        (LET (INFO1 TEXT STREAM DATE1POS ENDDATE1 DIR1 DIR2 (HEADER (CAR CDENTRIES))
                    NCHARSDIR1)
             (CL:UNLESS (STRINGP (CADR HEADER))
                 (SETQ HEADER (LIST [for E in CDENTRIES when (fetch INFO1
                                                                            of E)
                                       do (RETURN (PACKFILENAME 'NAME NIL 'EXTENSION NIL
                                                             'VERSION NIL 'BODY
                                                             (fetch FULLNAME
                                                                of (fetch INFO1 of E]
                                    [for E in CDENTRIES when (fetch INFO2
                                                                            of E)
                                       do (RETURN (PACKFILENAME 'NAME NIL 'EXTENSION NIL
                                                             'VERSION NIL 'BODY
                                                             (fetch FULLNAME
                                                                of (fetch INFO2 of E]
                                    NIL
                                    (DATE)))
                 (push CDENTRIES HEADER))
             (SETQ DIR1 (CAR HEADER))
             (SETQ NCHARSDIR1 (NCHARS DIR1))
             (SETQ DIR2 (CADR HEADER))
             (CL:UNLESS (SETQ STREAM (GETSTREAM FILE 'OUTPUT T))
                 [RESETSAVE (SETQ STREAM (OPENSTREAM (PACKFILENAME 'EXTENSION 'TXT 'BODY FILE)
                                                'OUTPUT
                                                'NEW))
                        '(PROGN (CLOSEF? OLDVALUE])
             (CL:WHEN DIR1
                 (PRINTOUT STREAM "Comparing " DIR1 6 "vs. " DIR2 T "as of " (CADDDR HEADER))
                 (CL:WHEN (CADDR HEADER)
                     (PRINTOUT STREAM " selecting " (CADDR HEADER)))
                 (PRINTOUT STREAM -2 (LENGTH (CDR CDENTRIES))
                        " entries" T T))
             (LINELENGTH 1000 STREAM)                        (* ; "Don't wrap")

             (* ;; "DATE1POS is the position of the first character of INFO1's date, used for tabbing.  We have to measure the filename, date, size, and author if desired")

             (if (CDR CDENTRIES)
                 then (for E INFO1 (MAXDATE1WIDTH _ 0)
                                 (SPACEWIDTH _ 1)
                                 (PARENWIDTH _ 2) in (CDR CDENTRIES)
                             when (SETQ INFO1 (fetch INFO1 of E))
                             largest [SETQ MAXDATE1WIDTH (IMAX MAXDATE1WIDTH
                                                                   (NCHARS (fetch DATE
                                                                              of INFO1]
                                   (IPLUS (- (NCHARS (fetch FULLNAME of INFO1))
                                             NCHARSDIR1)
                                          (NCHARS (fetch LENGTH of INFO1))
                                          (CL:IF PRINTAUTHOR
                                              (IPLUS SPACEWIDTH PARENWIDTH
                                                     (NCHARS (fetch AUTHOR of INFO1)))
                                              0)) finally 

                                                        (* ;; 
                            "First 4 for width of equiv.  $$EXTREME is NIL if there are no INFO1's")

                                                        (SETQ DATE1POS (IPLUS (OR $$EXTREME 10)
                                                                              4
                                                                              (ITIMES 3 SPACEWIDTH)))
                                                        (SETQ ENDDATE1 (IPLUS DATE1POS MAXDATE1WIDTH)
                                                         ))
                       (for E in (CDR CDENTRIES)
                          do (CDPRINT.LINE STREAM E PRINTAUTHOR DATE1POS ENDDATE1 NCHARSDIR1
                                        (NCHARS DIR2)))
               else (PRINTOUT T "CDENTRIES is empty" T))
             (AND STREAM (CLOSEF? STREAM))))])

(CDPRINT.LINE
  [LAMBDA (STREAM ENTRY PRINTAUTHOR DATE1POS ENDDATE1 NCHARSDIR1 NCHARSDIR2)
                                                             (* ; 
                                                           "Edited 13-Oct-2020 08:51 by rmk:")

    (* ;; "Format one line of the directory comparison listing.  If PRINTAUTHOR and AUTHOR1 or AUTHOR2 are non-NIL, list the author in parens; otherwise omit it.")

    (LET ((INFO1 (fetch INFO1 of ENTRY))
          (INFO2 (fetch INFO2 of ENTRY)))
         (PRINTOUT STREAM (SELECTQ (fetch EQUIV of ENTRY)
                              (T "==")
                              (NIL "  ")
                              (PROGN (SELECTQ (fetch EOL of INFO1)
                                         (CR 'C)
                                         (LF 'L)
                                         (CRLF 2)
                                         " ")
                                     (SELECTQ (fetch EOL of INFO2)
                                         (CR 'C)
                                         (LF 'L)
                                         (CRLF 2)
                                         " ")))
                " ")
         (CL:WHEN INFO1
             (PRINTOUT STREAM (SUBSTRING (fetch FULLNAME of INFO1)
                                     (ADD1 NCHARSDIR1)
                                     NIL
                                     (CONSTANT (CONCAT)))
                    " ")
             (CL:WHEN PRINTAUTHOR
                 (PRINTOUT STREAM "(" (fetch AUTHOR of INFO1)
                        ") "))
             (PRINTOUT STREAM (fetch LENGTH of INFO1)
                    .TAB0 DATE1POS (fetch DATE of INFO1)))
         (PRINTOUT STREAM .TAB0 ENDDATE1 "  " (fetch DATEREL of ENTRY)
                "  ")
         (CL:WHEN INFO2
             (PRINTOUT STREAM (fetch DATE of INFO2)
                    "   "
                    (SUBSTRING (fetch FULLNAME of INFO2)
                           (ADD1 NCHARSDIR2)
                           NIL
                           (CONSTANT (CONCAT)))
                    " ")
             (CL:WHEN PRINTAUTHOR
                 (PRINTOUT STREAM "(" (fetch AUTHOR of INFO2)
                        ") "))
             (PRINTOUT STREAM (fetch LENGTH of INFO2)))
         (TERPRI STREAM])
)
(DEFINEQ

(CDMAP
  [LAMBDA (CDENTRIES FN)                                     (* ; 
                                                           "Edited  6-Sep-2020 15:58 by rmk:")
    (CL:UNLESS CDENTRIES
        (PRINTOUT T T "Note:  Using LASTCDENTRIES" T T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (for CDE MATCHNAME INFO1 DATEREL INFO2 EQUIV in (CDR CDENTRIES)
       declare (SPECVARS MATCHNAME INFO1 DATEREL INFO2 EQUIV)
       eachtime (SETQ MATCHNAME (fetch MATCHNAME of CDE))
             (SETQ INFO1 (fetch INFO1 of CDE))
             (SETQ DATEREL (fetch DATEREL of CDE))
             (SETQ INFO2 (fetch INFO2 of CDE))
             (SETQ EQUIV (fetch EQUIV of CDE)) do (APPLY* FN CDE])

(CDENTRY
  [LAMBDA (MATCHNAME CDENTRIES)                          (* ; 
                                                           "Edited  5-Sep-2020 21:09 by rmk:")
    (ASSOC MATCHNAME (OR CDENTRIES LASTCDENTRIES])

(CDSUBSET
  [LAMBDA (CDENTRIES FN)                                     (* ; 
                                                           "Edited 15-Sep-2020 13:49 by rmk:")
    (CL:UNLESS CDENTRIES
        (PRINTOUT T T "Note:  Using LASTCDENTRIES" T T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (CONS (CAR CDENTRIES)
          (for CDE MATCHNAME INFO1 DATEREL INFO2 EQUIV in (CDR CDENTRIES)
             declare (SPECVARS MATCHNAME INFO1 DATEREL INFO2 EQUIV)
             eachtime (SETQ MATCHNAME (fetch MATCHNAME of CDE))
                   (SETQ INFO1 (fetch INFO1 of CDE))
                   (SETQ DATEREL (fetch DATEREL of CDE))
                   (SETQ INFO2 (fetch INFO2 of CDE))
                   (SETQ EQUIV (fetch EQUIV of CDE)) when (APPLY* FN CDE) collect
                                                                                      CDE])
)
(DEFINEQ

(BINCOMP
  [LAMBDA (FILE1 FILE2 EOLDIFFOK EOL1 EOL2)                  (* ; 
                                                           "Edited 13-Oct-2020 08:53 by rmk:")

    (* ;; "Returns T if FILE1 and FILE2 are byte-equivalent.  Returns EOLDIFF if they are byte equivalent except for CR/LF/CRLF exchanges.  ")

    (* ;; "If EOLDIFFOK, return indicates that the files are the same except for EOL mappings.  If EOL1 and EOL2 are not provided, they are computed here.")

    (if (IEQP (GETFILEINFO FILE1 'LENGTH)
                  (GETFILEINFO FILE2 'LENGTH))
        then [CL:WITH-OPEN-FILE
                  (STREAM1 FILE1 :DIRECTION :INPUT)
                  (CL:WITH-OPEN-FILE
                   (STREAM2 FILE2 :DIRECTION :INPUT)
                   (SETFILEINFO STREAM1 'ENDOFSTREAMOP (FUNCTION NILL))

                   (* ;; "Simpler code to recompute eol's even if provided")

                   (bind B1 B2 EOL1 EOL2 EOLDIFF while (SETQ B1 (\BIN STREAM1))
                      unless (EQ B1 (SETQ B2 (\BIN STREAM2)))
                      do (CL:UNLESS (AND EOLDIFFOK (SELCHARQ B1
                                                            (CR (CL:WHEN (EQ EOL1 'LF)
                                                                       (RETURN NIL))
                                                                (SETQ EOL1 'CR)
                                                                (SETQ EOL2 'LF)
                                                                (EQ B2 (CHARCODE LF)))
                                                            (LF (CL:WHEN (EQ EOL1 'CR)
                                                                       (RETURN NIL))
                                                                (SETQ EOL1 'LF)
                                                                (SETQ EOL2 'CR)
                                                                (EQ B2 (CHARCODE CR)))
                                                            NIL))
                                    (RETURN NIL))
                            (CL:UNLESS EOLDIFF
                                (SETQ EOLDIFF (LIST EOL1 EOL2))) finally (RETURN (OR EOLDIFF T]
      elseif EOLDIFFOK
        then 

              (* ;; "Lengths are different possibly because of CRLF to CR/LF substitutions.")

              (* ;; 
        "More complex code could detect the EOLTYPE incrementally without separate passes, but ...")

              (CL:UNLESS EOL1
                  (SETQ EOL1 (EOLTYPE FILE1)))
              (CL:UNLESS EOL2
                  (SETQ EOL2 (EOLTYPE FILE2)))
              (CL:WHEN (if [AND (EQ EOL1 'CRLF)
                                    (MEMB EOL2 '(LF CR]
                         elseif [AND (EQ EOL2 'CRLF)
                                         (MEMB EOL1 '(LF CR]
                           then (swap FILE1 FILE2))

                  (* ;; "FILE1 is now CRLF, FILE2 is not.  If FILE1 isn't longer, it can't have a CRLF that corresponds to a CR or LF.")

                  (CL:WHEN (IGREATERP (GETFILEINFO FILE1 'LENGTH)
                                  (GETFILEINFO FILE2 'LENGTH))
                      [CL:WITH-OPEN-FILE (STREAM1 FILE1 :DIRECTION :INPUT)
                             (CL:WITH-OPEN-FILE (STREAM2 FILE2 :DIRECTION :INPUT)
                                    (SETFILEINFO STREAM1 'ENDOFSTREAMOP (FUNCTION NILL))
                                    (bind B1 B2 EOLDIFF while (SETQ B1 (\BIN STREAM1))
                                       unless (EQ B1 (SETQ B2 (\BIN STREAM2)))
                                       do (CL:UNLESS [AND (EQ (CHARCODE CR)
                                                                  B1)
                                                              (EQ (CHARCODE LF)
                                                                  (\BIN STREAM1))
                                                              (MEMB B2 (CHARCODE (CR LF]
                                                     (RETURN NIL))
                                             (CL:UNLESS EOLDIFF
                                                 (SETQ EOLDIFF (LIST EOL1 EOL2)))
                                       finally (RETURN (OR EOLDIFF T]))])

(EOLTYPE
  [LAMBDA (FILE)                                             (* ; 
                                                           "Edited  3-Sep-2020 17:05 by rmk:")

    (* ;; "Returns the EOLCONVENTION of FILE if it only sees one kind, NIL if it can't decide.")

    (CL:WITH-OPEN-FILE (STREAM FILE :DIRECTION :INPUT)
           (SETFILEINFO STREAM 'ENDOFSTREAMOP (FUNCTION NILL))
           (bind EOLTYPE
              do (SELCHARQ (OR (\BIN STREAM)
                                   (RETURN EOLTYPE))
                          (CR (if (EQ (CHARCODE LF)
                                          (\PEEKBIN STREAM T))
                                  then (CL:WHEN (MEMB EOLTYPE '(LF CR))
                                                  (RETURN NIL))
                                        (\BIN STREAM)
                                        (SETQ EOLTYPE 'CRLF)
                                elseif (MEMB EOLTYPE '(LF CRLF))
                                  then (RETURN NIL)
                                else (SETQ EOLTYPE 'CR)))
                          (LF (CL:WHEN (MEMB EOLTYPE '(CR CRLF))
                                     (RETURN NIL))
                              (SETQ EOLTYPE 'LF))
                          NIL])
)
(DECLARE%: EVAL@COMPILE

(RECORD CDENTRY (MATCHNAME INFO1 DATEREL INFO2 . EQUIV))

(RECORD CDINFO (FULLNAME DATE LENGTH AUTHOR TYPE EOL))
)



(* ;; "look for compiled files older than the sources")

(DEFINEQ

(FIND-UNCOMPILED-FILES
  [LAMBDA (FILES DFASLMARGIN COMPILEEXTS)                    (* ; 
                                                           "Edited 20-Sep-2020 23:04 by rmk:")
                                                             (* ; "Edited  3-Nov-94 15:17 by jds")

    (* ;; "Produces a list of the source files in FILES that have no corresponding compiled file")

    (* ;; "This determines whether there is at least one compiled file.  If there are two or more, that's a problem")

    (* ;; "We want the most recent version only")

    (* ;; "Source files have a 2-element created-as with a non-NIL date")

    (SETQ FILES (for F in (OR (LISTP FILES)
                                      (FILDIR FILES)) unless (MEMB (SETQ F (PACKFILENAME
                                                                                'VERSION NIL
                                                                                'BODY F))
                                                                       $$VAL) collect F))
    (for F SCREATION FILES in FILES when (AND (CADR (SETQ SCREATION (CREATED-AS
                                                                                 F)))
                                                          (NOT (CDDR SCREATION)))
       when [SETQ FILES
                 (for CEXT CF in (OR COMPILEEXTS *COMPILED-EXTENSIONS*)
                    when (SETQ CF (INFILEP (PACKFILENAME 'EXTENSION CEXT 'VERSION NIL
                                                      'BODY F)))
                    collect (CL:WHEN (SOURCE-FOR-COMPILED-P SCREATION CF DFASLMARGIN)
                                       (RETURN NIL))
                          CF
                    finally 

                          (* ;; "If we found some compiled files, they weren't on this source.  If there weren't any compiled files to check, maybe there weren't any functions.")

                          (* ;; 
      "NLSETQ because we don't want to stop if there is an error, typically from a package problem")

                          (RETURN (OR $$VAL (LET [(FCOMS (CAR (NLSETQ (GETDEF (FILECOMS F)
                                                                             'VARS F]
                                                 (if (NULL FCOMS)
                                                     then 

                                                           (* ;; 
                                               "GETDEF caused an error.  Maybe a package problem. ")

                                                           (AND NIL 'NOCOMMANDS)
                                                   elseif (INFILECOMS? NIL '(FUNCTIONS FNS)
                                                                     FCOMS)
                                                     then T]
       collect (CONS F (SELECTQ FILES
                               (T NIL)
                               (NOCOMMANDS (CONS "No commands"))
                               (for CF in FILES collect 

                                                        (* ;; 
           "Positive means that compiled is later than source, normal order but maybe by too much.")

                                                              (* ;; 
                                            "Negative means that compiled came before source.  Odd")

                                                              (LIST CF (COMPILE-SOURCE-DATE-DIFF
                                                                        CF SCREATION])

(FIND-UNSOURCED-FILES
  [LAMBDA (FILES DFASLMARGIN COMPILEEXTS)                    (* ; 
                                                           "Edited 15-Sep-2020 15:32 by rmk:")
                                                             (* ; "Edited  3-Nov-94 15:17 by jds")

    (* ;; 
  "Produces a list of compiled FILES for which no source file can be found in the same directory.")

    (* ;; "The source date in at least one DFASL was off by a second, maybe some sort of IDATE rounding?  So, give a margin.")

    (* ;; 
"We want the most recent version only.  Check CREATED-AS to make sure it really is a compiled file.")

    (* ;; "Sort to get lcoms and dfasls next to each other.")

    (LET (CCREATEDS)
         (SETQ CCREATEDS (for CEXT FOUND CCREATED inside (OR COMPILEEXTS 
                                                                     *COMPILED-EXTENSIONS*)
                            join (for CF in [OR (LISTP FILES)
                                                            (FILDIR (PACKFILENAME 'EXTENSION CEXT
                                                                           'VERSION "" 'BODY
                                                                           '*]
                                        when (CDDR (SETQ CCREATED (CREATED-AS CF)))
                                        unless (MEMBER CCREATED $$VAL) collect CCREATED)))

         (* ;; "CCREATEDS is now a list of CREATED-AS items")

         (for CC SF in CCREATEDS unless (AND [SETQ SF (INFILEP (PACKFILENAME 'EXTENSION 
                                                                                  NIL 'VERSION NIL
                                                                                  'BODY
                                                                                  (CAR CC]
                                                         (SOURCE-FOR-COMPILED-P (SETQ SF
                                                                                     (CREATED-AS
                                                                                      SF))
                                                                CC DFASLMARGIN))
            collect [LIST (CAR CC)
                              (AND SF (LIST (CAR SF)
                                            (ROUND (COMPILE-SOURCE-DATE-DIFF CC SF]
            finally (RETURN (SORT $$VAL (FUNCTION (LAMBDA (CF1 CF2)
                                                        (ALPHORDER (FILENAMEFIELD (CAR CF1)
                                                                          'NAME)
                                                               (FILENAMEFIELD (CAR CF2)
                                                                      'NAME])

(FIND-SOURCE-FILES
  [LAMBDA (CFILES SDIRS DFASLMARGIN)                         (* ; 
                                                           "Edited  9-Sep-2020 12:26 by rmk:")

    (* ;; "Returns (CFILE . SFILES) pairs where CFILE is a Lisp compiled file in CFILES SFILES is a list of source files in SDIRS that CFILE was compiled on.")

    (* ;; "This suggests that one of CFILES should be copied to the SFILE directory.")

    (SETQ SDIRS (for SD inside (OR SDIRS T) collect (DIRECTORYNAME SD)))
    (SORT (for CF SFILES CNAME CCREATED in (OR (LISTP CFILES)
                                                       (FILDIR CFILES))
             when (AND (SETQ CNAME (INFILEP CF))
                           (CDDR (SETQ CCREATED (CREATED-AS CF)))
                           (SETQ SFILES (for SD SF in SDIRS
                                           when (AND (SETQ SF (INFILEP (PACKFILENAME
                                                                            'NAME
                                                                            (FILENAMEFIELD
                                                                             CF
                                                                             'NAME)
                                                                            'BODY SD)))
                                                         (SOURCE-FOR-COMPILED-P SF CCREATED 
                                                                DFASLMARGIN)) collect SF)))
             collect (CONS CNAME SFILES))
          (FUNCTION (LAMBDA (P1 P2)
                      (ALPHORDER (FILENAMEFIELD (CAR P1))
                             (FILENAMEFIELD (CAR P2])

(FIND-COMPILED-FILES
  [LAMBDA (SFILES CDIRS DFASLMARGIN)                         (* ; 
                                                           "Edited  9-Sep-2020 12:26 by rmk:")

    (* ;; "Returns (SFILE . CFILES) pairs where SFILE is a Lisp source file in SFILES CFILES is a list of compiled files in CDIRS that were compiled on SFILE.")

    (* ;; "FILEDATE is true for source files and compiled files")

    (* ;; "This suggests that one of CFILES should be copied to the SFILE directory.")

    (SETQ CDIRS (for CD inside (OR CDIRS T) collect (DIRECTORYNAME CD)))
    (SORT (for SF CFILES SNAME SCREATED in (OR (LISTP SFILES)
                                                       (FILDIR SFILES))
             when [AND (SETQ SNAME (INFILEP SF))
                           (SETQ SCREATED (CREATED-AS SF))
                           (NOT (CDDR SCREATED))
                           (SETQ CFILES (for CEXT (ROOT _ (FILENAMEFIELD SNAME 'NAME))
                                           in *COMPILED-EXTENSIONS*
                                           join (for CD CF in CDIRS
                                                       when (AND (SETQ CF
                                                                      (INFILEP (PACKFILENAME
                                                                                'NAME ROOT
                                                                                'EXTENSION CEXT
                                                                                'BODY CD)))
                                                                     (SOURCE-FOR-COMPILED-P
                                                                      SCREATED CF DFASLMARGIN))
                                                       collect CF] collect (CONS SNAME CFILES
                                                                                         ))
          (FUNCTION (LAMBDA (P1 P2)
                      (ALPHORDER (FILENAMEFIELD (CAR P1))
                             (FILENAMEFIELD (CAR P2])

(FIND-UNLOADED-FILES
  [LAMBDA (FILES)                                            (* ; 
                                                           "Edited  9-Sep-2020 19:35 by rmk:")

    (* ;; "Returns the files in FILES that don't have FILECREATED properties and presumably are therefore not loaded in the current sysout.")

    (for F in (OR (LISTP FILES)
                          (FILDIR FILES)) when (AND (SETQ F (INFILEP (CL:IF (LISTP F)
                                                                             (CAR F)
                                                                             F)))
                                                        (FILEDATE F))
       unless (GETP (FILENAMEFIELD F 'NAME)
                        'FILEDATES) collect F])

(FIND-LOADED-FILES
  [LAMBDA (ROOTFILENAMES)                                    (* ; 
                                                           "Edited 19-Sep-2020 07:20 by rmk:")
    (for RN inside ROOTFILENAMES when (GETP RN 'FILEDATES)
       collect (CONS RN (for F in LOADEDFILELST when (EQ RN (FILENAMEFIELD
                                                                             F
                                                                             'NAME)) collect
                                                                                     F])

(FIND-MULTICOMPILED-FILES
  [LAMBDA (FILES SHOWINFO)                                   (* ; 
                                                           "Edited 20-Sep-2020 20:57 by rmk:")

    (* ;; "Returns a list of names for files in FILES that have multiple compilations")

    (LET (SFILES)
         (for F EXT NAME in (OR (LISTP FILES)
                                        (FILDIR FILES)) when (MEMB (SETQ EXT (FILENAMEFIELD
                                                                                  F
                                                                                  'EXTENSION))
                                                                       *COMPILED-EXTENSIONS*)
            do (SETQ NAME (FILENAMEFIELD F 'NAME)) 

                  (* ;; "PUSHNEW because we haven't filtered out versions")

                  (pushnew [CDR (OR (ASSOC NAME SFILES)
                                        (CAR (push SFILES (CONS NAME]
                         EXT))
         (for S in SFILES when (CDDR S)
            collect (if SHOWINFO
                            then `[,(CAR S)
                                       ,(CADAR (FIND-LOADED-FILES (CAR S)))
                                       ,(CREATED-AS (CAR S))
                                       ,@(for EXT in (SORT (CDR S))
                                            collect (CREATED-AS (PACKFILENAME 'EXTENSION EXT
                                                                               'BODY
                                                                               (CAR S]
                          else (CAR S])
)
(DEFINEQ

(CREATED-AS
  [LAMBDA (FILE)                                             (* ; 
                                                           "Edited 20-Sep-2020 23:06 by rmk:")

    (* ;; "For lisp source files, returns (filecreatename filecreateddate)")

    (* ;; "For lisp compiled files, returns (cfilename cfiledate sfilecreatename sfilecreateddate)")

    (* ;; "For other files, (fullfilename NIL)")

    (* ;; "The cfilename is just the current directory name for DFASLs.")

    (* ;; "So:  (CADR value) is non-NIL for Lisp files.  Of those, (CDDR value) is non-NIL for compiled files.")

    (* ;; "We disable the package delimiter because the atoms in changes may have a packages that we don't know.")

    (CL:WITH-OPEN-FILE
     (STREAM FILE :DIRECTION :INPUT)
     (LET
      (FILEDATE FILENAME SOURCEDATE SOURCENAME LINE POS)
      [if (EQ (CHARCODE %()
                  (SKIPSEPRCODES STREAM))
          then                                           (* ; "Managed source or LCOM")
          (RESETLST
              [LET (FORM SFORM (RDTBL (FIND-READTABLE "OLD-INTERLISP-FILE")))
                   (SETQ POS (GETFILEPTR STREAM))
                   (READCCODE STREAM)
                   (if (EQ 'DEFINE-FILE-INFO (RATOM STREAM RDTBL))
                       then 

                             (* ;; "Reading is package-safe")

                             (SETFILEPTR STREAM POS)
                             (SETQ FORM (READ STREAM RDTBL))
                             (SETQ RDTBL (FIND-READTABLE (LISTGET (CDR FORM)
                                                                :READTABLE)))
                     else (SETFILEPTR STREAM POS))
                   (CL:WHEN (EQ 'PACKAGEDELIM (GETSYNTAX '%: RDTBL))
                       [RESETSAVE (SETSYNTAX '%: 'OTHER RDTBL)
                              `(SETSYNTAX %: PACKAGEDELIM ,RDTBL])

                   (* ;; "One way or the other, we're ready for the filecreated")

                   (CL:WHEN (EQ (CHARCODE %()
                                (SKIPSEPRCODES STREAM))
                       (SETQ FORM (READ STREAM RDTBL))
                       (CL:WHEN (MEMB (U-CASE (CAR FORM))
                                      '(FILECREATED IL%:FILECREATED))

                           (* ;; "IL%%:FILECREATED because we screwed the readtable.")

                           (if [STREQUAL "compiled on " (CAR (LISTP (CADDR FORM]
                               then                      (* ; "LCOM, get source info")
                                     (if [AND (EQ (CHARCODE %()
                                                      (SKIPSEPRCODES STREAM))
                                                  (MEMB [U-CASE (CAR (SETQ SFORM (READ STREAM RDTBL]
                                                        '(FILECREATED IL%:FILECREATED]
                                         then (SETQ FILENAME (FULLNAME STREAM))
                                               (SETQ FILEDATE (CADR FORM))
                                               (SETQ SOURCENAME (CADDR SFORM))
                                               (SETQ SOURCEDATE (CADR SFORM))
                                       else (SETQ FILENAME (FULLNAME STREAM))
                                             (SETQ FILEDATE (CADR FORM)))
                             else (SETQ FILENAME (CADDR FORM))
                                   (SETQ FILEDATE (CADR FORM)))))])
        elseif (SETQ POS (STRPOS "XCL Compiler output for source file " (SETQ LINE (CL:READ-LINE
                                                                                        STREAM))
                                    1 NIL NIL T))
          then                                           (* ; "DFASL compiled?")
                (SETQ SOURCENAME (SUBATOM LINE POS))
                (CL:WHEN (SETQ POS (STRPOS "Source file created " (SETQ LINE (CL:READ-LINE STREAM))
                                          1 NIL NIL T))
                    [SETQ SOURCEDATE (GDATE (IDATE (SUBSTRING LINE POS]
                    (CL:WHEN (SETQ POS (STRPOS "FASL file created " (SETQ LINE (CL:READ-LINE STREAM))
                                              1 NIL NIL T))
                        [SETQ FILEDATE (GDATE (IDATE (SUBSTRING LINE POS]))]

      (* ;; "Revert filenames to Interlisp package if needed:")

      (CL:WHEN (STRPOS "IL:" FILENAME)
          (SETQ FILENAME (SUBATOM FILENAME 4)))
      (CL:WHEN (STRPOS "IL:" SOURCENAME)
          (SETQ SOURCENAME (MKATOM SOURCENAME 4)))

      (* ;; "Return DATE NIL if file is not a Lisp file")

      `(,(OR FILENAME (FULLNAME STREAM))
        ,(AND FILEDATE (GDATE (IDATE FILEDATE)))
        ,@(CL:WHEN SOURCENAME
              (LIST SOURCENAME (GDATE (IDATE SOURCEDATE))))])

(SOURCE-FOR-COMPILED-P
  [LAMBDA (SOURCE COMPILED DFASLMARGIN)                      (* ; 
                                                           "Edited 31-Oct-2020 09:12 by rmk:")

    (* ;; "There seems to be some variation between the source dates in dfasl files and the filecreated date in the sources, they often don't match exactly.  But if they are within DFASLMARGIN, we assume a match.  We require exact date match for LCOMS")

    (* ;; "This is needed for dfasl files created before they recorded the source filecreated name and date instead of the directory source name and date when compile took place.")

    (* ;; "")

    (* ;; "DFASLMARGIN is a pair (after before) where we assume a match if the compiled date is no more than after minutes after the source date and no more than before minuts before (the diff is negative then).")

    (* ;; "A single positive integer x is interpreted as (x 0).  A single negative integer x is interpreted as (-x x) (before or after x).")

    (* ;; "Default is (20 0).")

    (* ;; "T is positive or negative infinity")

    (CL:UNLESS (LISTP SOURCE)
        (SETQ SOURCE (CREATED-AS SOURCE)))
    (CL:UNLESS (LISTP COMPILED)
        (SETQ COMPILED (CREATED-AS COMPILED)))
    (SETQ DFASLMARGIN (if (NULL DFASLMARGIN)
                          then 

                                (* ;; 
                       "If compiled is later than source by less than 20 minutes, it's probably OK")

                                '(20 0)
                        elseif (EQ T DFASLMARGIN)
                          then '(T 0)
                        elseif (LISTP DFASLMARGIN)
                        elseif (NOT (FIXP DFASLMARGIN))
                          then (ERROR "ILLEGAL DFASLMARGIN" DFASLMARGIN)
                        elseif (MINUSP DFASLMARGIN)
                          then (LIST (MINUS DFASLMARGIN)
                                         DFASLMARGIN)
                        else (LIST DFASLMARGIN 0)))
    (OR (EQUAL (CAR SOURCE)
               (CADDR COMPILED))
        (EQUAL (CADR SOURCE)
               (CADDDR COMPILED))
        (AND [EQ 'DFASL (U-CASE (FILENAMEFIELD (CAR COMPILED)
                                       'EXTENSION]
             (LET ((TIMEDIFF (COMPILE-SOURCE-DATE-DIFF COMPILED SOURCE)))

                  (* ;; "If compiled was no more than 20 minutes later, it's probably OK.  Of no more than DFASLMARGIN earlier, if it is negative.")

                  (AND (OR (EQ T (CAR DFASLMARGIN))
                           (LEQ TIMEDIFF (CAR DFASLMARGIN)))
                       (OR (EQ T (CADR DFASLMARGIN))
                           (GEQ TIMEDIFF (CADR DFASLMARGIN])

(COMPILE-SOURCE-DATE-DIFF
  [LAMBDA (CFILE SFILE)                                      (* ; 
                                                           "Edited 20-Sep-2020 22:59 by rmk:")

    (* ;; "Positive means that compiled is later than source, normal order but maybe by too much. Negative means that compiled came before source, i.e., compiled on a source that didn't yet exist.")

    (* ;; "Value is in minutes")

    (ROUND (FQUOTIENT [IDIFFERENCE [IDATE (CADDDR (OR (LISTP CFILE)
                                                      (CREATED-AS CFILE]
                             (IDATE (CADR (OR (LISTP SFILE)
                                              (CREATED-AS SFILE]
                  (TIMES 60 ONESECOND])
)
(DEFINEQ

(FIX-DIRECTORY-DATES
  [LAMBDA (FILES MARGIN)                                     (* ; 
                                                           "Edited 30-Oct-2020 22:01 by rmk:")

    (* ;; "For Lisp source and compiled files, ensures that the directory file date corresponds to the  filecreated date. Returns the list of files whose dates were changed.")

    (* ;; "This allows for the fact that directory dates that  are no later than, say, 30 seconds of the filecreated date are probably OK--the directory date may be set when the file is closed.")

    (* ;; "Use IDATEs in case FDCDATE is not Y2K.")

    (* ;; "Stop if directory date is more than 2 minutes earlier than the filecreated date.  Earlier could be because the dates are asserted at different points in the filing process.  But 2 minutes is worth thinking about.  Returning from HELP will get them aligned.")

    (SETQ MARGIN (ITIMES (OR MARGIN 2)
                        60 ONESECOND))
    (for F DIDATE FCDATE in (OR (LISTP FILES)
                                        (FILDIR FILES)) when (SETQ FCDATE (FILEDATE F))
       unless (IEQP (SETQ DIDATE (GETFILEINFO F 'ICREATIONDATE))
                        (SETQ FCDATE (IDATE FCDATE))) collect (CL:WHEN (IGREATERP (IDIFFERENCE
                                                                                       FCDATE DIDATE)
                                                                                  MARGIN)
                                                                      (HELP 
                                                       "DIRECTORY DATE EARLIER THAN FILECREATED DATE"
                                                                            (LIST F (GDATE DIDATE)
                                                                                  (GDATE FCDATE))))
                                                            (SETFILEINFO F 'ICREATIONDATE FCDATE)
                                                            F])

(FIX-EQUIV-DATES
  [LAMBDA (CDENTRIES)                                        (* ; 
                                                           "Edited  1-Sep-2020 16:21 by rmk:")

    (* ;; "For every entry whose files are EQUIVALENT and whose filedates are different, sets the directory of the file with the later date to be the date of the one with the earlier date.  This preumes that the later one must have been a copy. ")

    (CL:UNLESS CDENTRIES
        (PRINTOUT T "Note:  Using LASTCDENTRIES" T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (for CDE EARLY LATE in (CDR CDENTRIES) when (fetch EQUIV of CDE)
       unless (EQ '= (fetch DATEREL of CDE))
       collect (SELECTQ (fetch DATEREL of CDE)
                       (> (SETQ EARLY (fetch INFO2 of CDE))
                          (SETQ LATE (fetch INFO1 of CDE)))
                       (< (SETQ EARLY (fetch INFO1 of CDE))
                          (SETQ LATE (fetch INFO2 of CDE)))
                       (SHOULDNT))
             (SETFILEINFO (fetch FULLNAME of LATE)
                    'ICREATIONDATE
                    (GETFILEINFO (fetch FULLNAME of EARLY)
                           'ICREATIONDATE))
             (fetch FULLNAME of LATE])

(COPY-COMPARED-FILES
  [LAMBDA (CDENTRIES TARGET MATCHNAMES)                      (* ; 
                                                           "Edited  1-Sep-2020 16:20 by rmk:")

    (* ;; "Copies source files to target files whose matchname belongs to MATCHNAMES, if given.")

    (* ;; "TARGET is 1 or 2, indicating which side of the CD entry is the target.  Value is the list of matchnames whose files have been copied.")

    (* ;; "Directory filedates and other properties are preserved.")

    (CL:UNLESS (MEMB TARGET '(1 2))
           (ERROR "INVALID TARGET" TARGET))
    (CL:UNLESS CDENTRIES
        (PRINTOUT T "Note:  Using LASTCDENTRIES" T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (SETQ MATCHNAMES (MKLIST MATCHNAMES))
    (for CDE SINFO TINFO MATCHNAME in (CDR CDENTRIES) eachtime (SETQ SINFO
                                                                            (fetch INFO1
                                                                               of CDE))
                                                                    (SETQ TINFO (fetch INFO2
                                                                                   of CDE))
                                                                    (CL:WHEN (EQ TARGET 1)
                                                                           (swap SINFO TINFO))
                                                                    (SETQ MATCHNAME
                                                                     (fetch MATCHNAME
                                                                        of CDE))
       when (AND (fetch FULLNAME of SINFO)
                     (fetch FULLNAME of TINFO)) unless (AND MATCHNAMES
                                                                        (NOT (MEMB MATCHNAME 
                                                                                   MATCHNAMES)))
       collect (COPYFILE (fetch FULLNAME of SINFO)
                          (PACKFILENAME 'VERSION NIL 'BODY (fetch FULLNAME of TINFO)))
             MATCHNAME])

(COPY-MISSING-FILES
  [LAMBDA (CDENTRIES TARGET MATCHNAMES)                      (* ; 
                                                           "Edited  1-Sep-2020 16:21 by rmk:")

    (* ;; "Copies source files to target files whose matchname belongs to MATCHNAMES, if given.")

    (* ;; "TARGET is 1 or 2, indicating which side of the CD entry is the target.  Value is the list of matchnames whose files have been copied.")

    (* ;; "Directory filedates and other properties are preserved.")

    (CL:UNLESS (MEMB TARGET '(1 2))
           (ERROR "INVALID TARGET" TARGET))
    (CL:UNLESS CDENTRIES
        (PRINTOUT T "Note:  Using LASTCDENTRIES" T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (CL:UNLESS (STRINGP (CADR (CAR CDENTRIES)))
        (ERROR "(CAR CDENTRIES) IS NOT A VALID PARAMETER LIST" (CAR CDENTRIES)))
    (SETQ MATCHNAMES (MKLIST MATCHNAMES))
    (for CDE SINFO TINFO TDIR MATCHNAME (TDIR _ (CL:IF (EQ TARGET 1)
                                                        (CAAR CDENTRIES)
                                                        (CADAR CDENTRIES))) in (CDR CDENTRIES)
       eachtime (SETQ MATCHNAME (fetch MATCHNAME of CDE))
             (SETQ SINFO (fetch INFO1 of CDE))
             (SETQ TINFO (fetch INFO2 of CDE))
             (CL:WHEN (EQ TARGET 1)
                    (swap SINFO TINFO)) when (AND (fetch FULLNAME of SINFO)
                                                          (NOT (fetch FULLNAME of TINFO)))
       unless (AND MATCHNAMES (NOT (MEMB MATCHNAME MATCHNAMES)))
       collect 

             (* ;; "Using the source fullname in the target should preserve the version number")

             (COPYFILE (fetch FULLNAME of SINFO)
                    (PACKFILENAME 'BODY TDIR 'BODY (fetch FULLNAME of SINFO)))
             MATCHNAME])

(COMPILED-ON-SAME-SOURCE
  [LAMBDA (CDENTRIES)                                        (* ; 
                                                           "Edited  9-Sep-2020 13:00 by rmk:")

    (* ;; "Returms a subset of CDENTRIES consisting of files that are compiled on the same source (i.e. their source names or dates are the same). Preserves the header.")

    (CDSUBSET CDENTRIES (FUNCTION (LAMBDA (CDE)
                                        (DECLARE (USEDFREE INFO1 INFO2))
                                        (LET (CREATED1 CREATED2)
                                             (CL:WHEN [AND (EQ 'COMPILED (fetch TYPE of
                                                                                         INFO1))
                                                           (EQ 'COMPILED (fetch TYPE of
                                                                                         INFO2))
                                                           [CDDR (SETQ CREATED1
                                                                  (CREATED-AS (fetch FULLNAME
                                                                                     of INFO1]
                                                           (CDDR (SETQ CREATED2
                                                                  (CREATED-AS (fetch FULLNAME
                                                                                     of INFO2]
                                                 (OR (EQUAL (CADDR CREATED1)
                                                            (CADDR CREATED2))
                                                     (EQUAL (CADDDR CREATED1)
                                                            (CADDDR CREATED2))))])
)

(RPAQ ONESECOND (IDIFFERENCE (IDATE "1-Jan-2020 12:00:01")
                           (IDATE "1-Jan-2020 12:00:00")))

(RPAQ? LASTCDENTRIES NIL)
(DEFINEQ

(COMPARE-ENTRY-SOURCE-FILES
  [LAMBDA (CDENTRY LISTSTREAM EXAMINE DW?)               (* ; 
                                                           "Edited 30-Aug-2020 12:22 by rmk:")

    (* ;; "Wrapper to call COMPARESOURCES on the Lisp source files of CDENTRY")

    (CL:WHEN [AND (EQ 'SOURCE (fetch TYPE of (fetch INFO1 of CDENTRY)))
                  (EQ 'SOURCE (fetch TYPE of (fetch INFO2 of CDENTRY]
        (COMPARESOURCES (fetch FULLNAME of (fetch INFO1 of CDENTRY))
               (fetch FULLNAME of (fetch INFO2 of CDENTRY))
               EXAMINE DW? LISTSTREAM))])
)

(FILESLOAD COMPARESOURCES)
(PUTPROPS COMPAREDIRECTORIES COPYRIGHT ("Venue & Xerox Corporation" 1985 1986 1987 1988 1990 1994 1998
 2018 2020 2021))
(DECLARE%: DONTCOPY
  (FILEMAP (NIL (2361 17867 (COMPAREDIRECTORIES 2371 . 10922) (CDFILES 10924 . 15560) (
COMPAREDIRECTORIES.INFOS 15562 . 17142) (MATCHNAME 17144 . 17642) (MEDLEY-FIX-DIRS 17644 . 17865)) (
18053 25364 (CDPRINT 18063 . 22928) (CDPRINT.LINE 22930 . 25362)) (25365 27312 (CDMAP 25375 . 26136) (
CDENTRY 26138 . 26371) (CDSUBSET 26373 . 27310)) (27313 32974 (BINCOMP 27323 . 31677) (EOLTYPE 31679
 . 32972)) (33187 46849 (FIND-UNCOMPILED-FILES 33197 . 36905) (FIND-UNSOURCED-FILES 36907 . 39781) (
FIND-SOURCE-FILES 39783 . 41552) (FIND-COMPILED-FILES 41554 . 43697) (FIND-UNLOADED-FILES 43699 . 
44508) (FIND-LOADED-FILES 44510 . 45129) (FIND-MULTICOMPILED-FILES 45131 . 46847)) (46850 55247 (
CREATED-AS 46860 . 51722) (SOURCE-FOR-COMPILED-P 51724 . 54487) (COMPILE-SOURCE-DATE-DIFF 54489 . 
55245)) (55248 64552 (FIX-DIRECTORY-DATES 55258 . 57291) (FIX-EQUIV-DATES 57293 . 58618) (
COPY-COMPARED-FILES 58620 . 60809) (COPY-MISSING-FILES 60811 . 62715) (COMPILED-ON-SAME-SOURCE 62717
 . 64550)) (64707 65383 (COMPARE-ENTRY-SOURCE-FILES 64717 . 65381)))))
STOP
\ No newline at end of file
+(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)
(FILECREATED " 7-Jan-2021 23:21:40" 
{DSK}<Users>kaplan>Local>medley3.5>lispcore>lispusers>COMPAREDIRECTORIES.;275 63412  

      changes to%:  (FNS COMPAREDIRECTORIES)

      previous date%: "31-Oct-2020 09:13:05" 
{DSK}<Users>kaplan>Local>medley3.5>lispcore>lispusers>COMPAREDIRECTORIES.;274)


(* ; "
Copyright (c) 1985, 1986, 1987, 1988, 1990, 1994, 1998, 2018, 2020, 2021 by Venue & Xerox Corporation.  All rights reserved.
")

(PRETTYCOMPRINT COMPAREDIRECTORIESCOMS)

(RPAQQ COMPAREDIRECTORIESCOMS
       (
        (* ;; "Compare the contents of two directories.")

        (FNS COMPAREDIRECTORIES CDFILES COMPAREDIRECTORIES.INFOS MATCHNAME)
        (FNS CDPRINT CDPRINT.LINE)
        (FNS CDMAP CDENTRY CDSUBSET)
        (FNS BINCOMP EOLTYPE)
        (RECORDS CDENTRY CDINFO)
        
        (* ;; "look for compiled files older than the sources")

        (FNS FIND-UNCOMPILED-FILES FIND-UNSOURCED-FILES FIND-SOURCE-FILES FIND-COMPILED-FILES 
             FIND-UNLOADED-FILES FIND-LOADED-FILES FIND-MULTICOMPILED-FILES)
        (FNS CREATED-AS SOURCE-FOR-COMPILED-P COMPILE-SOURCE-DATE-DIFF)
        (FNS FIX-DIRECTORY-DATES FIX-EQUIV-DATES COPY-COMPARED-FILES COPY-MISSING-FILES 
             COMPILED-ON-SAME-SOURCE)
        [VARS (ONESECOND (IDIFFERENCE (IDATE "1-Jan-2020 12:00:01")
                                (IDATE "1-Jan-2020 12:00:00"]
        (INITVARS (LASTCDENTRIES NIL))
        (COMS (FNS COMPARE-ENTRY-SOURCE-FILES)
              (FILES COMPARESOURCES))))



(* ;; "Compare the contents of two directories.")

(DEFINEQ

(COMPAREDIRECTORIES
  [LAMBDA (DIR1 DIR2 SELECT FILEPATTERNS EXTENSIONSTOAVOID USEDIRECTORYDATE OUTPUTFILE ALLVERSIONS)
                                                            (* ; "Edited  7-Jan-2021 23:21 by rmk:")

    (* ;; "Compare the contents of two directories, e.g., for change-control purposes.  Compares files matching FILEPATTERN (or *.*;) on DIR1 and DIR2, listing which is newer, or when one is not found on the other.  If SELECT is or contains SAME/=, BEFORE/<, AFTER/>, then files where DIR1 is the same as, earlier than, or later than DIR2 are selected. SELECT= NIL is the same as (<  >), T is the same as (< > =).  Also allows selection based on file-length criteria.")

    (* ;; "")

    (* ;; "Unless USEDIRECTORYDATE, comparison is with respect to the the LISP filecreated dates if evailable.")

    (* ;; "")

    (* ;; "If OUTPUTFILE is NIL, the list of compared entries is returned.  Otherwise the selected entries are printed on OUTPUTFILE (T for the display).")

    [SETQ SELECT (SELECTQ SELECT
                     (NIL '(< > -* *-))
                     (T '(< > -* *- =))
                     (FOR S IN (MKLIST SELECT) COLLECT (SELECTQ S
                                                                       ((AFTER >) 
                                                                            '>)
                                                                       ((BEFORE <) 
                                                                            '<)
                                                                       ((SAME SAMEDATE =) 
                                                                            '=)
                                                                       (AUTHOR 'AUTHOR)
                                                                       (-* '-*)
                                                                       (*- '*-)
                                                                       (~= '~=)
                                                                       (ERROR 
                                                                      "UNRECOGNIZED SELECT PARAMETER"
                                                                              S]
    (PROG (INFOS1 INFOS2 CANDIDATES SELECTED COMPAREDATE DEPTH1 DEPTH2)
          [SETQ COMPAREDATE (INTERSECTION SELECT '(< > =]

     (* ;; "DIRECTORYNAME here to get unrelativized specifications for header.")

     (* ;; "Allow all subdirectories if a directory ends in *, but peel it off for the resolution")

          (CL:WHEN (EQ '* (NTHCHAR DIR1 -1))
              (SETQ DEPTH1 T)
              (SETQ DIR1 (SUBSTRING DIR1 1 -2)))
          (CL:WHEN (EQ '* (NTHCHAR DIR2 -1))
              (SETQ DEPTH2 T)
              (SETQ DIR2 (SUBSTRING DIR2 1 -2)))
          (SETQ DIR1 (OR (DIRECTORYNAME (OR DIR1 T))
                         (ERROR "DIRECTORY DOES NOT EXIST" DIR1)))
          (SETQ DIR2 (OR (DIRECTORYNAME (OR DIR2 T))
                         (ERROR "DIRECTORY DOES NOT EXIST" DIR2)))
          (PRINTOUT T "Comparing " DIR1 6 "vs. " DIR2 T "as of " (DATE)
                 " selecting " SELECT " ... ")
          (SETQ INFOS1 (COMPAREDIRECTORIES.INFOS (CDFILES DIR1 FILEPATTERNS EXTENSIONSTOAVOID
                                                            ALLVERSIONS DEPTH1)
                              USEDIRECTORYDATE))
          (SETQ INFOS2 (COMPAREDIRECTORIES.INFOS (CDFILES DIR2 FILEPATTERNS EXTENSIONSTOAVOID
                                                            ALLVERSIONS DEPTH2)
                              USEDIRECTORYDATE))
          (CL:UNLESS (AND INFOS2 INFOS1)
                 (RETURN))

     (* ;; "At this point the CAR of each info is the atomic match-name. Peel it off to produce candidate entries.")

     (* ;; 
   "Look through all of the I2's because multiple versions (if VERSIONS) have the same matchname")

          [SETQ CANDIDATES (FOR I1 IN INFOS1
                              JOIN (IF ALLVERSIONS
                                           THEN (OR (FOR I2 IN INFOS2
                                                           WHEN (EQ (CAR I2)
                                                                        (CAR I1))
                                                           COLLECT (LIST (CAR I1)
                                                                             (CDR I1)
                                                                             (CDR I2)))
                                                        (CONS (LIST (CAR I1)
                                                                    (CDR I1)
                                                                    NIL)))
                                         ELSE (CONS (LIST (CAR I1)
                                                              (CDR I1)
                                                              (CDR (ASSOC (CAR I1)
                                                                          INFOS2]

     (* ;; "Could be some 2's without 1's")

          (SORT [NCONC CANDIDATES (FOR I2 IN INFOS2 UNLESS (ASSOC (CAR I2)
                                                                              CANDIDATES)
                                     COLLECT (LIST (CAR I2)
                                                       NIL
                                                       (CDR I2]
                T)

     (* ;; "CANDIDATES is now a sorted list of the form (matchname entry1 entry2) where an entry consists of (fullname date length author)")

     (* ;; "Do the SELECT filtering and insert the date relation.")

          [SETQ SELECTED
           (FOR C MATCHNAME INFO1 INFO2 IDATE1 IDATE2 DATEREL BINCOMP IN CANDIDATES
              EACHTIME (SETQ MATCHNAME (POP C))
                    (SETQ INFO1 (POP C))
                    (SETQ INFO2 (POP C))
                    (IF (AND INFO1 INFO2)
                        THEN (SETQ IDATE1 (IDATE (FETCH DATE OF INFO1)))
                              (SETQ IDATE2 (IDATE (FETCH DATE OF INFO2)))
                              (SETQ DATEREL (IF (IGREATERP IDATE1 IDATE2)
                                                THEN '>
                                              ELSEIF (ILESSP IDATE1 IDATE2)
                                                THEN '<
                                              ELSE '=))
                      ELSE 

                            (* ;; "Just for printing--no comparison")

                            (SETQ DATEREL '*))
              WHEN (IF (AND INFO1 INFO2)
                           THEN (CL:WHEN (OR (NULL COMPAREDATE)
                                                 (SELECTQ DATEREL
                                                     (> (MEMB '> SELECT))
                                                     (< (MEMB '< SELECT))
                                                     (= (MEMB '= SELECT))
                                                     (SHOULDNT)))
                                        (SETQ BINCOMP (BINCOMP (FETCH FULLNAME OF INFO1)
                                                             (FETCH FULLNAME OF INFO2)
                                                             T
                                                             (FETCH EOL OF INFO1)
                                                             (FETCH EOL OF INFO2)))

                                 (* ;; "We want the ~= test to reflect exact byte equivalence, including the same EOL.  We use the BINCOMP value below to indicate EOL differences, so we check it here.")

                                        [NOT (AND (MEMB '~= SELECT)
                                                  BINCOMP
                                                  (EQ (FETCH EOL OF INFO1)
                                                      (FETCH EOL OF INFO2])
                         ELSEIF INFO1
                           THEN 

                                 (* ;; "OK if INFO2 is missing?")

                                 (MEMB '*- SELECT)
                         ELSE 

                               (* ;; "OK if INFO1 is missing?")

                               (MEMB '-* SELECT))
              COLLECT (CREATE CDENTRY
                                 MATCHNAME _ MATCHNAME
                                 INFO1 _ INFO1
                                 DATEREL _ DATEREL
                                 INFO2 _ INFO2
                                 EQUIV _ (CL:UNLESS (EQ DATEREL '*)
                                                BINCOMP]
          (PRINTOUT T (LENGTH SELECTED)
                 " entries" T)
          (PUSH SELECTED (LIST DIR1 DIR2 SELECT (DATE)))
          (SETQ LASTCDENTRIES SELECTED)
          (CL:UNLESS OUTPUTFILE (RETURN SELECTED))
          (RETURN (CDPRINT SELECTED OUTPUTFILE (MEMB 'AUTHOR SELECT SELECT])

(CDFILES
  [LAMBDA (DIR FILEPATTERNS EXTENSIONSTOAVOID ALLVERSIONS DEPTH)
                                                            (* ; "Edited 16-Oct-2020 13:42 by rmk:")

    (* ;; "Returns a list of fullnames for files that satisfy the criteria")

    (* ;; "For each name returned by (DIRECTORY DIR), assumes that FILEPATTERNS applies to the suffix after the directory (i.e. after NAMEPOS).  That includes possibly subdirectories, dotted files in ultimate file names, and versions.")

    (* ;; "     Exclude subdirectories unless FILEPATTERNS includes *>*")

    (* ;; "     Exclude dotted files (.xxx) unless FILEPATTERNS includes .*")

    (* ;; "     Exclude files with extensions in EXTENSIONSTOAVOID (*=NIL does no filtering)")

    (* ;; "     Exclude older versions unless ALLVERSIONS=T")

    (* ;; "  DEPTH is the number of subdirectories below the ones specified in DIR (NIL top-level of DIR only, T = any depth)")

    (* ;; "Resolve relative directories, so we can suppress subdirectory matches.   ")

    (SETQ EXTENSIONSTOAVOID (MKLIST (U-CASE EXTENSIONSTOAVOID)))
    [SETQ FILEPATTERNS (MKLIST (OR FILEPATTERNS '*]
    (FOR FP FN FPNAME FPEXT EXCLUDEDOTTED (TOPDIR _ (DIRECTORYNAME (OR DIR T))) IN 
                                                                                         FILEPATTERNS
       JOIN [SETQ FPNAME (U-CASE (FILENAMEFIELD FP 'NAME]
             [SETQ FPEXT (U-CASE (FILENAMEFIELD FP 'EXTENSION]
             (CL:UNLESS FPNAME
                 (IF FPEXT
                     THEN 

                           (* ;; ".XY")

                           (SETQ FPNAME (PACK* "." FPEXT))
                   ELSE (SETQ FPNAME '*)))
             (CL:UNLESS FPEXT
                 (SETQ FPEXT '*))
             (SETQ EXCLUDEDOTTED (NEQ (CHARCODE %.)
                                      (CHCON1 FPNAME)))
             (SETQ FN (PACKFILENAME.STRING 'VERSION (CL:IF ALLVERSIONS
                                                        '*
                                                        "")
                             'DIRECTORY TOPDIR 'NAME '* 'EXTENSION '*)) 

             (* ;; "DEPTH is the number of internal %">%"")

             [IF (EQ DEPTH T)
                 THEN (SETQ DEPTH MAX.SMALLP)
               ELSEIF DEPTH
               ELSE (SETQ DEPTH (BIND (CNT _ 0)
                                           (POS _ 0)
                                           (FNDIR _ (FILENAMEFIELD FN 'DIRECTORY))
                                       WHILE (SETQ POS (STRPOS ">" FNDIR (ADD1 POS)))
                                       DO (ADD CNT 1) FINALLY (RETURN CNT]
             (FOR FULLNAME NAME EXT THISDEPTH IN (DIRECTORY FN)
                EACHTIME [SETQ NAME (U-CASE (FILENAMEFIELD FULLNAME 'NAME]
                      [SETQ EXT (U-CASE (FILENAMEFIELD FULLNAME 'EXTENSION]
                      (CL:UNLESS NAME
                          (IF EXT
                              THEN 

                                    (* ;; ".XY")

                                    (SETQ NAME (PACK* "." EXT))
                                    (SETQ EXT NIL)))
                      (CL:WHEN (AND EXCLUDEDOTTED (EQ (CHARCODE %.)
                                                      (CHCON1 NAME)))
                             (GO $$ITERATE))
                      (SETQ THISDEPTH (BIND (CNT _ 0)
                                             (POS _ 0)
                                             (FNDIR _ (FILENAMEFIELD FULLNAME 'DIRECTORY))
                                         WHILE (SETQ POS (STRPOS ">" FNDIR (ADD1 POS)))
                                         DO (ADD CNT 1) FINALLY (RETURN CNT))) 

                      (* ;; "An empty subdirectory may appear without name or extensions")
 WHEN (AND (OR NAME EXT)
               (OR (EQ FPNAME '*)
                   (EQ FPNAME NAME))
               (OR (EQ FPEXT '*)
                   (EQ FPEXT EXT))) UNLESS [OR (IGREATERP THISDEPTH DEPTH)
                                                   (AND EXT (OR (MEMB '* EXTENSIONSTOAVOID)
                                                                (MEMB EXT EXTENSIONSTOAVOID]
                COLLECT FULLNAME) FINALLY (CL:UNLESS $$VAL (PRINTOUT T 
                                                                          "No relevant files in " 
                                                                          TOPDIR T])

(COMPAREDIRECTORIES.INFOS
  [LAMBDA (FILES USEDIRECTORYDATE)                      (* ; "Edited 13-Oct-2020 08:42 by rmk:")

    (* ;; "Value is a list of CDINFOS with the match-name consed on to the front")

    (FOR FULLNAME TYPE LDATE IN FILES
       COLLECT 

             (* ;; "GDATE/IDATE in case Y2K")

             (SETQ LDATE (FILEDATE FULLNAME))                (* ; "Is it a Lisp file?")
             (CONS (MATCHNAME FULLNAME)
                   (CREATE CDINFO
                          FULLNAME _ FULLNAME
                          DATE _ [GDATE (IDATE (IF USEDIRECTORYDATE
                                                   THEN (GETFILEINFO FULLNAME 'CREATIONDATE)
                                                 ELSEIF (OR LDATE (GETFILEINFO FULLNAME
                                                                             'CREATIONDATE]
                          LENGTH _ (GETFILEINFO FULLNAME 'LENGTH)
                          AUTHOR _ (GETFILEINFO FULLNAME 'AUTHOR)
                          TYPE _ (IF LDATE
                                     THEN (CL:IF (MEMB (FILENAMEFIELD FULLNAME 'EXTENSION)
                                                           *COMPILED-EXTENSIONS*)
                                                  'COMPILED
                                                  'SOURCE)
                                   ELSE (PRINTFILETYPE FULLNAME))
                          EOL _ (EOLTYPE FULLNAME])

(MATCHNAME
  [LAMBDA (NAME)                                        (* ; "Edited  5-Sep-2020 13:41 by rmk:")

    (* ;; "The NAME.DIR for matching related files")

    (LET ((M (PACKFILENAME 'HOST NIL 'VERSION NIL 'DIRECTORY NIL 'BODY NAME)))

         (* ;; "Strip off the nuisance period")

         (CL:IF (EQ (CHARCODE %.)
                    (NTHCHARCODE M -1))
             (SUBATOM M 1 -2)
             M)])
)
(DEFINEQ

(CDPRINT
  [LAMBDA (CDENTRIES FILE PRINTAUTHOR)                  (* ; "Edited 13-Oct-2020 08:38 by rmk:")

    (* ;; "Typically CDENTRIES will have a header.  If not, we fake one up, at least for the directories and today's date.")

    (CL:UNLESS CDENTRIES
        (PRINTOUT T T "Note:  Using LASTCDENTRIES" T T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (RESETLST
        (LET (INFO1 TEXT STREAM DATE1POS ENDDATE1 DIR1 DIR2 (HEADER (CAR CDENTRIES))
                    NCHARSDIR1)
             (CL:UNLESS (STRINGP (CADR HEADER))
                 (SETQ HEADER (LIST [FOR E IN CDENTRIES WHEN (FETCH INFO1
                                                                            OF E)
                                       DO (RETURN (PACKFILENAME 'NAME NIL 'EXTENSION NIL
                                                             'VERSION NIL 'BODY
                                                             (FETCH FULLNAME
                                                                OF (FETCH INFO1 OF E]
                                    [FOR E IN CDENTRIES WHEN (FETCH INFO2
                                                                            OF E)
                                       DO (RETURN (PACKFILENAME 'NAME NIL 'EXTENSION NIL
                                                             'VERSION NIL 'BODY
                                                             (FETCH FULLNAME
                                                                OF (FETCH INFO2 OF E]
                                    NIL
                                    (DATE)))
                 (PUSH CDENTRIES HEADER))
             (SETQ DIR1 (CAR HEADER))
             (SETQ NCHARSDIR1 (NCHARS DIR1))
             (SETQ DIR2 (CADR HEADER))
             (CL:UNLESS (SETQ STREAM (GETSTREAM FILE 'OUTPUT T))
                 [RESETSAVE (SETQ STREAM (OPENSTREAM (PACKFILENAME 'EXTENSION 'TXT 'BODY FILE)
                                                'OUTPUT
                                                'NEW))
                        '(PROGN (CLOSEF? OLDVALUE])
             (CL:WHEN DIR1
                 (PRINTOUT STREAM "Comparing " DIR1 6 "vs. " DIR2 T "as of " (CADDDR HEADER))
                 (CL:WHEN (CADDR HEADER)
                     (PRINTOUT STREAM " selecting " (CADDR HEADER)))
                 (PRINTOUT STREAM -2 (LENGTH (CDR CDENTRIES))
                        " entries" T T))
             (LINELENGTH 1000 STREAM)                        (* ; "Don't wrap")

             (* ;; "DATE1POS is the position of the first character of INFO1's date, used for tabbing.  We have to measure the filename, date, size, and author if desired")

             (IF (CDR CDENTRIES)
                 THEN (FOR E INFO1 (MAXDATE1WIDTH _ 0)
                                 (SPACEWIDTH _ 1)
                                 (PARENWIDTH _ 2) IN (CDR CDENTRIES)
                             WHEN (SETQ INFO1 (FETCH INFO1 OF E))
                             LARGEST [SETQ MAXDATE1WIDTH (IMAX MAXDATE1WIDTH
                                                                   (NCHARS (FETCH DATE
                                                                              OF INFO1]
                                   (IPLUS (- (NCHARS (FETCH FULLNAME OF INFO1))
                                             NCHARSDIR1)
                                          (NCHARS (FETCH LENGTH OF INFO1))
                                          (CL:IF PRINTAUTHOR
                                              (IPLUS SPACEWIDTH PARENWIDTH
                                                     (NCHARS (FETCH AUTHOR OF INFO1)))
                                              0)) FINALLY 

                                                        (* ;; 
                            "First 4 for width of equiv.  $$EXTREME is NIL if there are no INFO1's")

                                                        (SETQ DATE1POS (IPLUS (OR $$EXTREME 10)
                                                                              4
                                                                              (ITIMES 3 SPACEWIDTH)))
                                                        (SETQ ENDDATE1 (IPLUS DATE1POS MAXDATE1WIDTH)
                                                         ))
                       (FOR E IN (CDR CDENTRIES)
                          DO (CDPRINT.LINE STREAM E PRINTAUTHOR DATE1POS ENDDATE1 NCHARSDIR1
                                        (NCHARS DIR2)))
               ELSE (PRINTOUT T "CDENTRIES is empty" T))
             (AND STREAM (CLOSEF? STREAM))))])

(CDPRINT.LINE
  [LAMBDA (STREAM ENTRY PRINTAUTHOR DATE1POS ENDDATE1 NCHARSDIR1 NCHARSDIR2)
                                                            (* ; "Edited 13-Oct-2020 08:51 by rmk:")

    (* ;; "Format one line of the directory comparison listing.  If PRINTAUTHOR and AUTHOR1 or AUTHOR2 are non-NIL, list the author in parens; otherwise omit it.")

    (LET ((INFO1 (FETCH INFO1 OF ENTRY))
          (INFO2 (FETCH INFO2 OF ENTRY)))
         (PRINTOUT STREAM (SELECTQ (FETCH EQUIV OF ENTRY)
                              (T "==")
                              (NIL "  ")
                              (PROGN (SELECTQ (FETCH EOL OF INFO1)
                                         (CR 'C)
                                         (LF 'L)
                                         (CRLF 2)
                                         " ")
                                     (SELECTQ (FETCH EOL OF INFO2)
                                         (CR 'C)
                                         (LF 'L)
                                         (CRLF 2)
                                         " ")))
                " ")
         (CL:WHEN INFO1
             (PRINTOUT STREAM (SUBSTRING (FETCH FULLNAME OF INFO1)
                                     (ADD1 NCHARSDIR1)
                                     NIL
                                     (CONSTANT (CONCAT)))
                    " ")
             (CL:WHEN PRINTAUTHOR
                 (PRINTOUT STREAM "(" (FETCH AUTHOR OF INFO1)
                        ") "))
             (PRINTOUT STREAM (FETCH LENGTH OF INFO1)
                    .TAB0 DATE1POS (FETCH DATE OF INFO1)))
         (PRINTOUT STREAM .TAB0 ENDDATE1 "  " (FETCH DATEREL OF ENTRY)
                "  ")
         (CL:WHEN INFO2
             (PRINTOUT STREAM (FETCH DATE OF INFO2)
                    "   "
                    (SUBSTRING (FETCH FULLNAME OF INFO2)
                           (ADD1 NCHARSDIR2)
                           NIL
                           (CONSTANT (CONCAT)))
                    " ")
             (CL:WHEN PRINTAUTHOR
                 (PRINTOUT STREAM "(" (FETCH AUTHOR OF INFO2)
                        ") "))
             (PRINTOUT STREAM (FETCH LENGTH OF INFO2)))
         (TERPRI STREAM])
)
(DEFINEQ

(CDMAP
  [LAMBDA (CDENTRIES FN)                                (* ; "Edited  6-Sep-2020 15:58 by rmk:")
    (CL:UNLESS CDENTRIES
        (PRINTOUT T T "Note:  Using LASTCDENTRIES" T T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (FOR CDE MATCHNAME INFO1 DATEREL INFO2 EQUIV IN (CDR CDENTRIES)
       DECLARE (SPECVARS MATCHNAME INFO1 DATEREL INFO2 EQUIV)
       EACHTIME (SETQ MATCHNAME (FETCH MATCHNAME OF CDE))
             (SETQ INFO1 (FETCH INFO1 OF CDE))
             (SETQ DATEREL (FETCH DATEREL OF CDE))
             (SETQ INFO2 (FETCH INFO2 OF CDE))
             (SETQ EQUIV (FETCH EQUIV OF CDE)) DO (APPLY* FN CDE])

(CDENTRY
  [LAMBDA (MATCHNAME CDENTRIES)                     (* ; "Edited  5-Sep-2020 21:09 by rmk:")
    (ASSOC MATCHNAME (OR CDENTRIES LASTCDENTRIES])

(CDSUBSET
  [LAMBDA (CDENTRIES FN)                                (* ; "Edited 15-Sep-2020 13:49 by rmk:")
    (CL:UNLESS CDENTRIES
        (PRINTOUT T T "Note:  Using LASTCDENTRIES" T T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (CONS (CAR CDENTRIES)
          (FOR CDE MATCHNAME INFO1 DATEREL INFO2 EQUIV IN (CDR CDENTRIES)
             DECLARE (SPECVARS MATCHNAME INFO1 DATEREL INFO2 EQUIV)
             EACHTIME (SETQ MATCHNAME (FETCH MATCHNAME OF CDE))
                   (SETQ INFO1 (FETCH INFO1 OF CDE))
                   (SETQ DATEREL (FETCH DATEREL OF CDE))
                   (SETQ INFO2 (FETCH INFO2 OF CDE))
                   (SETQ EQUIV (FETCH EQUIV OF CDE)) WHEN (APPLY* FN CDE) COLLECT
                                                                                      CDE])
)
(DEFINEQ

(BINCOMP
  [LAMBDA (FILE1 FILE2 EOLDIFFOK EOL1 EOL2)             (* ; "Edited 13-Oct-2020 08:53 by rmk:")

    (* ;; "Returns T if FILE1 and FILE2 are byte-equivalent.  Returns EOLDIFF if they are byte equivalent except for CR/LF/CRLF exchanges.  ")

    (* ;; "If EOLDIFFOK, return indicates that the files are the same except for EOL mappings.  If EOL1 and EOL2 are not provided, they are computed here.")

    (IF (IEQP (GETFILEINFO FILE1 'LENGTH)
                  (GETFILEINFO FILE2 'LENGTH))
        THEN [CL:WITH-OPEN-FILE
                  (STREAM1 FILE1 :DIRECTION :INPUT)
                  (CL:WITH-OPEN-FILE
                   (STREAM2 FILE2 :DIRECTION :INPUT)
                   (SETFILEINFO STREAM1 'ENDOFSTREAMOP (FUNCTION NILL))

                   (* ;; "Simpler code to recompute eol's even if provided")

                   (BIND B1 B2 EOL1 EOL2 EOLDIFF WHILE (SETQ B1 (\BIN STREAM1))
                      UNLESS (EQ B1 (SETQ B2 (\BIN STREAM2)))
                      DO (CL:UNLESS (AND EOLDIFFOK (SELCHARQ B1
                                                            (CR (CL:WHEN (EQ EOL1 'LF)
                                                                       (RETURN NIL))
                                                                (SETQ EOL1 'CR)
                                                                (SETQ EOL2 'LF)
                                                                (EQ B2 (CHARCODE LF)))
                                                            (LF (CL:WHEN (EQ EOL1 'CR)
                                                                       (RETURN NIL))
                                                                (SETQ EOL1 'LF)
                                                                (SETQ EOL2 'CR)
                                                                (EQ B2 (CHARCODE CR)))
                                                            NIL))
                                    (RETURN NIL))
                            (CL:UNLESS EOLDIFF
                                (SETQ EOLDIFF (LIST EOL1 EOL2))) FINALLY (RETURN (OR EOLDIFF T]
      ELSEIF EOLDIFFOK
        THEN 

              (* ;; "Lengths are different possibly because of CRLF to CR/LF substitutions.")

              (* ;; 
        "More complex code could detect the EOLTYPE incrementally without separate passes, but ...")

              (CL:UNLESS EOL1
                  (SETQ EOL1 (EOLTYPE FILE1)))
              (CL:UNLESS EOL2
                  (SETQ EOL2 (EOLTYPE FILE2)))
              (CL:WHEN (IF [AND (EQ EOL1 'CRLF)
                                    (MEMB EOL2 '(LF CR]
                         ELSEIF [AND (EQ EOL2 'CRLF)
                                         (MEMB EOL1 '(LF CR]
                           THEN (SWAP FILE1 FILE2))

                  (* ;; "FILE1 is now CRLF, FILE2 is not.  If FILE1 isn't longer, it can't have a CRLF that corresponds to a CR or LF.")

                  (CL:WHEN (IGREATERP (GETFILEINFO FILE1 'LENGTH)
                                  (GETFILEINFO FILE2 'LENGTH))
                      [CL:WITH-OPEN-FILE (STREAM1 FILE1 :DIRECTION :INPUT)
                             (CL:WITH-OPEN-FILE (STREAM2 FILE2 :DIRECTION :INPUT)
                                    (SETFILEINFO STREAM1 'ENDOFSTREAMOP (FUNCTION NILL))
                                    (BIND B1 B2 EOLDIFF WHILE (SETQ B1 (\BIN STREAM1))
                                       UNLESS (EQ B1 (SETQ B2 (\BIN STREAM2)))
                                       DO (CL:UNLESS [AND (EQ (CHARCODE CR)
                                                                  B1)
                                                              (EQ (CHARCODE LF)
                                                                  (\BIN STREAM1))
                                                              (MEMB B2 (CHARCODE (CR LF]
                                                     (RETURN NIL))
                                             (CL:UNLESS EOLDIFF
                                                 (SETQ EOLDIFF (LIST EOL1 EOL2)))
                                       FINALLY (RETURN (OR EOLDIFF T]))])

(EOLTYPE
  [LAMBDA (FILE)                                        (* ; "Edited  3-Sep-2020 17:05 by rmk:")

    (* ;; "Returns the EOLCONVENTION of FILE if it only sees one kind, NIL if it can't decide.")

    (CL:WITH-OPEN-FILE (STREAM FILE :DIRECTION :INPUT)
           (SETFILEINFO STREAM 'ENDOFSTREAMOP (FUNCTION NILL))
           (BIND EOLTYPE
              DO (SELCHARQ (OR (\BIN STREAM)
                                   (RETURN EOLTYPE))
                          (CR (IF (EQ (CHARCODE LF)
                                          (\PEEKBIN STREAM T))
                                  THEN (CL:WHEN (MEMB EOLTYPE '(LF CR))
                                                  (RETURN NIL))
                                        (\BIN STREAM)
                                        (SETQ EOLTYPE 'CRLF)
                                ELSEIF (MEMB EOLTYPE '(LF CRLF))
                                  THEN (RETURN NIL)
                                ELSE (SETQ EOLTYPE 'CR)))
                          (LF (CL:WHEN (MEMB EOLTYPE '(CR CRLF))
                                     (RETURN NIL))
                              (SETQ EOLTYPE 'LF))
                          NIL])
)
(DECLARE%: EVAL@COMPILE

(RECORD CDENTRY (MATCHNAME INFO1 DATEREL INFO2 . EQUIV))

(RECORD CDINFO (FULLNAME DATE LENGTH AUTHOR TYPE EOL))
)



(* ;; "look for compiled files older than the sources")

(DEFINEQ

(FIND-UNCOMPILED-FILES
  [LAMBDA (FILES DFASLMARGIN COMPILEEXTS)               (* ; "Edited 20-Sep-2020 23:04 by rmk:")
                                                             (* ; "Edited  3-Nov-94 15:17 by jds")

    (* ;; "Produces a list of the source files in FILES that have no corresponding compiled file")

    (* ;; "This determines whether there is at least one compiled file.  If there are two or more, that's a problem")

    (* ;; "We want the most recent version only")

    (* ;; "Source files have a 2-element created-as with a non-NIL date")

    (SETQ FILES (FOR F IN (OR (LISTP FILES)
                                      (FILDIR FILES)) UNLESS (MEMB (SETQ F (PACKFILENAME
                                                                                'VERSION NIL
                                                                                'BODY F))
                                                                       $$VAL) COLLECT F))
    (FOR F SCREATION FILES IN FILES WHEN (AND (CADR (SETQ SCREATION (CREATED-AS
                                                                                 F)))
                                                          (NOT (CDDR SCREATION)))
       WHEN [SETQ FILES
                 (FOR CEXT CF IN (OR COMPILEEXTS *COMPILED-EXTENSIONS*)
                    WHEN (SETQ CF (INFILEP (PACKFILENAME 'EXTENSION CEXT 'VERSION NIL
                                                      'BODY F)))
                    COLLECT (CL:WHEN (SOURCE-FOR-COMPILED-P SCREATION CF DFASLMARGIN)
                                       (RETURN NIL))
                          CF
                    FINALLY 

                          (* ;; "If we found some compiled files, they weren't on this source.  If there weren't any compiled files to check, maybe there weren't any functions.")

                          (* ;; 
      "NLSETQ because we don't want to stop if there is an error, typically from a package problem")

                          (RETURN (OR $$VAL (LET [(FCOMS (CAR (NLSETQ (GETDEF (FILECOMS F)
                                                                             'VARS F]
                                                 (IF (NULL FCOMS)
                                                     THEN 

                                                           (* ;; 
                                               "GETDEF caused an error.  Maybe a package problem. ")

                                                           (AND NIL 'NOCOMMANDS)
                                                   ELSEIF (INFILECOMS? NIL '(FUNCTIONS FNS)
                                                                     FCOMS)
                                                     THEN T]
       COLLECT (CONS F (SELECTQ FILES
                               (T NIL)
                               (NOCOMMANDS (CONS "No commands"))
                               (FOR CF IN FILES COLLECT 

                                                        (* ;; 
           "Positive means that compiled is later than source, normal order but maybe by too much.")

                                                              (* ;; 
                                            "Negative means that compiled came before source.  Odd")

                                                              (LIST CF (COMPILE-SOURCE-DATE-DIFF
                                                                        CF SCREATION])

(FIND-UNSOURCED-FILES
  [LAMBDA (FILES DFASLMARGIN COMPILEEXTS)               (* ; "Edited 15-Sep-2020 15:32 by rmk:")
                                                             (* ; "Edited  3-Nov-94 15:17 by jds")

    (* ;; 
  "Produces a list of compiled FILES for which no source file can be found in the same directory.")

    (* ;; "The source date in at least one DFASL was off by a second, maybe some sort of IDATE rounding?  So, give a margin.")

    (* ;; 
"We want the most recent version only.  Check CREATED-AS to make sure it really is a compiled file.")

    (* ;; "Sort to get lcoms and dfasls next to each other.")

    (LET (CCREATEDS)
         (SETQ CCREATEDS (FOR CEXT FOUND CCREATED INSIDE (OR COMPILEEXTS 
                                                                     *COMPILED-EXTENSIONS*)
                            JOIN (FOR CF IN [OR (LISTP FILES)
                                                            (FILDIR (PACKFILENAME 'EXTENSION CEXT
                                                                           'VERSION "" 'BODY
                                                                           '*]
                                        WHEN (CDDR (SETQ CCREATED (CREATED-AS CF)))
                                        UNLESS (MEMBER CCREATED $$VAL) COLLECT CCREATED)))

         (* ;; "CCREATEDS is now a list of CREATED-AS items")

         (FOR CC SF IN CCREATEDS UNLESS (AND [SETQ SF (INFILEP (PACKFILENAME 'EXTENSION 
                                                                                  NIL 'VERSION NIL
                                                                                  'BODY
                                                                                  (CAR CC]
                                                         (SOURCE-FOR-COMPILED-P (SETQ SF
                                                                                     (CREATED-AS
                                                                                      SF))
                                                                CC DFASLMARGIN))
            COLLECT [LIST (CAR CC)
                              (AND SF (LIST (CAR SF)
                                            (ROUND (COMPILE-SOURCE-DATE-DIFF CC SF]
            FINALLY (RETURN (SORT $$VAL (FUNCTION (LAMBDA (CF1 CF2)
                                                        (ALPHORDER (FILENAMEFIELD (CAR CF1)
                                                                          'NAME)
                                                               (FILENAMEFIELD (CAR CF2)
                                                                      'NAME])

(FIND-SOURCE-FILES
  [LAMBDA (CFILES SDIRS DFASLMARGIN)                    (* ; "Edited  9-Sep-2020 12:26 by rmk:")

    (* ;; "Returns (CFILE . SFILES) pairs where CFILE is a Lisp compiled file in CFILES SFILES is a list of source files in SDIRS that CFILE was compiled on.")

    (* ;; "This suggests that one of CFILES should be copied to the SFILE directory.")

    (SETQ SDIRS (FOR SD INSIDE (OR SDIRS T) COLLECT (DIRECTORYNAME SD)))
    (SORT (FOR CF SFILES CNAME CCREATED IN (OR (LISTP CFILES)
                                                       (FILDIR CFILES))
             WHEN (AND (SETQ CNAME (INFILEP CF))
                           (CDDR (SETQ CCREATED (CREATED-AS CF)))
                           (SETQ SFILES (FOR SD SF IN SDIRS
                                           WHEN (AND (SETQ SF (INFILEP (PACKFILENAME
                                                                            'NAME
                                                                            (FILENAMEFIELD
                                                                             CF
                                                                             'NAME)
                                                                            'BODY SD)))
                                                         (SOURCE-FOR-COMPILED-P SF CCREATED 
                                                                DFASLMARGIN)) COLLECT SF)))
             COLLECT (CONS CNAME SFILES))
          (FUNCTION (LAMBDA (P1 P2)
                      (ALPHORDER (FILENAMEFIELD (CAR P1))
                             (FILENAMEFIELD (CAR P2])

(FIND-COMPILED-FILES
  [LAMBDA (SFILES CDIRS DFASLMARGIN)                    (* ; "Edited  9-Sep-2020 12:26 by rmk:")

    (* ;; "Returns (SFILE . CFILES) pairs where SFILE is a Lisp source file in SFILES CFILES is a list of compiled files in CDIRS that were compiled on SFILE.")

    (* ;; "FILEDATE is true for source files and compiled files")

    (* ;; "This suggests that one of CFILES should be copied to the SFILE directory.")

    (SETQ CDIRS (FOR CD INSIDE (OR CDIRS T) COLLECT (DIRECTORYNAME CD)))
    (SORT (FOR SF CFILES SNAME SCREATED IN (OR (LISTP SFILES)
                                                       (FILDIR SFILES))
             WHEN [AND (SETQ SNAME (INFILEP SF))
                           (SETQ SCREATED (CREATED-AS SF))
                           (NOT (CDDR SCREATED))
                           (SETQ CFILES (FOR CEXT (ROOT _ (FILENAMEFIELD SNAME 'NAME))
                                           IN *COMPILED-EXTENSIONS*
                                           JOIN (FOR CD CF IN CDIRS
                                                       WHEN (AND (SETQ CF
                                                                      (INFILEP (PACKFILENAME
                                                                                'NAME ROOT
                                                                                'EXTENSION CEXT
                                                                                'BODY CD)))
                                                                     (SOURCE-FOR-COMPILED-P
                                                                      SCREATED CF DFASLMARGIN))
                                                       COLLECT CF] COLLECT (CONS SNAME CFILES
                                                                                         ))
          (FUNCTION (LAMBDA (P1 P2)
                      (ALPHORDER (FILENAMEFIELD (CAR P1))
                             (FILENAMEFIELD (CAR P2])

(FIND-UNLOADED-FILES
  [LAMBDA (FILES)                                       (* ; "Edited  9-Sep-2020 19:35 by rmk:")

    (* ;; "Returns the files in FILES that don't have FILECREATED properties and presumably are therefore not loaded in the current sysout.")

    (FOR F IN (OR (LISTP FILES)
                          (FILDIR FILES)) WHEN (AND (SETQ F (INFILEP (CL:IF (LISTP F)
                                                                             (CAR F)
                                                                             F)))
                                                        (FILEDATE F))
       UNLESS (GETP (FILENAMEFIELD F 'NAME)
                        'FILEDATES) COLLECT F])

(FIND-LOADED-FILES
  [LAMBDA (ROOTFILENAMES)                               (* ; "Edited 19-Sep-2020 07:20 by rmk:")
    (FOR RN INSIDE ROOTFILENAMES WHEN (GETP RN 'FILEDATES)
       COLLECT (CONS RN (FOR F IN LOADEDFILELST WHEN (EQ RN (FILENAMEFIELD
                                                                             F
                                                                             'NAME)) COLLECT
                                                                                     F])

(FIND-MULTICOMPILED-FILES
  [LAMBDA (FILES SHOWINFO)                              (* ; "Edited 20-Sep-2020 20:57 by rmk:")

    (* ;; "Returns a list of names for files in FILES that have multiple compilations")

    (LET (SFILES)
         (FOR F EXT NAME IN (OR (LISTP FILES)
                                        (FILDIR FILES)) WHEN (MEMB (SETQ EXT (FILENAMEFIELD
                                                                                  F
                                                                                  'EXTENSION))
                                                                       *COMPILED-EXTENSIONS*)
            DO (SETQ NAME (FILENAMEFIELD F 'NAME)) 

                  (* ;; "PUSHNEW because we haven't filtered out versions")

                  (PUSHNEW [CDR (OR (ASSOC NAME SFILES)
                                        (CAR (PUSH SFILES (CONS NAME]
                         EXT))
         (FOR S IN SFILES WHEN (CDDR S)
            COLLECT (IF SHOWINFO
                            THEN `[,(CAR S)
                                       ,(CADAR (FIND-LOADED-FILES (CAR S)))
                                       ,(CREATED-AS (CAR S))
                                       ,@(FOR EXT IN (SORT (CDR S))
                                            COLLECT (CREATED-AS (PACKFILENAME 'EXTENSION EXT
                                                                               'BODY
                                                                               (CAR S]
                          ELSE (CAR S])
)
(DEFINEQ

(CREATED-AS
  [LAMBDA (FILE)                                        (* ; "Edited 20-Sep-2020 23:06 by rmk:")

    (* ;; "For lisp source files, returns (filecreatename filecreateddate)")

    (* ;; "For lisp compiled files, returns (cfilename cfiledate sfilecreatename sfilecreateddate)")

    (* ;; "For other files, (fullfilename NIL)")

    (* ;; "The cfilename is just the current directory name for DFASLs.")

    (* ;; "So:  (CADR value) is non-NIL for Lisp files.  Of those, (CDDR value) is non-NIL for compiled files.")

    (* ;; "We disable the package delimiter because the atoms in changes may have a packages that we don't know.")

    (CL:WITH-OPEN-FILE
     (STREAM FILE :DIRECTION :INPUT)
     (LET
      (FILEDATE FILENAME SOURCEDATE SOURCENAME LINE POS)
      [IF (EQ (CHARCODE %()
                  (SKIPSEPRCODES STREAM))
          THEN                                           (* ; "Managed source or LCOM")
          (RESETLST
              [LET (FORM SFORM (RDTBL (FIND-READTABLE "OLD-INTERLISP-FILE")))
                   (SETQ POS (GETFILEPTR STREAM))
                   (READCCODE STREAM)
                   (IF (EQ 'DEFINE-FILE-INFO (RATOM STREAM RDTBL))
                       THEN 

                             (* ;; "Reading is package-safe")

                             (SETFILEPTR STREAM POS)
                             (SETQ FORM (READ STREAM RDTBL))
                             (SETQ RDTBL (FIND-READTABLE (LISTGET (CDR FORM)
                                                                :READTABLE)))
                     ELSE (SETFILEPTR STREAM POS))
                   (CL:WHEN (EQ 'PACKAGEDELIM (GETSYNTAX '%: RDTBL))
                       [RESETSAVE (SETSYNTAX '%: 'OTHER RDTBL)
                              `(SETSYNTAX %: PACKAGEDELIM ,RDTBL])

                   (* ;; "One way or the other, we're ready for the filecreated")

                   (CL:WHEN (EQ (CHARCODE %()
                                (SKIPSEPRCODES STREAM))
                       (SETQ FORM (READ STREAM RDTBL))
                       (CL:WHEN (MEMB (U-CASE (CAR FORM))
                                      '(FILECREATED IL%:FILECREATED))

                           (* ;; "IL%%:FILECREATED because we screwed the readtable.")

                           (IF [STREQUAL "compiled on " (CAR (LISTP (CADDR FORM]
                               THEN                      (* ; "LCOM, get source info")
                                     (IF [AND (EQ (CHARCODE %()
                                                      (SKIPSEPRCODES STREAM))
                                                  (MEMB [U-CASE (CAR (SETQ SFORM (READ STREAM RDTBL]
                                                        '(FILECREATED IL%:FILECREATED]
                                         THEN (SETQ FILENAME (FULLNAME STREAM))
                                               (SETQ FILEDATE (CADR FORM))
                                               (SETQ SOURCENAME (CADDR SFORM))
                                               (SETQ SOURCEDATE (CADR SFORM))
                                       ELSE (SETQ FILENAME (FULLNAME STREAM))
                                             (SETQ FILEDATE (CADR FORM)))
                             ELSE (SETQ FILENAME (CADDR FORM))
                                   (SETQ FILEDATE (CADR FORM)))))])
        ELSEIF (SETQ POS (STRPOS "XCL Compiler output for source file " (SETQ LINE (CL:READ-LINE
                                                                                        STREAM))
                                    1 NIL NIL T))
          THEN                                           (* ; "DFASL compiled?")
                (SETQ SOURCENAME (SUBATOM LINE POS))
                (CL:WHEN (SETQ POS (STRPOS "Source file created " (SETQ LINE (CL:READ-LINE STREAM))
                                          1 NIL NIL T))
                    [SETQ SOURCEDATE (GDATE (IDATE (SUBSTRING LINE POS]
                    (CL:WHEN (SETQ POS (STRPOS "FASL file created " (SETQ LINE (CL:READ-LINE STREAM))
                                              1 NIL NIL T))
                        [SETQ FILEDATE (GDATE (IDATE (SUBSTRING LINE POS]))]

      (* ;; "Revert filenames to Interlisp package if needed:")

      (CL:WHEN (STRPOS "IL:" FILENAME)
          (SETQ FILENAME (SUBATOM FILENAME 4)))
      (CL:WHEN (STRPOS "IL:" SOURCENAME)
          (SETQ SOURCENAME (MKATOM SOURCENAME 4)))

      (* ;; "Return DATE NIL if file is not a Lisp file")

      `(,(OR FILENAME (FULLNAME STREAM))
        ,(AND FILEDATE (GDATE (IDATE FILEDATE)))
        ,@(CL:WHEN SOURCENAME
              (LIST SOURCENAME (GDATE (IDATE SOURCEDATE))))])

(SOURCE-FOR-COMPILED-P
  [LAMBDA (SOURCE COMPILED DFASLMARGIN)                 (* ; "Edited 31-Oct-2020 09:12 by rmk:")

    (* ;; "There seems to be some variation between the source dates in dfasl files and the filecreated date in the sources, they often don't match exactly.  But if they are within DFASLMARGIN, we assume a match.  We require exact date match for LCOMS")

    (* ;; "This is needed for dfasl files created before they recorded the source filecreated name and date instead of the directory source name and date when compile took place.")

    (* ;; "")

    (* ;; "DFASLMARGIN is a pair (after before) where we assume a match if the compiled date is no more than after minutes after the source date and no more than before minuts before (the diff is negative then).")

    (* ;; "A single positive integer x is interpreted as (x 0).  A single negative integer x is interpreted as (-x x) (before or after x).")

    (* ;; "Default is (20 0).")

    (* ;; "T is positive or negative infinity")

    (CL:UNLESS (LISTP SOURCE)
        (SETQ SOURCE (CREATED-AS SOURCE)))
    (CL:UNLESS (LISTP COMPILED)
        (SETQ COMPILED (CREATED-AS COMPILED)))
    (SETQ DFASLMARGIN (IF (NULL DFASLMARGIN)
                          THEN 

                                (* ;; 
                       "If compiled is later than source by less than 20 minutes, it's probably OK")

                                '(20 0)
                        ELSEIF (EQ T DFASLMARGIN)
                          THEN '(T 0)
                        ELSEIF (LISTP DFASLMARGIN)
                        ELSEIF (NOT (FIXP DFASLMARGIN))
                          THEN (ERROR "ILLEGAL DFASLMARGIN" DFASLMARGIN)
                        ELSEIF (MINUSP DFASLMARGIN)
                          THEN (LIST (MINUS DFASLMARGIN)
                                         DFASLMARGIN)
                        ELSE (LIST DFASLMARGIN 0)))
    (OR (EQUAL (CAR SOURCE)
               (CADDR COMPILED))
        (EQUAL (CADR SOURCE)
               (CADDDR COMPILED))
        (AND [EQ 'DFASL (U-CASE (FILENAMEFIELD (CAR COMPILED)
                                       'EXTENSION]
             (LET ((TIMEDIFF (COMPILE-SOURCE-DATE-DIFF COMPILED SOURCE)))

                  (* ;; "If compiled was no more than 20 minutes later, it's probably OK.  Of no more than DFASLMARGIN earlier, if it is negative.")

                  (AND (OR (EQ T (CAR DFASLMARGIN))
                           (LEQ TIMEDIFF (CAR DFASLMARGIN)))
                       (OR (EQ T (CADR DFASLMARGIN))
                           (GEQ TIMEDIFF (CADR DFASLMARGIN])

(COMPILE-SOURCE-DATE-DIFF
  [LAMBDA (CFILE SFILE)                                 (* ; "Edited 20-Sep-2020 22:59 by rmk:")

    (* ;; "Positive means that compiled is later than source, normal order but maybe by too much. Negative means that compiled came before source, i.e., compiled on a source that didn't yet exist.")

    (* ;; "Value is in minutes")

    (ROUND (FQUOTIENT [IDIFFERENCE [IDATE (CADDDR (OR (LISTP CFILE)
                                                      (CREATED-AS CFILE]
                             (IDATE (CADR (OR (LISTP SFILE)
                                              (CREATED-AS SFILE]
                  (TIMES 60 ONESECOND])
)
(DEFINEQ

(FIX-DIRECTORY-DATES
  [LAMBDA (FILES MARGIN)                                (* ; "Edited 30-Oct-2020 22:01 by rmk:")

    (* ;; "For Lisp source and compiled files, ensures that the directory file date corresponds to the  filecreated date. Returns the list of files whose dates were changed.")

    (* ;; "This allows for the fact that directory dates that  are no later than, say, 30 seconds of the filecreated date are probably OK--the directory date may be set when the file is closed.")

    (* ;; "Use IDATEs in case FDCDATE is not Y2K.")

    (* ;; "Stop if directory date is more than 2 minutes earlier than the filecreated date.  Earlier could be because the dates are asserted at different points in the filing process.  But 2 minutes is worth thinking about.  Returning from HELP will get them aligned.")

    (SETQ MARGIN (ITIMES (OR MARGIN 2)
                        60 ONESECOND))
    (FOR F DIDATE FCDATE IN (OR (LISTP FILES)
                                        (FILDIR FILES)) WHEN (SETQ FCDATE (FILEDATE F))
       UNLESS (IEQP (SETQ DIDATE (GETFILEINFO F 'ICREATIONDATE))
                        (SETQ FCDATE (IDATE FCDATE))) COLLECT (CL:WHEN (IGREATERP (IDIFFERENCE
                                                                                       FCDATE DIDATE)
                                                                                  MARGIN)
                                                                      (HELP 
                                                       "DIRECTORY DATE EARLIER THAN FILECREATED DATE"
                                                                            (LIST F (GDATE DIDATE)
                                                                                  (GDATE FCDATE))))
                                                            (SETFILEINFO F 'ICREATIONDATE FCDATE)
                                                            F])

(FIX-EQUIV-DATES
  [LAMBDA (CDENTRIES)                                   (* ; "Edited  1-Sep-2020 16:21 by rmk:")

    (* ;; "For every entry whose files are EQUIVALENT and whose filedates are different, sets the directory of the file with the later date to be the date of the one with the earlier date.  This preumes that the later one must have been a copy. ")

    (CL:UNLESS CDENTRIES
        (PRINTOUT T "Note:  Using LASTCDENTRIES" T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (FOR CDE EARLY LATE IN (CDR CDENTRIES) WHEN (FETCH EQUIV OF CDE)
       UNLESS (EQ '= (FETCH DATEREL OF CDE))
       COLLECT (SELECTQ (FETCH DATEREL OF CDE)
                       (> (SETQ EARLY (FETCH INFO2 OF CDE))
                          (SETQ LATE (FETCH INFO1 OF CDE)))
                       (< (SETQ EARLY (FETCH INFO1 OF CDE))
                          (SETQ LATE (FETCH INFO2 OF CDE)))
                       (SHOULDNT))
             (SETFILEINFO (FETCH FULLNAME OF LATE)
                    'ICREATIONDATE
                    (GETFILEINFO (FETCH FULLNAME OF EARLY)
                           'ICREATIONDATE))
             (FETCH FULLNAME OF LATE])

(COPY-COMPARED-FILES
  [LAMBDA (CDENTRIES TARGET MATCHNAMES)                 (* ; "Edited  1-Sep-2020 16:20 by rmk:")

    (* ;; "Copies source files to target files whose matchname belongs to MATCHNAMES, if given.")

    (* ;; "TARGET is 1 or 2, indicating which side of the CD entry is the target.  Value is the list of matchnames whose files have been copied.")

    (* ;; "Directory filedates and other properties are preserved.")

    (CL:UNLESS (MEMB TARGET '(1 2))
           (ERROR "INVALID TARGET" TARGET))
    (CL:UNLESS CDENTRIES
        (PRINTOUT T "Note:  Using LASTCDENTRIES" T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (SETQ MATCHNAMES (MKLIST MATCHNAMES))
    (FOR CDE SINFO TINFO MATCHNAME IN (CDR CDENTRIES) EACHTIME (SETQ SINFO
                                                                            (FETCH INFO1
                                                                               OF CDE))
                                                                    (SETQ TINFO (FETCH INFO2
                                                                                   OF CDE))
                                                                    (CL:WHEN (EQ TARGET 1)
                                                                           (SWAP SINFO TINFO))
                                                                    (SETQ MATCHNAME
                                                                     (FETCH MATCHNAME
                                                                        OF CDE))
       WHEN (AND (FETCH FULLNAME OF SINFO)
                     (FETCH FULLNAME OF TINFO)) UNLESS (AND MATCHNAMES
                                                                        (NOT (MEMB MATCHNAME 
                                                                                   MATCHNAMES)))
       COLLECT (COPYFILE (FETCH FULLNAME OF SINFO)
                          (PACKFILENAME 'VERSION NIL 'BODY (FETCH FULLNAME OF TINFO)))
             MATCHNAME])

(COPY-MISSING-FILES
  [LAMBDA (CDENTRIES TARGET MATCHNAMES)                 (* ; "Edited  1-Sep-2020 16:21 by rmk:")

    (* ;; "Copies source files to target files whose matchname belongs to MATCHNAMES, if given.")

    (* ;; "TARGET is 1 or 2, indicating which side of the CD entry is the target.  Value is the list of matchnames whose files have been copied.")

    (* ;; "Directory filedates and other properties are preserved.")

    (CL:UNLESS (MEMB TARGET '(1 2))
           (ERROR "INVALID TARGET" TARGET))
    (CL:UNLESS CDENTRIES
        (PRINTOUT T "Note:  Using LASTCDENTRIES" T)
        (SETQ CDENTRIES LASTCDENTRIES))
    (CL:UNLESS (STRINGP (CADR (CAR CDENTRIES)))
        (ERROR "(CAR CDENTRIES) IS NOT A VALID PARAMETER LIST" (CAR CDENTRIES)))
    (SETQ MATCHNAMES (MKLIST MATCHNAMES))
    (FOR CDE SINFO TINFO TDIR MATCHNAME (TDIR _ (CL:IF (EQ TARGET 1)
                                                        (CAAR CDENTRIES)
                                                        (CADAR CDENTRIES))) IN (CDR CDENTRIES)
       EACHTIME (SETQ MATCHNAME (FETCH MATCHNAME OF CDE))
             (SETQ SINFO (FETCH INFO1 OF CDE))
             (SETQ TINFO (FETCH INFO2 OF CDE))
             (CL:WHEN (EQ TARGET 1)
                    (SWAP SINFO TINFO)) WHEN (AND (FETCH FULLNAME OF SINFO)
                                                          (NOT (FETCH FULLNAME OF TINFO)))
       UNLESS (AND MATCHNAMES (NOT (MEMB MATCHNAME MATCHNAMES)))
       COLLECT 

             (* ;; "Using the source fullname in the target should preserve the version number")

             (COPYFILE (FETCH FULLNAME OF SINFO)
                    (PACKFILENAME 'BODY TDIR 'BODY (FETCH FULLNAME OF SINFO)))
             MATCHNAME])

(COMPILED-ON-SAME-SOURCE
  [LAMBDA (CDENTRIES)                                   (* ; "Edited  9-Sep-2020 13:00 by rmk:")

    (* ;; "Returms a subset of CDENTRIES consisting of files that are compiled on the same source (i.e. their source names or dates are the same). Preserves the header.")

    (CDSUBSET CDENTRIES (FUNCTION (LAMBDA (CDE)
                                        (DECLARE (USEDFREE INFO1 INFO2))
                                        (LET (CREATED1 CREATED2)
                                             (CL:WHEN [AND (EQ 'COMPILED (FETCH TYPE OF
                                                                                         INFO1))
                                                           (EQ 'COMPILED (FETCH TYPE OF
                                                                                         INFO2))
                                                           [CDDR (SETQ CREATED1
                                                                  (CREATED-AS (FETCH FULLNAME
                                                                                     OF INFO1]
                                                           (CDDR (SETQ CREATED2
                                                                  (CREATED-AS (FETCH FULLNAME
                                                                                     OF INFO2]
                                                 (OR (EQUAL (CADDR CREATED1)
                                                            (CADDR CREATED2))
                                                     (EQUAL (CADDDR CREATED1)
                                                            (CADDDR CREATED2))))])
)

(RPAQ ONESECOND (IDIFFERENCE (IDATE "1-Jan-2020 12:00:01")
                           (IDATE "1-Jan-2020 12:00:00")))

(RPAQ? LASTCDENTRIES NIL)
(DEFINEQ

(COMPARE-ENTRY-SOURCE-FILES
  [LAMBDA (CDENTRY LISTSTREAM EXAMINE DW?)              (* ; "Edited 30-Aug-2020 12:22 by rmk:")

    (* ;; "Wrapper to call COMPARESOURCES on the Lisp source files of CDENTRY")

    (CL:WHEN [AND (EQ 'SOURCE (FETCH TYPE OF (FETCH INFO1 OF CDENTRY)))
                  (EQ 'SOURCE (FETCH TYPE OF (FETCH INFO2 OF CDENTRY]
        (COMPARESOURCES (FETCH FULLNAME OF (FETCH INFO1 OF CDENTRY))
               (FETCH FULLNAME OF (FETCH INFO2 OF CDENTRY))
               EXAMINE DW? LISTSTREAM))])
)

(FILESLOAD COMPARESOURCES)
(PUTPROPS COMPAREDIRECTORIES COPYRIGHT ("Venue & Xerox Corporation" 1985 1986 1987 1988 1990 1994 1998
 2018 2020 2021))
(DECLARE%: DONTCOPY
  (FILEMAP (NIL (1632 17400 (COMPAREDIRECTORIES 1642 . 10869) (CDFILES 10871 . 15446) (
COMPAREDIRECTORIES.INFOS 15448 . 16963) (MATCHNAME 16965 . 17398)) (17401 24586 (CDPRINT 17411 . 22211
) (CDPRINT.LINE 22213 . 24584)) (24587 26339 (CDMAP 24597 . 25293) (CDENTRY 25295 . 25463) (CDSUBSET 
25465 . 26337)) (26340 31871 (BINCOMP 26350 . 30639) (EOLTYPE 30641 . 31869)) (32084 45291 (
FIND-UNCOMPILED-FILES 32094 . 35737) (FIND-UNSOURCED-FILES 35739 . 38548) (FIND-SOURCE-FILES 38550 . 
40254) (FIND-COMPILED-FILES 40256 . 42334) (FIND-UNLOADED-FILES 42336 . 43080) (FIND-LOADED-FILES 
43082 . 43636) (FIND-MULTICOMPILED-FILES 43638 . 45289)) (45292 53494 (CREATED-AS 45302 . 50099) (
SOURCE-FOR-COMPILED-P 50101 . 52799) (COMPILE-SOURCE-DATE-DIFF 52801 . 53492)) (53495 62474 (
FIX-DIRECTORY-DATES 53505 . 55473) (FIX-EQUIV-DATES 55475 . 56735) (COPY-COMPARED-FILES 56737 . 58861)
 (COPY-MISSING-FILES 58863 . 60702) (COMPILED-ON-SAME-SOURCE 60704 . 62472)) (62629 63240 (
COMPARE-ENTRY-SOURCE-FILES 62639 . 63238)))))
STOP
\ No newline at end of file
diff --git a/lispusers/COMPAREDIRECTORIES.LCOM b/lispusers/COMPAREDIRECTORIES.LCOM
index 12d29c5b..7a669cbf 100644
Binary files a/lispusers/COMPAREDIRECTORIES.LCOM and b/lispusers/COMPAREDIRECTORIES.LCOM differ
diff --git a/lispusers/COMPAREDIRECTORIES.TEDIT b/lispusers/COMPAREDIRECTORIES.TEDIT
index d3559442..9854a8ac 100644
--- a/lispusers/COMPAREDIRECTORIES.TEDIT
+++ b/lispusers/COMPAREDIRECTORIES.TEDIT
@@ -1,4 +1,4 @@
-XEROX	COMPAREDIRECTORIES
2

4

1

COMPAREDIRECTORIES
1

4

By:  Larry Masinter and Ron Kaplan
This document edited on
  December 2, 1987
  December 28, 1998 (Ron Kaplan)
  April 7, 2018 (Ron Kaplan)
  Rewritten August 25, 2020 (Ron Kaplan)

COMPAREDIRECTORIES compares the contents of two directories, identifying files according to their creation dates and lengths. It is called using the function
(COMPAREDIRECTORIES DIR1 DIR2 SELECT  FILEPATTERNS  EXTENSIONSTOAVOID  USEDIRECTORYDATES OUTPUTFILE  ALLVERSIONS)					[Function]
Compares the creation dates of files with matching names in the lists that CDFILES returns for DIR1 and DIR2.  Collects or prints CDENTRIES for those files that meet the SELECT criteria.  May also collect or print entries for relevant files that exist in DIR1 or DIR2 but not both.
SELECT specifies which the match/mismatch criteria for filtering the output. If SELECT is or contains
     AFTER or >:  select entries where file1 has a later date than  file2
     BEFORE or <: select entries where file1 has an earlier date than file2
     SAMEDATE or =: select entries where file1 and file2 have the same date
     -*: exclude entries where file1 does not exist
     *-: exclude entries where file2 does not exist
SELECT = NIL is equivalent to (< >  -* *-). Excludes files with matching dates, a useful default for identifying files that may require further attention.
SELECT = T is equivalent to (= < >  -* *-).  Includes all files for processing by other functions or later filtering by CDSUBSET (below).
SELECT may also contain the token AUTHOR to indicate that authors should be provided in the printed output (see CDPRINT below).
Unless USEDIRECTORYDATES, the FILECREATED date is used for the date comparison of Lisp source and compiled files, otherwise the file-system CREATIONDATE is used. 
If OUTPUTFILE=NIL, then a list of the form (Parameters . entries) is returned.  Parameters is a list (DIR1 DIR2 SELECT DATE) that records the parameters of the comparison.   Entries contains one entry for each of the file-comparisons that meets the SELECT criteria.  Each entry is a CDENTRY record with fields
   (matchname info1 daterel info2 equiv)
where matchname is the name.extension shared by the two files, and each file info is either NIL (for nonexistent files)  or a CDINFO record with fields
   (fullfilename date length author type eol)
type is SOURCE for Lisp source (filecreated) files, COMPILED for Lisp compiled files, otherwise the PRINTFILETYPE (TEXT, TEDIT...) or NIL.  eol is CR, LF, CRLF, or NIL.
When both files exist, the date relation is one of <, =, or >.  Otherwise, the date relation is * if only one file exists.  EQUIV is EQUIVALENT for files with different dates but exactly the same bytes, otherwise NIL.
If OUTPUTFILE is not NIL, then it is a filename or open stream on which selected entries will be printed (T for the terminal) by CDPRINT.  
COMPAREDIRECTORIES sets the variable LASTCDENTRIES is set to the selected entries.  This is used by the functions below if their CDENTRIES is NIL. 

(CDFILES DIR FILEPATTERNS EXTENSIONSTOAVOID ALLVERSIONS DEPTH)  [Function]
Returns a list of full filenames for files in directory DIR (NIL=T=the connected directory) that match the other file-name filtering criteria. Files are excluded if:
Their name does not match a pattern in FILEPATTERNS (NIL = *). Dotted files are excluded unless FILEPATTERNS includes .* and files in subdirectories are excluded if the number of subdirectories exceeds DEPTH (below).
Their extension is in the list EXTENSIONSTOAVOID (* excludes all extensions).
They are not the highest version unless ALLVERSIONS=T.
DEPTH controls the depth of subdirectory exploration.  T means all levels, NIL means no subdirectories.  Otherwise the maximum number of ">" characters below the starting DIR in the fullname of files.
(CDFILES) produces all the newest, undotted files in the immediate connected directory.

(CDPRINT CDENTRIES FILE PRINTAUTHOR)  [Function]
Prints CDENTRIES on FILE, with one line for each entry. The line for each entry is of the form
     FILE1 (AUTHOR) SIZE DATE relation DATE  FILE2 (AUTHOR) SIZE
For example
  ACE.;1 (Joe) 4035 2-May-1985 18:03:54 < 30-Sep-1985 11:14:48 ACE.;3 (Sam) 5096.
The line for byte-equivalent files is prefixed with ==.  If the files are equivalent except for a difference in end-of-line conventions, the equivalence prefix will indicate the convention for each file (C for CR, L, for LF, 2 for CRLF). Thus C2 indicates that the files are equivalent except that file1 marks line ends with CR and file2 with CRLF.
Note that because of the setting of LASTCDENTRIES, evaluating (CDPRINT) after COMPAREDIRECTORIES prints the results of the last comparision. 
For conciseness, authors are included only if PRINTAUTHOR or if AUTHOR is included in the SELECT parameter of CDENTRIES. Also, the redundant file-name hosts/directories are not printed. 

(CDMAP CDENTRIES FN)        [Function]
(CDSUBSET CDENTRIES FN)   [Function]
CDMAP applies FN to each CDENTRY in CDENTRIES. CDSUBSET applies FN and also returns the subset of CDENTRIES for which FN is non-NIL and preserves in the value the parameters of CDENTRIES. For convenience, at each invocation the variables MATCHNAME INFO1 DATEREL INFO2 and EQUIV are bound to the corresponding fields and can be used freely by FN.

USEFUL UTILITIES
(FIX-DIRECTORY-DATES FILES)        [Function]
For every file included in or specified by FILES, if it is a Lisp source or compiled whose directory creation date is more than 30 seconds later than its internal filecreated date (presumably because of copying), then its directory date is reset to match the internal date.  FILES can be a list of file names or a pattern interpretable by FILDIR.  Returns a list of files whose dates have been changed.

(FIX-EQUIV-DATES CDENTRIES)      [Function]
If there is an entry in CDENTRIES whose files are EQUIVALENT but with different directory creation dates, the directory date of the file with the later date (presumably a copy) is reset to match the date of the earlier file.  In the end all equivalent files will have the same (earliest) date. Returns a list of files whose dates have been changed.

(COPY-MISSING-FILES CDENTRIES TARGET MATCHNAMES)   [Function]
Target is 1 or 2, indicating the direction of potential copies.  If an entry with a source file but no target file has a matchname in MATCHNAMES, the source file is copied to the target directory.  All target-absent files are copied if MATCNAMES is NIL.  Source properties (including version number) are preserved in the target.

(COPY-COMPARED-FILES CDENTRIES TARGET MATCHNAMES)   [Function]
Target is 1 or 2, indicating the direction of potential copies.  If an entry with both source and target files has a matchname in MATCHNAMES, the source file is copied to a new version of the target file.  All files are copied if MATCHNAMES is NIL.  

(COMPARE-ENTRY-SOURCE-FILES CDENTRY LISTSTREAM EXAMINE DW?)  [Function]
This is a simple wrapper for calling COMPARESOURCES if the CDENTRY files are Lisp source files.  The function (CDENTRY MATCHNAME CDENTRIES is useful for extracting a particular entry, with CDENTRIES defaulting to LASTCDENTRIES.

(COMPILED-ON-SAME-SOURCE CDENTRIES)  [Function]
Returns the subset of entries with Lisp compiled files (dfasl or lcom) that are compiled on the same source, according to SOURCE-FOR-COMPILED-P below. Presumably one should be removed to avoid confusion.

(FIND-SOURCE-FILES CFILES SDIRS DFASLMARGIN)   [Function]
Returns (CFILE . SFILES) pairs where CFILE is a Lisp compiled file in CFILES and SFILES is list of files in SDIRS that CFILE was compiled on according to SOURCE-FOR-COMPILED-P. This suggests that at least one of SFILES should be copied to CFILE's location (or vice versa).

(FIND-COMPILED-FILES SFILES CDIRS DFASLMARGIN)   [Function]
Returns (SFILE . CFILES) pairs where SFILE is a Lisp source file in SFILES and CFILES are files in CDIRS that are compiled on SFILE according to SOURCE-FOR-COMPILED-P.  This suggests that at least one of CFILES should be copied to SFILE's location.  

(FIND-UNCOMPILED-FILES FILES DFASLMARGIN COMPILEXTS)  [Function]
Returns a list of elements each of which corresponds to a source file in FILES for which no appropriate compiled file can be found.   An appropriate compiled file is a file in the same location with extension in COMPILEEXTS (defaulting to *COMPILED-EXTENSIONS*) that satisfies SOURCE-FOR-COMPILED-P. Each element is a list of the form
    (sourcefile . cfiles)
cfiles contains compiled files that were compiled on a different version of sourcefile, NIL if no such files exist. Each cfile item is a pair (cfile  timediff) where timediff is the time difference (in minutes) between the creation date of the compiled-file's source and the creation date of sourcefile (positive if the cfile was compiled later, as should be the case). FILES can be an explicit list of files, or a file specification interpretable by FILDIR; in that case only the newest source-file versions are processed.  

(FIND-UNSOURCED-FILES CFILES DFASLMARGIN COMPILEXTS)  [Function]
Returns the subset of the compiled files specified by CFILES for which a corresponding source file according to SOURCE-FOR-COMPILED-P cannot be found in the same directory.  CFILES can be a list of files or a pattern that FILDIR can interpret.  COMPILEEXTS can be one or more explicit compile-file extensions, defaulting to *COMPILED-EXTENSIONS*.

(SOURCE-FOR-COMPILED-P SOURCE COMPILED DFASLMARGIN)  [Function]
Returns T if it can confirm that Lisp COMPILED file was compiled on Lisp SOURCE file.  SOURCE and COMPILED can be provided as CREATED-AS values, to avoid repetitive computation.  This compares the information in the filecreated expressions, original file names and original dates, and not the current directory names and dates.
It appears that the times in DFASL files may differ from the filecreated source dates by a few minutes.  The DFASLMARGIN can be provided to loosen up the date matching criterion.  DFASLMARGIN is a pair (max min) and a DFASL COMPILED is deemed to be compiled on SOURCE if the compiled's source date is no more than max and no less than min minutes after the source date.  A negative min allows for the possibility that the compiled-source date is earlier than the candidate source date.  DFASLMARGIN defaults to (20 0).  A single positive number x is coerced to (x 0).  A single negative number is coerced to (-x x) (compiled file is no more than x minutes later or earlier). T is infinity in either direction.  Examples:
    (T 0):  COMPILED compiled on source later than SOURCE
    (0 T):  COMPILED compiled on source earlier than SOURCE (odd)
    12:  COMPILED compiled on source later than SOURCE by no more than 12 minutes
     -12:   COMPILED compiled on source 12 minutes before or after SOURCE

(FIND-MULTICOMPILED-FILES FILES SHOWINFO)  [Function]
Returns a list of files in FILES that have more than one type of compiled file (e.g. LCOM and DFASL).  FILES is interpretable by FILDIR.  If SHOWINFO, then the value contains a list for each file of the form
   ÿÿï!ÿ(rootname loaded-version . CREATED-AS information for each compile-type)
 Otherwise just the rootname of the source is returns.

(CREATED-AS FILE)  [Function]
If FILE is a Lisp source or compiled file, returns a record of its original filename and filecreated dates, and for compiled files, also the original compiled-on name and date.  The return for a source file is a pair
     (sfullname sfilecreateddate)
The return for a compiled file is a quadruple
     (cfullname cfilecreated sfullname sfilecreateddate)
where sfullname and sourcefilecreated are extracted from the file's compiled-on information.  The return is (fullname NIL) for a non-Lisp file.

(EOLTYPE FILE)  [Function]
Returns the EOLTYPE of FILE (CR, LF, CRLF) if the type is unmistakable: contains at least one instance of one type and no instances of any others.

(BINCOMP FILE1 FILE2 EOLDIFFOK)   [Function]
Returns T if FILE1 and FILE2 are byte-identical.  If EOLDIFFOK and FILE1 and FILE2 differ only in their eol conventions, the value is a list of the form (EOL1 EOL2), e.g. (CR CRLF).  Otherwise the value is NIL.  



	



(LIST ((PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC) STARTINGPAGE# 1) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC)) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC)) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL)))))4ÈÈ40ÈÈ4ÈÈ4ÈÈ.4@È4ÈÈ.È.ŠŠ8.ŠŠ8JÈÈPAGEHEADINGRUNNINGHEAD.
+XEROX	COMPAREDIRECTORIES
2

4

1

COMPAREDIRECTORIES
1

4

By:  Larry Masinter and Ron Kaplan
This document edited on
  December 2, 1987
  December 28, 1998 (Ron Kaplan)
  April 7, 2018 (Ron Kaplan)
  Rewritten August 25, 2020 (Ron Kaplan)

COMPAREDIRECTORIES compares the contents of two directories, identifying files according to their creation dates and lengths. It is called using the function
(COMPAREDIRECTORIES DIR1 DIR2 SELECT  FILEPATTERNS  EXTENSIONSTOAVOID  USEDIRECTORYDATES OUTPUTFILE  ALLVERSIONS)					[Function]
Compares the creation dates of files with matching names in the lists that CDFILES returns for DIR1 and DIR2.  Collects or prints CDENTRIES for those files that meet the SELECT criteria.  May also collect or print entries for relevant files that exist in DIR1 or DIR2 but not both.
SELECT specifies which the match/mismatch criteria for filtering the output. If SELECT is or contains
     AFTER or >:  select entries where file1 has a later date than  file2
     BEFORE or <: select entries where file1 has an earlier date than file2
     SAMEDATE or =: select entries where file1 and file2 have the same date
     -*: exclude entries where file1 does not exist
     *-: exclude entries where file2 does not exist
     ~=: exclude entries where file1 and file2 are byte-equivalent
SELECT = NIL is equivalent to (< >  -* *-). Excludes files with matching dates, a useful default for identifying files that may require further attention.
SELECT = T is equivalent to (= < >  -* *-).  Includes all files for processing by other functions or later filtering by CDSUBSET (below).
SELECT may also contain the token AUTHOR to indicate that authors should be provided in the printed output (see CDPRINT below).
Unless USEDIRECTORYDATES, the FILECREATED date is used for the date comparison of Lisp source and compiled files, otherwise the file-system CREATIONDATE is used. 
If OUTPUTFILE=NIL, then a list of the form (Parameters . entries) is returned.  Parameters is a list (DIR1 DIR2 SELECT DATE) that records the parameters of the comparison.   Entries contains one entry for each of the file-comparisons that meets the SELECT criteria.  Each entry is a CDENTRY record with fields
   (matchname info1 daterel info2 equiv)
where matchname is the name.extension shared by the two files, and each file info is either NIL (for nonexistent files)  or a CDINFO record with fields
   (fullfilename date length author type eol)
type is SOURCE for Lisp source (filecreated) files, COMPILED for Lisp compiled files, otherwise the PRINTFILETYPE (TEXT, TEDIT...) or NIL.  eol is CR, LF, CRLF, or NIL.
When both files exist, the date relation is one of <, =, or >.  Otherwise, the date relation is * if only one file exists.  EQUIV is EQUIVALENT for files with different dates but exactly the same bytes, otherwise NIL.
If OUTPUTFILE is not NIL, then it is a filename or open stream on which selected entries will be printed (T for the terminal) by CDPRINT.  
COMPAREDIRECTORIES sets the variable LASTCDENTRIES is set to the selected entries.  This is used by the functions below if their CDENTRIES is NIL. 

(CDFILES DIR FILEPATTERNS EXTENSIONSTOAVOID ALLVERSIONS DEPTH)  [Function]
Returns a list of full filenames for files in directory DIR (NIL=T=the connected directory) that match the other file-name filtering criteria. Files are excluded if:
Their name does not match a pattern in FILEPATTERNS (NIL = *). Dotted files are excluded unless FILEPATTERNS includes .* and files in subdirectories are excluded if the number of subdirectories exceeds DEPTH (below).
Their extension is in the list EXTENSIONSTOAVOID (* excludes all extensions).
They are not the highest version unless ALLVERSIONS=T.
DEPTH controls the depth of subdirectory exploration.  T means all levels, NIL means no subdirectories.  Otherwise the maximum number of ">" characters below the starting DIR in the fullname of files.
(CDFILES) produces all the newest, undotted files in the immediate connected directory.

(CDPRINT CDENTRIES FILE PRINTAUTHOR)  [Function]
Prints CDENTRIES on FILE, with one line for each entry. The line for each entry is of the form
     FILE1 (AUTHOR) SIZE DATE relation DATE  FILE2 (AUTHOR) SIZE
For example
  ACE.;1 (Joe) 4035 2-May-1985 18:03:54 < 30-Sep-1985 11:14:48 ACE.;3 (Sam) 5096.
The line for byte-equivalent files is prefixed with ==.  If the files are equivalent except for a difference in end-of-line conventions, the equivalence prefix will indicate the convention for each file (C for CR, L, for LF, 2 for CRLF). Thus C2 indicates that the files are equivalent except that file1 marks line ends with CR and file2 with CRLF.
Note that because of the setting of LASTCDENTRIES, evaluating (CDPRINT) after COMPAREDIRECTORIES prints the results of the last comparision. 
For conciseness, authors are included only if PRINTAUTHOR or if AUTHOR is included in the SELECT parameter of CDENTRIES. Also, the redundant file-name hosts/directories are not printed. 

(CDMAP CDENTRIES FN)        [Function]
(CDSUBSET CDENTRIES FN)   [Function]
CDMAP applies FN to each CDENTRY in CDENTRIES. CDSUBSET applies FN and also returns the subset of CDENTRIES for which FN is non-NIL and preserves in the value the parameters of CDENTRIES. For convenience, at each invocation the variables MATCHNAME INFO1 DATEREL INFO2 and EQUIV are bound to the corresponding fields and can be used freely by FN.

USEFUL UTILITIES
(FIX-DIRECTORY-DATES FILES)        [Function]
For every file included in or specified by FILES, if it is a Lisp source or compiled whose directory creation date is more than 30 seconds later than its internal filecreated date (presumably because of copying), then its directory date is reset to match the internal date.  FILES can be a list of file names or a pattern interpretable by FILDIR.  Returns a list of files whose dates have been changed.

(FIX-EQUIV-DATES CDENTRIES)      [Function]
If there is an entry in CDENTRIES whose files are EQUIVALENT but with different directory creation dates, the directory date of the file with the later date (presumably a copy) is reset to match the date of the earlier file.  In the end all equivalent files will have the same (earliest) date. Returns a list of files whose dates have been changed.

(COPY-MISSING-FILES CDENTRIES TARGET MATCHNAMES)   [Function]
Target is 1 or 2, indicating the direction of potential copies.  If an entry with a source file but no target file has a matchname in MATCHNAMES, the source file is copied to the target directory.  All target-absent files are copied if MATCNAMES is NIL.  Source properties (including version number) are preserved in the target.

(COPY-COMPARED-FILES CDENTRIES TARGET MATCHNAMES)   [Function]
Target is 1 or 2, indicating the direction of potential copies.  If an entry with both source and target files has a matchname in MATCHNAMES, the source file is copied to a new version of the target file.  All files are copied if MATCHNAMES is NIL.  

(COMPARE-ENTRY-SOURCE-FILES CDENTRY LISTSTREAM EXAMINE DW?)  [Function]
This is a simple wrapper for calling COMPARESOURCES if the CDENTRY files are Lisp source files.  The function (CDENTRY MATCHNAME CDENTRIES is useful for extracting a particular entry, with CDENTRIES defaulting to LASTCDENTRIES.

(COMPILED-ON-SAME-SOURCE CDENTRIES)  [Function]
Returns the subset of entries with Lisp compiled files (dfasl or lcom) that are compiled on the same source, according to SOURCE-FOR-COMPILED-P below. Presumably one should be removed to avoid confusion.

(FIND-SOURCE-FILES CFILES SDIRS DFASLMARGIN)   [Function]
Returns (CFILE . SFILES) pairs where CFILE is a Lisp compiled file in CFILES and SFILES is list of files in SDIRS that CFILE was compiled on according to SOURCE-FOR-COMPILED-P. This suggests that at least one of SFILES should be copied to CFILE's location (or vice versa).

(FIND-COMPILED-FILES SFILES CDIRS DFASLMARGIN)   [Function]
Returns (SFILE . CFILES) pairs where SFILE is a Lisp source file in SFILES and CFILES are files in CDIRS that are compiled on SFILE according to SOURCE-FOR-COMPILED-P.  This suggests that at least one of CFILES should be copied to SFILE's location.  

(FIND-UNCOMPILED-FILES FILES DFASLMARGIN COMPILEXTS)  [Function]
Returns a list of elements each of which corresponds to a source file in FILES for which no appropriate compiled file can be found.   An appropriate compiled file is a file in the same location with extension in COMPILEEXTS (defaulting to *COMPILED-EXTENSIONS*) that satisfies SOURCE-FOR-COMPILED-P. Each element is a list of the form
    (sourcefile . cfiles)
cfiles contains compiled files that were compiled on a different version of sourcefile, NIL if no such files exist. Each cfile item is a pair (cfile  timediff) where timediff is the time difference (in minutes) between the creation date of the compiled-file's source and the creation date of sourcefile (positive if the cfile was compiled later, as should be the case). FILES can be an explicit list of files, or a file specification interpretable by FILDIR; in that case only the newest source-file versions are processed.  

(FIND-UNSOURCED-FILES CFILES DFASLMARGIN COMPILEXTS)  [Function]
Returns the subset of the compiled files specified by CFILES for which a corresponding source file according to SOURCE-FOR-COMPILED-P cannot be found in the same directory.  CFILES can be a list of files or a pattern that FILDIR can interpret.  COMPILEEXTS can be one or more explicit compile-file extensions, defaulting to *COMPILED-EXTENSIONS*.

(SOURCE-FOR-COMPILED-P SOURCE COMPILED DFASLMARGIN)  [Function]
Returns T if it can confirm that Lisp COMPILED file was compiled on Lisp SOURCE file.  SOURCE and COMPILED can be provided as CREATED-AS values, to avoid repetitive computation.  This compares the information in the filecreated expressions, original file names and original dates, and not the current directory names and dates.
It appears that the times in DFASL files may differ from the filecreated source dates by a few minutes.  The DFASLMARGIN can be provided to loosen up the date matching criterion.  DFASLMARGIN is a pair (max min) and a DFASL COMPILED is deemed to be compiled on SOURCE if the compiled's source date is no more than max and no less than min minutes after the source date.  A negative min allows for the possibility that the compiled-source date is earlier than the candidate source date.  DFASLMARGIN defaults to (20 0).  A single positive number x is coerced to (x 0).  A single negative number is coerced to (-x x) (compiled file is no more than x minutes later or earlier). T is infinity in either direction.  Examples:
    (T 0):  COMPILED compiled on source later than SOURCE
    (0 T):  COMPILED compiled on source earlier than SOURCE (odd)
    12:  COMPILED compiled on source later than SOURCE by no more than 12 minutes
     -12:   COMPILED compiled on source 12 minutes before or after SOURCE

(FIND-MULTICOMPILED-FILES FILES SHOWINFO)  [Function]
Returns a list of files in FILES that have more than one type of compiled file (e.g. LCOM and DFASL).  FILES is interpretable by FILDIR.  If SHOWINFO, then the value contains a list for each file of the form
   ÿÿï!ÿ(rootname loaded-version . CREATED-AS information for each compile-type)
 Otherwise just the rootname of the source is returns.

(CREATED-AS FILE)  [Function]
If FILE is a Lisp source or compiled file, returns a record of its original filename and filecreated dates, and for compiled files, also the original compiled-on name and date.  The return for a source file is a pair
     (sfullname sfilecreateddate)
The return for a compiled file is a quadruple
     (cfullname cfilecreated sfullname sfilecreateddate)
where sfullname and sourcefilecreated are extracted from the file's compiled-on information.  The return is (fullname NIL) for a non-Lisp file.

(EOLTYPE FILE)  [Function]
Returns the EOLTYPE of FILE (CR, LF, CRLF) if the type is unmistakable: contains at least one instance of one type and no instances of any others.

(BINCOMP FILE1 FILE2 EOLDIFFOK)   [Function]
Returns T if FILE1 and FILE2 are byte-identical.  If EOLDIFFOK and FILE1 and FILE2 differ only in their eol conventions, the value is a list of the form (EOL1 EOL2), e.g. (CR CRLF).  Otherwise the value is NIL.  



	



(LIST ((PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC) STARTINGPAGE# 1) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC)) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC)) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD CENTERED) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC)) (174 36 288 36) NIL) (HEADING NIL (HEADINGTYPE RUNNINGHEAD) (84 744 528 36) NIL) (TEXT NIL NIL (84 96 456 600) NIL)))))4ÈÈ40ÈÈ4ÈÈ4ÈÈ.4@È4ÈÈ.È.ŠŠ8.ŠŠ8JÈÈPAGEHEADINGRUNNINGHEAD.
 GACHA
 TERMINALMODERN
 MODERN
@@ -14,5 +14,5 @@ XEROX	COMPAREDIRECTORIES
2

4

1

COMPAREDIRECTORIES
1

4

By:  Larry Masinter a
 HRULE.GETFNMODERN#!(ž
 
 \
-fJLL44›Š€£6)˜.©Ú‹”K¦ÙN7ÉX1_AP]Ž»'%Z.“,]>I?û=ä0Ì:<ûAOA[@HÑ:BRJ6ÐK7Ù".9�“-Õ
-/Êzº
\ No newline at end of file
+fJLL44C›Š€£6)˜.©Ú‹”K¦ÙN7ÉX1_AP]Ž»'%Z.“,]>I?û=ä0Ì:<ûAOA[@HÑ:BRJ6ÐK7Ù".9�“-Õ
+0
zº
\ No newline at end of file
