Changeset 314
- Timestamp:
- Jan 17, 2004, 7:46:12 PM (21 years ago)
- File:
-
- 1 edited
-
trunk/ccl/level-1/l1-files.lisp (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/ccl/level-1/l1-files.lisp
r299 r314 181 181 182 182 183 #|184 (defstruct (pattern185 (:constructor make-pattern (pieces)))186 (pieces nil :type list))187 188 (defmethod make-load-form ((p pattern))189 (make-load-form-saving-slots p))190 191 (defmethod print-object ((p pattern) stream)192 (print-unreadable-object (p stream :type t)193 (let* ((pieces (pattern-pieces p)))194 (if *print-pretty*195 (let ((*print-escape* t))196 (pprint-fill stream pieces nil))197 (prin1 pieces stream)))))198 199 (defvar *ignore-wildcards* nil)200 201 202 (defun remove-backslashes (namestr start end)203 "Remove and occurences of \\ from the string because we've already204 checked for whatever they may have been backslashed."205 (declare (type simple-base-string namestr)206 (type index start end))207 (let* ((result (make-string (- end start) :element-type 'base-char))208 (dst 0)209 (quoted nil))210 (do ((src start (1+ src)))211 ((= src end))212 (cond (quoted213 (setf (schar result dst) (schar namestr src))214 (setf quoted nil)215 (incf dst))216 (t217 (let ((char (schar namestr src)))218 (cond ((char= char #\\)219 (setq quoted t))220 (t221 (setf (schar result dst) char)222 (incf dst)))))))223 (when quoted224 (error 'namestring-parse-error225 :complaint "Backslash in bad place."226 :namestring namestr227 :offset (1- end)))228 (shrink-vector result dst)))229 230 (defun maybe-make-pattern (namestr start end)231 (declare (type simple-base-string namestr)232 (type index start end))233 (if *ignore-wildcards*234 (subseq namestr start end)235 (let* ((pattern ()))236 (let* ((quoted nil)237 (any-quotes nil)238 (last-regular-char nil)239 (index start))240 (flet ((flush-pending-regulars ()241 (when last-regular-char242 (push (if any-quotes243 (remove-backslashes namestr244 last-regular-char245 index)246 (subseq namestr last-regular-char index))247 pattern)248 (setf any-quotes nil)249 (setf last-regular-char nil))))250 (loop251 (when (>= index end)252 (return))253 (let ((char (schar namestr index)))254 (cond (quoted255 (incf index)256 (setf quoted nil))257 ((char= char #\\)258 (setf quoted t)259 (setf any-quotes t)260 (unless last-regular-char261 (setf last-regular-char index))262 (incf index))263 ((char= char #\?)264 (flush-pending-regulars)265 (push :single-char-wild pattern)266 (incf index))267 ((char= char #\*)268 (flush-pending-regulars)269 (push :multi-char-wild pattern)270 (incf index))271 ((char= char #\[)272 (flush-pending-regulars)273 (let ((close-bracket274 (position #\] namestr :start index :end end)))275 (unless close-bracket276 (error 'namestring-parse-error277 :complaint "``['' with no corresponding ``]''"278 :namestring namestr279 :offset index))280 (push (list :character-set281 (subseq namestr282 (1+ index)283 close-bracket))284 pattern)285 (setf index (1+ close-bracket))))286 (t287 (unless last-regular-char288 (setf last-regular-char index))289 (incf index)))))290 (flush-pending-regulars)))291 (cond ((null (setq pattern (nreverse pattern)))292 "")293 ((null (cdr pattern))294 (let ((piece (first pattern)))295 (typecase piece296 ((member :multi-char-wild) :wild)297 (simple-string piece)298 (t299 (make-pattern pattern)))))300 (t301 (make-pattern pattern))))))302 303 (defun extract-name-type-and-version (namestr start end)304 (declare (type simple-base-string namestr)305 (type index start end))306 (let* ((last-dot (position #\. namestr :start (1+ start) :end end307 :from-end t))308 (second-to-last-dot (and last-dot309 (position #\. namestr :start (1+ start)310 :end last-dot :from-end t)))311 (version nil))312 ;; If there is a second-to-last dot, check to see if there is a valid313 ;; version after the last dot.314 (when second-to-last-dot315 (cond ((and (= (+ last-dot 2) end)316 (char= (schar namestr (1+ last-dot)) #\*))317 (setf version :wild))318 ((and (< (1+ last-dot) end)319 (do ((index (1+ last-dot) (1+ index)))320 ((= index end) t)321 (unless (char<= #\0 (schar namestr index) #\9)322 (return nil))))323 (setf version324 (parse-integer namestr :start (1+ last-dot) :end end)))325 (t326 (setf second-to-last-dot nil))))327 (cond (second-to-last-dot328 (values (maybe-make-pattern namestr start second-to-last-dot)329 (maybe-make-pattern namestr330 (1+ second-to-last-dot)331 last-dot)332 version))333 (last-dot334 (values (maybe-make-pattern namestr start last-dot)335 (maybe-make-pattern namestr (1+ last-dot) end)336 version))337 (t338 (values (maybe-make-pattern namestr start end)339 nil340 version)))))341 342 ;;; Take a string and return a list of cons cells that mark the char343 ;;; separated subseq. The first value t if absolute directories location.344 ;;;345 (defun split-at-slashes (namestr start end)346 (declare (type simple-base-string namestr)347 (type index start end))348 (let ((absolute (and (/= start end)349 (char= (schar namestr start) #\/))))350 (when absolute351 (incf start))352 ;; Next, split the remainder into slash seperated chunks.353 (let* ((pieces ()))354 (loop355 (let ((slash (position #\/ namestr :start start :end end)))356 (push (cons start (or slash end)) pieces)357 (unless slash358 (return))359 (setf start (1+ slash))))360 (values absolute (nreverse pieces)))))361 362 (defun parse-unix-namestring (namestr start end)363 (declare (type simple-base-string namestr)364 (type index start end))365 (multiple-value-bind366 (absolute pieces)367 (split-at-slashes namestr start end)368 (multiple-value-bind369 (name type)370 (let* ((tail (car (last pieces)))371 (tail-start (car tail))372 (tail-end (cdr tail)))373 (unless (= tail-start tail-end)374 (setf pieces (butlast pieces))375 (extract-name-type-and-version namestr tail-start tail-end)))376 ;; Now we have everything we want. So return it.377 (values nil ; no host for unix namestrings.378 (let* ((dirs ()))379 (dolist (piece pieces)380 (let* ((piece-start (car piece))381 (piece-end (cdr piece)))382 (unless (= piece-start piece-end)383 (cond ((string= namestr ".." :start1 piece-start384 :end1 piece-end)385 (push :up dirs))386 ((string= namestr "**" :start1 piece-start387 :end1 piece-end)388 (push :wild-inferiors dirs))389 (t390 (push (maybe-make-pattern namestr391 piece-start392 piece-end)393 dirs))))))394 (setq dirs (nreverse dirs))395 (cond (absolute396 (cons :absolute dirs))397 (dirs398 (cons :relative dirs))399 (t400 nil)))401 name402 type403 nil))))404 405 (defun unparse-unix-piece (thing)406 (etypecase thing407 ((member :wild) "*")408 (simple-string409 (let* ((srclen (length thing))410 (dstlen srclen))411 (dotimes (i srclen)412 (case (schar thing i)413 ((#\* #\? #\[)414 (incf dstlen))))415 (let ((result (make-string dstlen :element-type 'base-char))416 (dst 0))417 (dotimes (src srclen)418 (let ((char (schar thing src)))419 (case char420 ((#\* #\? #\[)421 (setf (schar result dst) #\\)422 (incf dst)))423 (setf (schar result dst) char)424 (incf dst)))425 result)))426 (pattern427 (let* ((strings ()))428 (dolist (piece (pattern-pieces thing))429 (etypecase piece430 (simple-string431 (push piece strings))432 (symbol433 (ecase piece434 (:multi-char-wild435 (push "*" strings))436 (:single-char-wild437 (push "?" strings))))438 (cons439 (case (car piece)440 (:character-set441 (push "[" strings)442 (push (cdr piece) strings)443 (push "]" strings))444 (t445 (error "Invalid pattern piece: ~S" piece))))))446 (apply #'concatenate447 'simple-string448 (nreverse strings))))))449 450 (defun unparse-unix-directory-list (directory)451 (declare (type list directory))452 (let* ((pieces ()))453 (when directory454 (ecase (pop directory)455 (:absolute456 (push "/" pieces))457 (:relative458 ;; Nothing special.459 ))460 (dolist (dir directory)461 (typecase dir462 ((member :up)463 (push "../" pieces))464 ((member :back)465 (error ":BACK cannot be represented in namestrings."))466 ((member :wild-inferiors)467 (push "**/" pieces))468 ((or simple-string pattern)469 (push (unparse-unix-piece dir) pieces)470 (push "/" pieces))471 (t472 (error "Invalid directory component: ~S" dir)))))473 (apply #'concatenate 'simple-string (nreverse pieces))))474 475 (defun %pathname-host (pathname)476 (if (logical-pathname-p pathname)477 (%logical-pathname-host pathname)478 :unspecific))479 480 (defun %pathname-version (pathname)481 (if (logical-pathname-p pathname)482 (%logical-pathname-version pathname)483 :newest))484 485 (defun unparse-unix-file (pathname)486 (declare (type pathname pathname))487 (let* ((strings ()))488 (let* ((name (%pathname-name pathname))489 (type (%pathname-type pathname))490 (type-supplied (not (or (null type) (eq type :unspecific))))491 (version (%pathname-version pathname))492 (version-supplied (not (or (null version) (eq version :newest)))))493 (when name494 (push (unparse-unix-piece name) strings))495 (when type-supplied496 (push "." strings)497 (push (unparse-unix-piece type) strings))498 (when version-supplied499 (unless type-supplied500 (error "Cannot specify the version without a type: ~S" pathname))501 (push (if (eq version :wild)502 ".*"503 (format nil ".~D" version))504 strings)))505 (apply #'concatenate 'simple-string (nreverse strings))))506 507 (defun unparse-unix-namestring (pathname)508 (declare (type pathname pathname))509 (concatenate 'simple-string510 (unparse-unix-directory-list (%pathname-directory pathname))511 (unparse-unix-file pathname)))512 513 (defun unparse-logical-piece (thing)514 (etypecase thing515 (simple-string thing)516 (pattern517 (let* ((strings ()))518 (dolist (piece (pattern-pieces thing))519 (etypecase piece520 (simple-string (push piece strings))521 (keyword522 (cond ((eq piece :wild-inferiors)523 (push "**" strings))524 ((eq piece :multi-char-wild)525 (push "*" strings))526 (t (error "Invalid keyword: ~S" piece))))))527 (apply #'concatenate 'simple-string (nreverse strings))))))528 529 (defun unparse-logical-directory (pathname)530 (declare (type pathname pathname))531 (let* ((pieces ()))532 (let ((directory (%pathname-directory pathname)))533 (when directory534 (ecase (pop directory)535 (:absolute) ;; Nothing special.536 (:relative (push ";" pieces)))537 (dolist (dir directory)538 (cond ((or (stringp dir) (pattern-p dir))539 (push (unparse-logical-piece dir) pieces)540 (push ";" pieces))541 ((eq dir :wild)542 (push "*;" pieces))543 ((eq dir :wild-inferiors)544 (push "**;" pieces))545 (t546 (error "Invalid directory component: ~S" dir))))))547 (apply #'concatenate 'simple-string (nreverse pieces))))548 549 (defun unparse-logical-namestring (pathname)550 (declare (type logical-pathname pathname))551 (concatenate 'simple-string552 (%pathname-host pathname) ":"553 (unparse-logical-directory pathname)554 (unparse-unix-file pathname)))555 556 (defun maybe-make-logical-pattern (namestring chunks)557 (let* ((chunk (caar chunks)))558 (let* ((pattern ()))559 (let* ((last-pos 0)560 (len (length chunk)))561 (declare (fixnum last-pos))562 (loop563 (when (= last-pos len) (return))564 (let ((pos (or (position #\* chunk :start last-pos) len)))565 (if (= pos last-pos)566 (when pattern567 (error 'namestring-parse-error568 :complaint "Double asterisk inside of logical ~569 word: ~S"570 :arguments (list chunk)571 :namestring namestring572 :offset (+ (cdar chunks) pos)))573 (push (subseq chunk last-pos pos) pattern))574 (if (= pos len)575 (return)576 (push :multi-char-wild pattern))577 (setq last-pos (1+ pos)))))578 (setq pattern (nreverse pattern))579 (if (cdr pattern)580 (make-pattern pattern)581 (let ((x (car pattern)))582 (if (eq x :multi-char-wild)583 :wild584 x))))))585 586 (defun logical-chunkify (namestr start end)587 (let* ((chunks nil))588 (do ((i start (1+ i))589 (prev 0))590 ((= i end)591 (when (> end prev)592 (push (cons (subseq namestr prev end) prev) chunks)))593 (let ((ch (schar namestr i)))594 (unless (or (alpha-char-p ch) (digit-char-p ch)595 (member ch '(#\- #\*)))596 (when (> i prev)597 (push (cons (subseq namestr prev i) prev) chunks))598 (setq prev (1+ i))599 (unless (member ch '(#\; #\: #\.))600 (error 'namestring-parse-error601 :complaint "Illegal character for logical pathname:~% ~S"602 :arguments (list ch)603 :namestring namestr604 :offset i))605 (push (cons ch i) chunks))))606 (nreverse chunks)))607 608 (defun find-logical-host (hostname &optional (errorp t))609 (let* ((found (%str-assoc hostname %logical-host-translations%)))610 (unless (or found (not errorp))611 (error "Logical host not yet defined: ~S" hostname))612 (car found)))613 614 (defun parse-logical-namestring (namestr start end)615 (declare (type simple-base-string namestr)616 (type index start end))617 (let* ((directory ()))618 (let* ((host nil)619 (name nil)620 (type nil)621 (version nil))622 (labels ((expecting (what chunks)623 (unless (and chunks (simple-string-p (caar chunks)))624 (error 'namestring-parse-error625 :complaint "Expecting ~A, got ~:[nothing~;~S~] ."626 :arguments (list what (caar chunks) (caar chunks))627 :namestring namestr628 :offset (if chunks (cdar chunks) end)))629 (caar chunks))630 (parse-host (chunks)631 (case (caadr chunks)632 (#\:633 (setq host634 (find-logical-host (expecting "a host name" chunks)))635 (parse-relative (cddr chunks)))636 (t637 (parse-relative chunks))))638 (parse-relative (chunks)639 (case (caar chunks)640 (#\;641 (push :relative directory)642 (parse-directory (cdr chunks)))643 (t644 (push :absolute directory) ; Assumption! Maybe revoked later.645 (parse-directory chunks))))646 (parse-directory (chunks)647 (case (caadr chunks)648 (#\;649 (push650 (let ((res (expecting "a directory name" chunks)))651 (cond ((string= res "..") :up)652 ((string= res "**") :wild-inferiors)653 (t654 (maybe-make-logical-pattern namestr chunks))))655 directory)656 (parse-directory (cddr chunks)))657 (t658 (parse-name chunks))))659 (parse-name (chunks)660 (when chunks661 (expecting "a file name" chunks)662 (setq name (maybe-make-logical-pattern namestr chunks))663 (expecting-dot (cdr chunks))))664 (expecting-dot (chunks)665 (when chunks666 (unless (eql (caar chunks) #\.)667 (error 'namestring-parse-error668 :complaint "Expecting a dot, got ~S."669 :arguments (list (caar chunks))670 :namestring namestr671 :offset (cdar chunks)))672 (if type673 (parse-version (cdr chunks))674 (parse-type (cdr chunks)))))675 (parse-type (chunks)676 (expecting "a file type" chunks)677 (setq type (maybe-make-logical-pattern namestr chunks))678 (expecting-dot (cdr chunks)))679 (parse-version (chunks)680 (let ((str (expecting "a positive integer, * or NEWEST"681 chunks)))682 (cond683 ((string= str "*") (setq version :wild))684 ((string= str "NEWEST") (setq version :newest))685 (t686 (multiple-value-bind687 (res pos)688 (parse-integer str :junk-allowed t)689 (unless (and res (plusp res))690 (error 'namestring-parse-error691 :complaint "Expected a positive integer, ~692 got ~S"693 :arguments (list str)694 :namestring namestr695 :offset (+ pos (cdar chunks))))696 (setq version res)))))697 (when (cdr chunks)698 (error 'namestring-parse-error699 :complaint "Extra stuff after end of file name."700 :namestring namestr701 :offset (cdadr chunks)))))702 (parse-host (logical-chunkify namestr start end)))703 (setq directory (nreverse directory))704 (values host705 (and (not (equal directory '(:absolute)))directory)706 name type version))))707 708 (defun extract-logical-host-prefix (namestr start end)709 (declare (type simple-base-string namestr)710 (type index start end)711 (values (or logical-host null)))712 (let ((colon-pos (position #\: namestr :start start :end end)))713 (if colon-pos714 (%str-assoc (subseq namestr start colon-pos)715 %logical-host-translations%)716 nil)))717 718 (defun %parse-namestring (namestr host defaults start end junk-allowed)719 (declare (type string namestr)720 (type index start) (type (or index null) end))721 (if junk-allowed722 (handler-case723 (%parse-namestring namestr host defaults start end nil)724 (namestring-parse-error (condition)725 (values nil (namestring-parse-error-offset condition))))726 (let* ((end (or end (length namestr)))727 (logical-host (car (extract-logical-host-prefix namestr start end)))728 (parse-host (or host logical-host (pathname-host defaults))))729 (unless parse-host730 (error "When Host arg is not supplied, Defaults arg must ~731 have a non-null PATHNAME-HOST."))732 (if (eq host :unspecific)733 (setq host nil))734 (setq host (or host logical-host))735 (multiple-value-bind736 (new-host directory name type version)737 (if host738 (parse-logical-namestring namestr start end)739 (parse-unix-namestring namestr start end))740 (when (and host new-host (not (equal new-host host)))741 (error "Host in namestring: ~S~@742 does not match explicit host argument: ~S"743 (subseq namestr start end)744 host))745 (cons-pathname directory name type host version)))))746 747 748 (defun parse-namestring (thing749 &optional host (defaults *default-pathname-defaults*)750 &key (start 0) end junk-allowed)751 (declare (type pathname defaults)752 (type index start)753 (type (or index null) end)754 (type (or t null) junk-allowed)755 (values (or null pathname) (or null index)))756 (typecase thing757 (simple-string758 (%parse-namestring thing host defaults start end junk-allowed))759 (string760 (%parse-namestring (coerce thing 'simple-string)761 host defaults start end junk-allowed))762 (pathname763 (let ((host (if host host (%pathname-host defaults))))764 (unless (equal host (%pathname-host thing))765 (error "Hosts do not match: ~S and ~S."766 host (%pathname-host thing))))767 (values thing start))768 (stream769 (let ((name (stream-pathname thing)))770 (unless name771 (error "Can't figure out the file associated with stream:~% ~S"772 thing))773 name))))774 775 (defun namestring (path &key)776 (typecase path777 (logical-pathname (unparse-logical-namestring path))778 (pathname (unparse-unix-namestring path))779 (t (namestring (pathname path)))))780 781 |#782 783 183 ;; The following assumptions are deeply embedded in all our pathname code: 784 184 ;; (1) Non-logical pathname host is always :unspecific. … … 842 242 dirlist) 843 243 844 ; ? is (:absolute "a" :up "b") = (:absolute "b") - seems reasonable845 244 ; destructively mungs dir 846 245 (defun remove-up (dir) … … 938 337 ((nil :unspecific) "") 939 338 (:wild "*") 940 (t name))339 (t (%path-std-quotes name nil "."))) 941 340 (if (or type version) 942 341 (%str-cat (case type 943 342 ((nil) ".") 944 343 (:wild ".*") 945 (t (%str-cat "." type)))344 (t (%str-cat "." (%path-std-quotes type nil ".")))) 946 345 (case version 947 346 ((nil) "") … … 1098 497 (unless directory-p '(:absolute))) 1099 498 name type host version))) 499 (when (and (eq (car directory) :absolute) 500 (member (cadr directory) '(:up :back))) 501 (error 'simple-file-error :pathname path :error-type "Second element of absolute directory component in ~s is ~s" :format-arguments (list (cadr directory)))) 502 (let* ((after-wif (cadr (member :wild-inferiors directory)))) 503 (when (member after-wif '(:up :back)) 504 (error 'simple-file-error :pathname path :error-type "Directory component in ~s contains :WILD-INFERIORS followed by ~s" :format-arguments (list after-wif)))) 505 1100 506 (when (and case (neq case :local)) 1101 507 (setf (%pathname-directory path) (%reverse-component-case (%pathname-directory path) case)
Note:
See TracChangeset
for help on using the changeset viewer.
