;;; directories represented as streams ;;; This file is part of the Scheme Untergrund Library. ;;; Copyright (c) 2002-2003 by Martin Gasbichler. ;;; Copyright (c) 2002 by Eric Knauel ;;; Copyright (c) 2002 by Matthias Neubauer ;;; For copyright information, see the file COPYING which comes with ;;; the distribution. ;; dir-stream === ;; (make-dir-stream file-info (stream of file-info) (stream of dir-stream) (define-record-type dir-stream :dir-stream (make-dir-stream dir-info files-stream subdir-stream) dir-stream? (dir-info dir-stream-info) (files-stream dir-stream-files-stream) (subdir-stream dir-stream-subdir-stream)) (define-record-type fs-object :fs-object (really-make-fs-object parent name info) fs-object? (parent fs-object-parent) (name fs-object-name) (info fs-object-info)) (define-record-discloser :fs-object (lambda (r) `(fs-object ,(fs-object-name r) ,(fs-object-parent r)))) (define (make-fs-object parent name chase?) (really-make-fs-object parent name (file-info (combine-path parent name) chase?))) (define (combine-path parent name) (if (string=? parent "") name (string-append parent "/" name))) (define (fs-object-file-name fs-object) (combine-path (fs-object-parent fs-object) (fs-object-name fs-object))) (define (dir-stream-from-dir-name dir-name . args) ;; skip file in case of an error during file-info (define (next-info ds parent dir-name chase?) (let ((file (read-directory-stream ds))) (if file (call-with-current-continuation (lambda (k) (with-handler (lambda (cond more) (k (next-info ds parent dir-name chase?))) (lambda () (cons (make-fs-object (combine-path parent dir-name) file chase?) ds))))) (begin (close-directory-stream ds) #f)))) (let-optionals args ((chase? #t) (parent "")) (let ((info-stream (stream-unfold (lambda (ds) (next-info ds parent dir-name chase?)) (call-with-current-continuation (lambda (k) (with-handler (lambda (cond more) (make-empty-stream)) (lambda () (open-directory-stream (combine-path parent dir-name))))))))) (make-dir-stream (make-fs-object parent dir-name chase?) (stream-filter-map (lambda (fso) (and (not (file-info-dir? (fs-object-info fso))) fso)) info-stream) (stream-filter-map (lambda (fso) (and (file-info-dir? (fs-object-info fso)) (dir-stream-from-dir-name (fs-object-name fso) chase? (fs-object-parent fso)))) info-stream))))) (define (dir-stream-filter ds file-pred dir-pred) (make-dir-stream (dir-stream-info ds) (stream-filter file-pred (dir-stream-files-stream ds)) (stream-filter-map (lambda (subdir) (and (dir-pred (dir-stream-info subdir)) (dir-stream-filter subdir file-pred dir-pred))) (dir-stream-subdir-stream ds)))) ;; dir-stream a b = make-dir-tream a (stream of b) (stream of (dir-stream a b)) ;; dir-stream-fold-right: dir-stream a b -> (a -> c -> d -> e) -> ;; (b -> c -> c) -> c -> ;; (e -> d -> d) -> d -> e ;; Krass Sach!!! (define (dir-stream-fold-right ds make-dir-stream files-make-stream files-stream-empty subdirs-make-stream subdirs-empty) (make-dir-stream (dir-stream-info ds) (stream-fold-right files-make-stream files-stream-empty (dir-stream-files-stream ds)) (stream-fold-right (lambda (subdir accu) (subdirs-make-stream (dir-stream-fold-right subdir make-dir-stream files-make-stream files-stream-empty subdirs-make-stream subdirs-empty) accu)) subdirs-empty (dir-stream-subdir-stream ds)))) ; Example: ; (define (disc-usage ds) ; (dir-stream-fold-right ds (lambda (fso sum subdirs) (list (fs-object-file-name fso) ; (apply + sum (map cadr subdirs)) ; subdirs)) ; (lambda (fso accu) ; (+ accu (file-info:size (fs-object-info fso)))) ; 0 ; cons ; '())) (define (apply-to-dir-stream stream-f) (lambda (ds file-f dir-f) (make-dir-stream (dir-f (dir-stream-info ds)) (stream-f file-f (dir-stream-files-stream ds)) (stream-f (lambda (sub-ds) ((apply-to-dir-stream stream-f) sub-ds file-f dir-f)) (dir-stream-subdir-stream ds))))) (define dir-stream-map (apply-to-dir-stream stream-map)) (define dir-stream-filter-map (apply-to-dir-stream stream-filter-map)) (define (dir-stream-for-each ds file-f dir-f) (dir-f (dir-stream-info ds)) (stream-for-each file-f (dir-stream-files-stream ds)) (stream-for-each (lambda (sub-ds) (dir-stream-for-each sub-ds file-f dir-f)) (dir-stream-subdir-stream ds))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (file-info-dir? fi) (eq? (file-info:type fi) 'directory)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;(filter x file? dir?) -> x ;(define (filter p l) ; (fold-right (lambda (e a) ; (if (p e) ; (cons e a) ; a)) ; '() ; l)) ;(define-structure dir :dir ; (make-dir info files)) ;; dir = (make-dir dir-info (stream of (union file-info dir))) ;(define (dir-filter dir file-pred dir-pred) ; dir -> p1 -> p2 -> dir ; (make-dir ; (dir-info dir) ; (let lp ((stream (dir-files dir))) ; stream -> steam ; (if (stream-empty? stream) ; (make-empty-stream) ; (let ((head (stream-head dir))) ; (cond ((file? head) ; (if (file-pred head) ; (make-stream ; (lambda () head) ; (lambda () (lp (stream-tail stream)))) ; (lp (stream-tail stream)))) ; (else (if (dir-pred (dir-info head)) ; (make-steam ; (lambda () (dir-filter head file-pred dir-pred)) ; (lambda () (lp (steam-tail stream)))) ; (lp (stream-tail stream))))))))))