X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Ftarget-pathname.lisp;h=9f72ccd4df4f721a632c35286746c2a946e3e17b;hb=771b864c8f32af7734bc0550aeaf1539fc4df194;hp=cca306882c9d3e6d6f38ef50fde8c9aa301baee1;hpb=dccfa0f4e378a267744c03b1416accdf9d888987;p=sbcl.git diff --git a/src/code/target-pathname.lisp b/src/code/target-pathname.lisp index cca3068..9f72ccd 100644 --- a/src/code/target-pathname.lisp +++ b/src/code/target-pathname.lisp @@ -13,10 +13,30 @@ #!-sb-fluid (declaim (freeze-type logical-pathname logical-host)) -;;; host methods - -(def!method print-object ((host host) stream) - (print-unreadable-object (host stream :type t :identity t))) +;;;; UNIX-HOST stuff + +(def!struct (unix-host + (:make-load-form-fun make-unix-host-load-form) + (:include host + (parse #'parse-unix-namestring) + (unparse #'unparse-unix-namestring) + (unparse-host #'unparse-unix-host) + (unparse-directory #'unparse-unix-directory) + (unparse-file #'unparse-unix-file) + (unparse-enough #'unparse-unix-enough) + (customary-case :lower)))) + +(defvar *unix-host* (make-unix-host)) + +(defun make-unix-host-load-form (host) + (declare (ignore host)) + '*unix-host*) + +;;; Return a value suitable, e.g., for preinitializing +;;; *DEFAULT-PATHNAME-DEFAULTS* before *DEFAULT-PATHNAME-DEFAULTS* is +;;; initialized (at which time we can't safely call e.g. #'PATHNAME). +(defun make-trivial-default-pathname () + (%make-pathname *unix-host* nil nil nil nil :newest)) ;;; pathname methods @@ -25,12 +45,10 @@ (error nil)))) (if namestring (format stream "#P~S" namestring) - ;; FIXME: This code was rewritten and should be tested. (How does - ;; control get to this case anyhow? Perhaps we could just punt it?) (print-unreadable-object (pathname stream :type t) (format stream - "(with no namestring) :HOST ~S :DEVICE ~S :DIRECTORY ~S ~ - :NAME ~S :TYPE ~S :VERSION ~S" + "~@<(with no namestring) ~_:HOST ~S ~_:DEVICE ~S ~_:DIRECTORY ~S ~ + ~_:NAME ~S ~_:TYPE ~S ~_:VERSION ~S~:>" (%pathname-host pathname) (%pathname-device pathname) (%pathname-directory pathname) @@ -40,27 +58,6 @@ (def!method make-load-form ((pathname pathname) &optional environment) (make-load-form-saving-slots pathname :environment environment)) - -;;; The potential conflict with search lists requires isolating the -;;; printed representation to use the i/o macro #.(logical-pathname -;;; ). -;;; -;;; FIXME: We don't use search lists any more, so that comment is -;;; stale, right? -(def!method print-object ((pathname logical-pathname) stream) - (let ((namestring (handler-case (namestring pathname) - (error nil)))) - (if namestring - (format stream "#.(CL:LOGICAL-PATHNAME ~S)" namestring) - (print-unreadable-object (pathname stream :type t) - (format - stream - "~_:HOST ~S ~_:DIRECTORY ~S ~_:FILE ~S ~_:NAME ~S ~_:VERSION ~S" - (%pathname-host pathname) - (%pathname-directory pathname) - (%pathname-name pathname) - (%pathname-type pathname) - (%pathname-version pathname)))))) ;;; A pathname is logical if the host component is a logical host. ;;; This constructor is used to make an instance of the correct type @@ -79,7 +76,9 @@ (upcase-maybe name) (upcase-maybe type) version) - (%make-pathname host device directory name type version)))) + (progn + (aver (eq host *unix-host*)) + (%make-pathname host device directory name type version))))) ;;; Hash table searching maps a logical pathname's host to its ;;; physical pathname translation. @@ -102,22 +101,22 @@ (let ((pieces1 (pattern-pieces pattern1)) (pieces2 (pattern-pieces pattern2))) (and (= (length pieces1) (length pieces2)) - (every #'(lambda (piece1 piece2) - (typecase piece1 - (simple-string - (and (simple-string-p piece2) - (string= piece1 piece2))) - (cons - (and (consp piece2) - (eq (car piece1) (car piece2)) - (string= (cdr piece1) (cdr piece2)))) - (t - (eq piece1 piece2)))) + (every (lambda (piece1 piece2) + (typecase piece1 + (simple-string + (and (simple-string-p piece2) + (string= piece1 piece2))) + (cons + (and (consp piece2) + (eq (car piece1) (car piece2)) + (string= (cdr piece1) (cdr piece2)))) + (t + (eq piece1 piece2)))) pieces1 pieces2)))) -;;; If the string matches the pattern returns the multiple values T and a -;;; list of the matched strings. +;;; If the string matches the pattern returns the multiple values T +;;; and a list of the matched strings. (defun pattern-matches (pattern string) (declare (type pattern pattern) (type simple-string string)) @@ -249,8 +248,9 @@ (%pathname-name pathname2)) (compare-component (%pathname-type pathname1) (%pathname-type pathname2)) - (compare-component (%pathname-version pathname1) - (%pathname-version pathname2)))) + (or (eq (%pathname-host pathname1) *unix-host*) + (compare-component (%pathname-version pathname1) + (%pathname-version pathname2))))) ;;; Convert PATHNAME-DESIGNATOR (a pathname, or string, or ;;; stream), into a pathname in pathname. @@ -264,7 +264,7 @@ (,pathname (etypecase ,pd0 (pathname ,pd0) (string (parse-namestring ,pd0)) - (stream (file-name ,pd0))))) + (file-stream (file-name ,pd0))))) ,@body))) ;;; Convert the var, a host or string name for a host, into a @@ -300,9 +300,9 @@ (simple-string (check-for pred piece)) (cons - (case (car in) + (case (car piece) (:character-set - (check-for pred (cdr in)))))) + (check-for pred (cdr piece)))))) (return t)))) (list (dolist (x in) @@ -317,19 +317,19 @@ (typecase thing (pattern (make-pattern - (mapcar #'(lambda (piece) - (typecase piece - (simple-base-string - (funcall fun piece)) - (cons - (case (car piece) - (:character-set - (cons :character-set - (funcall fun (cdr piece)))) - (t - piece))) - (t - piece))) + (mapcar (lambda (piece) + (typecase piece + (simple-base-string + (funcall fun piece)) + (cons + (case (car piece) + (:character-set + (cons :character-set + (funcall fun (cdr piece)))) + (t + piece))) + (t + piece))) (pattern-pieces thing)))) (list (mapcar fun thing)) @@ -340,20 +340,20 @@ (let ((any-uppers (check-for #'upper-case-p thing)) (any-lowers (check-for #'lower-case-p thing))) (cond ((and any-uppers any-lowers) - ;; Mixed case, stays the same. + ;; mixed case, stays the same thing) (any-uppers - ;; All uppercase, becomes all lower case. - (diddle-with #'(lambda (x) (if (stringp x) - (string-downcase x) - x)) thing)) + ;; all uppercase, becomes all lower case + (diddle-with (lambda (x) (if (stringp x) + (string-downcase x) + x)) thing)) (any-lowers - ;; All lowercase, becomes all upper case. - (diddle-with #'(lambda (x) (if (stringp x) - (string-upcase x) - x)) thing)) + ;; all lowercase, becomes all upper case + (diddle-with (lambda (x) (if (stringp x) + (string-upcase x) + x)) thing)) (t - ;; No letters? I guess just leave it. + ;; no letters? I guess just leave it. thing)))) thing)) @@ -365,7 +365,8 @@ (flet ((add (dir) (if (and (eq dir :back) results - (not (eq (car results) :back))) + (not (member (car results) + '(:back :wild-inferiors)))) (pop results) (push dir results)))) (dolist (dir (maybe-diddle-case dir2 diddle-case)) @@ -408,6 +409,7 @@ (maybe-diddle-case (%pathname-type defaults) diddle-case)) (or (%pathname-version pathname) + (and (not (%pathname-name pathname)) (%pathname-version defaults)) default-version)))))) (defun import-directory (directory diddle-case) @@ -417,13 +419,7 @@ ((member :unspecific) '(:relative)) (list (collect ((results)) - (ecase (pop directory) - (:absolute - (results :absolute) - (when (search-list-p (car directory)) - (results (pop directory)))) - (:relative - (results :relative))) + (results (pop directory)) (dolist (piece directory) (cond ((member piece '(:wild :wild-inferiors :up :back)) (results piece)) @@ -467,11 +463,11 @@ a host-structure or string." (default-host (if defaults (%pathname-host defaults) (pathname-host *default-pathname-defaults*))) - ;; toy@rtp.ericsson.se: CLHS says make-pathname can take a + ;; Raymond Toy writes: CLHS says make-pathname can take a ;; string (as a logical-host) for the host part. We map that ;; string into the corresponding logical host structure. ;; - ;; pw@snoopy.mv.com: + ;; Paul Werkowski writes: ;; HyperSpec says for the arg to MAKE-PATHNAME; ;; "host---a valid physical pathname host. ..." ;; where it probably means -- a valid pathname host. @@ -487,6 +483,7 @@ a host-structure or string." ;; It seems an error message is appropriate. (host (typecase host (host host) ; A valid host, use it. + ((string 0) *unix-host*) ; "" cannot be a logical host (string (find-logical-host host t)) ; logical-host or lose. (t default-host))) ; unix-host (diddle-args (and (eq (host-customary-case host) :lower) @@ -593,6 +590,41 @@ a host-structure or string." ;;;; namestrings +;;; Handle the case for PARSE-NAMESTRING parsing a potentially +;;; syntactically valid logical namestring with an explicit host. +;;; +;;; This then isn't fully general -- we are relying on the fact that +;;; we will only pass to parse-namestring namestring with an explicit +;;; logical host, so that we can pass the host return from +;;; parse-logical-namestring through to %PARSE-NAMESTRING as a truth +;;; value. Yeah, this is probably a KLUDGE - CSR, 2002-04-18 +(defun parseable-logical-namestring-p (namestr start end) + (catch 'exit + (handler-bind + ((namestring-parse-error (lambda (c) + (declare (ignore c)) + (throw 'exit nil)))) + (let ((colon (position #\: namestr :start start :end end))) + (when colon + (let ((potential-host + (logical-word-or-lose (subseq namestr start colon)))) + ;; depending on the outcome of CSR comp.lang.lisp post + ;; "can PARSE-NAMESTRING create logical hosts", we may need + ;; to do things with potential-host (create it + ;; temporarily, parse the namestring and unintern the + ;; logical host potential-host on failure. + (declare (ignore potential-host)) + (let ((result + (handler-bind + ((simple-type-error (lambda (c) + (declare (ignore c)) + (throw 'exit nil)))) + (parse-logical-namestring namestr start end)))) + ;; if we got this far, we should have an explicit host + ;; (first return value of parse-logical-namestring) + (aver result) + result))))))) + ;;; Handle the case where PARSE-NAMESTRING is actually parsing a ;;; namestring. We pick off the :JUNK-ALLOWED case then find a host to ;;; use for parsing, call the parser, then check whether the host matches. @@ -601,40 +633,71 @@ a host-structure or string." (type string namestr) (type index start) (type (or index null) end)) - (if junk-allowed - (handler-case - (%parse-namestring namestr host defaults start end nil) - (namestring-parse-error (condition) - (values nil (namestring-parse-error-offset condition)))) - (let* ((end (or end (length namestr))) - (parse-host (or host - (extract-logical-host-prefix namestr start end) - (pathname-host defaults)))) - (unless parse-host - (error "When no HOST argument is supplied, the DEFAULTS argument ~ - must have a non-null PATHNAME-HOST.")) - - (multiple-value-bind (new-host device directory file type version) - (funcall (host-parse parse-host) namestr start end) - (when (and host new-host (not (eq new-host host))) - (error 'simple-type-error - :datum new-host - ;; Note: ANSI requires that this be a TYPE-ERROR, - ;; but there seems to be no completely correct - ;; value to use for TYPE-ERROR-EXPECTED-TYPE. - ;; Instead, we return a sort of "type error allowed - ;; type", trying to say "it would be OK if you - ;; passed NIL as the host value" but not mentioning - ;; that a matching string would be OK too. - :expected-type 'null - :format-control - "The host in the namestring, ~S,~@ - does not match the explicit HOST argument, ~S." - :format-arguments (list new-host host))) - (let ((pn-host (or new-host parse-host))) - (values (%make-maybe-logical-pathname - pn-host device directory file type version) - end)))))) + (cond + (junk-allowed + (handler-case + (%parse-namestring namestr host defaults start end nil) + (namestring-parse-error (condition) + (values nil (namestring-parse-error-offset condition))))) + (t + (let* ((end (%check-vector-sequence-bounds namestr start end))) + (multiple-value-bind (new-host device directory file type version) + ;; Comments below are quotes from the HyperSpec + ;; PARSE-NAMESTRING entry, reproduced here to demonstrate + ;; that we actually have to do things this way rather than + ;; some possibly more logical way. - CSR, 2002-04-18 + (cond + ;; "If host is a logical host then thing is parsed as a + ;; logical pathname namestring on the host." + (host (funcall (host-parse host) namestr start end)) + ;; "If host is nil and thing is a syntactically valid + ;; logical pathname namestring containing an explicit + ;; host, then it is parsed as a logical pathname + ;; namestring." + ((parseable-logical-namestring-p namestr start end) + (parse-logical-namestring namestr start end)) + ;; "If host is nil, default-pathname is a logical + ;; pathname, and thing is a syntactically valid logical + ;; pathname namestring without an explicit host, then it + ;; is parsed as a logical pathname namestring on the + ;; host that is the host component of default-pathname." + ;; + ;; "Otherwise, the parsing of thing is + ;; implementation-defined." + ;; + ;; Both clauses are handled here, as the default + ;; *DEFAULT-PATHNAME-DEFAULTS has a SB-IMPL::UNIX-HOST + ;; for a host. + ((pathname-host defaults) + (funcall (host-parse (pathname-host defaults)) + namestr + start + end)) + ;; I don't think we should ever get here, as the default + ;; host will always have a non-null HOST, given that we + ;; can't create a new pathname without going through + ;; *DEFAULT-PATHNAME-DEFAULTS*, which has a non-null + ;; host... + (t (bug "Fallen through COND in %PARSE-NAMESTRING"))) + (when (and host new-host (not (eq new-host host))) + (error 'simple-type-error + :datum new-host + ;; Note: ANSI requires that this be a TYPE-ERROR, + ;; but there seems to be no completely correct + ;; value to use for TYPE-ERROR-EXPECTED-TYPE. + ;; Instead, we return a sort of "type error allowed + ;; type", trying to say "it would be OK if you + ;; passed NIL as the host value" but not mentioning + ;; that a matching string would be OK too. + :expected-type 'null + :format-control + "The host in the namestring, ~S,~@ + does not match the explicit HOST argument, ~S." + :format-arguments (list new-host host))) + (let ((pn-host (or new-host host (pathname-host defaults)))) + (values (%make-maybe-logical-pathname + pn-host device directory file type version) + end))))))) ;;; If NAMESTR begins with a colon-terminated, defined, logical host, ;;; then return that host, otherwise return NIL. @@ -653,9 +716,8 @@ a host-structure or string." host (defaults *default-pathname-defaults*) &key (start 0) end junk-allowed) - (declare (type pathname-designator thing) + (declare (type pathname-designator thing defaults) (type (or list host string (member :unspecific)) host) - (type pathname defaults) (type index start) (type (or index null) end) (type (or t null) junk-allowed) @@ -685,6 +747,12 @@ a host-structure or string." ;; A logical host is an object of implementation-dependent nature. In ;; SBCL, it's a member of the HOST class (a subclass of STRUCTURE-OBJECT). (let ((found-host (etypecase host + ((string 0) + ;; This is a special host. It's not valid as a + ;; logical host, so it is a sensible thing to + ;; designate the physical Unix host object. So + ;; we do that. + *unix-host*) (string ;; In general ANSI-compliant Common Lisps, a ;; string might also be a physical pathname host, @@ -706,8 +774,18 @@ a host-structure or string." supported in this implementation:~% ~S" host)) (host - host)))) - (declare (type (or null host) found-host)) + host))) + ;; According to ANSI defaults may be any valid pathname designator + (defaults (etypecase defaults + (pathname + defaults) + (string + (aver (pathnamep *default-pathname-defaults*)) + (parse-namestring defaults)) + (stream + (truename defaults))))) + (declare (type (or null host) found-host) + (type pathname defaults)) (etypecase thing (simple-string (%parse-namestring thing found-host defaults start end junk-allowed)) @@ -732,21 +810,19 @@ a host-structure or string." (defun namestring (pathname) #!+sb-doc "Construct the full (name)string form of the pathname." - (declare (type pathname-designator pathname) - (values (or null simple-base-string))) + (declare (type pathname-designator pathname)) (with-pathname (pathname pathname) (when pathname (let ((host (%pathname-host pathname))) (unless host (error "can't determine the namestring for pathnames with no ~ - host:~% ~S" pathname)) + host:~% ~S" pathname)) (funcall (host-unparse host) pathname))))) (defun host-namestring (pathname) #!+sb-doc - "Returns a string representation of the name of the host in the pathname." - (declare (type pathname-designator pathname) - (values (or null simple-base-string))) + "Return a string representation of the name of the host in the pathname." + (declare (type pathname-designator pathname)) (with-pathname (pathname pathname) (let ((host (%pathname-host pathname))) (if host @@ -757,9 +833,8 @@ a host-structure or string." (defun directory-namestring (pathname) #!+sb-doc - "Returns a string representation of the directories used in the pathname." - (declare (type pathname-designator pathname) - (values (or null simple-base-string))) + "Return a string representation of the directories used in the pathname." + (declare (type pathname-designator pathname)) (with-pathname (pathname pathname) (let ((host (%pathname-host pathname))) (if host @@ -770,9 +845,8 @@ a host-structure or string." (defun file-namestring (pathname) #!+sb-doc - "Returns a string representation of the name used in the pathname." - (declare (type pathname-designator pathname) - (values (or null simple-base-string))) + "Return a string representation of the name used in the pathname." + (declare (type pathname-designator pathname)) (with-pathname (pathname pathname) (let ((host (%pathname-host pathname))) (if host @@ -785,7 +859,7 @@ a host-structure or string." &optional (defaults *default-pathname-defaults*)) #!+sb-doc - "Returns an abbreviated pathname sufficent to identify the pathname relative + "Return an abbreviated pathname sufficent to identify the pathname relative to the defaults." (declare (type pathname-designator pathname)) (with-pathname (pathname pathname) @@ -829,7 +903,7 @@ a host-structure or string." (declare (type pathname-designator in-pathname)) (with-pathname (pathname in-pathname) (with-pathname (wildname in-wildname) - (macrolet ((frob (field &optional (op 'components-match )) + (macrolet ((frob (field &optional (op 'components-match)) `(or (null (,field wildname)) (,op (,field pathname) (,field wildname))))) (and (or (null (%pathname-host wildname)) @@ -838,7 +912,8 @@ a host-structure or string." (frob %pathname-directory directory-components-match) (frob %pathname-name) (frob %pathname-type) - (frob %pathname-version)))))) + (or (eq (%pathname-host wildname) *unix-host*) + (frob %pathname-version))))))) ;;; Place the substitutions into the pattern and return the string or pattern ;;; that results. If DIDDLE-CASE is true, we diddle the result case as well, @@ -862,7 +937,7 @@ a host-structure or string." (setf in-wildcard t) (unless subs (error "not enough wildcards in FROM pattern to match ~ - TO pattern:~% ~S" + TO pattern:~% ~S" pattern)) (let ((sub (pop subs))) (typecase sub @@ -877,7 +952,7 @@ a host-structure or string." (push sub strings)) (t (error "can't substitute this into the middle of a word:~ - ~% ~S" + ~% ~S" sub))))))) (when strings @@ -894,10 +969,11 @@ a host-structure or string." ;;; Called when we can't see how source and from matched. (defun didnt-match-error (source from) (error "Pathname components from SOURCE and FROM args to TRANSLATE-PATHNAME~@ - did not match:~% ~S ~S" + did not match:~% ~S ~S" source from)) -;;; Do TRANSLATE-COMPONENT for all components except host and directory. +;;; Do TRANSLATE-COMPONENT for all components except host, directory +;;; and version. (defun translate-component (source from to diddle-case) (typecase to (pattern @@ -938,7 +1014,7 @@ a host-structure or string." (collect ((subs)) (loop (unless source - (unless (every #'(lambda (x) (eq x :wild-inferiors)) from) + (unless (every (lambda (x) (eq x :wild-inferiors)) from) (didnt-match-error orig-source orig-from)) (subs ()) (return)) @@ -1006,14 +1082,14 @@ a host-structure or string." (let ((match (pop subs-left))) (when (listp match) (error ":WILD-INFERIORS is not paired in from and to ~ - patterns:~% ~S ~S" from to)) + patterns:~% ~S ~S" from to)) (res (maybe-diddle-case match diddle-case)))) ((member :wild-inferiors) (aver subs-left) (let ((match (pop subs-left))) (unless (listp match) (error ":WILD-INFERIORS not paired in from and to ~ - patterns:~% ~S ~S" from to)) + patterns:~% ~S ~S" from to)) (dolist (x match) (res (maybe-diddle-case x diddle-case))))) (pattern @@ -1034,6 +1110,7 @@ a host-structure or string." (with-pathname (from from-wildname) (with-pathname (to to-wildname) (let* ((source-host (%pathname-host source)) + (from-host (%pathname-host from)) (to-host (%pathname-host to)) (diddle-case (and source-host to-host @@ -1053,174 +1130,16 @@ a host-structure or string." (frob %pathname-directory translate-directories) (frob %pathname-name) (frob %pathname-type) - (frob %pathname-version)))))))) - -;;;; search lists - -(def!struct (search-list (:make-load-form-fun - (lambda (s) - (values `(intern-search-list - ',(search-list-name s)) - nil)))) - ;; The name of this search-list. Always stored in lowercase. - (name (required-argument) :type simple-string) - ;; T if this search-list has been defined. Otherwise NIL. - (defined nil :type (member t nil)) - ;; the list of expansions for this search-list. Each expansion is - ;; the list of directory components to use in place of this - ;; search-list. - (expansions nil :type list)) -(def!method print-object ((sl search-list) stream) - (print-unreadable-object (sl stream :type t) - (write-string (search-list-name sl) stream))) - -;;; a hash table mapping search-list names to search-list structures -(defvar *search-lists* (make-hash-table :test 'equal)) - -;;; When search-lists are encountered in namestrings, they are -;;; converted to search-list structures right then, instead of waiting -;;; until the search list used. This allows us to verify ahead of time -;;; that there are no circularities and makes expansion much quicker. -(defun intern-search-list (name) - (let ((name (string-downcase name))) - (or (gethash name *search-lists*) - (let ((new (make-search-list :name name))) - (setf (gethash name *search-lists*) new) - new)))) - -;;; Clear the definition. Note: we can't remove it from the hash-table -;;; because there may be pathnames still refering to it. So we just -;;; clear out the expansions and ste defined to NIL. -(defun clear-search-list (name) - #!+sb-doc - "Clear the current definition for the search-list NAME. Returns T if such - a definition existed, and NIL if not." - (let* ((name (string-downcase name)) - (search-list (gethash name *search-lists*))) - (when (and search-list (search-list-defined search-list)) - (setf (search-list-defined search-list) nil) - (setf (search-list-expansions search-list) nil) - t))) - -;;; As in CLEAR-SEARCH-LIST, we can't actually remove the entries from -;;; the hash-table, so we just mark them as being undefined. -(defun clear-all-search-lists () - #!+sb-doc - "Clear the definition for all search-lists. Only use this if you know - what you are doing." - (maphash #'(lambda (name search-list) - (declare (ignore name)) - (setf (search-list-defined search-list) nil) - (setf (search-list-expansions search-list) nil)) - *search-lists*) - nil) - -;;; Extract the search-list from PATHNAME and return it. If PATHNAME -;;; doesn't start with a search-list, then either error (if -;;; FLAME-IF-NONE is true) or return NIL (if FLAME-IF-NONE is false). -(defun extract-search-list (pathname flame-if-none) - (with-pathname (pathname pathname) - (let* ((directory (%pathname-directory pathname)) - (search-list (cadr directory))) - (cond ((search-list-p search-list) - search-list) - (flame-if-none - (error "~S doesn't start with a search-list." pathname)) - (t - nil))))) - -;;; We have to convert the internal form of the search-list back into -;;; a bunch of pathnames. -(defun search-list (pathname) - #!+sb-doc - "Return the expansions for the search-list starting PATHNAME. If PATHNAME - does not start with a search-list, then an error is signaled. If - the search-list has not been defined yet, then an error is signaled. - The expansion for a search-list can be set with SETF." - (with-pathname (pathname pathname) - (let ((search-list (extract-search-list pathname t)) - (host (pathname-host pathname))) - (if (search-list-defined search-list) - (mapcar #'(lambda (directory) - (make-pathname :host host - :directory (cons :absolute directory))) - (search-list-expansions search-list)) - (error "Search list ~S has not been defined yet." pathname))))) - -(defun search-list-defined-p (pathname) - #!+sb-doc - "Returns T if the search-list starting PATHNAME is currently defined, and - NIL otherwise. An error is signaled if PATHNAME does not start with a - search-list." - (with-pathname (pathname pathname) - (search-list-defined (extract-search-list pathname t)))) - -;;; Set the expansion for the search list in PATHNAME. If this would -;;; result in any circularities, we flame out. If anything goes wrong, -;;; we leave the old definition intact. -(defun %set-search-list (pathname values) - (let ((search-list (extract-search-list pathname t))) - (labels - ((check (target-list path) - (when (eq search-list target-list) - (error "That would result in a circularity:~% ~ - ~A~{ -> ~A~} -> ~A" - (search-list-name search-list) - (reverse path) - (search-list-name target-list))) - (when (search-list-p target-list) - (push (search-list-name target-list) path) - (dolist (expansion (search-list-expansions target-list)) - (check (car expansion) path)))) - (convert (pathname) - (with-pathname (pathname pathname) - (when (or (pathname-name pathname) - (pathname-type pathname) - (pathname-version pathname)) - (error "Search-lists cannot expand into pathnames that have ~ - a name, type, or ~%version specified:~% ~S" - pathname)) - (let ((directory (pathname-directory pathname))) - (let ((expansion - (if directory - (ecase (car directory) - (:absolute (cdr directory)) - (:relative (cons (intern-search-list "default") - (cdr directory)))) - (list (intern-search-list "default"))))) - (check (car expansion) nil) - expansion))))) - (setf (search-list-expansions search-list) - (if (listp values) - (mapcar #'convert values) - (list (convert values))))) - (setf (search-list-defined search-list) t)) - values) - -(defun %enumerate-search-list (pathname function) - (let* ((pathname (physicalize-pathname pathname)) - (search-list (extract-search-list pathname nil))) - (cond - ((not search-list) - (funcall function pathname)) - ((not (search-list-defined search-list)) - (error "undefined search list: ~A" - (search-list-name search-list))) - (t - (let ((tail (cddr (pathname-directory pathname)))) - (dolist (expansion - (search-list-expansions search-list)) - (%enumerate-search-list (make-pathname :defaults pathname - :directory - (cons :absolute - (append expansion - tail))) - function))))))) + (if (eq from-host *unix-host*) + (if (eq (%pathname-version to) :wild) + (%pathname-version from) + (%pathname-version to)) + (frob %pathname-version))))))))) ;;;; logical pathname support. ANSI 92-102 specification. ;;;; ;;;; As logical-pathname translations are loaded they are -;;;; canonicalized as patterns to enable rapid efficent translation +;;;; canonicalized as patterns to enable rapid efficient translation ;;;; into physical pathnames. ;;;; utilities @@ -1229,14 +1148,20 @@ a host-structure or string." ;;; contains only legal characters. (defun logical-word-or-lose (word) (declare (string word)) + (when (string= word "") + (error 'namestring-parse-error + :complaint "Attempted to treat invalid logical hostname ~ + as a logical host:~% ~S" + :args (list word) + :namestring word :offset 0)) (let ((word (string-upcase word))) (dotimes (i (length word)) (let ((ch (schar word i))) (unless (or (alpha-char-p ch) (digit-char-p ch) (char= ch #\-)) (error 'namestring-parse-error :complaint "logical namestring character which ~ - is not alphanumeric or hyphen:~% ~S" - :arguments (list ch) + is not alphanumeric or hyphen:~% ~S" + :args (list ch) :namestring word :offset i)))) word)) @@ -1288,8 +1213,8 @@ a host-structure or string." (when (pattern) (error 'namestring-parse-error :complaint "double asterisk inside of logical ~ - word: ~S" - :arguments (list chunk) + word: ~S" + :args (list chunk) :namestring namestring :offset (+ (cdar chunks) pos))) (pattern (subseq chunk last-pos pos))) @@ -1323,7 +1248,7 @@ a host-structure or string." (unless (member ch '(#\; #\: #\.)) (error 'namestring-parse-error :complaint "illegal character for logical pathname:~% ~S" - :arguments (list ch) + :args (list ch) :namestring namestr :offset i)) (chunks (cons ch i))))) @@ -1343,7 +1268,7 @@ a host-structure or string." (unless (and chunks (simple-string-p (caar chunks))) (error 'namestring-parse-error :complaint "expecting ~A, got ~:[nothing~;~S~]." - :arguments (list what (caar chunks) (caar chunks)) + :args (list what (caar chunks) (caar chunks)) :namestring namestr :offset (if chunks (cdar chunks) end))) (caar chunks)) @@ -1385,7 +1310,7 @@ a host-structure or string." (unless (eql (caar chunks) #\.) (error 'namestring-parse-error :complaint "expecting a dot, got ~S." - :arguments (list (caar chunks)) + :args (list (caar chunks)) :namestring namestr :offset (cdar chunks))) (if type @@ -1407,8 +1332,8 @@ a host-structure or string." (unless (and res (plusp res)) (error 'namestring-parse-error :complaint "expected a positive integer, ~ - got ~S" - :arguments (list str) + got ~S" + :args (list str) :namestring namestr :offset (+ pos (cdar chunks)))) (setq version res))))) @@ -1418,12 +1343,10 @@ a host-structure or string." :namestring namestr :offset (cdadr chunks))))) (parse-host (logical-chunkify namestr start end))) - (values host :unspecific - (and (not (equal (directory)'(:absolute))) - (directory)) - name type version)))) + (values host :unspecific (directory) name type version)))) -;;; We can't initialize this yet because not all host methods are loaded yet. +;;; We can't initialize this yet because not all host methods are +;;; loaded yet. (defvar *logical-pathname-defaults*) (defun logical-pathname (pathspec) @@ -1464,6 +1387,7 @@ a host-structure or string." (defun unparse-logical-piece (thing) (etypecase thing + ((member :wild) "*") (simple-string thing) (pattern (collect ((strings)) @@ -1478,6 +1402,36 @@ a host-structure or string." (t (error "invalid keyword: ~S" piece)))))) (apply #'concatenate 'simple-string (strings)))))) +(defun unparse-logical-file (pathname) + (declare (type pathname pathname)) + (collect ((strings)) + (let* ((name (%pathname-name pathname)) + (type (%pathname-type pathname)) + (version (%pathname-version pathname)) + (type-supplied (not (or (null type) (eq type :unspecific)))) + (version-supplied (not (or (null version) + (eq version :unspecific))))) + (when name + (when (and (null type) (position #\. name :start 1)) + (error "too many dots in the name: ~S" pathname)) + (strings (unparse-logical-piece name))) + (when type-supplied + (unless name + (error "cannot specify the type without a file: ~S" pathname)) + (when (typep type 'simple-base-string) + (when (position #\. type) + (error "type component can't have a #\. inside: ~S" pathname))) + (strings ".") + (strings (unparse-logical-piece type))) + (when version-supplied + (unless type-supplied + (error "cannot specify the version without a type: ~S" pathname)) + (etypecase version + ((member :newest) (strings ".NEWEST")) + ((member :wild) (strings ".*")) + (fixnum (strings ".") (strings (format nil "~D" version)))))) + (apply #'concatenate 'simple-string (strings)))) + ;;; Unparse a logical pathname string. (defun unparse-enough-namestring (pathname defaults) (let* ((path-directory (pathname-directory pathname)) @@ -1502,18 +1456,19 @@ a host-structure or string." ;; DEF-DIRECTORY is :ABSOLUTE, as handled above. so return ;; the original directory. path-directory)))) - (make-pathname :host (pathname-host pathname) - :directory enough-directory - :name (pathname-name pathname) - :type (pathname-type pathname) - :version (pathname-version pathname)))) + (unparse-logical-namestring + (make-pathname :host (pathname-host pathname) + :directory enough-directory + :name (pathname-name pathname) + :type (pathname-type pathname) + :version (pathname-version pathname))))) (defun unparse-logical-namestring (pathname) (declare (type logical-pathname pathname)) (concatenate 'simple-string (logical-host-name (%pathname-host pathname)) ":" (unparse-logical-directory pathname) - (unparse-unix-file pathname))) + (unparse-logical-file pathname))) ;;;; logical pathname translations @@ -1540,8 +1495,7 @@ a host-structure or string." (defun (setf logical-pathname-translations) (translations host) #!+sb-doc - "Set the translations list for the logical host argument. - Return translations." + "Set the translations list for the logical host argument." (declare (type (or string logical-host) host) (type list translations) (values list)) @@ -1567,8 +1521,7 @@ a host-structure or string." (return (translate-logical-pathname (translate-pathname pathname from to))))))) (pathname pathname) - (stream (translate-logical-pathname (pathname pathname))) - (t (translate-logical-pathname (logical-pathname pathname))))) + (t (translate-logical-pathname (pathname pathname))))) (defvar *logical-pathname-defaults* (%make-logical-pathname (make-logical-host :name "BOGUS") @@ -1584,7 +1537,10 @@ a host-structure or string." (values (member t nil))) (if (find-logical-host host nil) ;; This host is already defined, all is well and good. - t + nil ;; ANSI: "The specific nature of the search is ;; implementation-defined." SBCL: doesn't search at all + ;; + ;; FIXME: now that we have a SYS host that the system uses, it + ;; might be cute to search in "SYS:TRANSLATIONS;.LISP" (error "logical host ~S not found" host)))