(defun directory-pathname-p (p)

(and

(not (component-present-p (pathname-name p)))

(not (component-present-p (pathname-type p)))

p))

(defun pathname-as-directory (name)

(let ((pathname (pathname name)))

(when (wild-pathname-p pathname)

(error 'Can't reliably convert wild pathnames.'))

(if (not (directory-pathname-p name))

(make-pathname

:directory (append (or (pathname-directory pathname) (list :relative))

(list (file-namestring pathname)))

:name nil

:type nil

:defaults pathname)

pathname)))

Now it seems you could generate a wild pathname to pass to DIRECTORY by calling MAKE-PATHNAME with a directory form name returned by pathname-as-directory. Unfortunately, it's not quite that simple, thanks to a quirk in CLISP's implementation of DIRECTORY. In CLISP, DIRECTORY won't return files with no extension unless the type component of the wildcard is NIL rather than :wild. So you can define a function, directory-wildcard, that takes a pathname in either directory or file form and returns a proper wildcard for the given implementation using read-time conditionalization to make a pathname with a :wild type component in all implementations except for CLISP and NIL in CLISP.

(defun directory-wildcard (dirname)

(make-pathname

:name :wild

:type #-clisp :wild #+clisp nil

:defaults (pathname-as-directory dirname)))

Note how each read-time conditional operates at the level of a single expression After #-clisp, the expression :wild is either read or skipped; likewise, after #+clisp, the NIL is read or skipped.

Now you can take a first crack at the list-directory function.

(defun list-directory (dirname)

(when (wild-pathname-p dirname)

(error 'Can only list concrete directory names.'))

(directory (directory-wildcard dirname)))

As it stands, this function would work in SBCL, CMUCL, and LispWorks. Unfortunately, a couple more implementation differences remain to be smoothed over. One is that not all implementations will return subdirectories of the given directory. Allegro, SBCL, CMUCL, and LispWorks do. OpenMCL doesn't by default but will if you pass DIRECTORY a true value via the implementation-specific keyword argument :directories. CLISP's DIRECTORY returns subdirectories only when it's passed a wildcard pathname with :wild as the last element of the directory component and NIL name and type components. In this case, it returns only subdirectories, so you'll need to call DIRECTORY twice with different wildcards and combine the results.

Once you get all the implementations returning directories, you'll discover they can also differ in whether they return the names of directories in directory or file form. You want list-directory to always return directory names in directory form so you can differentiate subdirectories from regular files based on just the name. Except for Allegro, all the implementations this library will support do that. Allegro, on the other hand, requires you to pass DIRECTORY the implementation-specific keyword argument :directories-are-files NIL to get it to return directories in file form.

Once you know how to make each implementation do what you want, actually writing list- directory is simply a matter of combining the different versions using read-time conditionals.

(defun list-directory (dirname)

(when (wild-pathname-p dirname)

(error 'Can only list concrete directory names.'))

(let ((wildcard (directory-wildcard dirname)))

#+(or sbcl cmu lispworks)

(directory wildcard)

#+openmcl

(directory wildcard :directories t)

#+allegro

(directory wildcard :directories-are-files nil)

#+clisp

(nconc

(directory wildcard)

(directory (clisp-subdirectories-wildcard wildcard)))

#-(or sbcl cmu lispworks openmcl allegro clisp)

(error 'list-directory not implemented')))

The function clisp-subdirectories-wildcard isn't actually specific to CLISP, but since it isn't needed by any other implementation, you can guard its definition with a read-time conditional. In this case, since the expression following the #+ is the whole DEFUN, the whole function definition will be included or not, depending on whether clisp is present in *FEATURES*.

#+clisp

(defun clisp-subdirectories-wildcard (wildcard)

(make-pathname

:directory (append (pathname-directory wildcard) (list :wild))

:name nil

:type nil

:defaults wildcard))

Testing a File's Existence

To replace PROBE-FILE, you can define a function called file-

Вы читаете Practical Common Lisp
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату