Subject: [clisp-list] Re: [ clisp-Bugs-580613 ] directory does not show directories

From: Marco Baringer <[email-masked]>
Date: Sat Jul 13 08:16:02 2002

[note: this was originally posted to clisp-dev via sourceforge's bug
tracker. it's something i took a while to figure out so i figured i'd
share what i found out with CLISP's users.]

> Hi,
> there seems to be no way to get a listing of *all*
> files (which should include directories???) in a
> directory, like I would expect 
> (directory "/") or (directory "/*") to return something
> like
> '("/usr" "/bin" ...)
> 
> [149]> (lisp-implementation-version)
> "2.28 (released 2002-03-03) (built 3232861331) (memory
> 3235285635)"
> [150]> (directory "/")
> (#P"/")
> [151]> (directory "/*")
> (#P"/.journal" #P"/.autofsck" #P"/System.old"
> #P"/vmlinuz.old" #P"/System.map" #P"/vmlinuz"
> #P"/.bash_history")
> [152]> 
> 
> regs,
> Frank.

directory is not a directory listing function, ie it is not ls nor
readdir. it could be called find-me-the-pathnames-which-match-this-one.

The description of #'directory in the HyperSpec reads:

    Determines which, if any, files that are present in the file
  system have names MATCHING PATHSPEC, and returns a fresh list of
  pathnames corresponding to the truenames of those files.

[upcase mine]

with the following note:

    If the pathspec is not wild, the resulting list will contain
  either zero or one elements.

Then there's this taken from src/pathname.d:

# UP: Returns a list of all matching pathnames.
# directory_search(pathname)
# > pathname: pathname with device /= :WILD
#ifdef UNIX
# > STACK_1: Circle-Flag
#endif
# > STACK_0: Full-Flag
# < result:
#     if name=NIL and type=NIL:     list of all matching directories,
#     else (name=NIL -> name=:WILD):  list of all matching files.
#     as absolute pathname without wildcards at a time,

directory_search is used by #'directory to do the actual work.

so basically if we want directories we can't specify a name and a type
part in the pathname, but there's a gotcha: how do we ask for
directories who's names are wild if by specifying a wild name we get
only files? what we need to do is specify a wild not in the name slot,
but in the directory slot.

here's me playing around with directory and make-pathname:

;; just to show what's in the current directory 
[1]> (run-program "ls" :arguments '("-F" "/Users/marco/t"))
onis-0.3.3/
onis-0.3.3.tar
onis-0.3.3.tar.gz
posix.tar.gz
0
;; we ask for all the pathnames with :name :wild and :directory
;; '(:absolute "Users" "marco" "t"). considering we've specified a non
;; wild directory this can only return files
[2]> (directory (make-pathname :directory '(:absolute "Users" "marco" "t") :name :wild))
(#P"/Users/marco/t/posix.tar.gz" #P"/Users/marco/t/onis-0.3.3.tar.gz" #P"/Users/marco/t/onis-0.3.3.tar")
;; we ask for all pathnames with a wild directory part and name and
;; type nil. because of how directory_search works this returns only
;; directories.
[3]> (directory (make-pathname :directory '(:absolute "Users" "marco" "t" "*")))
(#P"/Users/marco/t/onis-0.3.3/")
;; we now ask for for all the pathnames whose directory part contains
;; 4 elements, the last of which is wild and whose name is wild. what
;; get is all the files in the subdirectories of
;; /Users/marco/t. notice how does return the subdirectories
;; themselves or the files in the current directory.
[4]> (directory (make-pathname :directory '(:absolute "Users" "marco" "t" "*") :name "*"))
(#P"/Users/marco/t/onis-0.3.3/timestamp" #P"/Users/marco/t/onis-0.3.3/README" #P"/Users/marco/t/onis-0.3.3/onis"
 #P"/Users/marco/t/onis-0.3.3/html.pm" #P"/Users/marco/t/onis-0.3.3/COPYING" #P"/Users/marco/t/onis-0.3.3/Config.pm"
 #P"/Users/marco/t/onis-0.3.3/config" #P"/Users/marco/t/onis-0.3.3/CHANGELOG")
;; as a final example we ask for all the pathnames whoses directory
;; part contains 5 elements, the final two of which are wild.
[5]> (directory (make-pathname :directory '(:absolute "Users" "marco" "t" "*" "*")))
(#P"/Users/marco/t/onis-0.3.3/plugins/" #P"/Users/marco/t/onis-0.3.3/parser/" #P"/Users/marco/t/onis-0.3.3/images/")

the conclusion is that there is no way to get both files and
directories from a single call to #'directory. if we want all the
"files" (in the modern unix sense of the word) in "/foo" (ie 'ls
/foo') we do:

(append (directory (make-pathname :directory '(:absolute "foo") :name :wild))
        (directory (make-pathname :directory '(:absolute "foo" "*"))))

we can also see why this removes "." and ".." from the results
returned by directory. in the case of :directory '(:absolute "foo"
"*") the . directory is '(:absolute "foo") which having only 2
elements does not match the three element list '(:absolute "foo"
"*"). the .. directory has one less element than . (and so two
elements less than what we pass to #'directory) and so for the same
reason fails to match.

finally, what kind of namestring should we use if we want a wild
directory? to enfore name nil and type nil we need a trailing '/'.

[37]> (equal (parse-namestring "/*/") (make-pathname :directory '(:absolute "*")))
T

so the example above can be rewritten as:

(append (directory #P"/foo/*")
        (directory #P"/foo/*/"))

which is probably what you want.

-- 
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
     -Leonard Cohen

---

From: Sam Steingold <[email-masked]>
Date: Sat Jul 13 16:07:03 2002

> * In message <[email-masked]>
> * On the subject of "[clisp-list] Re: [ clisp-Bugs-580613 ] directory does not show directories"
> * Sent on 13 Jul 2002 17:14:58 +0200
> * Honorable Marco Baringer <[email-masked]> writes:
>

thanks for your message.
I hope I clarified the matters sufficiently in the implementation notes.
<http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/~checkout~/clisp/clisp/doc/impnotes.html?content-type=text/html#dir>

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
(let((a'(list'let(list(list'a(list'quote a)))a)))`(let((a(quote ,a))),a))