source: trunk/src/external/pathnames.lisp

Last change on this file was 2, checked in by cludwig, 15 years ago

initial upload of isidorus

  • Property svn:eol-style set to native
File size: 7.7 KB
Line 
1;; code taken from Peter Seibel's practicals-1.0.3.tar.gz (http://www.gigamonkeys.com/book/)
2;; in accordance to its license, cf. isidorus/src/externals/PRACTICALS_LICENSE.
3
4(in-package #:com.gigamonkeys.pathnames)
5
6(defun list-directory (dirname)
7  "Return a list of the contents of the directory named by dirname.
8Names of subdirectories will be returned in `directory normal
9form'. Unlike CL:DIRECTORY, LIST-DIRECTORY does not accept
10wildcard pathnames; `dirname' should simply be a pathname that
11names a directory. It can be in either file or directory form."
12  (when (wild-pathname-p dirname)
13    (error "Can only list concrete directory names."))
14
15  (let ((wildcard (directory-wildcard dirname)))
16
17    #+(or sbcl cmu lispworks)
18    ;; SBCL, CMUCL, and Lispworks return subdirectories in directory
19    ;; form just the way we want.
20    (directory wildcard)
21   
22    #+openmcl
23    ;; OpenMCl by default doesn't return subdirectories at all. But
24    ;; when prodded to do so with the special argument :directories,
25    ;; it returns them in directory form.
26    (directory wildcard :directories t)
27           
28    #+allegro
29    ;; Allegro normally return directories in file form but we can
30    ;; change that with the :directories-are-files argument.
31    (directory wildcard :directories-are-files nil)
32           
33    #+clisp
34    ;; CLISP has a particularly idiosyncratic view of things. But we
35    ;; can bludgeon even it into doing what we want.
36    (nconc 
37     ;; CLISP won't list files without an extension when :type is
38     ;; wild so we make a special wildcard for it.
39     (directory wildcard)
40     ;; And CLISP doesn't consider subdirectories to match unless
41     ;; there is a :wild in the directory component.
42     (directory (clisp-subdirectories-wildcard wildcard)))
43
44    #-(or sbcl cmu lispworks openmcl allegro clisp)
45    (error "list-directory not implemented")))
46
47
48
49
50(defun file-exists-p (pathname)
51  "Similar to CL:PROBE-FILE except it always returns directory names
52in `directory normal form'. Returns truename which will be in
53`directory form' if file named is, in fact, a directory."
54
55  #+(or sbcl lispworks openmcl)
56  ;; These implementations do "The Right Thing" as far as we are
57  ;; concerned. They return a truename of the file or directory if it
58  ;; exists and the truename of a directory is in directory normal
59  ;; form.
60  (probe-file pathname)
61
62  #+(or allegro cmu)
63  ;; These implementations accept the name of a directory in either
64  ;; form and return the name in the form given. However the name of a
65  ;; file must be given in file form. So we try first with a directory
66  ;; name which will return NIL if either the file doesn't exist at
67  ;; all or exists and is not a directory. Then we try with a file
68  ;; form name.
69  (or (probe-file (pathname-as-directory pathname))
70      (probe-file pathname))
71
72  #+clisp
73  ;; Once again CLISP takes a particularly unforgiving approach,
74  ;; signalling ERRORs at the slightest provocation.
75
76  ;; pathname in file form and actually a file      -- (probe-file file)      ==> truename
77  ;; pathname in file form and doesn't exist        -- (probe-file file)      ==> NIL
78  ;; pathname in dir form and actually a directory  -- (probe-directory file) ==> truename
79  ;; pathname in dir form and doesn't exist         -- (probe-directory file) ==> NIL
80
81  ;; pathname in file form and actually a directory -- (probe-file file)      ==> ERROR
82  ;; pathname in dir form and actually a file       -- (probe-directory file) ==> ERROR
83  (or (ignore-errors
84        ;; PROBE-FILE will return the truename if file exists and is a
85        ;; file or NIL if it doesn't exist at all. If it exists but is
86        ;; a directory PROBE-FILE will signal an error which we
87        ;; ignore.
88        (probe-file (pathname-as-file pathname)))
89      (ignore-errors
90        ;; PROBE-DIRECTORY returns T if the file exists and is a
91        ;; directory or NIL if it doesn't exist at all. If it exists
92        ;; but is a file, PROBE-DIRECTORY will signal an error.
93        (let ((directory-form (pathname-as-directory pathname)))
94          (when (ext:probe-directory directory-form)
95            directory-form))))
96
97
98    #-(or sbcl cmu lispworks openmcl allegro clisp)
99    (error "list-directory not implemented"))
100
101(defun directory-wildcard (dirname)
102  (make-pathname 
103   :name :wild
104   :type #-clisp :wild #+clisp nil
105   :defaults (pathname-as-directory dirname)))
106
107#+clisp
108(defun clisp-subdirectories-wildcard (wildcard)
109  (make-pathname
110   :directory (append (pathname-directory wildcard) (list :wild))
111   :name nil
112   :type nil
113   :defaults wildcard))
114
115
116(defun directory-pathname-p (p)
117  "Is the given pathname the name of a directory? This function can
118usefully be used to test whether a name returned by LIST-DIRECTORIES
119or passed to the function in WALK-DIRECTORY is the name of a directory
120in the file system since they always return names in `directory normal
121form'."
122  (flet ((component-present-p (value)
123           (and value (not (eql value :unspecific)))))
124    (and 
125     (not (component-present-p (pathname-name p)))
126     (not (component-present-p (pathname-type p)))
127     p)))
128
129
130(defun file-pathname-p (p)
131  (unless (directory-pathname-p p) p))
132
133(defun pathname-as-directory (name)
134  "Return a pathname reperesenting the given pathname in
135`directory normal form', i.e. with all the name elements in the
136directory component and NIL in the name and type components. Can
137not be used on wild pathnames because there's not portable way to
138convert wildcards in the name and type into a single directory
139component. Returns its argument if name and type are both nil or
140:unspecific."
141  (let ((pathname (pathname name)))
142    (when (wild-pathname-p pathname)
143      (error "Can't reliably convert wild pathnames."))
144    (if (not (directory-pathname-p name))
145      (make-pathname 
146       :directory (append (or (pathname-directory pathname) (list :relative))
147                          (list (file-namestring pathname)))
148       :name      nil
149       :type      nil
150       :defaults pathname)
151      pathname)))
152
153(defun pathname-as-file (name)
154  "Return a pathname reperesenting the given pathname in `file form',
155i.e. with the name elements in the name and type component. Can't
156convert wild pathnames because of problems mapping wild directory
157component into name and type components. Returns its argument if
158it is already in file form."
159  (let ((pathname (pathname name)))
160    (when (wild-pathname-p pathname)
161      (error "Can't reliably convert wild pathnames."))
162    (if (directory-pathname-p name)
163      (let* ((directory (pathname-directory pathname))
164             (name-and-type (pathname (first (last directory)))))
165        (make-pathname 
166         :directory (butlast directory)
167         :name (pathname-name name-and-type)
168         :type (pathname-type name-and-type)
169         :defaults pathname))
170      pathname)))
171
172(defun walk-directory (dirname fn &key directories (test (constantly t)))
173  "Walk a directory invoking `fn' on each pathname found. If `test' is
174supplied fn is invoked only on pathnames for which `test' returns
175true. If `directories' is t invokes `test' and `fn' on directory
176pathnames as well."
177  (labels
178      ((walk (name)
179         (cond
180           ((directory-pathname-p name)
181            (when (and directories (funcall test name))
182              (funcall fn name))
183            (dolist (x (list-directory name)) (walk x)))
184           ((funcall test name) (funcall fn name)))))
185    (walk (pathname-as-directory dirname))))
186
187(defun directory-p (name)
188  "Is `name' the name of an existing directory."
189  (let ((truename (file-exists-p name)))
190    (and truename (directory-pathname-p name))))
191
192(defun file-p (name)
193  "Is `name' the name of an existing file, i.e. not a directory."
194  (let ((truename (file-exists-p name)))
195    (and truename (file-pathname-p name))))
196
197
Note: See TracBrowser for help on using the repository browser.