Changeset 14362


Ignore:
Timestamp:
01/28/13 13:24:57 (11 years ago)
Author:
Mark Evenson
Message:

asdf-2.26.158.1: current asdf plus ABCL conditional for SETF DOCUMENTATION bug.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/asdf.lisp

    r14361 r14362  
    1 ;; -*- mode: Common-Lisp; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
    2 ;;; This is ASDF 2.26.143.1: Another System Definition Facility.
     1;;; -*- mode: Common-Lisp; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
     2;;; This is ASDF 2.26.158.1: Another System Definition Facility.
    33;;;
    44;;; Feedback, bug reports, and patches are all welcome:
     
    6161#+(or abcl clisp cmu)
    6262(eval-when (:load-toplevel :compile-toplevel :execute)
    63   (unless (member :asdf2.27 *features*)
     63  (unless (member :asdf3 *features*)
    6464    (let* ((existing-version
    6565             (when (find-package :asdf)
     
    8282;;
    8383;; CAUTION: we must handle the first few packages specially for hot-upgrade.
    84 ;; asdf/package will be frozen as of 2.27
     84;; asdf/package will be frozen as of ASDF 3
    8585;; to forever export the same exact symbols.
    8686;; Any other symbol must be import-from'ed
     
    423423                                recycle mix reexport
    424424                                unintern)
    425     (declare (ignorable documentation))
     425    #+(or gcl2.6 genera) (declare (ignore documentation))
    426426    (macrolet ((when-fishy (&body body) `(when-package-fishiness ,@body))
    427427               (fishy (&rest info) `(note-package-fishiness ,@info)))
     
    592592                     (when (and accessible (eq ustat :external))
    593593                       (ensure-exported name sym u)))))))
    594           #-(or gcl genera) (setf (documentation package t) documentation) #+gcl documentation
     594          #-(or gcl2.6 genera)
     595          (when documentation (setf (documentation package t) documentation))
    595596          (loop :for p :in (set-difference (package-use-list package) (append mix use))
    596597                :do (fishy :use (package-names p)) (unuse-package p package))
     
    708709        (remove "asdf" excl::*autoload-package-name-alist*
    709710                :test 'equalp :key 'car))
    710 
    711711  #+gcl
    712712  ;; Debian's GCL 2.7 has bugs with compiling multiple-value stuff,
     
    737737  (:recycle :asdf/common-lisp :asdf)
    738738  #+allegro (:intern #:*acl-warn-save*)
     739  #+cormanlisp (:shadow #:user-homedir-pathname)
    739740  #+cormanlisp
    740741  (:export
     
    775776  (defun make-broadcast-stream () *error-output*)
    776777  (defun translate-logical-pathname (x) x)
     778  (defun user-homedir-pathname (&optional host)
     779    (declare (ignore host))
     780    (parse-namestring (format nil "~A\\" (cl:user-homedir-pathname))))
    777781  (defun file-namestring (p)
    778782    (setf p (pathname p))
     
    858862
    859863
    860 ;;;; compatfmt: avoid fancy format directives when unsupported
    861 
     864;;;; Looping
    862865(defmacro loop* (&rest rest)
    863866  #-genera `(loop ,@rest)
    864867  #+genera `(lisp:loop ,@rest)) ;; In genera, CL:LOOP can't destructure, so we use LOOP*. Sigh.
    865868
     869
     870;;;; compatfmt: avoid fancy format directives when unsupported
    866871(eval-when (:load-toplevel :compile-toplevel :execute)
    867   (defun strcat (&rest strings)
    868     (apply 'concatenate 'string strings)))
     872  (defun remove-substrings (substrings string)
     873    (let ((length (length string)) (stream nil))
     874      (labels ((emit (start end)
     875                 (when (and (zerop start) (= end length))
     876                   (return-from remove-substrings string))
     877                 (unless stream (setf stream (make-string-output-stream)))
     878                 (write-string string stream :start start :end end))
     879               (recurse (substrings start end)
     880                 (cond
     881                   ((= start end))
     882                   ((null substrings) (emit start end))
     883                   (t (let* ((sub (first substrings))
     884                             (found (search sub string))
     885                             (more (rest substrings)))
     886                        (cond
     887                          (found
     888                           (recurse more start found)
     889                           (recurse more (+ found (length sub)) end))
     890                          (t
     891                           (recurse more start end))))))))
     892        (recurse substrings 0 length))
     893      (if stream (get-output-stream-string stream) ""))))
    869894
    870895(defmacro compatfmt (format)
    871896  #+(or gcl genera)
    872   (loop* :for (unsupported . replacement)
    873          :in (append
    874               '(("~3i~_" . ""))
    875               #+(or genera gcl2.6) '(("~@<" . "") ("; ~@;" . "; ") ("~@:>" . "") ("~:>" . ""))) :do
    876       (loop :for found = (search unsupported format) :while found :do
    877         (setf format (strcat (subseq format 0 found) replacement
    878                              (subseq format (+ found (length unsupported)))))))
    879     format)
     897  (remove-substrings `("~3i~_" #+(or genera gcl2.6) ,@'("~@<" "~@;" "~@:>" "~:>")) format)
     898  #-(or gcl genera) format)
     899
     900
    880901;;;; -------------------------------------------------------------------------
    881902;;;; General Purpose Utilities for ASDF
     
    885906  (:use :asdf/common-lisp :asdf/package)
    886907  ;; import and reexport a few things defined in :asdf/common-lisp
    887   (:import-from :asdf/common-lisp #:strcat #:compatfmt #:loop*
     908  (:import-from :asdf/common-lisp #:compatfmt #:loop* #:remove-substrings
    888909   #+ecl #:use-ecl-byte-compiler-p #+mcl #:probe-posix)
    889   (:export #:nil #:strcat #:compatfmt #:loop*
     910  (:export #:compatfmt #:loop* #:remove-substrings #:compatfmt
    890911   #+ecl #:use-ecl-byte-compiler-p #+mcl #:probe-posix)
    891912  (:export
     
    896917   #:while-collecting #:appendf #:length=n-p #:remove-plist-keys #:remove-plist-key ;; lists and plists
    897918   #:emptyp ;; sequences
    898    #:first-char #:last-char #:split-string ;; strings
     919   #:strcat #:first-char #:last-char #:split-string ;; strings
    899920   #:string-prefix-p #:string-enclosed-p #:string-suffix-p
    900921   #:find-class* ;; CLOS
     
    959980;;; Magic debugging help. See contrib/debug.lisp
    960981(defvar *asdf-debug-utility*
    961   '(ignore-errors (merge-pathnames "cl/asdf/contrib/debug.lisp" (user-homedir-pathname)))
     982  '(or (ignore-errors
     983        (symbol-call :asdf :system-relative-pathname :asdf-driver "contrib/debug.lisp"))
     984    (merge-pathnames "cl/asdf/contrib/debug.lisp" (user-homedir-pathname)))
    962985  "form that evaluates to the pathname to your favorite debugging utilities")
    963986
     
    10411064
    10421065;;; Strings
     1066(defun* strcat (&rest strings)
     1067  (apply 'concatenate 'string strings))
    10431068
    10441069(defun* first-char (s)
     
    12821307  `(call-with-muffled-uninteresting-conditions #'(lambda () ,@body) ,conditions))
    12831308
     1309
     1310;;;; ---------------------------------------------------------------------------
     1311;;;; Access to the Operating System
     1312
     1313(asdf/package:define-package :asdf/os
     1314  (:recycle :asdf/os :asdf)
     1315  (:use :asdf/common-lisp :asdf/package :asdf/utility)
     1316  (:export
     1317   #:featurep #:os-unix-p #:os-windows-p #:os-genera-p #:detect-os ;; features
     1318   #:getenv #:getenvp ;; environment variables
     1319   #:implementation-identifier ;; implementation identifier
     1320   #:implementation-type #:*implementation-type*
     1321   #:operating-system #:architecture #:lisp-version-string
     1322   #:hostname #:getcwd #:chdir
     1323   ;; Windows shortcut support
     1324   #:read-null-terminated-string #:read-little-endian
     1325   #:parse-file-location-info #:parse-windows-shortcut))
     1326(in-package :asdf/os)
     1327
     1328;;; Features
     1329(eval-when (:compile-toplevel :load-toplevel :execute)
     1330  (defun* featurep (x &optional (*features* *features*))
     1331    (cond
     1332      ((atom x) (and (member x *features*) t))
     1333      ((eq :not (car x)) (assert (null (cddr x))) (not (featurep (cadr x))))
     1334      ((eq :or (car x)) (some #'featurep (cdr x)))
     1335      ((eq :and (car x)) (every #'featurep (cdr x)))
     1336      (t (error "Malformed feature specification ~S" x))))
     1337
     1338  (defun* os-unix-p ()
     1339    (or #+abcl (featurep :unix)
     1340        #+(and (not abcl) (or unix cygwin darwin)) t))
     1341
     1342  (defun* os-windows-p ()
     1343    (or #+abcl (featurep :windows)
     1344        #+(and (not (or unix cygwin darwin)) (or win32 windows mswindows mingw32)) t))
     1345
     1346  (defun* os-genera-p ()
     1347    (or #+genera t))
     1348
     1349  (defun* detect-os ()
     1350    (flet ((yes (yes) (pushnew yes *features*))
     1351           (no (no) (setf *features* (remove no *features*))))
     1352      (cond
     1353        ((os-unix-p) (yes :os-unix) (no :os-windows) (no :genera))
     1354        ((os-windows-p) (yes :os-windows) (no :os-unix) (no :genera))
     1355        ((os-genera-p) (no :os-unix) (no :os-windows) (yes :genera))
     1356        (t (error "Congratulations for trying XCVB on an operating system~%~
     1357that is neither Unix, nor Windows, nor even Genera.~%Now you port it.")))))
     1358
     1359  (detect-os))
     1360
     1361;;;; Environment variables: getting them, and parsing them.
     1362
     1363(defun* getenv (x)
     1364  (declare (ignorable x))
     1365  #+(or abcl clisp ecl xcl) (ext:getenv x)
     1366  #+allegro (sys:getenv x)
     1367  #+clozure (ccl:getenv x)
     1368  #+(or cmu scl) (cdr (assoc x ext:*environment-list* :test #'string=))
     1369  #+cormanlisp
     1370  (let* ((buffer (ct:malloc 1))
     1371         (cname (ct:lisp-string-to-c-string x))
     1372         (needed-size (win:getenvironmentvariable cname buffer 0))
     1373         (buffer1 (ct:malloc (1+ needed-size))))
     1374    (prog1 (if (zerop (win:getenvironmentvariable cname buffer1 needed-size))
     1375               nil
     1376               (ct:c-string-to-lisp-string buffer1))
     1377      (ct:free buffer)
     1378      (ct:free buffer1)))
     1379  #+gcl (system:getenv x)
     1380  #+genera nil
     1381  #+lispworks (lispworks:environment-variable x)
     1382  #+mcl (ccl:with-cstrs ((name x))
     1383          (let ((value (_getenv name)))
     1384            (unless (ccl:%null-ptr-p value)
     1385              (ccl:%get-cstring value))))
     1386  #+mkcl (#.(or (find-symbol* 'getenv :si nil) (find-symbol* 'getenv :mk-ext nil)) x)
     1387  #+sbcl (sb-ext:posix-getenv x)
     1388  #-(or abcl allegro clisp clozure cmu cormanlisp ecl gcl genera lispworks mcl mkcl sbcl scl xcl)
     1389  (error "~S is not supported on your implementation" 'getenv))
     1390
     1391(defun* getenvp (x)
     1392  "Predicate that is true if the named variable is present in the libc environment,
     1393then returning the non-empty string value of the variable"
     1394  (let ((g (getenv x))) (and (not (emptyp g)) g)))
     1395
     1396
     1397;;;; implementation-identifier
     1398;;
     1399;; produce a string to identify current implementation.
     1400;; Initially stolen from SLIME's SWANK, completely rewritten since.
     1401;; We're back to runtime checking, for the sake of e.g. ABCL.
     1402
     1403(defun* first-feature (feature-sets)
     1404  (dolist (x feature-sets)
     1405    (multiple-value-bind (short long feature-expr)
     1406        (if (consp x)
     1407            (values (first x) (second x) (cons :or (rest x)))
     1408            (values x x x))
     1409      (when (featurep feature-expr)
     1410        (return (values short long))))))
     1411
     1412(defun* implementation-type ()
     1413  (first-feature
     1414   '(:abcl (:acl :allegro) (:ccl :clozure) :clisp (:corman :cormanlisp)
     1415     (:cmu :cmucl :cmu) :ecl :gcl
     1416     (:lwpe :lispworks-personal-edition) (:lw :lispworks)
     1417     :mcl :mkcl :sbcl :scl (:smbx :symbolics) :xcl)))
     1418
     1419(defvar *implementation-type* (implementation-type))
     1420
     1421(defun* operating-system ()
     1422  (first-feature
     1423   '(:cygwin (:win :windows :mswindows :win32 :mingw32) ;; try cygwin first!
     1424     (:linux :linux :linux-target) ;; for GCL at least, must appear before :bsd
     1425     (:macosx :macosx :darwin :darwin-target :apple) ; also before :bsd
     1426     (:solaris :solaris :sunos) (:bsd :bsd :freebsd :netbsd :openbsd) :unix
     1427     :genera)))
     1428
     1429(defun* architecture ()
     1430  (first-feature
     1431   '((:x64 :x86-64 :x86_64 :x8664-target :amd64 (:and :word-size=64 :pc386))
     1432     (:x86 :x86 :i386 :i486 :i586 :i686 :pentium3 :pentium4 :pc386 :iapx386 :x8632-target)
     1433     (:ppc64 :ppc64 :ppc64-target) (:ppc32 :ppc32 :ppc32-target :ppc :powerpc)
     1434     :hppa64 :hppa :sparc64 (:sparc32 :sparc32 :sparc)
     1435     :mipsel :mipseb :mips :alpha (:arm :arm :arm-target) :imach
     1436     ;; Java comes last: if someone uses C via CFFI or otherwise JNA or JNI,
     1437     ;; we may have to segregate the code still by architecture.
     1438     (:java :java :java-1.4 :java-1.5 :java-1.6 :java-1.7))))
     1439
     1440#+clozure
     1441(defun* ccl-fasl-version ()
     1442  ;; the fasl version is target-dependent from CCL 1.8 on.
     1443  (or (let ((s 'ccl::target-fasl-version))
     1444        (and (fboundp s) (funcall s)))
     1445      (and (boundp 'ccl::fasl-version)
     1446           (symbol-value 'ccl::fasl-version))
     1447      (error "Can't determine fasl version.")))
     1448
     1449(defun* lisp-version-string ()
     1450  (let ((s (lisp-implementation-version)))
     1451    (car ; as opposed to OR, this idiom prevents some unreachable code warning
     1452     (list
     1453      #+allegro
     1454      (format nil "~A~@[~A~]~@[~A~]~@[~A~]"
     1455              excl::*common-lisp-version-number*
     1456              ;; M means "modern", as opposed to ANSI-compatible mode (which I consider default)
     1457              (and (eq excl:*current-case-mode* :case-sensitive-lower) "M")
     1458              ;; Note if not using International ACL
     1459              ;; see http://www.franz.com/support/documentation/8.1/doc/operators/excl/ics-target-case.htm
     1460              (excl:ics-target-case (:-ics "8"))
     1461              (and (member :smp *features*) "S"))
     1462      #+armedbear (format nil "~a-fasl~a" s system::*fasl-version*)
     1463      #+clisp
     1464      (subseq s 0 (position #\space s)) ; strip build information (date, etc.)
     1465      #+clozure
     1466      (format nil "~d.~d-f~d" ; shorten for windows
     1467              ccl::*openmcl-major-version*
     1468              ccl::*openmcl-minor-version*
     1469              (logand (ccl-fasl-version) #xFF))
     1470      #+cmu (substitute #\- #\/ s)
     1471      #+scl (format nil "~A~A" s
     1472                    ;; ANSI upper case vs lower case.
     1473                    (ecase ext:*case-mode* (:upper "") (:lower "l")))
     1474      #+ecl (format nil "~A~@[-~A~]" s
     1475                    (let ((vcs-id (ext:lisp-implementation-vcs-id)))
     1476                      (subseq vcs-id 0 (min (length vcs-id) 8))))
     1477      #+gcl (subseq s (1+ (position #\space s)))
     1478      #+genera
     1479      (multiple-value-bind (major minor) (sct:get-system-version "System")
     1480        (format nil "~D.~D" major minor))
     1481      #+mcl (subseq s 8) ; strip the leading "Version "
     1482      s))))
     1483
     1484(defun* implementation-identifier ()
     1485  (substitute-if
     1486   #\_ #'(lambda (x) (find x " /:;&^\\|?<>(){}[]$#`'\""))
     1487   (format nil "~(~a~@{~@[-~a~]~}~)"
     1488           (or (implementation-type) (lisp-implementation-type))
     1489           (or (lisp-version-string) (lisp-implementation-version))
     1490           (or (operating-system) (software-type))
     1491           (or (architecture) (machine-type)))))
     1492
     1493
     1494;;;; Other system information
     1495
     1496(defun* hostname ()
     1497  ;; Note: untested on RMCL
     1498  #+(or abcl clozure cmucl ecl genera lispworks mcl mkcl sbcl scl xcl) (machine-instance)
     1499  #+cormanlisp "localhost" ;; is there a better way? Does it matter?
     1500  #+allegro (symbol-call :excl.osi :gethostname)
     1501  #+clisp (first (split-string (machine-instance) :separator " "))
     1502  #+gcl (system:gethostname))
     1503
     1504
     1505;;; Current directory
     1506
     1507(defun* getcwd ()
     1508  "Get the current working directory as per POSIX getcwd(3), as a pathname object"
     1509  (or #+abcl (parse-namestring
     1510              (java:jstatic "getProperty" "java.lang.System" "user.dir") :ensure-directory t)
     1511      #+allegro (excl::current-directory)
     1512      #+clisp (ext:default-directory)
     1513      #+clozure (ccl:current-directory)
     1514      #+(or cmu scl) (ext:parse-unix-namestring
     1515                      (nth-value 1 (unix:unix-current-directory)) :ensure-directory t)
     1516      #+cormanlisp (pathname (pl::get-current-directory)) ;; Q: what type does it return?
     1517      #+ecl (ext:getcwd)
     1518      #+gcl (parse-namestring ;; this is a joke. Isn't there a better way?
     1519             (first (symbol-call :asdf/driver :run-program '("/bin/pwd") :output :lines)))
     1520      #+genera *default-pathname-defaults* ;; on a Lisp OS, it *is* canonical!
     1521      #+lispworks (system:current-directory)
     1522      #+mkcl (mk-ext:getcwd)
     1523      #+sbcl (sb-ext:parse-native-namestring (sb-unix:posix-getcwd/))
     1524      #+xcl (extensions:current-directory)
     1525      (error "getcwd not supported on your implementation")))
     1526
     1527(defun* chdir (x)
     1528  "Change current directory, as per POSIX chdir(2)"
     1529  (declare (ignorable x))
     1530  (or #+abcl (java:jstatic "setProperty" "java.lang.System" "user.dir" (namestring x))
     1531      #+allegro (excl:chdir x)
     1532      #+clisp (ext:cd x)
     1533      #+clozure (setf (ccl:current-directory) x)
     1534      #+(or cmu scl) (unix:unix-chdir (ext:unix-namestring x))
     1535      #+cormanlisp (unless (zerop (win32::_chdir (namestring x)))
     1536                     (error "Could not set current directory to ~A" x))
     1537      #+ecl (ext:chdir x)
     1538      #+genera (setf *default-pathname-defaults* (pathname x))
     1539      #+lispworks (hcl:change-directory x)
     1540      #+mkcl (mk-ext:chdir x)
     1541      #+sbcl (symbol-call :sb-posix :chdir (sb-ext:native-namestring x))
     1542      (error "chdir not supported on your implementation")))
     1543
     1544
     1545;;;; -----------------------------------------------------------------
     1546;;;; Windows shortcut support.  Based on:
     1547;;;;
     1548;;;; Jesse Hager: The Windows Shortcut File Format.
     1549;;;; http://www.wotsit.org/list.asp?fc=13
     1550
     1551#-(or clisp genera) ; CLISP doesn't need it, and READ-SEQUENCE annoys old Genera.
     1552(progn
     1553(defparameter *link-initial-dword* 76)
     1554(defparameter *link-guid* #(1 20 2 0 0 0 0 0 192 0 0 0 0 0 0 70))
     1555
     1556(defun* read-null-terminated-string (s)
     1557  (with-output-to-string (out)
     1558    (loop :for code = (read-byte s)
     1559      :until (zerop code)
     1560      :do (write-char (code-char code) out))))
     1561
     1562(defun* read-little-endian (s &optional (bytes 4))
     1563  (loop :for i :from 0 :below bytes
     1564    :sum (ash (read-byte s) (* 8 i))))
     1565
     1566(defun* parse-file-location-info (s)
     1567  (let ((start (file-position s))
     1568        (total-length (read-little-endian s))
     1569        (end-of-header (read-little-endian s))
     1570        (fli-flags (read-little-endian s))
     1571        (local-volume-offset (read-little-endian s))
     1572        (local-offset (read-little-endian s))
     1573        (network-volume-offset (read-little-endian s))
     1574        (remaining-offset (read-little-endian s)))
     1575    (declare (ignore total-length end-of-header local-volume-offset))
     1576    (unless (zerop fli-flags)
     1577      (cond
     1578        ((logbitp 0 fli-flags)
     1579          (file-position s (+ start local-offset)))
     1580        ((logbitp 1 fli-flags)
     1581          (file-position s (+ start
     1582                              network-volume-offset
     1583                              #x14))))
     1584      (strcat (read-null-terminated-string s)
     1585              (progn
     1586                (file-position s (+ start remaining-offset))
     1587                (read-null-terminated-string s))))))
     1588
     1589(defun* parse-windows-shortcut (pathname)
     1590  (with-open-file (s pathname :element-type '(unsigned-byte 8))
     1591    (handler-case
     1592        (when (and (= (read-little-endian s) *link-initial-dword*)
     1593                   (let ((header (make-array (length *link-guid*))))
     1594                     (read-sequence header s)
     1595                     (equalp header *link-guid*)))
     1596          (let ((flags (read-little-endian s)))
     1597            (file-position s 76)        ;skip rest of header
     1598            (when (logbitp 0 flags)
     1599              ;; skip shell item id list
     1600              (let ((length (read-little-endian s 2)))
     1601                (file-position s (+ length (file-position s)))))
     1602            (cond
     1603              ((logbitp 1 flags)
     1604                (parse-file-location-info s))
     1605              (t
     1606                (when (logbitp 2 flags)
     1607                  ;; skip description string
     1608                  (let ((length (read-little-endian s 2)))
     1609                    (file-position s (+ length (file-position s)))))
     1610                (when (logbitp 3 flags)
     1611                  ;; finally, our pathname
     1612                  (let* ((length (read-little-endian s 2))
     1613                         (buffer (make-array length)))
     1614                    (read-sequence buffer s)
     1615                    (map 'string #'code-char buffer)))))))
     1616      (end-of-file (c)
     1617        (declare (ignore c))
     1618        nil)))))
     1619
     1620
    12841621;;;; -------------------------------------------------------------------------
    12851622;;;; Portability layer around Common Lisp pathnames
     
    12871624(asdf/package:define-package :asdf/pathname
    12881625  (:recycle :asdf/pathname :asdf)
    1289   (:use :asdf/common-lisp :asdf/package :asdf/utility)
     1626  (:use :asdf/common-lisp :asdf/package :asdf/utility :asdf/os)
    12901627  (:export
    12911628   #:*resolve-symlinks*
    1292    ;; Making and merging pathnames, portably
     1629   ;; Making pathnames, portably
    12931630   #:normalize-pathname-directory-component #:denormalize-pathname-directory-component
    1294    #:pathname-equal
    1295    #:merge-pathname-directory-components #:make-pathname* #:*unspecific-pathname-type*
     1631   #:merge-pathname-directory-components #:*unspecific-pathname-type* #:make-pathname*
    12961632   #:make-pathname-component-logical #:make-pathname-logical
    12971633   #:merge-pathnames*
     1634   ;; Predicates
     1635   #:pathname-equal #:logical-pathname-p #:physical-pathname-p
     1636   #:absolute-pathname-p #:relative-pathname-p #:hidden-pathname-p #:file-pathname-p
    12981637   ;; Directories
    12991638   #:pathname-directory-pathname #:pathname-parent-directory-pathname
    1300    #:directory-pathname-p #:ensure-directory-pathname #:file-pathname-p
    1301    ;; Absolute vs relative pathnames
    1302    #:ensure-pathname-absolute
    1303    #:relativize-directory-component #:relativize-pathname-directory
    1304    ;; Parsing filenames and lists thereof
     1639   #:directory-pathname-p #:ensure-directory-pathname
     1640   ;; defaults
     1641   #:nil-pathname #:with-pathname-defaults #:*nil-pathname*
     1642   ;; Parsing filenames
    13051643   #:component-name-to-pathname-components
    13061644   #:split-name-type #:parse-unix-namestring #:unix-namestring
    13071645   #:split-unix-namestring-directory-components
    1308    #:subpathname #:subpathname* #:subpathp
     1646   #:native-namestring #:parse-native-namestring
     1647   #:subpathname #:subpathname*
     1648   ;; Wildcard pathnames
     1649   #:*wild* #:*wild-file* #:*wild-directory* #:*wild-inferiors* #:*wild-path* #:wilden
     1650   ;; probe filesystem
     1651   #:truename* #:safe-file-write-date #:probe-file*
     1652   #:directory* #:filter-logical-directory-results #:directory-files #:subdirectories
     1653   #:collect-sub*directories
     1654   ;; Absolute vs relative pathnames
     1655   #:ensure-pathname-absolute
     1656   #:pathname-root #:pathname-host-pathname
     1657   #:subpathp
    13091658   ;; Resolving symlinks somewhat
    13101659   #:truenamize #:resolve-symlinks #:resolve-symlinks*
    1311    ;; Wildcard pathnames
    1312    #:*wild* #:*wild-file* #:*wild-directory* #:*wild-inferiors* #:*wild-path* #:wilden
    1313    ;; Pathname host and its root
    1314    #:absolute-pathname-p #:relative-pathname-p #:hidden-pathname-p
    1315    #:pathname-root #:directory-separator-for-host
    1316    #:directorize-pathname-host-device
    1317    ;; defaults
    1318    #:nil-pathname #:with-pathname-defaults
    1319    ;; probe filesystem
    1320    #:truename* #:probe-file* #:safe-file-write-date
    1321    #:subdirectories #:directory-files #:directory*
    1322    #:filter-logical-directory-results #:collect-sub*directories
    1323    ;; Simple filesystem operations
    1324    #:ensure-all-directories-exist
    1325    #:rename-file-overwriting-target
    1326    #:delete-file-if-exists
    1327    ;; Translate a pathname
    1328    #:translate-pathname*
    1329    ;; temporary
    1330    #:add-pathname-suffix #:tmpize-pathname
    1331    #:call-with-staging-pathname #:with-staging-pathname
    1332    ;; physical pathnames
    1333    #:logical-pathname-p #:physical-pathname-p #:sane-physical-pathname #:root-pathname
    1334    ;; Windows shortcut support
    1335    #:read-null-terminated-string #:read-little-endian
    1336    #:parse-file-location-info #:parse-windows-shortcut
    13371660   ;; Checking constraints
    13381661   #:ensure-pathname
    1339    #:absolutize-pathnames
    1340    ;; Output translations
     1662   ;; merging with cwd
     1663   #:get-pathname-defaults #:call-with-current-directory #:with-current-directory
     1664   ;; Environment pathnames
     1665   #:inter-directory-separator #:split-native-pathnames-string
     1666   #:getenv-pathname #:getenv-pathnames
     1667   #:getenv-absolute-directory #:getenv-absolute-directories
     1668   #:lisp-implementation-directory #:lisp-implementation-pathname-p
     1669   ;; Translate a pathname
     1670   #:relativize-directory-component #:relativize-pathname-directory
     1671   #:directory-separator-for-host #:directorize-pathname-host-device
     1672   #:translate-pathname*
    13411673   #:*output-translation-function*))
    13421674
     
    14101742  #+(or clisp ecl #|These haven't been tested:|# cormanlisp mcl) nil)
    14111743
    1412 (defun* make-pathname* (&rest keys &key (directory nil directoryp)
    1413                               host (device () devicep) name type version defaults
     1744(defun* make-pathname* (&rest keys &key (directory nil #+gcl2.6 directoryp)
     1745                              host (device () #+allegro devicep) name type version defaults
    14141746                              #+scl &allow-other-keys)
    14151747  "Takes arguments like CL:MAKE-PATHNAME in the CLHS, and
    14161748   tries hard to make a pathname that will actually behave as documented,
    14171749   despite the peculiarities of each implementation"
    1418   (declare (ignorable host device devicep name type version defaults))
     1750  (declare (ignorable host device directory name type version defaults))
    14191751  (apply 'make-pathname
    14201752         (append
    14211753          #+allegro (when (and devicep (null device)) `(:device :unspecific))
     1754          #+gcl2.6
    14221755          (when directoryp
    14231756            `(:directory ,(denormalize-pathname-directory-component directory)))
     
    14421775   :version (make-pathname-component-logical (pathname-version pathname))))
    14431776
    1444 
    1445 ;;; Some pathname predicates
    1446 
    1447 (defun* pathname-equal (p1 p2)
    1448   (when (stringp p1) (setf p1 (pathname p1)))
    1449   (when (stringp p2) (setf p2 (pathname p2)))
    1450   (flet ((normalize-component (x)
    1451            (unless (member x '(nil :unspecific :newest (:relative)) :test 'equal)
    1452              x)))
    1453     (macrolet ((=? (&rest accessors)
    1454                  (flet ((frob (x)
    1455                           (reduce 'list (cons 'normalize-component accessors)
    1456                                   :initial-value x :from-end t)))
    1457                    `(equal ,(frob 'p1) ,(frob 'p2)))))
    1458       (or (and (null p1) (null p2))
    1459           (and (pathnamep p1) (pathnamep p2)
    1460                (and (=? pathname-host)
    1461                     (=? pathname-device)
    1462                     (=? normalize-pathname-directory-component pathname-directory)
    1463                     (=? pathname-name)
    1464                     (=? pathname-type)
    1465                     (=? pathname-version)))))))
    1466 
    1467 (defun* logical-pathname-p (x)
    1468   (typep x 'logical-pathname))
    1469 
    1470 (defun* physical-pathname-p (x)
    1471   (and (pathnamep x) (not (logical-pathname-p x))))
    1472 
    1473 (defun* absolute-pathname-p (pathspec)
    1474   "If PATHSPEC is a pathname or namestring object that parses as a pathname
    1475 possessing an :ABSOLUTE directory component, return the (parsed) pathname.
    1476 Otherwise return NIL"
    1477   (and pathspec
    1478        (typep pathspec '(or null pathname string))
    1479        (let ((pathname (pathname pathspec)))
    1480          (and (eq :absolute (car (normalize-pathname-directory-component
    1481                                   (pathname-directory pathname))))
    1482               pathname))))
    1483 
    1484 (defun* relative-pathname-p (pathspec)
    1485   "If PATHSPEC is a pathname or namestring object that parses as a pathname
    1486 possessing a :RELATIVE or NIL directory component, return the (parsed) pathname.
    1487 Otherwise return NIL"
    1488   (and pathspec
    1489        (typep pathspec '(or null pathname string))
    1490        (let* ((pathname (pathname pathspec))
    1491               (directory (normalize-pathname-directory-component
    1492                           (pathname-directory pathname))))
    1493          (when (or (null directory) (eq :relative (car directory)))
    1494            pathname))))
    1495 
    1496 (defun* hidden-pathname-p (pathname)
    1497   "Return a boolean that is true if the pathname is hidden as per Unix style,
    1498 i.e. its name starts with a dot."
    1499   (and pathname (equal (first-char (pathname-name pathname)) #\.)))
    1500 
    1501 
    1502 ;;;; merging pathnames
    15031777(defun* merge-pathnames* (specified &optional (defaults *default-pathname-defaults*))
    15041778  "MERGE-PATHNAMES* is like MERGE-PATHNAMES except that
     
    15241798         (version (or (pathname-version specified) (pathname-version defaults))))
    15251799    (labels ((unspecific-handler (p)
    1526                (if (logical-pathname-p p) #'make-pathname-component-logical #'identity)))
     1800               (if (typep p 'logical-pathname) #'make-pathname-component-logical #'identity)))
    15271801      (multiple-value-bind (host device directory unspecific-handler)
    15281802          (ecase (first directory)
     
    15421816                        :version (funcall unspecific-handler version))))))
    15431817
    1544 ;;; Directories
     1818
     1819;;; Some pathname predicates
     1820
     1821(defun* pathname-equal (p1 p2)
     1822  (when (stringp p1) (setf p1 (pathname p1)))
     1823  (when (stringp p2) (setf p2 (pathname p2)))
     1824  (flet ((normalize-component (x)
     1825           (unless (member x '(nil :unspecific :newest (:relative)) :test 'equal)
     1826             x)))
     1827    (macrolet ((=? (&rest accessors)
     1828                 (flet ((frob (x)
     1829                          (reduce 'list (cons 'normalize-component accessors)
     1830                                  :initial-value x :from-end t)))
     1831                   `(equal ,(frob 'p1) ,(frob 'p2)))))
     1832      (or (and (null p1) (null p2))
     1833          (and (pathnamep p1) (pathnamep p2)
     1834               (and (=? pathname-host)
     1835                    (=? pathname-device)
     1836                    (=? normalize-pathname-directory-component pathname-directory)
     1837                    (=? pathname-name)
     1838                    (=? pathname-type)
     1839                    (=? pathname-version)))))))
     1840
     1841(defun* logical-pathname-p (x)
     1842  (typep x 'logical-pathname))
     1843
     1844(defun* physical-pathname-p (x)
     1845  (and (pathnamep x) (not (logical-pathname-p x))))
     1846
     1847(defun* absolute-pathname-p (pathspec)
     1848  "If PATHSPEC is a pathname or namestring object that parses as a pathname
     1849possessing an :ABSOLUTE directory component, return the (parsed) pathname.
     1850Otherwise return NIL"
     1851  (and pathspec
     1852       (typep pathspec '(or null pathname string))
     1853       (let ((pathname (pathname pathspec)))
     1854         (and (eq :absolute (car (normalize-pathname-directory-component
     1855                                  (pathname-directory pathname))))
     1856              pathname))))
     1857
     1858(defun* relative-pathname-p (pathspec)
     1859  "If PATHSPEC is a pathname or namestring object that parses as a pathname
     1860possessing a :RELATIVE or NIL directory component, return the (parsed) pathname.
     1861Otherwise return NIL"
     1862  (and pathspec
     1863       (typep pathspec '(or null pathname string))
     1864       (let* ((pathname (pathname pathspec))
     1865              (directory (normalize-pathname-directory-component
     1866                          (pathname-directory pathname))))
     1867         (when (or (null directory) (eq :relative (car directory)))
     1868           pathname))))
     1869
     1870(defun* hidden-pathname-p (pathname)
     1871  "Return a boolean that is true if the pathname is hidden as per Unix style,
     1872i.e. its name starts with a dot."
     1873  (and pathname (equal (first-char (pathname-name pathname)) #\.)))
     1874
     1875(defun* file-pathname-p (pathname)
     1876  "Does PATHNAME represent a file, i.e. has a non-null NAME component?
     1877
     1878Accepts NIL, a string (converted through PARSE-NAMESTRING) or a PATHNAME.
     1879
     1880Note that this does _not_ check to see that PATHNAME points to an
     1881actually-existing file.
     1882
     1883Returns the (parsed) PATHNAME when true"
     1884  (when pathname
     1885    (let* ((pathname (pathname pathname))
     1886           (name (pathname-name pathname)))
     1887      (when (not (member name '(nil :unspecific "") :test 'equal))
     1888        pathname))))
     1889
     1890
     1891;;; Directory pathnames
    15451892(defun* pathname-directory-pathname (pathname)
    15461893  "Returns a new pathname with same HOST, DEVICE, DIRECTORY as PATHNAME,
     
    15761923             t)))))
    15771924
    1578 (defun* file-pathname-p (pathname)
    1579   "Does PATHNAME represent a file, i.e. has a non-null NAME component?
    1580 
    1581 Accepts NIL, a string (converted through PARSE-NAMESTRING) or a PATHNAME.
    1582 
    1583 Note that this does _not_ check to see that PATHNAME points to an
    1584 actually-existing file.
    1585 
    1586 Returns the (parsed) PATHNAME when true"
    1587   (when pathname
    1588     (let* ((pathname (pathname pathname))
    1589            (name (pathname-name pathname)))
    1590       (when (not (member name '(nil :unspecific "") :test 'equal))
    1591         pathname))))
    1592 
    1593 (defun* ensure-directory-pathname (pathspec)
     1925(defun* ensure-directory-pathname (pathspec &optional (on-error 'error))
    15941926  "Converts the non-wild pathname designator PATHSPEC to directory form."
    15951927  (cond
     
    15971929    (ensure-directory-pathname (pathname pathspec)))
    15981930   ((not (pathnamep pathspec))
    1599     (error (compatfmt "~@<Invalid pathname designator ~S~@:>") pathspec))
     1931    (call-function on-error (compatfmt "~@<Invalid pathname designator ~S~@:>") pathspec))
    16001932   ((wild-pathname-p pathspec)
    1601     (error (compatfmt "~@<Can't reliably convert wild pathname ~3i~_~S~@:>") pathspec))
     1933    (call-function on-error (compatfmt "~@<Can't reliably convert wild pathname ~3i~_~S~@:>") pathspec))
    16021934   ((directory-pathname-p pathspec)
    16031935    pathspec)
     
    16081940                                       (list (file-namestring pathspec)))
    16091941                    :name nil :type nil :version nil :defaults pathspec))))
     1942
     1943
     1944;;; defaults
     1945(defun* nil-pathname (&optional (defaults *default-pathname-defaults*))
     1946  "A pathname that is as neutral as possible for use as defaults
     1947   when merging, making or parsing pathnames"
     1948  ;; 19.2.2.2.1 says a NIL host can mean a default host;
     1949  ;; see also "valid physical pathname host" in the CLHS glossary, that suggests
     1950  ;; strings and lists of strings or :unspecific
     1951  ;; But CMUCL decides to die on NIL.
     1952  (make-pathname* :directory nil :name nil :type nil :version nil :device nil
     1953                  :host (or #+cmu lisp::*unix-host*)
     1954                  ;; the default shouldn't matter, but we really want something physical
     1955                  :defaults defaults))
     1956
     1957(defvar *nil-pathname* (nil-pathname (translate-logical-pathname (user-homedir-pathname))))
     1958
     1959(defmacro with-pathname-defaults ((&optional defaults) &body body)
     1960  `(let ((*default-pathname-defaults* ,(or defaults '*nil-pathname*))) ,@body))
     1961
     1962
     1963;;; Parsing filenames and lists thereof
     1964(defun* split-unix-namestring-directory-components
     1965    (unix-namestring &key ensure-directory dot-dot)
     1966  "Splits the path string UNIX-NAMESTRING, returning four values:
     1967A flag that is either :absolute or :relative, indicating
     1968   how the rest of the values are to be interpreted.
     1969A directory path --- a list of strings and keywords, suitable for
     1970   use with MAKE-PATHNAME when prepended with the flag value.
     1971   Directory components with an empty name or the name . are removed.
     1972   Any directory named .. is read as DOT-DOT, or :BACK if it's NIL (not :UP).
     1973A last-component, either a file-namestring including type extension,
     1974   or NIL in the case of a directory pathname.
     1975A flag that is true iff the unix-style-pathname was just
     1976   a file-namestring without / path specification.
     1977ENSURE-DIRECTORY forces the namestring to be interpreted as a directory pathname:
     1978the third return value will be NIL, and final component of the namestring
     1979will be treated as part of the directory path.
     1980
     1981An empty string is thus read as meaning a pathname object with all fields nil.
     1982
     1983Note that : characters will NOT be interpreted as host specification.
     1984Absolute pathnames are only appropriate on Unix-style systems.
     1985
     1986The intention of this function is to support structured component names,
     1987e.g., \(:file \"foo/bar\"\), which will be unpacked to relative pathnames."
     1988  (check-type unix-namestring string)
     1989  (check-type dot-dot (member nil :back :up))
     1990  (if (and (not (find #\/ unix-namestring)) (not ensure-directory)
     1991           (plusp (length unix-namestring)))
     1992      (values :relative () unix-namestring t)
     1993      (let* ((components (split-string unix-namestring :separator "/"))
     1994             (last-comp (car (last components))))
     1995        (multiple-value-bind (relative components)
     1996            (if (equal (first components) "")
     1997                (if (equal (first-char unix-namestring) #\/)
     1998                    (values :absolute (cdr components))
     1999                    (values :relative nil))
     2000                (values :relative components))
     2001          (setf components (remove-if #'(lambda (x) (member x '("" ".") :test #'equal))
     2002                                      components))
     2003          (setf components (substitute (or dot-dot :back) ".." components :test #'equal))
     2004          (cond
     2005            ((equal last-comp "")
     2006             (values relative components nil nil)) ; "" already removed from components
     2007            (ensure-directory
     2008             (values relative components nil nil))
     2009            (t
     2010             (values relative (butlast components) last-comp nil)))))))
     2011
     2012(defun* split-name-type (filename)
     2013  "Split a filename into two values NAME and TYPE that are returned.
     2014We assume filename has no directory component.
     2015The last . if any separates name and type from from type,
     2016except that if there is only one . and it is in first position,
     2017the whole filename is the NAME with an empty type.
     2018NAME is always a string.
     2019For an empty type, *UNSPECIFIC-PATHNAME-TYPE* is returned."
     2020  (check-type filename string)
     2021  (assert (plusp (length filename)))
     2022  (destructuring-bind (name &optional (type *unspecific-pathname-type*))
     2023      (split-string filename :max 2 :separator ".")
     2024    (if (equal name "")
     2025        (values filename *unspecific-pathname-type*)
     2026        (values name type))))
     2027
     2028(defun* parse-unix-namestring (name &rest keys &key type defaults dot-dot ensure-directory
     2029                                    &allow-other-keys)
     2030  "Coerce NAME into a PATHNAME using standard Unix syntax.
     2031
     2032Unix syntax is used whether or not the underlying system is Unix;
     2033on such non-Unix systems it is only usable but for relative pathnames;
     2034but especially to manipulate relative pathnames portably, it is of crucial
     2035to possess a portable pathname syntax independent of the underlying OS.
     2036This is what PARSE-UNIX-NAMESTRING provides, and why we use it in ASDF.
     2037
     2038When given a PATHNAME object, just return it untouched.
     2039When given NIL, just return NIL.
     2040When given a non-null SYMBOL, first downcase its name and treat it as a string.
     2041When given a STRING, portably decompose it into a pathname as below.
     2042
     2043#\\/ separates directory components.
     2044
     2045The last #\\/-separated substring is interpreted as follows:
     20461- If TYPE is :DIRECTORY or ENSURE-DIRECTORY is true,
     2047 the string is made the last directory component, and NAME and TYPE are NIL.
     2048 if the string is empty, it's the empty pathname with all slots NIL.
     20492- If TYPE is NIL, the substring is file-namestring, and its NAME and TYPE
     2050 are separated by SPLIT-NAME-TYPE.
     20513- If TYPE is a string, it is the given TYPE, and the whole string is the NAME.
     2052
     2053Directory components with an empty name the name . are removed.
     2054Any directory named .. is read as DOT-DOT,
     2055which must be one of :BACK or :UP and defaults to :BACK.
     2056
     2057HOST, DEVICE and VERSION components are taken from DEFAULTS,
     2058which itself defaults to *NIL-PATHNAME*, also used if DEFAULTS in NIL.
     2059No host or device can be specified in the string itself,
     2060which makes it unsuitable for absolute pathnames outside Unix.
     2061
     2062For relative pathnames, these components (and hence the defaults) won't matter
     2063if you use MERGE-PATHNAMES* but will matter if you use MERGE-PATHNAMES,
     2064which is an important reason to always use MERGE-PATHNAMES*.
     2065
     2066Arbitrary keys are accepted, and the parse result is passed to ENSURE-PATHNAME
     2067with those keys, removing TYPE DEFAULTS and DOT-DOT.
     2068When you're manipulating pathnames that are supposed to make sense portably
     2069even though the OS may not be Unixish, we recommend you use :WANT-RELATIVE T
     2070to throw an error if the pathname is absolute"
     2071  (block nil
     2072    (check-type type (or null string (eql :directory)))
     2073    (when ensure-directory
     2074      (setf type :directory))
     2075    (etypecase name
     2076      ((or null pathname) (return name))
     2077      (symbol
     2078       (setf name (string-downcase name)))
     2079      (string))
     2080    (multiple-value-bind (relative path filename file-only)
     2081        (split-unix-namestring-directory-components
     2082         name :dot-dot dot-dot :ensure-directory (eq type :directory))
     2083      (multiple-value-bind (name type)
     2084          (cond
     2085            ((or (eq type :directory) (null filename))
     2086             (values nil nil))
     2087            (type
     2088             (values filename type))
     2089            (t
     2090             (split-name-type filename)))
     2091        (apply 'ensure-pathname
     2092               (make-pathname*
     2093                :directory (unless file-only (cons relative path))
     2094                :name name :type type
     2095                :defaults (or defaults *nil-pathname*))
     2096               (remove-plist-keys '(:type :dot-dot :defaults) keys))))))
     2097
     2098(defun* unix-namestring (pathname)
     2099  "Given a non-wild PATHNAME, return a Unix-style namestring for it.
     2100If the PATHNAME is NIL or a STRING, return it unchanged.
     2101
     2102This only considers the DIRECTORY, NAME and TYPE components of the pathname.
     2103This is a portable solution for representing relative pathnames,
     2104But unless you are running on a Unix system, it is not a general solution
     2105to representing native pathnames.
     2106
     2107An error is signaled if the argument is not NULL, a STRING or a PATHNAME,
     2108or if it is a PATHNAME but some of its components are not recognized."
     2109  (etypecase pathname
     2110    ((or null string) pathname)
     2111    (pathname
     2112     (with-output-to-string (s)
     2113       (flet ((err () (error "Not a valid unix-namestring ~S" pathname)))
     2114         (let* ((dir (normalize-pathname-directory-component (pathname-directory pathname)))
     2115                (name (pathname-name pathname))
     2116                (type (pathname-type pathname))
     2117                (type (and (not (eq type :unspecific)) type)))
     2118           (cond
     2119             ((eq dir ()))
     2120             ((eq dir '(:relative)) (princ "./" s))
     2121             ((consp dir)
     2122              (destructuring-bind (relabs &rest dirs) dir
     2123                (or (member relabs '(:relative :absolute)) (err))
     2124                (when (eq relabs :absolute) (princ #\/ s))
     2125                (loop :for x :in dirs :do
     2126                  (cond
     2127                    ((member x '(:back :up)) (princ "../" s))
     2128                    ((equal x "") (err))
     2129                    ;;((member x '("." "..") :test 'equal) (err))
     2130                    ((stringp x) (format s "~A/" x))
     2131                    (t (err))))))
     2132             (t (err)))
     2133           (cond
     2134             (name
     2135              (or (and (stringp name) (or (null type) (stringp type))) (err))
     2136              (format s "~A~@[.~A~]" name type))
     2137             (t
     2138              (or (null type) (err))))))))))
     2139
     2140(defun* native-namestring (x)
     2141  "From a non-wildcard CL pathname, a return namestring suitable for passing to the operating system"
     2142  (when x
     2143    (let ((p (pathname x)))
     2144      #+clozure (with-pathname-defaults () (ccl:native-translated-namestring p)) ; see ccl bug 978
     2145      #+(or cmu scl) (ext:unix-namestring p nil)
     2146      #+sbcl (sb-ext:native-namestring p)
     2147      #-(or clozure cmu sbcl scl)
     2148      (if (os-unix-p) (unix-namestring p)
     2149          (namestring p)))))
     2150
     2151(defun* parse-native-namestring (string &rest constraints &key ensure-directory &allow-other-keys)
     2152  "From a native namestring suitable for use by the operating system, return
     2153a CL pathname satisfying all the specified constraints as per ENSURE-PATHNAME"
     2154  (check-type string (or string null))
     2155  (let* ((pathname
     2156           (when string
     2157             (with-pathname-defaults ()
     2158               #+clozure (ccl:native-to-pathname string)
     2159               #+sbcl (sb-ext:parse-native-namestring string)
     2160               #-(or clozure sbcl)
     2161               (if (os-unix-p)
     2162                   (parse-unix-namestring string :ensure-directory ensure-directory)
     2163                   (parse-namestring string)))))
     2164         (pathname
     2165           (if ensure-directory
     2166               (and pathname (ensure-directory-pathname pathname))
     2167               pathname)))
     2168    (apply 'ensure-pathname pathname constraints)))
     2169
     2170(defun* subpathname (pathname subpath &key type)
     2171  "This function takes a PATHNAME and a SUBPATH and a TYPE.
     2172If SUBPATH is already a PATHNAME object (not namestring),
     2173and is an absolute pathname at that, it is returned unchanged;
     2174otherwise, SUBPATH is turned into a relative pathname with given TYPE
     2175as per PARSE-UNIX-NAMESTRING with :WANT-RELATIVE T :TYPE TYPE,
     2176then it is merged with the PATHNAME-DIRECTORY-PATHNAME of PATHNAME."
     2177  (or (and (pathnamep subpath) (absolute-pathname-p subpath))
     2178      (merge-pathnames* (parse-unix-namestring subpath :type type :want-relative t)
     2179                        (pathname-directory-pathname pathname))))
     2180
     2181(defun* subpathname* (pathname subpath &key type)
     2182  "returns NIL if the base pathname is NIL, otherwise like SUBPATHNAME."
     2183  (and pathname
     2184       (subpathname (ensure-directory-pathname pathname) subpath :type type)))
    16102185
    16112186
     
    16312206
    16322207;;; Probing the filesystem
    1633 (defun* nil-pathname (&optional (defaults *default-pathname-defaults*))
    1634   ;; 19.2.2.2.1 says a NIL host can mean a default host;
    1635   ;; see also "valid physical pathname host" in the CLHS glossary, that suggests
    1636   ;; strings and lists of strings or :unspecific
    1637   ;; But CMUCL decides to die on NIL.
    1638   (make-pathname* :directory nil :name nil :type nil :version nil :device nil
    1639                   :host (or #+cmu lisp::*unix-host*)
    1640                   ;; the default shouldn't matter, but we really want something physical
    1641                   :defaults defaults))
    1642 
    1643 (defmacro with-pathname-defaults ((&optional defaults) &body body)
    1644   `(let ((*default-pathname-defaults* ,(or defaults '(nil-pathname)))) ,@body))
    1645 
    16462208(defun* truename* (p)
    16472209  ;; avoids both logical-pathname merging and physical resolution issues
    1648   (and p (ignore-errors (with-pathname-defaults () (truename p)))))
     2210  (and p (handler-case (with-pathname-defaults () (truename p)) (file-error () nil))))
     2211
     2212(defun* safe-file-write-date (pathname)
     2213  ;; If FILE-WRITE-DATE returns NIL, it's possible that
     2214  ;; the user or some other agent has deleted an input file.
     2215  ;; Also, generated files will not exist at the time planning is done
     2216  ;; and calls compute-action-stamp which calls safe-file-write-date.
     2217  ;; So it is very possible that we can't get a valid file-write-date,
     2218  ;; and we can survive and we will continue the planning
     2219  ;; as if the file were very old.
     2220  ;; (or should we treat the case in a different, special way?)
     2221  (handler-case (file-write-date pathname) (file-error () nil)))
    16492222
    16502223(defun* probe-file* (p &key truename)
     
    16572230      (null nil)
    16582231      (string (probe-file* (parse-namestring p) :truename truename))
    1659       (pathname (unless (wild-pathname-p p)
    1660                   (let ((foundtrue
    1661                           #.(or #+(or allegro clozure cmu cormanlisp ecl lispworks mkcl sbcl scl)
    1662                                 '(probe-file p)
    1663                                 #+clisp (if-let (it (find-symbol* '#:probe-pathname :ext nil))
    1664                                           `(ignore-errors (,it p)))
    1665                                 #+gcl2.6
    1666                                 '(or (probe-file p)
    1667                                   (and (directory-pathname-p p)
    1668                                    (ignore-errors
    1669                                     (ensure-directory-pathname
    1670                                      (truename* (subpathname
    1671                                                  (ensure-directory-pathname p) "."))))))
    1672                                 '(truename* p))))
    1673                     (cond
    1674                       (truename foundtrue)
    1675                       (foundtrue p)
    1676                       (t nil))))))))
    1677 
    1678 (defun* safe-file-write-date (pathname)
    1679   ;; If FILE-WRITE-DATE returns NIL, it's possible that
    1680   ;; the user or some other agent has deleted an input file.
    1681   ;; Also, generated files will not exist at the time planning is done
    1682   ;; and calls compute-action-stamp which calls safe-file-write-date.
    1683   ;; So it is very possible that we can't get a valid file-write-date,
    1684   ;; and we can survive and we will continue the planning
    1685   ;; as if the file were very old.
    1686   ;; (or should we treat the case in a different, special way?)
    1687   (and (probe-file* pathname) (ignore-errors (file-write-date pathname))))
     2232      (pathname
     2233       (handler-case
     2234           (or
     2235            #+allegro
     2236            (probe-file p :follow-symlinks truename)
     2237            #-(or allegro clisp gcl2.6)
     2238            (if truename
     2239                (probe-file p)
     2240                (and (ignore-errors
     2241                      #+(or cmu scl) (unix:unix-stat (ext:unix-namestring (translate-logical-pathname p)))
     2242                      #+(and lispworks unix) (system:get-file-stat p)
     2243                      #+sbcl (sb-unix:unix-stat (sb-ext:native-namestring (translate-logical-pathname p)))
     2244                      #-(or cmu (and lispworks unix) sbcl scl)
     2245                      (file-write-date p))
     2246                     p))
     2247            #+(or clisp gcl2.6)
     2248            #.(flet ((probe (probe)
     2249                       `(let ((foundtrue ,probe))
     2250                          (cond
     2251                            (truename foundtrue)
     2252                            (foundtrue p)))))
     2253                #+gcl2.6
     2254                (probe '(or (probe-file p)
     2255                         (and (directory-pathname-p p)
     2256                          (ignore-errors
     2257                           (ensure-directory-pathname
     2258                            (truename* (subpathname
     2259                                        (ensure-directory-pathname p) ".")))))))
     2260                #+clisp
     2261                (let ((fs (find-symbol* '#:file-stat :posix nil))
     2262                      (pp (find-symbol* '#:probe-pathname :ext nil))
     2263                      (resolve (if pp
     2264                                   `(ignore-errors (,pp p))
     2265                                   '(or (truename* p)
     2266                                     (truename* (ensure-directory-pathname p))))))
     2267                  (if fs
     2268                      `(if truename
     2269                           ,resolve
     2270                           (and (,fs p) p))
     2271                      (probe resolve)))))
     2272         (file-error () nil))))))
    16882273
    16892274(defun* directory* (pathname-spec &rest keys &key &allow-other-keys)
     
    17792364
    17802365
    1781 ;;; Parsing filenames and lists thereof
    1782 (defun* split-unix-namestring-directory-components
    1783     (unix-namestring &key ensure-directory dot-dot)
    1784   "Splits the path string UNIX-NAMESTRING, returning four values:
    1785 A flag that is either :absolute or :relative, indicating
    1786    how the rest of the values are to be interpreted.
    1787 A directory path --- a list of strings and keywords, suitable for
    1788    use with MAKE-PATHNAME when prepended with the flag value.
    1789    Directory components with an empty name or the name . are removed.
    1790    Any directory named .. is read as DOT-DOT, or :BACK if it's NIL (not :UP).
    1791 A last-component, either a file-namestring including type extension,
    1792    or NIL in the case of a directory pathname.
    1793 A flag that is true iff the unix-style-pathname was just
    1794    a file-namestring without / path specification.
    1795 ENSURE-DIRECTORY forces the namestring to be interpreted as a directory pathname:
    1796 the third return value will be NIL, and final component of the namestring
    1797 will be treated as part of the directory path.
    1798 
    1799 An empty string is thus read as meaning a pathname object with all fields nil.
    1800 
    1801 Note that : characters will NOT be interpreted as host specification.
    1802 Absolute pathnames are only appropriate on Unix-style systems.
    1803 
    1804 The intention of this function is to support structured component names,
    1805 e.g., \(:file \"foo/bar\"\), which will be unpacked to relative pathnames."
    1806   (check-type unix-namestring string)
    1807   (check-type dot-dot (member nil :back :up))
    1808   (if (and (not (find #\/ unix-namestring)) (not ensure-directory)
    1809            (plusp (length unix-namestring)))
    1810       (values :relative () unix-namestring t)
    1811       (let* ((components (split-string unix-namestring :separator "/"))
    1812              (last-comp (car (last components))))
    1813         (multiple-value-bind (relative components)
    1814             (if (equal (first components) "")
    1815                 (if (equal (first-char unix-namestring) #\/)
    1816                     (values :absolute (cdr components))
    1817                     (values :relative nil))
    1818                 (values :relative components))
    1819           (setf components (remove-if #'(lambda (x) (member x '("" ".") :test #'equal))
    1820                                       components))
    1821           (setf components (substitute (or dot-dot :back) ".." components :test #'equal))
    1822           (cond
    1823             ((equal last-comp "")
    1824              (values relative components nil nil)) ; "" already removed from components
    1825             (ensure-directory
    1826              (values relative components nil nil))
    1827             (t
    1828              (values relative (butlast components) last-comp nil)))))))
    1829 
    1830 (defun* split-name-type (filename)
    1831   "Split a filename into two values NAME and TYPE that are returned.
    1832 We assume filename has no directory component.
    1833 The last . if any separates name and type from from type,
    1834 except that if there is only one . and it is in first position,
    1835 the whole filename is the NAME with an empty type.
    1836 NAME is always a string.
    1837 For an empty type, *UNSPECIFIC-PATHNAME-TYPE* is returned."
    1838   (check-type filename string)
    1839   (assert (plusp (length filename)))
    1840   (destructuring-bind (name &optional (type *unspecific-pathname-type*))
    1841       (split-string filename :max 2 :separator ".")
    1842     (if (equal name "")
    1843         (values filename *unspecific-pathname-type*)
    1844         (values name type))))
    1845 
    1846 (defun* parse-unix-namestring (name &rest keys &key type defaults dot-dot ensure-directory
    1847                                     &allow-other-keys)
    1848   "Coerce NAME into a PATHNAME using standard Unix syntax.
    1849 
    1850 Unix syntax is used whether or not the underlying system is Unix;
    1851 on such non-Unix systems it is only usable but for relative pathnames;
    1852 but especially to manipulate relative pathnames portably, it is of crucial
    1853 to possess a portable pathname syntax independent of the underlying OS.
    1854 This is what PARSE-UNIX-NAMESTRING provides, and why we use it in ASDF.
    1855 
    1856 When given a PATHNAME object, just return it untouched.
    1857 When given NIL, just return NIL.
    1858 When given a non-null SYMBOL, first downcase its name and treat it as a string.
    1859 When given a STRING, portably decompose it into a pathname as below.
    1860 
    1861 #\\/ separates directory components.
    1862 
    1863 The last #\\/-separated substring is interpreted as follows:
    1864 1- If TYPE is :DIRECTORY or ENSURE-DIRECTORY is true,
    1865  the string is made the last directory component, and NAME and TYPE are NIL.
    1866  if the string is empty, it's the empty pathname with all slots NIL.
    1867 2- If TYPE is NIL, the substring is file-namestring, and its NAME and TYPE
    1868  are separated by SPLIT-NAME-TYPE.
    1869 3- If TYPE is a string, it is the given TYPE, and the whole string is the NAME.
    1870 
    1871 Directory components with an empty name the name . are removed.
    1872 Any directory named .. is read as DOT-DOT,
    1873 which must be one of :BACK or :UP and defaults to :BACK.
    1874 
    1875 HOST, DEVICE and VERSION components are taken from DEFAULTS,
    1876 which itself defaults to (ROOT-PATHNAME), also used if DEFAULTS in NIL.
    1877 No host or device can be specified in the string itself,
    1878 which makes it unsuitable for absolute pathnames outside Unix.
    1879 
    1880 For relative pathnames, these components (and hence the defaults) won't matter
    1881 if you use MERGE-PATHNAMES* but will matter if you use MERGE-PATHNAMES,
    1882 which is an important reason to always use MERGE-PATHNAMES*.
    1883 
    1884 Arbitrary keys are accepted, and the parse result is passed to ENSURE-PATHNAME
    1885 with those keys, removing TYPE DEFAULTS and DOT-DOT.
    1886 When you're manipulating pathnames that are supposed to make sense portably
    1887 even though the OS may not be Unixish, we recommend you use :WANT-RELATIVE T
    1888 to throw an error if the pathname is absolute"
    1889   (block nil
    1890     (check-type type (or null string (eql :directory)))
    1891     (when ensure-directory
    1892       (setf type :directory))
    1893     (etypecase name
    1894       ((or null pathname) (return name))
    1895       (symbol
    1896        (setf name (string-downcase name)))
    1897       (string))
    1898     (multiple-value-bind (relative path filename file-only)
    1899         (split-unix-namestring-directory-components
    1900          name :dot-dot dot-dot :ensure-directory (eq type :directory))
    1901       (multiple-value-bind (name type)
    1902           (cond
    1903             ((or (eq type :directory) (null filename))
    1904              (values nil nil))
    1905             (type
    1906              (values filename type))
    1907             (t
    1908              (split-name-type filename)))
    1909         (apply 'ensure-pathname
    1910                (make-pathname*
    1911                 :directory (unless file-only (cons relative path))
    1912                 :name name :type type
    1913                 :defaults (or defaults (nil-pathname)))
    1914                (remove-plist-keys '(:type :dot-dot :defaults) keys))))))
    1915 
    1916 (defun* unix-namestring (pathname)
    1917   "Given a non-wild PATHNAME, return a Unix-style namestring for it.
    1918 If the PATHNAME is NIL or a STRING, return it unchanged.
    1919 
    1920 This only considers the DIRECTORY, NAME and TYPE components of the pathname.
    1921 This is a portable solution for representing relative pathnames,
    1922 But unless you are running on a Unix system, it is not a general solution
    1923 to representing native pathnames.
    1924 
    1925 An error is signaled if the argument is not NULL, a STRING or a PATHNAME,
    1926 or if it is a PATHNAME but some of its components are not recognized."
    1927   (etypecase pathname
    1928     ((or null string) pathname)
    1929     (pathname
    1930      (with-output-to-string (s)
    1931        (flet ((err () (error "Not a valid unix-namestring ~S" pathname)))
    1932          (let* ((dir (normalize-pathname-directory-component (pathname-directory pathname)))
    1933                 (name (pathname-name pathname))
    1934                 (type (pathname-type pathname))
    1935                 (type (and (not (eq type :unspecific)) type)))
    1936            (cond
    1937              ((eq dir ()))
    1938              ((eq dir '(:relative)) (princ "./" s))
    1939              ((consp dir)
    1940               (destructuring-bind (relabs &rest dirs) dir
    1941                 (or (member relabs '(:relative :absolute)) (err))
    1942                 (when (eq relabs :absolute) (princ #\/ s))
    1943                 (loop :for x :in dirs :do
    1944                   (cond
    1945                     ((member x '(:back :up)) (princ "../" s))
    1946                     ((equal x "") (err))
    1947                     ;;((member x '("." "..") :test 'equal) (err))
    1948                     ((stringp x) (format s "~A/" x))
    1949                     (t (err))))))
    1950              (t (err)))
    1951            (cond
    1952              (name
    1953               (or (and (stringp name) (or (null type) (stringp type))) (err))
    1954               (format s "~A~@[.~A~]" name type))
    1955              (t
    1956               (or (null type) (err))))))))))
    1957 
    1958 (defun* subpathname (pathname subpath &key type)
    1959   "This function takes a PATHNAME and a SUBPATH and a TYPE.
    1960 If SUBPATH is already a PATHNAME object (not namestring),
    1961 and is an absolute pathname at that, it is returned unchanged;
    1962 otherwise, SUBPATH is turned into a relative pathname with given TYPE
    1963 as per PARSE-UNIX-NAMESTRING with :WANT-RELATIVE T :TYPE TYPE,
    1964 then it is merged with the PATHNAME-DIRECTORY-PATHNAME of PATHNAME."
    1965   (or (and (pathnamep subpath) (absolute-pathname-p subpath))
    1966       (merge-pathnames* (parse-unix-namestring subpath :type type :want-relative t)
    1967                         (pathname-directory-pathname pathname))))
    1968 
    1969 (defun* subpathname* (pathname subpath &key type)
    1970   "returns NIL if the base pathname is NIL, otherwise like SUBPATHNAME."
    1971   (and pathname
    1972        (subpathname (ensure-directory-pathname pathname) subpath :type type)))
    1973 
    19742366;;; Pathname host and its root
    19752367(defun* pathname-root (pathname)
     
    19862378                  ;; scheme-specific parts: port username password, not others:
    19872379                  . #.(or #+scl '(:parameters nil :query nil :fragment nil))))
    1988 
    1989 #-scl
    1990 (defun* directory-separator-for-host (&optional (pathname *default-pathname-defaults*))
    1991   (let ((foo (make-pathname* :directory '(:absolute "FOO") :defaults pathname)))
    1992     (last-char (namestring foo))))
    1993 
    1994 #-scl
    1995 (defun* directorize-pathname-host-device (pathname)
    1996   (let* ((root (pathname-root pathname))
    1997          (wild-root (wilden root))
    1998          (absolute-pathname (merge-pathnames* pathname root))
    1999          (separator (directory-separator-for-host root))
    2000          (root-namestring (namestring root))
    2001          (root-string
    2002           (substitute-if #\/
    2003                          #'(lambda (x) (or (eql x #\:)
    2004                                            (eql x separator)))
    2005                          root-namestring)))
    2006     (multiple-value-bind (relative path filename)
    2007         (split-unix-namestring-directory-components root-string :ensure-directory t)
    2008       (declare (ignore relative filename))
    2009       (let ((new-base
    2010              (make-pathname* :defaults root :directory `(:absolute ,@path))))
    2011         (translate-pathname absolute-pathname wild-root (wilden new-base))))))
    2012 
    2013 #+scl
    2014 (defun* directorize-pathname-host-device (pathname)
    2015   (let ((scheme (ext:pathname-scheme pathname))
    2016         (host (pathname-host pathname))
    2017         (port (ext:pathname-port pathname))
    2018         (directory (pathname-directory pathname)))
    2019     (flet ((specificp (x) (and x (not (eq x :unspecific)))))
    2020       (if (or (specificp port)
    2021               (and (specificp host) (plusp (length host)))
    2022               (specificp scheme))
    2023         (let ((prefix ""))
    2024           (when (specificp port)
    2025             (setf prefix (format nil ":~D" port)))
    2026           (when (and (specificp host) (plusp (length host)))
    2027             (setf prefix (strcat host prefix)))
    2028           (setf prefix (strcat ":" prefix))
    2029           (when (specificp scheme)
    2030             (setf prefix (strcat scheme prefix)))
    2031           (assert (and directory (eq (first directory) :absolute)))
    2032           (make-pathname* :directory `(:absolute ,prefix ,@(rest directory))
    2033                           :defaults pathname)))
    2034     pathname)))
    20352380
    20362381(defun* subpathp (maybe-subpath base-pathname)
     
    20432388           (and (relative-pathname-p enough) (pathname enough))))))
    20442389
     2390(defun* ensure-pathname-absolute (path &optional defaults (on-error 'error))
     2391  (cond
     2392    ((absolute-pathname-p path))
     2393    ((stringp path) (ensure-pathname-absolute (pathname path) defaults))
     2394    ((not (pathnamep path)) (call-function on-error "not a valid pathname designator ~S" path))
     2395    ((let ((default-pathname (if (pathnamep defaults) defaults (call-function defaults))))
     2396       (or (if (absolute-pathname-p default-pathname)
     2397               (absolute-pathname-p (merge-pathnames* path default-pathname))
     2398               (call-function on-error "Default pathname ~S is not an absolute pathname"
     2399                              default-pathname))
     2400           (call-function on-error "Failed to merge ~S with ~S into an absolute pathname"
     2401                          path default-pathname))))
     2402    (t (call-function on-error
     2403                      "Cannot ensure ~S is evaluated as an absolute pathname with defaults ~S"
     2404                      path defaults))))
     2405
    20452406
    20462407;;; Resolving symlinks somewhat
    2047 (defun* truenamize (pathname &optional (defaults *default-pathname-defaults*))
     2408(defun* truenamize (pathname)
    20482409  "Resolve as much of a pathname as possible"
    20492410  (block nil
    20502411    (when (typep pathname '(or null logical-pathname)) (return pathname))
    2051     (let ((p (merge-pathnames* pathname defaults)))
     2412    (let ((p pathname))
     2413      (unless (absolute-pathname-p p)
     2414        (setf p (or (absolute-pathname-p (ensure-pathname-absolute p 'get-pathname-defaults nil))
     2415                    (return p))))
    20522416      (when (logical-pathname-p p) (return p))
    20532417      (let ((found (probe-file* p :truename t)))
    20542418        (when found (return found)))
    2055       (unless (absolute-pathname-p p)
    2056         (let ((true-defaults (truename* defaults)))
    2057           (when true-defaults
    2058             (setf p (merge-pathnames pathname true-defaults)))))
    2059       (unless (absolute-pathname-p p) (return p))
    2060       (let ((sofar (probe-file* (pathname-root p) :truename t)))
    2061         (unless sofar (return p))
    2062         (flet ((solution (directories)
    2063                  (merge-pathnames*
    2064                   (make-pathname* :host nil :device nil
    2065                                   :directory `(:relative ,@directories)
    2066                                   :name (pathname-name p)
    2067                                   :type (pathname-type p)
    2068                                   :version (pathname-version p))
    2069                   sofar)))
    2070           (loop :with directory = (normalize-pathname-directory-component
    2071                                    (pathname-directory p))
    2072             :for dir :in (cdr directory)
    2073             :for rest :on (cdr directory)
    2074             :for more = (probe-file*
    2075                          (merge-pathnames*
    2076                           (make-pathname* :directory `(:relative ,dir))
    2077                           sofar) :truename t) :do
    2078             (if more
    2079                 (setf sofar more)
    2080                 (return (solution rest)))
    2081             :finally
    2082             (return (solution nil))))))))
     2419      (let* ((directory (normalize-pathname-directory-component (pathname-directory p)))
     2420             (up-components (reverse (rest directory)))
     2421             (down-components ()))
     2422        (assert (eq :absolute (first directory)))
     2423        (loop :while up-components :do
     2424          (if-let (parent (probe-file* (make-pathname* :directory `(:absolute ,@(reverse up-components))
     2425                                                       :name nil :type nil :version nil :defaults p)))
     2426            (return (merge-pathnames* (make-pathname* :directory `(:relative ,@down-components)
     2427                                                      :defaults p)
     2428                                      (ensure-directory-pathname parent)))
     2429            (push (pop up-components) down-components))
     2430          :finally (return p))))))
    20832431
    20842432(defun* resolve-symlinks (path)
     
    20932441      (and path (resolve-symlinks path))
    20942442      path))
    2095 
    2096 
    2097 ;;; absolute vs relative
    2098 (defun* ensure-pathname-absolute (path &optional defaults (on-error 'error))
    2099   (cond
    2100     ((absolute-pathname-p path))
    2101     ((stringp path) (ensure-pathname-absolute (pathname path) defaults))
    2102     ((not (pathnamep path)) (call-function on-error "not a valid pathname designator ~S" path))
    2103     ((absolute-pathname-p defaults)
    2104      (or (absolute-pathname-p (merge-pathnames* path defaults))
    2105          (call-function on-error "Failed to merge ~S with ~S into an absolute pathname"
    2106                         path defaults)))
    2107     (t (call-function on-error
    2108                       "Cannot ensure ~S is evaluated as an absolute pathname with defaults ~S"
    2109                       path defaults))))
    2110 
    2111 (defun relativize-directory-component (directory-component)
    2112   (let ((directory (normalize-pathname-directory-component directory-component)))
    2113     (cond
    2114       ((stringp directory)
    2115        (list :relative directory))
    2116       ((eq (car directory) :absolute)
    2117        (cons :relative (cdr directory)))
    2118       (t
    2119        directory))))
    2120 
    2121 (defun* relativize-pathname-directory (pathspec)
    2122   (let ((p (pathname pathspec)))
    2123     (make-pathname*
    2124      :directory (relativize-directory-component (pathname-directory p))
    2125      :defaults p)))
    2126 
    2127 
    2128 ;;; Simple filesystem operations
    2129 (defun* ensure-all-directories-exist (pathnames)
    2130    (dolist (pathname pathnames)
    2131      (ensure-directories-exist (translate-logical-pathname pathname))))
    2132 
    2133 (defun* rename-file-overwriting-target (source target)
    2134   #+clisp ;; But for a bug in CLISP 2.48, we should use :if-exists :overwrite and be atomic
    2135   (posix:copy-file source target :method :rename)
    2136   #-clisp
    2137   (rename-file source target
    2138                #+clozure :if-exists #+clozure :rename-and-delete))
    2139 
    2140 (defun* delete-file-if-exists (x)
    2141   (when (probe-file* x)
    2142     (delete-file x)))
    2143 
    2144 ;;; Translate a pathname
    2145 (defun* (translate-pathname*) (path absolute-source destination &optional root source)
    2146   (declare (ignore source))
    2147   (cond
    2148     ((functionp destination)
    2149      (funcall destination path absolute-source))
    2150     ((eq destination t)
    2151      path)
    2152     ((not (pathnamep destination))
    2153      (error "Invalid destination"))
    2154     ((not (absolute-pathname-p destination))
    2155      (translate-pathname path absolute-source (merge-pathnames* destination root)))
    2156     (root
    2157      (translate-pathname (directorize-pathname-host-device path) absolute-source destination))
    2158     (t
    2159      (translate-pathname path absolute-source destination))))
    2160 
    2161 
    2162 ;;; Temporary pathnames
    2163 (defun* add-pathname-suffix (pathname suffix)
    2164   (make-pathname :name (strcat (pathname-name pathname) suffix)
    2165                  :defaults pathname))
    2166 
    2167 (defun* tmpize-pathname (x)
    2168   (add-pathname-suffix x "-ASDF-TMP"))
    2169 
    2170 (defun* call-with-staging-pathname (pathname fun)
    2171   "Calls fun with a staging pathname, and atomically
    2172 renames the staging pathname to the pathname in the end.
    2173 Note: this protects only against failure of the program,
    2174 not against concurrent attempts.
    2175 For the latter case, we ought pick random suffix and atomically open it."
    2176   (let* ((pathname (pathname pathname))
    2177          (staging (tmpize-pathname pathname)))
    2178     (unwind-protect
    2179          (multiple-value-prog1
    2180              (funcall fun staging)
    2181            (rename-file-overwriting-target staging pathname))
    2182       (delete-file-if-exists staging))))
    2183 
    2184 (defmacro with-staging-pathname ((pathname-var &optional (pathname-value pathname-var)) &body body)
    2185   `(call-with-staging-pathname ,pathname-value #'(lambda (,pathname-var) ,@body)))
    2186 
    2187 ;;; Basic pathnames
    2188 (defun* sane-physical-pathname (&key defaults (keep t) fallback want-existing)
    2189   (flet ((sanitize (x)
    2190            (setf x (and x (ignore-errors (translate-logical-pathname x))))
    2191            (when (pathnamep x)
    2192              (setf x
    2193                    (ecase keep
    2194                      ((t) x)
    2195                      ((:directory) (pathname-directory-pathname x))
    2196                      ((:root) (pathname-root x))
    2197                      ((:host) (pathname-host-pathname x))
    2198                      ((nil) (nil-pathname x))))
    2199              (when want-existing ;; CCL's probe-file will choke if d-p-d is logical
    2200                (setf x (probe-file* x)))
    2201              (and (physical-pathname-p x) x))))
    2202     (or (sanitize defaults)
    2203         (when fallback
    2204           (or (sanitize (nil-pathname))
    2205               (sanitize (ignore-errors (user-homedir-pathname)))))
    2206         (error "Could not find a sane a physical pathname~
    2207                 ~@[ from ~S~]~@[~:*~@[ or~*~] fallbacks~]"
    2208                defaults fallback))))
    2209 
    2210 (defun* root-pathname ()
    2211   "On a Unix system, this will presumably be the root pathname /.
    2212 Otherwise, this will be the root of some implementation-dependent filesystem host."
    2213   (sane-physical-pathname :keep :root :fallback t))
    2214 
    2215 
    2216 ;;;; -----------------------------------------------------------------
    2217 ;;;; Windows shortcut support.  Based on:
    2218 ;;;;
    2219 ;;;; Jesse Hager: The Windows Shortcut File Format.
    2220 ;;;; http://www.wotsit.org/list.asp?fc=13
    2221 
    2222 #-(or clisp genera) ; CLISP doesn't need it, and READ-SEQUENCE annoys old Genera.
    2223 (progn
    2224 (defparameter *link-initial-dword* 76)
    2225 (defparameter *link-guid* #(1 20 2 0 0 0 0 0 192 0 0 0 0 0 0 70))
    2226 
    2227 (defun* read-null-terminated-string (s)
    2228   (with-output-to-string (out)
    2229     (loop :for code = (read-byte s)
    2230       :until (zerop code)
    2231       :do (write-char (code-char code) out))))
    2232 
    2233 (defun* read-little-endian (s &optional (bytes 4))
    2234   (loop :for i :from 0 :below bytes
    2235     :sum (ash (read-byte s) (* 8 i))))
    2236 
    2237 (defun* parse-file-location-info (s)
    2238   (let ((start (file-position s))
    2239         (total-length (read-little-endian s))
    2240         (end-of-header (read-little-endian s))
    2241         (fli-flags (read-little-endian s))
    2242         (local-volume-offset (read-little-endian s))
    2243         (local-offset (read-little-endian s))
    2244         (network-volume-offset (read-little-endian s))
    2245         (remaining-offset (read-little-endian s)))
    2246     (declare (ignore total-length end-of-header local-volume-offset))
    2247     (unless (zerop fli-flags)
    2248       (cond
    2249         ((logbitp 0 fli-flags)
    2250           (file-position s (+ start local-offset)))
    2251         ((logbitp 1 fli-flags)
    2252           (file-position s (+ start
    2253                               network-volume-offset
    2254                               #x14))))
    2255       (strcat (read-null-terminated-string s)
    2256               (progn
    2257                 (file-position s (+ start remaining-offset))
    2258                 (read-null-terminated-string s))))))
    2259 
    2260 (defun* parse-windows-shortcut (pathname)
    2261   (with-open-file (s pathname :element-type '(unsigned-byte 8))
    2262     (handler-case
    2263         (when (and (= (read-little-endian s) *link-initial-dword*)
    2264                    (let ((header (make-array (length *link-guid*))))
    2265                      (read-sequence header s)
    2266                      (equalp header *link-guid*)))
    2267           (let ((flags (read-little-endian s)))
    2268             (file-position s 76)        ;skip rest of header
    2269             (when (logbitp 0 flags)
    2270               ;; skip shell item id list
    2271               (let ((length (read-little-endian s 2)))
    2272                 (file-position s (+ length (file-position s)))))
    2273             (cond
    2274               ((logbitp 1 flags)
    2275                 (parse-file-location-info s))
    2276               (t
    2277                 (when (logbitp 2 flags)
    2278                   ;; skip description string
    2279                   (let ((length (read-little-endian s 2)))
    2280                     (file-position s (+ length (file-position s)))))
    2281                 (when (logbitp 3 flags)
    2282                   ;; finally, our pathname
    2283                   (let* ((length (read-little-endian s 2))
    2284                          (buffer (make-array length)))
    2285                     (read-sequence buffer s)
    2286                     (map 'string #'code-char buffer)))))))
    2287       (end-of-file (c)
    2288         (declare (ignore c))
    2289         nil)))))
    22902443
    22912444
     
    24112564
    24122565
    2413 (defun absolutize-pathnames
    2414     (pathnames &key type (resolve-symlinks *resolve-symlinks*) truename)
    2415     "Given a list of PATHNAMES where each is in the context of the next ones,
    2416 try to resolve these pathnames into an absolute pathname; first gently, then harder."
    2417   (block nil
    2418     (labels ((resolve (x)
    2419                (or (when truename
    2420                      (absolute-pathname-p (truename* x)))
    2421                    (when resolve-symlinks
    2422                      (absolute-pathname-p (resolve-symlinks x)))
    2423                    (absolute-pathname-p x)
    2424                    (unless resolve-symlinks
    2425                      (absolute-pathname-p (resolve-symlinks x)))
    2426                    (unless truename
    2427                      (absolute-pathname-p (truename* x)))
    2428                    (return nil)))
    2429              (tryone (x type rest)
    2430                (resolve (or (absolute-pathname-p x)
    2431                             (subpathname (recurse rest :directory) x :type type))))
    2432              (recurse (pathnames type)
    2433                (if (null pathnames) (return nil)
    2434                    (tryone (first pathnames) type (rest pathnames)))))
    2435       (recurse pathnames type))))
    2436 
     2566;;; Environment pathnames
     2567(defun* inter-directory-separator ()
     2568  (if (os-unix-p) #\: #\;))
     2569
     2570(defun* split-native-pathnames-string (string &rest constraints &key &allow-other-keys)
     2571  (loop :for namestring :in (split-string string :separator (string (inter-directory-separator)))
     2572        :collect (apply 'parse-native-namestring namestring constraints)))
     2573
     2574(defun* getenv-pathname (x &rest constraints &key on-error &allow-other-keys)
     2575  (apply 'parse-native-namestring (getenvp x)
     2576         :on-error (or on-error
     2577                       `(error "In (~S ~S), invalid pathname ~*~S: ~*~?" getenv-pathname ,x))
     2578         constraints))
     2579(defun* getenv-pathnames (x &rest constraints &key on-error &allow-other-keys)
     2580  (apply 'split-native-pathnames-string (getenvp x)
     2581         :on-error (or on-error
     2582                       `(error "In (~S ~S), invalid pathname ~*~S: ~*~?" getenv-pathnames ,x))
     2583         constraints))
     2584(defun* getenv-absolute-directory (x)
     2585  (getenv-pathname x :want-absolute t :ensure-directory t))
     2586(defun* getenv-absolute-directories (x)
     2587  (getenv-pathnames x :want-absolute t :ensure-directory t))
     2588
     2589(defun* lisp-implementation-directory (&key truename)
     2590  (let ((dir
     2591          (ignore-errors
     2592           #+clozure #p"ccl:"
     2593           #+(or ecl mkcl) #p"SYS:"
     2594           #+gcl system::*system-directory*
     2595           #+sbcl (if-let (it (find-symbol* :sbcl-homedir-pathname :sb-int nil))
     2596                     (funcall it)
     2597                     (getenv-pathname "SBCL_HOME" :ensure-directory t)))))
     2598    (if (and dir truename)
     2599        (truename* dir)
     2600        dir)))
     2601
     2602(defun* lisp-implementation-pathname-p (pathname)
     2603  ;; Other builtin systems are those under the implementation directory
     2604  (and (when pathname
     2605         (if-let (impdir (lisp-implementation-directory))
     2606           (or (subpathp pathname impdir)
     2607               (when *resolve-symlinks*
     2608                 (if-let (truename (truename* pathname))
     2609                   (if-let (trueimpdir (truename* impdir))
     2610                     (subpathp truename trueimpdir)))))))
     2611       t))
     2612
     2613
     2614;;; Pathname defaults and current directory
     2615(defun* get-pathname-defaults (&optional (defaults *default-pathname-defaults*))
     2616  (or (absolute-pathname-p defaults)
     2617      (merge-pathnames* defaults (getcwd))))
     2618
     2619(defun* call-with-current-directory (dir thunk)
     2620  (if dir
     2621      (let* ((dir (resolve-symlinks* (get-pathname-defaults (pathname-directory-pathname dir))))
     2622             (*default-pathname-defaults* dir)
     2623             (cwd (getcwd)))
     2624        (chdir dir)
     2625        (unwind-protect
     2626             (funcall thunk)
     2627          (chdir cwd)))
     2628      (funcall thunk)))
     2629
     2630(defmacro with-current-directory ((&optional dir) &body body)
     2631  "Call BODY while the POSIX current working directory is set to DIR"
     2632  `(call-with-current-directory ,dir #'(lambda () ,@body)))
     2633
     2634
     2635;;; Translate a pathname
     2636(defun relativize-directory-component (directory-component)
     2637  (let ((directory (normalize-pathname-directory-component directory-component)))
     2638    (cond
     2639      ((stringp directory)
     2640       (list :relative directory))
     2641      ((eq (car directory) :absolute)
     2642       (cons :relative (cdr directory)))
     2643      (t
     2644       directory))))
     2645
     2646(defun* relativize-pathname-directory (pathspec)
     2647  (let ((p (pathname pathspec)))
     2648    (make-pathname*
     2649     :directory (relativize-directory-component (pathname-directory p))
     2650     :defaults p)))
     2651
     2652(defun* directory-separator-for-host (&optional (pathname *default-pathname-defaults*))
     2653  (let ((foo (make-pathname* :directory '(:absolute "FOO") :defaults pathname)))
     2654    (last-char (namestring foo))))
     2655
     2656#-scl
     2657(defun* directorize-pathname-host-device (pathname)
     2658  #+(or unix abcl)
     2659  (when (and #+abcl (os-unix-p) (physical-pathname-p pathname))
     2660    (return-from directorize-pathname-host-device pathname))
     2661  (let* ((root (pathname-root pathname))
     2662         (wild-root (wilden root))
     2663         (absolute-pathname (merge-pathnames* pathname root))
     2664         (separator (directory-separator-for-host root))
     2665         (root-namestring (namestring root))
     2666         (root-string
     2667          (substitute-if #\/
     2668                         #'(lambda (x) (or (eql x #\:)
     2669                                           (eql x separator)))
     2670                         root-namestring)))
     2671    (multiple-value-bind (relative path filename)
     2672        (split-unix-namestring-directory-components root-string :ensure-directory t)
     2673      (declare (ignore relative filename))
     2674      (let ((new-base
     2675             (make-pathname* :defaults root :directory `(:absolute ,@path))))
     2676        (translate-pathname absolute-pathname wild-root (wilden new-base))))))
     2677
     2678#+scl
     2679(defun* directorize-pathname-host-device (pathname)
     2680  (let ((scheme (ext:pathname-scheme pathname))
     2681        (host (pathname-host pathname))
     2682        (port (ext:pathname-port pathname))
     2683        (directory (pathname-directory pathname)))
     2684    (flet ((specificp (x) (and x (not (eq x :unspecific)))))
     2685      (if (or (specificp port)
     2686              (and (specificp host) (plusp (length host)))
     2687              (specificp scheme))
     2688        (let ((prefix ""))
     2689          (when (specificp port)
     2690            (setf prefix (format nil ":~D" port)))
     2691          (when (and (specificp host) (plusp (length host)))
     2692            (setf prefix (strcat host prefix)))
     2693          (setf prefix (strcat ":" prefix))
     2694          (when (specificp scheme)
     2695            (setf prefix (strcat scheme prefix)))
     2696          (assert (and directory (eq (first directory) :absolute)))
     2697          (make-pathname* :directory `(:absolute ,prefix ,@(rest directory))
     2698                          :defaults pathname)))
     2699    pathname)))
     2700
     2701(defun* (translate-pathname*) (path absolute-source destination &optional root source)
     2702  (declare (ignore source))
     2703  (cond
     2704    ((functionp destination)
     2705     (funcall destination path absolute-source))
     2706    ((eq destination t)
     2707     path)
     2708    ((not (pathnamep destination))
     2709     (error "Invalid destination"))
     2710    ((not (absolute-pathname-p destination))
     2711     (translate-pathname path absolute-source (merge-pathnames* destination root)))
     2712    (root
     2713     (translate-pathname (directorize-pathname-host-device path) absolute-source destination))
     2714    (t
     2715     (translate-pathname path absolute-source destination))))
    24372716
    24382717;;; Hook for output translations
    24392718(defvar *output-translation-function* 'identity)
     2719
     2720
    24402721;;;; ---------------------------------------------------------------------------
    24412722;;;; Utilities related to streams
     
    24432724(asdf/package:define-package :asdf/stream
    24442725  (:recycle :asdf/stream)
    2445   (:use :asdf/common-lisp :asdf/package :asdf/utility :asdf/pathname)
     2726  (:use :asdf/common-lisp :asdf/package :asdf/utility :asdf/os :asdf/pathname)
    24462727  (:export
    24472728   #:*default-stream-element-type* #:*stderr* #:setup-stderr
     
    24582739   #:detect-encoding #:*encoding-detection-hook* #:always-default-encoding
    24592740   #:encoding-external-format #:*encoding-external-format-hook* #:default-encoding-external-format
    2460    #:*default-encoding* #:*utf-8-external-format*))
     2741   #:*default-encoding* #:*utf-8-external-format*
     2742   #:ensure-all-directories-exist
     2743   #:rename-file-overwriting-target
     2744   #:delete-file-if-exists
     2745   #:*temporary-directory* #:temporary-directory #:default-temporary-directory
     2746   #:setup-temporary-directory
     2747   #:call-with-temporary-file #:with-temporary-file
     2748   #:add-pathname-suffix #:tmpize-pathname
     2749   #:call-with-staging-pathname #:with-staging-pathname))
    24612750(in-package :asdf/stream)
    24622751
     
    27913080  (funcall *encoding-external-format-hook* encoding))
    27923081
    2793 ;;;; ---------------------------------------------------------------------------
    2794 ;;;; Access to the Operating System
    2795 
    2796 (asdf/package:define-package :asdf/os
    2797   (:recycle :asdf/os :asdf)
    2798   (:use :asdf/common-lisp :asdf/package :asdf/utility :asdf/pathname :asdf/stream)
    2799   (:export
    2800    #:featurep #:os-unix-p #:os-windows-p ;; features
    2801    #:getenv #:getenvp ;; environment variables
    2802    #:native-namestring #:parse-native-namestring
    2803    #:inter-directory-separator #:split-native-pathnames-string
    2804    #:getenv-pathname #:getenv-pathnames
    2805    #:getenv-absolute-directory #:getenv-absolute-directories
    2806    #:implementation-identifier ;; implementation identifier
    2807    #:implementation-type #:*implementation-type*
    2808    #:operating-system #:architecture #:lisp-version-string
    2809    #:hostname #:user-homedir #:lisp-implementation-directory
    2810    #:getcwd #:chdir #:call-with-current-directory #:with-current-directory
    2811    #:*temporary-directory* #:temporary-directory #:default-temporary-directory
    2812    #:setup-temporary-directory
    2813    #:call-with-temporary-file #:with-temporary-file))
    2814 (in-package :asdf/os)
    2815 
    2816 ;;; Features
    2817 (eval-when (:compile-toplevel :load-toplevel :execute)
    2818   (defun* featurep (x &optional (*features* *features*))
    2819     (cond
    2820       ((atom x) (and (member x *features*) t))
    2821       ((eq :not (car x)) (assert (null (cddr x))) (not (featurep (cadr x))))
    2822       ((eq :or (car x)) (some #'featurep (cdr x)))
    2823       ((eq :and (car x)) (every #'featurep (cdr x)))
    2824       (t (error "Malformed feature specification ~S" x))))
    2825 
    2826   (defun* os-unix-p ()
    2827     (featurep '(:or :unix :cygwin :darwin)))
    2828 
    2829   (defun* os-windows-p ()
    2830     (and (not (os-unix-p)) (featurep '(:or :win32 :windows :mswindows :mingw32))))
    2831 
    2832   (defun* os-genera-p ()
    2833     (featurep :genera))
    2834 
    2835   (defun* detect-os ()
    2836     (flet ((yes (yes) (pushnew yes *features*))
    2837            (no (no) (setf *features* (remove no *features*))))
    2838       (cond
    2839         ((os-unix-p) (yes :os-unix) (no :os-windows))
    2840         ((os-windows-p) (yes :os-windows) (no :os-unix))
    2841         ((os-genera-p) (no :os-unix) (no :os-windows))
    2842         (t (error "Congratulations for trying XCVB on an operating system~%~
    2843 that is neither Unix, nor Windows, nor even Genera.~%Now you port it.")))))
    2844 
    2845   (detect-os))
    2846 
    2847 ;;;; Environment variables: getting them, and parsing them.
    2848 
    2849 (defun* getenv (x)
    2850   (declare (ignorable x))
    2851   #+(or abcl clisp ecl xcl) (ext:getenv x)
    2852   #+allegro (sys:getenv x)
    2853   #+clozure (ccl:getenv x)
    2854   #+(or cmu scl) (cdr (assoc x ext:*environment-list* :test #'string=))
    2855   #+cormanlisp
    2856   (let* ((buffer (ct:malloc 1))
    2857          (cname (ct:lisp-string-to-c-string x))
    2858          (needed-size (win:getenvironmentvariable cname buffer 0))
    2859          (buffer1 (ct:malloc (1+ needed-size))))
    2860     (prog1 (if (zerop (win:getenvironmentvariable cname buffer1 needed-size))
    2861                nil
    2862                (ct:c-string-to-lisp-string buffer1))
    2863       (ct:free buffer)
    2864       (ct:free buffer1)))
    2865   #+gcl (system:getenv x)
    2866   #+genera nil
    2867   #+lispworks (lispworks:environment-variable x)
    2868   #+mcl (ccl:with-cstrs ((name x))
    2869           (let ((value (_getenv name)))
    2870             (unless (ccl:%null-ptr-p value)
    2871               (ccl:%get-cstring value))))
    2872   #+mkcl (#.(or (find-symbol* 'getenv :si nil) (find-symbol* 'getenv :mk-ext nil)) x)
    2873   #+sbcl (sb-ext:posix-getenv x)
    2874   #-(or abcl allegro clisp clozure cmu cormanlisp ecl gcl genera lispworks mcl mkcl sbcl scl xcl)
    2875   (error "~S is not supported on your implementation" 'getenv))
    2876 
    2877 (defun* getenvp (x)
    2878   "Predicate that is true if the named variable is present in the libc environment,
    2879 then returning the non-empty string value of the variable"
    2880   (let ((g (getenv x))) (and (not (emptyp g)) g)))
    2881 
    2882 
    2883 ;;; Native vs Lisp syntax
    2884 
    2885 (defun* native-namestring (x)
    2886   "From a CL pathname, a return namestring suitable for passing to the operating system"
    2887   (when x
    2888     (let ((p (pathname x)))
    2889       #+clozure (with-pathname-defaults ((root-pathname))
    2890                   (ccl:native-translated-namestring p)) ; see ccl bug 978
    2891       #+(or cmu scl) (ext:unix-namestring p nil)
    2892       #+sbcl (sb-ext:native-namestring p)
    2893       #-(or clozure cmu sbcl scl)
    2894       (if (os-unix-p) (unix-namestring p)
    2895           (namestring p)))))
    2896 
    2897 (defun* parse-native-namestring (string &rest constraints &key ensure-directory &allow-other-keys)
    2898   "From a native namestring suitable for use by the operating system, return
    2899 a CL pathname satisfying all the specified constraints as per ENSURE-PATHNAME"
    2900   (check-type string (or string null))
    2901   (let* ((pathname
    2902            (when string
    2903              (with-pathname-defaults ((root-pathname))
    2904                #+clozure (ccl:native-to-pathname string)
    2905                #+sbcl (sb-ext:parse-native-namestring string)
    2906                #-(or clozure sbcl)
    2907                (if (os-unix-p)
    2908                    (parse-unix-namestring string :ensure-directory ensure-directory)
    2909                    (parse-namestring string)))))
    2910          (pathname
    2911            (if ensure-directory
    2912                (and pathname (ensure-directory-pathname pathname))
    2913                pathname)))
    2914     (apply 'ensure-pathname pathname constraints)))
    2915 
    2916 
    2917 ;;; Native pathnames in environment
    2918 (defun* inter-directory-separator ()
    2919   (if (os-unix-p) #\: #\;))
    2920 (defun* split-native-pathnames-string (string &rest constraints &key &allow-other-keys)
    2921   (loop :for namestring :in (split-string string :separator (string (inter-directory-separator)))
    2922         :collect (apply 'parse-native-namestring namestring constraints)))
    2923 (defun* getenv-pathname (x &rest constraints &key on-error &allow-other-keys)
    2924   (apply 'parse-native-namestring (getenvp x)
    2925          :on-error (or on-error
    2926                        `(error "In (~S ~S), invalid pathname ~*~S: ~*~?" getenv-pathname ,x))
    2927          constraints))
    2928 (defun* getenv-pathnames (x &rest constraints &key on-error &allow-other-keys)
    2929   (apply 'split-native-pathnames-string (getenvp x)
    2930          :on-error (or on-error
    2931                        `(error "In (~S ~S), invalid pathname ~*~S: ~*~?" getenv-pathnames ,x))
    2932          constraints))
    2933 (defun* getenv-absolute-directory (x)
    2934   (getenv-pathname x :want-absolute t :ensure-directory t))
    2935 (defun* getenv-absolute-directories (x)
    2936   (getenv-pathnames x :want-absolute t :ensure-directory t))
    2937 
    2938 
    2939 ;;;; implementation-identifier
    2940 ;;
    2941 ;; produce a string to identify current implementation.
    2942 ;; Initially stolen from SLIME's SWANK, completely rewritten since.
    2943 ;; We're back to runtime checking, for the sake of e.g. ABCL.
    2944 
    2945 (defun* first-feature (feature-sets)
    2946   (dolist (x feature-sets)
    2947     (multiple-value-bind (short long feature-expr)
    2948         (if (consp x)
    2949             (values (first x) (second x) (cons :or (rest x)))
    2950             (values x x x))
    2951       (when (featurep feature-expr)
    2952         (return (values short long))))))
    2953 
    2954 (defun* implementation-type ()
    2955   (first-feature
    2956    '(:abcl (:acl :allegro) (:ccl :clozure) :clisp (:corman :cormanlisp)
    2957      (:cmu :cmucl :cmu) :ecl :gcl
    2958      (:lwpe :lispworks-personal-edition) (:lw :lispworks)
    2959      :mcl :mkcl :sbcl :scl (:smbx :symbolics) :xcl)))
    2960 
    2961 (defvar *implementation-type* (implementation-type))
    2962 
    2963 (defun* operating-system ()
    2964   (first-feature
    2965    '(:cygwin (:win :windows :mswindows :win32 :mingw32) ;; try cygwin first!
    2966      (:linux :linux :linux-target) ;; for GCL at least, must appear before :bsd
    2967      (:macosx :macosx :darwin :darwin-target :apple) ; also before :bsd
    2968      (:solaris :solaris :sunos) (:bsd :bsd :freebsd :netbsd :openbsd) :unix
    2969      :genera)))
    2970 
    2971 (defun* architecture ()
    2972   (first-feature
    2973    '((:x64 :x86-64 :x86_64 :x8664-target :amd64 (:and :word-size=64 :pc386))
    2974      (:x86 :x86 :i386 :i486 :i586 :i686 :pentium3 :pentium4 :pc386 :iapx386 :x8632-target)
    2975      (:ppc64 :ppc64 :ppc64-target) (:ppc32 :ppc32 :ppc32-target :ppc :powerpc)
    2976      :hppa64 :hppa :sparc64 (:sparc32 :sparc32 :sparc)
    2977      :mipsel :mipseb :mips :alpha (:arm :arm :arm-target) :imach
    2978      ;; Java comes last: if someone uses C via CFFI or otherwise JNA or JNI,
    2979      ;; we may have to segregate the code still by architecture.
    2980      (:java :java :java-1.4 :java-1.5 :java-1.6 :java-1.7))))
    2981 
    2982 #+clozure
    2983 (defun* ccl-fasl-version ()
    2984   ;; the fasl version is target-dependent from CCL 1.8 on.
    2985   (or (let ((s 'ccl::target-fasl-version))
    2986         (and (fboundp s) (funcall s)))
    2987       (and (boundp 'ccl::fasl-version)
    2988            (symbol-value 'ccl::fasl-version))
    2989       (error "Can't determine fasl version.")))
    2990 
    2991 (defun* lisp-version-string ()
    2992   (let ((s (lisp-implementation-version)))
    2993     (car ; as opposed to OR, this idiom prevents some unreachable code warning
    2994      (list
    2995       #+allegro
    2996       (format nil "~A~@[~A~]~@[~A~]~@[~A~]"
    2997               excl::*common-lisp-version-number*
    2998               ;; M means "modern", as opposed to ANSI-compatible mode (which I consider default)
    2999               (and (eq excl:*current-case-mode* :case-sensitive-lower) "M")
    3000               ;; Note if not using International ACL
    3001               ;; see http://www.franz.com/support/documentation/8.1/doc/operators/excl/ics-target-case.htm
    3002               (excl:ics-target-case (:-ics "8"))
    3003               (and (member :smp *features*) "S"))
    3004       #+armedbear (format nil "~a-fasl~a" s system::*fasl-version*)
    3005       #+clisp
    3006       (subseq s 0 (position #\space s)) ; strip build information (date, etc.)
    3007       #+clozure
    3008       (format nil "~d.~d-f~d" ; shorten for windows
    3009               ccl::*openmcl-major-version*
    3010               ccl::*openmcl-minor-version*
    3011               (logand (ccl-fasl-version) #xFF))
    3012       #+cmu (substitute #\- #\/ s)
    3013       #+scl (format nil "~A~A" s
    3014                     ;; ANSI upper case vs lower case.
    3015                     (ecase ext:*case-mode* (:upper "") (:lower "l")))
    3016       #+ecl (format nil "~A~@[-~A~]" s
    3017                     (let ((vcs-id (ext:lisp-implementation-vcs-id)))
    3018                       (subseq vcs-id 0 (min (length vcs-id) 8))))
    3019       #+gcl (subseq s (1+ (position #\space s)))
    3020       #+genera
    3021       (multiple-value-bind (major minor) (sct:get-system-version "System")
    3022         (format nil "~D.~D" major minor))
    3023       #+mcl (subseq s 8) ; strip the leading "Version "
    3024       s))))
    3025 
    3026 (defun* implementation-identifier ()
    3027   (substitute-if
    3028    #\_ #'(lambda (x) (find x " /:;&^\\|?<>(){}[]$#`'\""))
    3029    (format nil "~(~a~@{~@[-~a~]~}~)"
    3030            (or (implementation-type) (lisp-implementation-type))
    3031            (or (lisp-version-string) (lisp-implementation-version))
    3032            (or (operating-system) (software-type))
    3033            (or (architecture) (machine-type)))))
    3034 
    3035 
    3036 ;;;; Other system information
    3037 
    3038 (defun* hostname ()
    3039   ;; Note: untested on RMCL
    3040   #+(or abcl clozure cmucl ecl genera lispworks mcl mkcl sbcl scl xcl) (machine-instance)
    3041   #+cormanlisp "localhost" ;; is there a better way? Does it matter?
    3042   #+allegro (symbol-call :excl.osi :gethostname)
    3043   #+clisp (first (split-string (machine-instance) :separator " "))
    3044   #+gcl (system:gethostname))
    3045 
    3046 (defun* user-homedir ()
    3047   (truenamize
    3048    (pathname-directory-pathname
    3049     #+cormanlisp (ensure-directory-pathname (user-homedir-pathname))
    3050     #+mcl (current-user-homedir-pathname)
    3051     #-(or cormanlisp mcl) (user-homedir-pathname))))
    3052 
    3053 (defun* lisp-implementation-directory (&key truename)
    3054   (let ((dir
    3055           (ignore-errors
    3056            #+clozure #p"ccl:"
    3057            #+(or ecl mkcl) #p"SYS:"
    3058            #+gcl system::*system-directory*
    3059            #+sbcl (if-let (it (find-symbol* :sbcl-homedir-pathname :sb-int nil))
    3060                      (funcall it)
    3061                      (getenv-pathname "SBCL_HOME" :ensure-directory t)))))
    3062     (if (and dir truename)
    3063         (truename* dir)
    3064         dir)))
    3065 
    3066 
    3067 ;;; Current directory
    3068 
    3069 (defun* getcwd ()
    3070   "Get the current working directory as per POSIX getcwd(3), as a pathname object"
    3071   (or #+abcl (parse-native-namestring
    3072               (java:jstatic "getProperty" "java.lang.System" "user.dir") :ensure-directory t)
    3073       #+allegro (excl::current-directory)
    3074       #+clisp (ext:default-directory)
    3075       #+clozure (ccl:current-directory)
    3076       #+(or cmu scl) (parse-native-namestring
    3077                       (nth-value 1 (unix:unix-current-directory)) :ensure-directory t)
    3078       #+cormanlisp (pathname (pl::get-current-directory)) ;; Q: what type does it return?
    3079       #+ecl (ext:getcwd)
    3080       #+gcl (parse-native-namestring ;; this is a joke. Isn't there a better way?
    3081              (first (symbol-call :asdf/driver :run-program '("/bin/pwd") :output :lines)))
    3082       #+genera *default-pathname-defaults* ;; on a Lisp OS, it *is* canonical!
    3083       #+lispworks (system:current-directory)
    3084       #+mkcl (mk-ext:getcwd)
    3085       #+sbcl (parse-native-namestring (sb-unix:posix-getcwd/))
    3086       #+xcl (extensions:current-directory)
    3087       (error "getcwd not supported on your implementation")))
    3088 
    3089 (defun* chdir (x)
    3090   "Change current directory, as per POSIX chdir(2)"
    3091   #-(or clisp clozure) (when (pathnamep x) (setf x (native-namestring x)))
    3092   (or #+clisp (ext:cd x)
    3093       #+clozure (setf (ccl:current-directory) x)
    3094       #+cormanlisp (unless (zerop (win32::_chdir x))
    3095                      (error "Could not set current directory to ~A" x))
    3096       #+sbcl (symbol-call :sb-posix :chdir x)
    3097       (error "chdir not supported on your implementation")))
    3098 
    3099 (defun* call-with-current-directory (dir thunk)
    3100   (if dir
    3101       (let* ((dir (truename (merge-pathnames (pathname-directory-pathname dir))))
    3102              (*default-pathname-defaults* dir)
    3103              (cwd (getcwd)))
    3104         (chdir dir)
    3105         (unwind-protect
    3106              (funcall thunk)
    3107           (chdir cwd)))
    3108       (funcall thunk)))
    3109 
    3110 (defmacro with-current-directory ((dir) &body body)
    3111   "Call BODY while the POSIX current working directory is set to DIR"
    3112   `(call-with-current-directory ,dir #'(lambda () ,@body)))
     3082
     3083;;; Simple filesystem operations
     3084(defun* ensure-all-directories-exist (pathnames)
     3085   (dolist (pathname pathnames)
     3086     (ensure-directories-exist (translate-logical-pathname pathname))))
     3087
     3088(defun* rename-file-overwriting-target (source target)
     3089  #+clisp ;; But for a bug in CLISP 2.48, we should use :if-exists :overwrite and be atomic
     3090  (posix:copy-file source target :method :rename)
     3091  #-clisp
     3092  (rename-file source target
     3093               #+clozure :if-exists #+clozure :rename-and-delete))
     3094
     3095(defun* delete-file-if-exists (x)
     3096  (handler-case (delete-file x) (file-error () nil)))
    31133097
    31143098
    31153099;;; Using temporary files
    3116 
    31173100(defun* default-temporary-directory ()
    31183101  (or
     
    31223105   (when (os-windows-p)
    31233106     (getenv-pathname "TEMP" :ensure-directory t))
    3124    (subpathname (user-homedir) "tmp/")))
     3107   (subpathname (user-homedir-pathname) "tmp/")))
    31253108
    31263109(defvar *temporary-directory* nil)
     
    31823165      ,@(when element-type `(:element-type ,element-type))
    31833166      ,@(when external-format `(:external-format external-format)))))
     3167
     3168;;; Temporary pathnames
     3169(defun* add-pathname-suffix (pathname suffix)
     3170  (make-pathname :name (strcat (pathname-name pathname) suffix)
     3171                 :defaults pathname))
     3172
     3173(defun* tmpize-pathname (x)
     3174  (add-pathname-suffix x "-ASDF-TMP"))
     3175
     3176(defun* call-with-staging-pathname (pathname fun)
     3177  "Calls fun with a staging pathname, and atomically
     3178renames the staging pathname to the pathname in the end.
     3179Note: this protects only against failure of the program,
     3180not against concurrent attempts.
     3181For the latter case, we ought pick random suffix and atomically open it."
     3182  (let* ((pathname (pathname pathname))
     3183         (staging (tmpize-pathname pathname)))
     3184    (unwind-protect
     3185         (multiple-value-prog1
     3186             (funcall fun staging)
     3187           (rename-file-overwriting-target staging pathname))
     3188      (delete-file-if-exists staging))))
     3189
     3190(defmacro with-staging-pathname ((pathname-var &optional (pathname-value pathname-var)) &body body)
     3191  `(call-with-staging-pathname ,pathname-value #'(lambda (,pathname-var) ,@body)))
     3192
    31843193
    31853194;;;; -------------------------------------------------------------------------
     
    35033512;;; Some universal image restore hooks
    35043513(map () 'register-image-restore-hook
    3505      '(setup-temporary-directory setup-stderr setup-command-line-arguments))
     3514     '(setup-temporary-directory setup-stderr setup-command-line-arguments
     3515       #+abcl detect-os))
    35063516;;;; -------------------------------------------------------------------------
    35073517;;;; run-program initially from xcvb-driver.
     
    39083918   #:check-lisp-compile-results #:check-lisp-compile-warnings
    39093919   #:*uninteresting-compiler-conditions* #:*uninteresting-loader-conditions*
    3910    #:*deferred-warnings*
    39113920   ;; Functions & Macros
    39123921   #:get-optimization-settings #:proclaim-optimization-settings
     
    39163925   #:reify-deferred-warnings #:reify-undefined-warning #:unreify-deferred-warnings
    39173926   #:reset-deferred-warnings #:save-deferred-warnings #:check-deferred-warnings
    3918    #:with-saved-deferred-warnings #:warnings-file-p #:warnings-file-type
     3927   #:with-saved-deferred-warnings #:warnings-file-p #:warnings-file-type #:*warnings-file-type*
    39193928   #:call-with-asdf-compilation-unit #:with-asdf-compilation-unit
    39203929   #:current-lisp-file-pathname #:load-pathname
     
    40034012   #+clisp '(clos::simple-gf-replacing-method-warning))
    40044013  "Additional conditions that may be skipped while loading")
    4005 
    4006 (defvar *deferred-warnings* ()
    4007   "Warnings the handling of which is deferred until the end of the compilation unit")
    40084014
    40094015;;;; ----- Filtering conditions while building -----
     
    40754081
    40764082;;;; Deferred-warnings treatment, originally implemented by Douglas Katzman.
     4083;;
     4084;; To support an implementation, three functions must be implemented:
     4085;; reify-deferred-warnings unreify-deferred-warnings reset-deferred-warnings
     4086;; See their respective docstrings.
    40774087
    40784088(defun reify-simple-sexp (sexp)
     
    41394149
    41404150(defun reify-deferred-warnings ()
     4151  "return a portable S-expression, portably readable and writeable in any Common Lisp implementation
     4152using READ within a WITH-SAFE-IO-SYNTAX, that represents the warnings currently deferred by
     4153WITH-COMPILATION-UNIT. One of three functions required for deferred-warnings support in ASDF."
    41414154  #+clozure
    41424155  (mapcar 'reify-deferred-warning
     
    41604173
    41614174(defun unreify-deferred-warnings (reified-deferred-warnings)
     4175  "given a S-expression created by REIFY-DEFERRED-WARNINGS, reinstantiate the corresponding
     4176deferred warnings as to be handled at the end of the current WITH-COMPILATION-UNIT.
     4177Handle any warning that has been resolved already,
     4178such as an undefined function that has been defined since.
     4179One of three functions required for deferred-warnings support in ASDF."
    41624180  (declare (ignorable reified-deferred-warnings))
    41634181  #+clozure
     
    41944212
    41954213(defun reset-deferred-warnings ()
     4214  "Reset the set of deferred warnings to be handled at the end of the current WITH-COMPILATION-UNIT.
     4215One of three functions required for deferred-warnings support in ASDF."
    41964216  #+clozure
    41974217  (if-let (dw ccl::*outstanding-deferred-warnings*)
     
    42214241    ((:clozure :ccl) "ccl-warnings")))
    42224242
     4243(defvar *warnings-file-type* (warnings-file-type)
     4244  "Type for warnings files")
     4245
    42234246(defun* warnings-file-p (file &optional implementation-type)
    4224   (if-let (type (warnings-file-type implementation-type))
     4247  (if-let (type (if implementation-type
     4248                    (warnings-file-type implementation-type)
     4249                    *warnings-file-type*))
    42254250    (equal (pathname-type file) type)))
    42264251
     
    42734298  (if warnings-file
    42744299      (with-compilation-unit (:override t)
    4275         (let ((*deferred-warnings* ())
    4276               #+sbcl (sb-c::*undefined-warnings* nil))
     4300        (let (#+sbcl (sb-c::*undefined-warnings* nil))
    42774301          (multiple-value-prog1
    42784302              (with-muffled-compiler-conditions ()
     
    45014525               `(,(subpathname* (get-folder-path :local-appdata) "common-lisp/config/")
    45024526                 ,(subpathname* (get-folder-path :appdata) "common-lisp/config/")))
    4503            ,(subpathname (user-homedir) ".config/common-lisp/"))))
     4527           ,(subpathname (user-homedir-pathname) ".config/common-lisp/"))))
    45044528    (remove-duplicates (remove-if-not #'absolute-pathname-p dirs)
    45054529                       :from-end t :test 'equal)))
     
    46794703        (let ((p (make-pathname* :directory '(:relative))))
    46804704          (if wilden (wilden p) p))))
    4681      ((eql :home) (user-homedir))
     4705     ((eql :home) (user-homedir-pathname))
    46824706     ((eql :here) (resolve-absolute-location
    46834707                   *here-directory* :ensure-directory t :wilden nil))
     
    46854709                         *user-cache* :ensure-directory t :wilden nil)))
    46864710   :wilden (and wilden (not (pathnamep x)))
     4711   :resolve-symlinks *resolve-symlinks*
    46874712   :want-absolute t))
    46884713
     
    46924717
    46934718(defun* (resolve-location) (x &key ensure-directory wilden directory)
    4694   (when directory (setf ensure-directory t)) ;; :directory backward compatibility, until 2014-01-16.
    4695   (if (atom x)
    4696       (resolve-absolute-location x :ensure-directory ensure-directory :wilden wilden)
    4697       (loop* :with (first . rest) = x
    4698         :with path = (resolve-absolute-location
    4699                           first :ensure-directory (and (or ensure-directory rest) t)
    4700                           :wilden (and wilden (null rest)))
    4701         :for (element . morep) :on rest
    4702         :for dir = (and (or morep ensure-directory) t)
    4703         :for wild = (and wilden (not morep))
    4704         :do (setf path (merge-pathnames*
    4705                         (resolve-relative-location
    4706                          element :ensure-directory dir :wilden wild)
    4707                         path))
    4708         :finally (return path))))
     4719  ;; :directory backward compatibility, until 2014-01-16: accept directory as well as ensure-directory
     4720  (loop* :with dirp = (or directory ensure-directory)
     4721         :with (first . rest) = (if (atom x) (list x) x)
     4722         :with path = (resolve-absolute-location
     4723                       first :ensure-directory (and (or dirp rest) t)
     4724                             :wilden (and wilden (null rest)))
     4725         :for (element . morep) :on rest
     4726         :for dir = (and (or morep dirp) t)
     4727         :for wild = (and wilden (not morep))
     4728         :for sub = (merge-pathnames*
     4729                     (resolve-relative-location
     4730                      element :ensure-directory dir :wilden wild)
     4731                     path)
     4732         :do (setf path (if (absolute-pathname-p sub) (resolve-symlinks* sub) sub))
     4733         :finally (return path)))
    47094734
    47104735(defun* location-designator-p (x)
     
    47914816   :asdf/pathname :asdf/stream :asdf/os :asdf/image
    47924817   :asdf/run-program :asdf/lisp-build
    4793    :asdf/configuration))
     4818   :asdf/configuration :asdf/backward-driver))
    47944819;;;; -------------------------------------------------------------------------
    47954820;;;; Handle upgrade as forward- and backward-compatibly as possible
     
    48294854         ;; "2.345.0.7" would be your seventh local modification of official release 2.345
    48304855         ;; "2.345.6.7" would be your seventh local modification of development version 2.345.6
    4831          (asdf-version "2.26.143.1")
     4856         (asdf-version "2.26.158.1")
    48324857         (existing-asdf (find-class (find-symbol* :component :asdf nil) nil))
    48334858         (existing-version *asdf-version*)
     
    49644989   #:component-description #:component-long-description
    49654990   #:component-version #:version-satisfies
    4966    #:component-properties #:component-property ;; backward-compatibility only. DO NOT USE!
    49674991   #:component-inline-methods ;; backward-compatibility only. DO NOT USE!
    49684992   #:component-operation-times ;; For internal use only.
     
    49734997   #:module-default-component-class
    49744998   #:module-components ;; backward-compatibility. DO NOT USE.
     4999   #:sub-components
    49755000
    49765001   ;; Internals we'd like to share with the ASDF package, especially for upgrade purposes
     
    49965021pathname, because an absolute pathname may be interpreted relative to
    49975022another pathname in a degenerate way."))
    4998 (defgeneric* component-property (component property))
    4999 #-gcl2.6
    5000 (defgeneric* (setf component-property) (new-value component property))
    50015023(defgeneric* component-external-format (component))
    50025024(defgeneric* component-encoding (component))
     
    50505072                    :accessor component-operation-times)
    50515073   (around-compile :initarg :around-compile)
     5074   (properties) ;; Only for backward-compatibility during upgrades from ASDF2. DO NOT USE.
    50525075   (%encoding :accessor %component-encoding :initform nil :initarg :encoding)
    5053    ;; ASDF3: get rid of these "component properties" ?
    5054    (properties :accessor component-properties :initarg :properties
    5055                :initform nil)
    5056    ;; For backward-compatibility, this slot is part of component rather than child-component
     5076   ;; For backward-compatibility, this slot is part of component rather than child-component. ASDF4: don't.
    50575077   (parent :initarg :parent :initform nil :reader component-parent)
    50585078   (build-operation
     
    51775197
    51785198
    5179 ;;;; General component-property - ASDF3: remove? Define clean subclasses, not messy "properties".
    5180 
    5181 (defmethod component-property ((c component) property)
    5182   (cdr (assoc property (slot-value c 'properties) :test #'equal)))
    5183 
    5184 (defmethod (setf component-property) (new-value (c component) property)
    5185   (let ((a (assoc property (slot-value c 'properties) :test #'equal)))
    5186     (if a
    5187         (setf (cdr a) new-value)
    5188         (setf (slot-value c 'properties)
    5189               (acons property new-value (slot-value c 'properties)))))
    5190   new-value)
    5191 
    5192 
    51935199;;;; Encodings
    51945200
     
    52245230(defmethod version-satisfies ((cver string) version)
    52255231  (version-compatible-p cver version))
     5232
     5233
     5234;;; all sub-components (of a given type)
     5235
     5236(defun* sub-components (component &key (type t))
     5237  (while-collecting (c)
     5238    (labels ((recurse (x)
     5239               (when (if-let (it (component-if-feature x)) (featurep it) t)
     5240                 (when (typep x type)
     5241                   (c x))
     5242                 (when (typep x 'parent-component)
     5243                   (map () #'recurse (component-children x))))))
     5244      (recurse component))))
    52265245;;;; -------------------------------------------------------------------------
    52275246;;;; Systems
     
    52385257   #:system-defsystem-depends-on
    52395258   #:component-build-pathname #:build-pathname
     5259   #:component-entry-point #:entry-point
    52405260   #:find-system #:builtin-system-p)) ;; forward-reference, defined in find-system
    52415261(in-package :asdf/system)
     
    52445264(defgeneric* (system-source-file) (system)
    52455265  (:documentation "Return the source file in which system is defined."))
    5246 (defgeneric* builtin-system-p (system))
    52475266(defgeneric* component-build-pathname (component))
     5267
     5268(defgeneric* component-entry-point (component))
     5269(defmethod component-entry-point ((c component))
     5270  (declare (ignorable c))
     5271  nil)
     5272
    52485273
    52495274;;;; The system class
     
    52555280
    52565281(defclass system (module proto-system)
    5257   ;; Backward-compatibility: inherit from module. ASDF3: only inherit from parent-component.
     5282  ;; Backward-compatibility: inherit from module. ASDF4: only inherit from parent-component.
    52585283  (;; {,long-}description is now inherited from component, but we add the legacy accessors
    52595284   (description :accessor system-description)
     
    52635288   (licence :accessor system-licence :initarg :licence
    52645289            :accessor system-license :initarg :license)
     5290   (builtin-system-p :accessor builtin-system-p :initform nil :initarg :builtin-system-p)
    52655291   (build-pathname
    52665292    :initform nil :initarg :build-pathname :accessor component-build-pathname)
     5293   (entry-point
     5294    :initform nil :initarg :entry-point :accessor component-entry-point)
    52675295   (source-file :initform nil :initarg :source-file :accessor system-source-file)
    52685296   (defsystem-depends-on :reader system-defsystem-depends-on :initarg :defsystem-depends-on)))
     
    53085336  nil)
    53095337;;;; -------------------------------------------------------------------------
     5338;;;; Stamp cache
     5339
     5340(asdf/package:define-package :asdf/cache
     5341  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade)
     5342  (:export #:get-file-stamp #:compute-file-stamp #:register-file-stamp
     5343           #:consult-asdf-cache #:do-asdf-cache
     5344           #:call-with-asdf-cache #:with-asdf-cache #:*asdf-cache*))
     5345(in-package :asdf/cache)
     5346
     5347;;; This stamp cache is useful for:
     5348;; * consistency of stamps used within a single run
     5349;; * fewer accesses to the filesystem
     5350;; * the ability to test with fake timestamps, without touching files
     5351
     5352(defvar *asdf-cache* nil)
     5353
     5354(defun set-asdf-cache-entry (key value-list)
     5355  (apply 'values
     5356         (if *asdf-cache*
     5357             (setf (gethash key *asdf-cache*) value-list)
     5358             value-list)))
     5359
     5360(defun consult-asdf-cache (key thunk)
     5361  (if *asdf-cache*
     5362      (multiple-value-bind (results foundp) (gethash key *asdf-cache*)
     5363        (if foundp
     5364            (apply 'values results)
     5365            (set-asdf-cache-entry key (multiple-value-list (funcall thunk)))))
     5366      (funcall thunk)))
     5367
     5368(defmacro do-asdf-cache (key &body body)
     5369  `(consult-asdf-cache ,key #'(lambda () ,@body)))
     5370
     5371(defun call-with-asdf-cache (thunk &key override)
     5372  (if (and *asdf-cache* (not override))
     5373      (funcall thunk)
     5374      (let ((*asdf-cache* (make-hash-table :test 'equal)))
     5375        (funcall thunk))))
     5376
     5377(defmacro with-asdf-cache ((&key override) &body body)
     5378  `(call-with-asdf-cache #'(lambda () ,@body) :override ,override))
     5379
     5380(defun compute-file-stamp (file)
     5381  (safe-file-write-date file))
     5382
     5383(defun register-file-stamp (file &optional (stamp (compute-file-stamp file)))
     5384  (set-asdf-cache-entry `(get-file-stamp ,file) (list stamp)))
     5385
     5386(defun get-file-stamp (file)
     5387  (do-asdf-cache `(get-file-stamp ,file) (compute-file-stamp file)))
     5388;;;; -------------------------------------------------------------------------
    53105389;;;; Finding systems
    53115390
     
    53135392  (:recycle :asdf/find-system :asdf)
    53145393  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
    5315    :asdf/component :asdf/system)
     5394   :asdf/component :asdf/system :asdf/cache)
    53165395  (:export
    53175396   #:remove-entry-from-registry #:coerce-entry-to-directory
    53185397   #:coerce-name #:primary-system-name
    5319    #:find-system #:locate-system #:load-sysdef #:with-system-definitions
     5398   #:find-system #:locate-system #:load-asd #:with-system-definitions
    53205399   #:system-registered-p #:register-system #:registered-systems #:clear-system #:map-systems
    53215400   #:system-definition-error #:missing-component #:missing-requires #:missing-parent
     
    53245403   #:*system-definition-search-functions* #:search-for-system-definition
    53255404   #:*central-registry* #:probe-asd #:sysdef-central-registry-search
    5326    #:make-temporary-package #:find-system-if-being-defined #:*systems-being-defined*
     5405   #:find-system-if-being-defined #:*systems-being-defined*
    53275406   #:contrib-sysdef-search #:sysdef-find-asdf ;; backward compatibility symbols, functions removed
    53285407   #:system-find-preloaded-system #:register-preloaded-system #:*preloaded-systems*
     
    54025481      (setf (gethash name *defined-systems*)
    54035482            (cons (if-let (file (ignore-errors (system-source-file system)))
    5404                     (safe-file-write-date file))
     5483                    (get-file-stamp file))
    54055484                  system)))))
    54065485
     
    54655544  (block nil
    54665545    (when (directory-pathname-p defaults)
    5467       (let* ((file (probe-file*
    5468                     (absolutize-pathnames
    5469                      (list (make-pathname :name name :type "asd")
    5470                            defaults *default-pathname-defaults* (getcwd))
    5471                      :resolve-symlinks truename)
    5472                     :truename truename)))
    5473         (when file
    5474           (return file)))
     5546      (if-let (file (probe-file*
     5547                     (ensure-pathname-absolute
     5548                      (parse-unix-namestring name :type "asd")
     5549                      #'(lambda () (ensure-pathname-absolute defaults 'get-pathname-defaults nil))
     5550                      nil)
     5551                     :truename truename))
     5552        (return file))
    54755553      #-(or clisp genera) ; clisp doesn't need it, plain genera doesn't have read-sequence(!)
    54765554      (when (os-windows-p)
     
    55325610                          (subseq *central-registry* (1+ position))))))))))
    55335611
    5534 (defun* make-temporary-package ()
    5535   (make-package (fresh-package-name :prefix :asdf :index 0) :use '(:cl :asdf/interface)))
    5536 
    55375612(defmethod find-system ((name null) &optional (error-p t))
    55385613  (declare (ignorable name))
     
    55525627(defun* call-with-system-definitions (thunk)
    55535628  (if *systems-being-defined*
    5554       (funcall thunk)
     5629      (call-with-asdf-cache thunk)
    55555630      (let ((*systems-being-defined* (make-hash-table :test 'equal)))
    5556         (funcall thunk))))
     5631        (call-with-asdf-cache thunk))))
    55575632
    55585633(defmacro with-system-definitions ((&optional) &body body)
    55595634  `(call-with-system-definitions #'(lambda () ,@body)))
    55605635
    5561 (defun* load-sysdef (name pathname)
     5636(defun* load-asd (pathname &key name (external-format (encoding-external-format (detect-encoding pathname))))
    55625637  ;; Tries to load system definition with canonical NAME from PATHNAME.
    55635638  (with-system-definitions ()
    5564     (let ((package (make-temporary-package))) ;; ASDF3: get rid of that.
    5565       (unwind-protect
    5566            (handler-bind
    5567                ((error #'(lambda (condition)
    5568                            (error 'load-system-definition-error
    5569                                   :name name :pathname pathname
    5570                                   :condition condition))))
    5571              (let ((*package* package)
    5572                    (*default-pathname-defaults*
    5573                     ;; resolve logical-pathnames so they won't wreak havoc in parsing namestrings.
    5574                     (pathname-directory-pathname (translate-logical-pathname pathname)))
    5575                    (external-format (encoding-external-format (detect-encoding pathname))))
    5576                (asdf-message (compatfmt "~&~@<; ~@;Loading system definition from ~A into ~A~@:>~%")
    5577                              pathname package)
    5578                (with-muffled-loader-conditions ()
    5579                  (load* pathname :external-format external-format))))
    5580         (delete-package package)))))
     5639    (let ((*package* (find-package :asdf-user))
     5640          (*default-pathname-defaults*
     5641            ;; resolve logical-pathnames so they won't wreak havoc in parsing namestrings.
     5642            (pathname-directory-pathname (translate-logical-pathname pathname))))
     5643      (handler-bind
     5644          ((error #'(lambda (condition)
     5645                      (error 'load-system-definition-error
     5646                             :name name :pathname pathname
     5647                             :condition condition))))
     5648        (asdf-message (compatfmt "~&~@<; ~@;Loading system definition~@[ for ~A~] from ~A~@:>~%")
     5649                      name pathname)
     5650        (with-muffled-loader-conditions ()
     5651          (load* pathname :external-format external-format))))))
    55815652
    55825653(defun* locate-system (name)
     
    56255696                                             (translate-logical-pathname pathname)
    56265697                                             (translate-logical-pathname previous-pathname))))
    5627                                    (stamp<= (safe-file-write-date pathname) previous-time))))
     5698                                   (stamp<= (get-file-stamp pathname) previous-time))))
    56285699                ;; only load when it's a pathname that is different or has newer content
    5629                 (load-sysdef name pathname)))
     5700                (load-asd pathname :name name)))
    56305701            (let ((in-memory (system-registered-p name))) ; try again after loading from disk if needed
    56315702              (return
     
    56335704                  (in-memory
    56345705                   (when pathname
    5635                      (setf (car in-memory) (safe-file-write-date pathname)))
     5706                     (setf (car in-memory) (get-file-stamp pathname)))
    56365707                   (cdr in-memory))
    56375708                  (error-p
     
    56565727(register-preloaded-system "asdf-driver")
    56575728
    5658 ;;;; Beware of builtin systems
    5659 (defmethod builtin-system-p ((s system))
    5660   (or
    5661    ;; For most purposes, asdf itself specially counts as builtin.
    5662    ;; if you want to link it or do something forbidden to builtins,
    5663    ;; specify separate dependencies on asdf-driver and asdf-defsystem.
    5664    (equal "asdf" (coerce-name s))
    5665    ;; Other builtin systems are those under the implementation directory
    5666    (let* ((system (find-system s nil))
    5667           (sysdir (and system (component-pathname system)))
    5668           (truesysdir (truename* sysdir))
    5669           (impdir (lisp-implementation-directory))
    5670           (trueimpdir (truename* impdir)))
    5671      (and sysdir impdir
    5672           (or (subpathp sysdir impdir)
    5673               (subpathp truesysdir trueimpdir))))))
    56745729;;;; -------------------------------------------------------------------------
    56755730;;;; Finding components
     
    58665921  (:recycle :asdf/action :asdf)
    58675922  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
    5868    :asdf/component :asdf/system :asdf/find-system :asdf/find-component :asdf/operation)
     5923   :asdf/component :asdf/system #:asdf/cache :asdf/find-system :asdf/find-component :asdf/operation)
    58695924  (:intern #:stamp #:done-p)
    58705925  (:export
    58715926   #:action #:define-convenience-action-methods
    5872    #:explain #:operation-description
     5927   #:explain #:action-description
    58735928   #:downward-operation #:upward-operation #:sibling-operation
    58745929   #:component-depends-on #:component-self-dependencies
     
    58785933   #:perform #:perform-with-restarts #:retry #:accept #:feature
    58795934   #:traverse-actions #:traverse-sub-actions #:required-components ;; in plan
    5880    #:action-path #:find-action
    5881    ))
     5935   #:action-path #:find-action))
    58825936(in-package :asdf/action)
    58835937
     
    59135967                     `(apply 'make-operation ,operation :original-initargs ,rest ,rest)
    59145968                     `(make-operation ,operation))
    5915                  `(find-component () ,component))
     5969                 `(or (find-component () ,component) ,if-no-component))
    59165970               ,if-no-operation))
    59175971         (defmethod ,function ((,operation operation) ,component ,@more-args)
    59185972           (if (typep ,component 'component)
    5919                (error "No defined method for ~S on ~S" ',function ,component)
     5973               (error "No defined method for ~S on ~/asdf-action:format-action/"
     5974                      ',function (cons ,operation ,component))
    59205975               (let ((,found (find-component () ,component)))
    59215976                 (if ,found
     
    59265981;;;; self-description
    59275982
    5928 (defgeneric* operation-description (operation component) ;; ASDF3: rename to action-description
     5983(defgeneric* action-description (operation component)
    59295984  (:documentation "returns a phrase that describes performing this operation
    59305985on this component, e.g. \"loading /a/b/c\".
    59315986You can put together sentences using this phrase."))
    5932 (defmethod operation-description (operation component)
     5987(defmethod action-description (operation component)
    59335988  (format nil (compatfmt "~@<~A on ~A~@:>")
    59345989          (type-of operation) component))
    59355990(defgeneric* (explain) (operation component))
    59365991(defmethod explain ((o operation) (c component))
    5937   (asdf-message (compatfmt "~&~@<; ~@;~A~:>~%") (operation-description o c)))
     5992  (asdf-message (compatfmt "~&~@<; ~@;~A~:>~%") (action-description o c)))
    59385993(define-convenience-action-methods explain (operation component))
    59395994
     
    59415996  (assert (null colon-p)) (assert (null at-sign-p))
    59425997  (destructuring-bind (operation . component) action
    5943     (princ (operation-description operation component) stream)))
     5998    (princ (action-description operation component) stream)))
    59445999
    59456000
    59466001;;;; Dependencies
    59476002
    5948 (defgeneric* component-depends-on (operation component) ;; ASDF3: rename to component-dependencies
     6003(defgeneric* component-depends-on (operation component) ;; ASDF4: rename to component-dependencies
    59496004  (:documentation
    59506005   "Returns a list of dependencies needed by the component to perform
     
    59936048    :initform nil :initarg :downward-operation :reader upward-operation)))
    59946049;; For backward-compatibility reasons, a system inherits from module and is a child-component
    5995 ;; so we must guard against this case. ASDF3: remove that.
     6050;; so we must guard against this case. ASDF4: remove that.
    59966051(defmethod component-depends-on ((o upward-operation) (c child-component))
    59976052  `(,@(if-let (p (component-parent c))
     
    60246079
    60256080(defmethod output-files :around (operation component)
    6026   "Translate output files, unless asked not to"
     6081  "Translate output files, unless asked not to. Memoize the result."
    60276082  operation component ;; hush genera, not convinced by declare ignorable(!)
    6028   (values
    6029    (multiple-value-bind (pathnames fixedp) (call-next-method)
    6030      ;; 1- Make sure we have absolute pathnames
    6031      (let* ((directory (pathname-directory-pathname
    6032                         (component-pathname (find-component () component))))
    6033             (absolute-pathnames
    6034               (loop
    6035                 :for pathname :in pathnames
    6036                 :collect (ensure-pathname-absolute pathname directory))))
    6037        ;; 2- Translate those pathnames as required
    6038        (if fixedp
    6039            absolute-pathnames
    6040            (mapcar *output-translation-function* absolute-pathnames))))
    6041    t))
     6083  (do-asdf-cache `(output-files ,operation ,component)
     6084    (values
     6085     (multiple-value-bind (pathnames fixedp) (call-next-method)
     6086       ;; 1- Make sure we have absolute pathnames
     6087       (let* ((directory (pathname-directory-pathname
     6088                          (component-pathname (find-component () component))))
     6089              (absolute-pathnames
     6090                (loop
     6091                  :for pathname :in pathnames
     6092                  :collect (ensure-pathname-absolute pathname directory))))
     6093         ;; 2- Translate those pathnames as required
     6094         (if fixedp
     6095             absolute-pathnames
     6096             (mapcar *output-translation-function* absolute-pathnames))))
     6097     t)))
    60426098(defmethod output-files ((o operation) (c component))
    60436099  (declare (ignorable o c))
     
    60496105    (first files)))
    60506106
     6107(defmethod input-files :around (operation component)
     6108  "memoize input files."
     6109  (do-asdf-cache `(input-files ,operation ,component)
     6110    (call-next-method)))
     6111
    60516112(defmethod input-files ((o operation) (c parent-component))
    60526113  (declare (ignorable o c))
     
    60646125;;;; Done performing
    60656126
    6066 (defgeneric* component-operation-time (operation component)) ;; ASDF3: hide it behind plan-action-stamp
     6127(defgeneric* component-operation-time (operation component)) ;; ASDF4: hide it behind plan-action-stamp
    60676128(define-convenience-action-methods component-operation-time (operation component))
    60686129
    6069 
    6070 (defgeneric* mark-operation-done (operation component)) ;; ASDF3: hide it behind (setf plan-action-stamp)
     6130(defgeneric* mark-operation-done (operation component)) ;; ASDF4: hide it behind (setf plan-action-stamp)
    60716131(defgeneric* compute-action-stamp (plan operation component &key just-done)
    60726132  (:documentation "Has this action been successfully done already,
     
    61386198        (lambda (s)
    61396199          (format s (compatfmt "~@<Retry ~A.~@:>")
    6140                   (operation-description operation component))))
     6200                  (action-description operation component))))
    61416201      (accept ()
    61426202        :report
    61436203        (lambda (s)
    61446204          (format s (compatfmt "~@<Continue, treating ~A as having been successful.~@:>")
    6145                   (operation-description operation component)))
     6205                  (action-description operation component)))
    61466206        (mark-operation-done operation component)
    61476207        (return)))))
     
    62026262
    62036263;;; prepare-op
    6204 (defmethod operation-description ((o prepare-op) (c component))
     6264(defmethod action-description ((o prepare-op) (c component))
    62056265  (declare (ignorable o))
    62066266  (format nil (compatfmt "~@<loading dependencies of ~3i~_~A~@:>") c))
     
    62166276
    62176277;;; compile-op
    6218 (defmethod operation-description ((o compile-op) (c component))
     6278(defmethod action-description ((o compile-op) (c component))
    62196279  (declare (ignorable o))
    62206280  (format nil (compatfmt "~@<compiling ~3i~_~A~@:>") c))
    6221 (defmethod operation-description ((o compile-op) (c parent-component))
     6281(defmethod action-description ((o compile-op) (c parent-component))
    62226282  (declare (ignorable o))
    62236283  (format nil (compatfmt "~@<completing compilation for ~3i~_~A~@:>") c))
     
    62986358(defmethod input-files ((o compile-op) (c system))
    62996359  (declare (ignorable o c))
    6300   (unless (builtin-system-p c)
    6301     (loop* :for (sub-o . sub-c)
    6302            :in (traverse-sub-actions
    6303                 o c :other-systems nil
    6304                     :keep-operation 'compile-op :keep-component 'cl-source-file)
    6305            :append (remove-if-not 'warnings-file-p
    6306                                   (output-files sub-o sub-c)))))
     6360  (when *warnings-file-type*
     6361    (unless (builtin-system-p c)
     6362      ;; The most correct way to do it would be to use:
     6363      ;; (traverse-sub-actions o c :other-systems nil :keep-operation 'compile-op :keep-component 'cl-source-file)
     6364      ;; but it's expensive and we don't care too much about file order or ASDF extensions.
     6365      (loop :for sub :in (sub-components c :type 'cl-source-file)
     6366            :nconc (remove-if-not 'warnings-file-p (output-files o sub))))))
    63076367#+sbcl
    63086368(defmethod output-files ((o compile-op) (c system))
     
    63126372
    63136373;;; load-op
    6314 (defmethod operation-description ((o load-op) (c cl-source-file))
     6374(defmethod action-description ((o load-op) (c cl-source-file))
    63156375  (declare (ignorable o))
    63166376  (format nil (compatfmt "~@<loading FASL for ~3i~_~A~@:>") c))
    6317 (defmethod operation-description ((o load-op) (c parent-component))
     6377(defmethod action-description ((o load-op) (c parent-component))
    63186378  (declare (ignorable o))
    63196379  (format nil (compatfmt "~@<completing load for ~3i~_~A~@:>") c))
    6320 (defmethod operation-description ((o load-op) component)
     6380(defmethod action-description ((o load-op) component)
    63216381  (declare (ignorable o))
    63226382  (format nil (compatfmt "~@<loading ~3i~_~A~@:>")
     
    63506410
    63516411;;; prepare-source-op
    6352 (defmethod operation-description ((o prepare-source-op) (c component))
     6412(defmethod action-description ((o prepare-source-op) (c component))
    63536413  (declare (ignorable o))
    63546414  (format nil (compatfmt "~@<loading source for dependencies of ~3i~_~A~@:>") c))
     
    63646424
    63656425;;; load-source-op
    6366 (defmethod operation-description ((o load-source-op) c)
     6426(defmethod action-description ((o load-source-op) c)
    63676427  (declare (ignorable o))
    63686428  (format nil (compatfmt "~@<Loading source of ~3i~_~A~@:>") c))
    6369 (defmethod operation-description ((o load-source-op) (c parent-component))
     6429(defmethod action-description ((o load-source-op) (c parent-component))
    63706430  (declare (ignorable o))
    63716431  (format nil (compatfmt "~@<Loaded source of ~3i~_~A~@:>") c))
     
    64086468  (:recycle :asdf/plan :asdf)
    64096469  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
    6410    :asdf/component :asdf/operation :asdf/system :asdf/find-system :asdf/find-component
     6470   :asdf/component :asdf/operation :asdf/system
     6471   :asdf/cache :asdf/find-system :asdf/find-component
    64116472   :asdf/operation :asdf/action)
    64126473  (:export
     
    66006661
    66016662(defmethod compute-action-stamp (plan (o operation) (c component) &key just-done)
    6602   ;; In a distant future, safe-file-write-date and component-operation-time
     6663  ;; In a distant future, get-file-stamp and component-operation-time
    66036664  ;; shall also be parametrized by the plan, or by a second model object.
    66046665  (let* ((stamp-lookup #'(lambda (o c)
     
    66156676         (dep-stamp (visit-dependencies plan o c stamp-lookup))
    66166677         ;; Time stamps from the files at hand, and whether any is missing
    6617          (out-stamps (mapcar #'safe-file-write-date out-files))
    6618          (in-stamps (mapcar #'safe-file-write-date in-files))
     6678         (out-stamps (mapcar (if just-done 'register-file-stamp 'get-file-stamp) out-files))
     6679         (in-stamps (mapcar #'get-file-stamp in-files))
    66196680         (missing-in
    66206681           (loop :for f :in in-files :for s :in in-stamps :unless s :collect f))
     
    66336694      (warn "~A completed without ~:[~*~;~*its input file~:p~2:*~{ ~S~}~*~]~
    66346695             ~:[~; or ~]~:[~*~;~*its output file~:p~2:*~{ ~S~}~*~]"
    6635             (operation-description o c)
     6696            (action-description o c)
    66366697            missing-in (length missing-in) (and missing-in missing-out)
    66376698            missing-out (length missing-out)))
     
    67806841    (plan-actions plan)))
    67816842
    6782 
    6783 (defmethod perform-plan ((steps list) &key)
     6843(defmethod perform-plan :around (plan &key)
     6844  (declare (ignorable plan))
    67846845  (let ((*package* *package*)
    67856846        (*readtable* *readtable*))
    6786     (loop* :for (op . component) :in steps :do
    6787       (perform-with-restarts op component))))
     6847    (with-compilation-unit () ;; backward-compatibility.
     6848      (call-next-method))))   ;; Going forward, see deferred-warning support in lisp-build.
     6849
     6850(defmethod perform-plan ((steps list) &key)
     6851  (loop* :for (op . component) :in steps :do
     6852         (perform-with-restarts op component)))
    67886853
    67896854(defmethod plan-operates-on-p ((plan list) (component-path list))
     
    70327097   #:environment-output-translations #:process-output-translations
    70337098   #:compute-output-translations
     7099   #+abcl #:translate-jar-pathname
    70347100   ))
    70357101(in-package :asdf/output-translations)
     
    74867552(defun* default-source-registry ()
    74877553  `(:source-registry
    7488     #+sbcl (:directory ,(subpathname (user-homedir) ".sbcl/systems/"))
     7554    #+sbcl (:directory ,(subpathname (user-homedir-pathname) ".sbcl/systems/"))
    74897555    ,@(loop :for dir :in
    74907556        `(,@(when (os-unix-p)
    74917557              `(,(or (getenv-absolute-directory "XDG_DATA_HOME")
    7492                      (subpathname (user-homedir) ".local/share/"))
     7558                     (subpathname (user-homedir-pathname) ".local/share/"))
    74937559                ,@(or (getenv-absolute-directories "XDG_DATA_DIRS")
    74947560                      '("/usr/local/share" "/usr/share"))))
     
    76427708  (:recycle :asdf/backward-internals :asdf)
    76437709  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
    7644    :asdf/system :asdf/component :asdf/find-system :asdf/action)
     7710   :asdf/system :asdf/component :asdf/operation
     7711   :asdf/find-system :asdf/action :asdf/lisp-action)
    76457712  (:export ;; for internal use
     7713   #:load-sysdef #:make-temporary-package
    76467714   #:%refresh-component-inline-methods
    76477715   #:%resolve-if-component-dep-fails
    7648    #:make-sub-operation))
     7716   #:make-sub-operation
     7717   #:load-sysdef #:make-temporary-package))
    76497718(in-package :asdf/backward-internals)
    76507719
     
    76927761  (asdf-message "The system definition for ~S uses deprecated ~
    76937762                 ASDF option :IF-COMPONENT-DEP-DAILS. ~
    7694                  Starting with ASDF 2.27, please use :IF-FEATURE instead"
     7763                 Starting with ASDF 3, please use :IF-FEATURE instead"
    76957764                (coerce-name (component-system component)))
    76967765  ;; This only supports the pattern of use of the "feature" seen in the wild
     
    76987767  (check-type if-component-dep-fails (member :fail :ignore :try-next))
    76997768  (unless (eq if-component-dep-fails :fail)
    7700     (loop :with o = (make-instance 'compile-op)
     7769    (loop :with o = (make-operation 'compile-op)
    77017770      :for c :in (component-children component) :do
    77027771        (loop* :for (feature? feature) :in (component-depends-on o c)
     
    77077776  (defun* make-sub-operation (c o dep-c dep-o)
    77087777    (declare (ignore c o dep-c dep-o)) (asdf-upgrade-error)))
     7778
     7779
     7780;;;; load-sysdef
     7781(defun* load-sysdef (name pathname)
     7782  (load-asd pathname :name name))
     7783
     7784(defun* make-temporary-package ()
     7785  (make-package (fresh-package-name :prefix :asdf :index 0) :use '(:cl :asdf/interface)))
     7786
     7787
    77097788;;;; -------------------------------------------------------------------------
    77107789;;;; Defsystem
     
    77137792  (:recycle :asdf/defsystem :asdf)
    77147793  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
    7715    :asdf/component :asdf/system
     7794   :asdf/component :asdf/system :asdf/cache
    77167795   :asdf/find-system :asdf/find-component :asdf/lisp-action :asdf/operate
    77177796   :asdf/backward-internals)
     
    77407819  ;; If no absolute pathname was found, we return NIL.
    77417820  (check-type pathname (or null string pathname))
    7742   (let ((pathname (parse-unix-namestring pathname :type :directory))
    7743         (load-pathname (load-pathname)))
    7744     (when (or pathname load-pathname)
    7745       (pathname-directory-pathname
    7746        (absolutize-pathnames
    7747         (list pathname load-pathname *default-pathname-defaults* (getcwd))
    7748         :resolve-symlinks *resolve-symlinks*)))))
     7821  (resolve-symlinks*
     7822   (ensure-pathname-absolute
     7823    (parse-unix-namestring pathname :type :directory)
     7824    #'(lambda () (ensure-pathname-absolute
     7825                  (load-pathname) 'get-pathname-defaults nil))
     7826    nil)))
    77497827
    77507828
     
    78117889  (destructuring-bind
    78127890      (type name &rest rest &key
     7891       (builtin-system-p () bspp)
    78137892       ;; the following list of keywords is reproduced below in the
    78147893       ;; remove-plist-keys form.  important to keep them in sync
     
    78187897       ;; list ends
    78197898       &allow-other-keys) options
    7820     (declare (ignorable perform explain output-files operation-done-p))
     7899    (declare (ignorable perform explain output-files operation-done-p builtin-system-p))
    78217900    (check-component-input type name weakly-depends-on depends-on components)
    78227901    (when (and parent
     
    78267905                       (class-for-type parent type))))
    78277906      (error 'duplicate-names :name name))
    7828     (when do-first (error "DO-FIRST is not supported anymore as of ASDF 2.27"))
     7907    (when do-first (error "DO-FIRST is not supported anymore as of ASDF 3"))
    78297908    (let* ((args `(:name ,(coerce-name name)
    78307909                   :pathname ,pathname
     
    78377916           (component (find-component parent name)))
    78387917      (when weakly-depends-on
    7839         ;; ASDF3: deprecate this feature and remove it.
     7918        ;; ASDF4: deprecate this feature and remove it.
    78407919        (appendf depends-on
    78417920                 (remove-if (complement #'(lambda (x) (find-system x nil))) weakly-depends-on)))
     
    78477926      (component-pathname component) ; eagerly compute the absolute pathname
    78487927      (let ((sysdir (system-source-directory (component-system component)))) ;; requires the previous
     7928        (when (and (typep component 'system) (not bspp))
     7929          (setf (builtin-system-p component) (lisp-implementation-pathname-p sysdir)))
    78497930        (setf version (normalize-version version sysdir)))
    78507931      (when (and versionp version (not (parse-version version nil)))
     
    78637944                :when serial :do (setf previous-component name)))
    78647945        (compute-children-by-name component))
    7865       ;; Used by POIU. ASDF3: rename to component-depends-on
     7946      ;; Used by POIU. ASDF4: rename to component-depends-on?
    78667947      (setf (component-sibling-dependencies component) depends-on)
    78677948      (%refresh-component-inline-methods component rest)
     
    78847965           (registered (system-registered-p name))
    78857966           (registered! (if registered
    7886                             (rplaca registered (safe-file-write-date source-file))
     7967                            (rplaca registered (get-file-stamp source-file))
    78877968                            (register-system
    78887969                             (make-instance 'system :name name :source-file source-file))))
     
    79238004   #+ecl #:make-build
    79248005   #:register-pre-built-system
    7925    #:build-args #:name-suffix #:prologue-code #:epilogue-code #:static-library
    7926    #:component-entry-point #:entry-point))
     8006   #:build-args #:name-suffix #:prologue-code #:epilogue-code #:static-library))
    79278007(in-package :asdf/bundle)
    79288008
     
    79828062  ;; All: create an executable file from the system and its dependencies
    79838063  ((bundle-type :initform :program)))
    7984 
    7985 (defgeneric* component-entry-point (component))
    7986 
    7987 (defmethod component-entry-point ((c component))
    7988   (declare (ignorable c))
    7989   nil)
    7990 
    7991 (defclass bundle-system (system)
    7992   ((entry-point
    7993     :initform nil :initarg :entry-point :accessor component-entry-point)))
    79948064
    79958065(defun* bundle-pathname-type (bundle-type)
     
    84888558  (:recycle :asdf/backward-interface :asdf)
    84898559  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
    8490    :asdf/component :asdf/system :asdf/operation :asdf/action
     8560   :asdf/component :asdf/system :asdf/find-system :asdf/operation :asdf/action
    84918561   :asdf/lisp-build :asdf/operate :asdf/output-translations)
    84928562  (:export
     
    85548624     (centralize-lisp-binaries nil)
    85558625     (default-toplevel-directory
    8556          (subpathname (user-homedir) ".fasls/")) ;; Use ".cache/common-lisp/" instead ???
     8626         (subpathname (user-homedir-pathname) ".fasls/")) ;; Use ".cache/common-lisp/" instead ???
    85578627     (include-per-user-information nil)
    85588628     (map-all-source-files (or #+(or clisp ecl mkcl) t nil))
    8559      (source-to-target-mappings nil))
     8629     (source-to-target-mappings nil)
     8630     (file-types (list (compile-file-type)
     8631                         #+ecl (compile-file-type :type :object)
     8632                         #+mkcl (compile-file-type :fasl-p nil)
     8633                         #+clisp "lib" #+sbcl "cfasl"
     8634                         #+sbcl "sbcl-warnings" #+clozure "ccl-warnings")))
    85608635  #+(or clisp ecl mkcl)
    85618636  (when (null map-all-source-files)
    85628637    (error "asdf:enable-asdf-binary-locations-compatibility doesn't support :map-all-source-files nil on CLISP, ECL and MKCL"))
    8563   (let* ((fasl-type (compile-file-type))
    8564          (mapped-files (if map-all-source-files *wild-file*
    8565                            (make-pathname :type fasl-type :defaults *wild-file*)))
     8638  (let* ((patterns (if map-all-source-files (list *wild-file*)
     8639                       (loop :for type :in file-types
     8640                             :collect (make-pathname :type type :defaults *wild-file*))))
    85668641         (destination-directory
    85678642          (if centralize-lisp-binaries
    85688643              `(,default-toplevel-directory
    85698644                ,@(when include-per-user-information
    8570                         (cdr (pathname-directory (user-homedir))))
     8645                        (cdr (pathname-directory (user-homedir-pathname))))
    85718646                :implementation ,*wild-inferiors*)
    85728647              `(:root ,*wild-inferiors* :implementation))))
     
    85768651       #+abcl (#p"jar:file:/**/*.jar!/**/*.*" (:function translate-jar-pathname))
    85778652       #+abcl (#p"/___jar___file___root___/**/*.*" (,@destination-directory))
    8578        ((:root ,*wild-inferiors* ,mapped-files)
    8579         (,@destination-directory ,mapped-files))
     8653       ,@(loop :for pattern :in patterns
     8654               :collect `((:root ,*wild-inferiors* ,pattern)
     8655                          (,@destination-directory ,pattern)))
    85808656       (t t)
    85818657       :ignore-inherited-configuration))))
     
    86108686    (asdf-message "; $ ~A~%" command)
    86118687    (run-program command :force-shell t :ignore-error-status t :output *verbose-out*)))
     8688
    86128689;;;; ---------------------------------------------------------------------------
    86138690;;;; Handle ASDF package upgrade, including implementation-dependent magic.
     
    86228699   #:loaded-systems ; makes for annoying SLIME completion
    86238700   #:output-files-for-system-and-operation) ; obsolete ASDF-BINARY-LOCATION function
    8624   (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
     8701  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade :asdf/cache
    86258702   :asdf/component :asdf/system :asdf/find-system :asdf/find-component
    86268703   :asdf/operation :asdf/action :asdf/lisp-action
     
    86438720   #:implementation-identifier #:implementation-type #:hostname
    86448721   #:input-files #:output-files #:output-file #:perform
    8645    #:operation-done-p #:explain #:component-sibling-dependencies
     8722   #:operation-done-p #:explain #:action-description #:component-sibling-dependencies
    86468723   #:needed-in-image-p
    86478724   ;; #:run-program ; we can't export it, because SB-GROVEL :use's both ASDF and SB-EXT.
     
    86738750   #:component-version
    86748751   #:component-parent
    8675    #:component-property
    86768752   #:component-system
    86778753   #:component-encoding
     
    86938769   #:map-systems
    86948770
    8695    #:operation-description
    8696 
    86978771   #:*system-definition-search-functions*   ; variables
    86988772   #:*central-registry*
     
    87068780   #:asdf-version
    87078781
    8708    #:operation-error #:compile-failed #:compile-warned #:compile-error
     8782   #:compile-condition #:compile-file-error #:compile-warned-error #:compile-failed-error
     8783   #:compile-warned-warning #:compile-failed-warning
     8784   #:operation-error #:compile-failed #:compile-warned #:compile-error ;; backward compatibility
    87098785   #:error-name
    87108786   #:error-pathname
     
    87398815   #:compile-file*
    87408816   #:compile-file-pathname*
     8817   #:*warnings-file-type*
    87418818   #:enable-asdf-binary-locations-compatibility
    87428819   #:*default-source-registries*
     
    87598836   #:system-source-registry-directory))
    87608837
     8838;;;; ---------------------------------------------------------------------------
     8839;;;; ASDF-USER, where the action happens.
     8840
     8841(asdf/package:define-package :asdf/user
     8842  (:nicknames :asdf-user)
     8843  (:use :asdf/common-lisp :asdf/package :asdf/interface))
    87618844;;;; -----------------------------------------------------------------------
    87628845;;;; ASDF Footer: last words and cleanup
     
    87718854(in-package :asdf/footer)
    87728855
    8773 ;;;; Configure
    8774 (setf asdf/utility:*asdf-debug-utility*
    8775       '(asdf/system:system-relative-pathname :asdf "contrib/debug.lisp"))
    8776 
    87778856;;;; Hook ASDF into the implementation's REQUIRE and other entry points.
    87788857
    87798858#+(or abcl clisp clozure cmu ecl mkcl sbcl)
    8780 (let ((x (and #+clisp (find-symbol* '#:*module-provider-functions* :custom nil))))
    8781   (when x
    8782     (eval `(pushnew 'module-provide-asdf
    8783             #+abcl sys::*module-provider-functions*
    8784             #+clisp ,x
    8785             #+clozure ccl:*module-provider-functions*
    8786             #+(or cmu ecl) ext:*module-provider-functions*
    8787             #+mkcl mk-ext:*module-provider-functions*
    8788             #+sbcl sb-ext:*module-provider-functions*))))
     8859(if-let (x (and #+clisp (find-symbol* '#:*module-provider-functions* :custom nil)))
     8860  (eval `(pushnew 'module-provide-asdf
     8861                  #+abcl sys::*module-provider-functions*
     8862                  #+clisp ,x
     8863                  #+clozure ccl:*module-provider-functions*
     8864                  #+(or cmu ecl) ext:*module-provider-functions*
     8865                  #+mkcl mk-ext:*module-provider-functions*
     8866                  #+sbcl sb-ext:*module-provider-functions*)))
    87898867
    87908868#+(or ecl mkcl)
     
    88228900    (setf excl:*warn-on-nested-reader-conditionals* asdf/common-lisp::*acl-warn-save*)))
    88238901
    8824 (dolist (f '(:asdf :asdf2 :asdf2.27)) (pushnew f *features*))
     8902(dolist (f '(:asdf :asdf2 :asdf3)) (pushnew f *features*))
    88258903
    88268904(provide :asdf)
Note: See TracChangeset for help on using the changeset viewer.