From: ·············@gmail.com
Subject: Simple question about directories
Date: 
Message-ID: <1188385324.814407.3040@22g2000hsm.googlegroups.com>
I can't figure this out, even reading the hyperspec or searching this
group. I know the answer is probably simple... anyway, here's the
question:

I have a pathname object specifiying a directory (e.g. "/home/
alessio/"). Suppose I want to obtain from it a new pathname object
representing a subdirectory (e.g. "/home/alessio/lisp/"). Is there a
good, portable way of doing this?

I'm aware of various examples of code to portably list all
subdirectories of a given dir. But if I understand correctly the
directory component of a pathname can be an implementation- and os-
dependent string identifying the directory, as such it can contain,
besides the directory name, other things like pathname separators,
parent directories etc. so it's not feasible to portably extract from
it the actual directory name. Am I complicating things more than it's
needed?

Thanks for any help...
Alessio S.

From: John Thingstad
Subject: Re: Simple question about directories
Date: 
Message-ID: <op.txtixdxypqzri1@pandora.upc.no>
P� Wed, 29 Aug 2007 13:02:04 +0200, skrev <·············@gmail.com>:

> I can't figure this out, even reading the hyperspec or searching this
> group. I know the answer is probably simple... anyway, here's the
> question:
>
> I have a pathname object specifiying a directory (e.g. "/home/
> alessio/"). Suppose I want to obtain from it a new pathname object
> representing a subdirectory (e.g. "/home/alessio/lisp/"). Is there a
> good, portable way of doing this?
>
> I'm aware of various examples of code to portably list all
> subdirectories of a given dir. But if I understand correctly the
> directory component of a pathname can be an implementation- and os-
> dependent string identifying the directory, as such it can contain,
> besides the directory name, other things like pathname separators,
> parent directories etc. so it's not feasible to portably extract from
> it the actual directory name. Am I complicating things more than it's
> needed?
>
> Thanks for any help...
> Alessio S.
>

merge-pathnames

example:


(defconstant *my-documents*
   (make-pathname
    :directory
    (pathname-directory
     (concatenate 'string
                  (ppcre:regex-replace-all
                   "\\"
                   (sys:get-folder-path :my-documents)  "/")
                  "/")))) ;; sys:get-folder-path is spesifice to LispWorks  
on Mac/Windows
(defconstant *blog-path*
   (merge-pathnames
    (make-pathname :directory '(:relative "Lisp Programs" "Blog"))
    *my-documents*))
(defconstant *blog-static-dir*
   (merge-pathnames
    (make-pathname :directory '(:relative "static-files"))
    *blog-path*))
(defconstant *log-file*
   (merge-pathnames
    (make-pathname :directory '(:relative "log") :name  "log")
    *blog-path*))
From: John Thingstad
Subject: Re: Simple question about directories
Date: 
Message-ID: <op.txti1xukpqzri1@pandora.upc.no>
P� Wed, 29 Aug 2007 13:16:15 +0200, skrev John Thingstad  
<··············@chello.no>:

use +name+ for constants not *name* which is better for global variables.
From: Rainer Joswig
Subject: Re: Simple question about directories
Date: 
Message-ID: <joswig-C3A50B.13580729082007@news-europe.giganews.com>
In article <······················@22g2000hsm.googlegroups.com>,
 ·············@gmail.com wrote:

> I can't figure this out, even reading the hyperspec or searching this
> group. I know the answer is probably simple... anyway, here's the
> question:
> 
> I have a pathname object specifiying a directory (e.g. "/home/
> alessio/"). Suppose I want to obtain from it a new pathname object
> representing a subdirectory (e.g. "/home/alessio/lisp/"). Is there a
> good, portable way of doing this?

I use this:


(let ((pathname (pathname "rj:>joswig>")))
    (make-pathname :defaults pathname
                   :directory (append (pathname-directory pathname)
                                      (list "lisp"))))

#P"RJ:>joswig>lisp>"

You can easily make it a utility function...


> 
> I'm aware of various examples of code to portably list all
> subdirectories of a given dir. But if I understand correctly the
> directory component of a pathname can be an implementation- and os-
> dependent string identifying the directory, as such it can contain,
> besides the directory name, other things like pathname separators,
> parent directories etc. so it's not feasible to portably extract from
> it the actual directory name. Am I complicating things more than it's
> needed?
> 
> Thanks for any help...
> Alessio S.

-- 
http://lispm.dyndns.org
From: ·············@gmail.com
Subject: Re: Simple question about directories
Date: 
Message-ID: <1188390075.149981.239820@r34g2000hsd.googlegroups.com>
Thank you both, John and Rainer. It turned out that I was
misinterpreting the hyperspec where it says that the directory
component of a pathname can be a string. I thought it could be a
string specifying an os-dependent path, e.g. "/home/alessio/", while
the hyperspec clearly states that strings in the directory component
name "a single level of directory structure". I'll double-read it the
next time :)

Cheers
Alessio
From: Richard M Kreuter
Subject: Re: Simple question about directories
Date: 
Message-ID: <87wsvecd05.fsf@progn.net>
·············@gmail.com writes:

> Thank you both, John and Rainer. It turned out that I was
> misinterpreting the hyperspec where it says that the directory
> component of a pathname can be a string. I thought it could be a
> string specifying an os-dependent path, e.g. "/home/alessio/", while
> the hyperspec clearly states that strings in the directory component
> name "a single level of directory structure". I'll double-read it the
> next time :)

(This post might be overkill for somebody who hasn't stared at chapter
19 for a while.  Apologies in advance.)

ISTM that allowing the directory component to be a non-list was
probably a compatibility sop for some implementations of the day.  In
my opinion this is a fairly grievous bug with precisely one
nonobvious, not-standardly-usable benefit.

The problem is that the spot that you're quoting, 19.2.2.4.3, says
that "The directory might be a string, :wild, :unspecific, or nil",
and so conforming programs must be prepared to cope with such values,
but the spec doesn't really specify what it means for the directory
component to be a string or :WILD, and various undesirable things
follow from this possibility.

Now, the dictionary entry for MAKE-PATHNAME says that specifying a
string str for the directory argument is equivalent to specifying
(:ABSOLUTE str), and so I think we may conclude that MAKE-PATHNAME is
supposed to return pathnames with the directory canonicalized into
lists in such cases, and likewise when MAKE-PATHNAME is called with
:WILD as the directory.  So I think it follows that you can't
explicitly construct a pathname whose directory is a string or :WILD.

But what happens if an implementation hands you a pathname that does
have a string or :WILD in the directory?  (Not every pathname is
necessarily constructed by invocations of MAKE-PATHNAME; for example,
some initial pathname must been constructed specially, because
*DEFAULT-PATHNAME-DEFAULTS* can't have a pathname value if no
pathnames eixst yet.) For one thing, the dictionary entry for
MERGE-PATHNAMES is quite clear that if *P* is a pathname with a string
or :WILD for the directory, then

(pathname-directory
 (merge-pathnames (make-pathname :directory '(:relative "SUBDIR")
                                 :case :common)
                  *p*))
=> (:RELATIVE "SUBDIR")

because MERGE-PATHNAMES's special handling of relative directories is
defined to occur if and only if the first argument's directory is a
list whose car is :RELATIVE and the second argument's directory is a
list.  But then something crazy follows:

(let ((p2 (make-pathname :directory (pathname-directory *p*)
                         :defaults *p*)))
  (pathname-directory
    (merge-pathnames (make-pathname :directory '(:relative "SUBDIR")
                                    :case :common)
                     p2)))
=> (:ABSOLUTE str "SUBDIR") ; or
=> (:ABSOLUTE :WILD "SUBDIR")

That is, *P* and a pathname constructed entirely from *P*'s components
will have different merging properties!

Similarly, :WILD as the whole component leads to a problem with
PATHNAME-MATCH-P:

;; Suppose that *P* is a pathname whose directory is :WILD, and that
;; the file system is hierarchical.
(pathname-match-p (make-pathname :directory (:absolute "FOO" "BAR")
                                 :case :common
                                 :defaults *p*)
                  *p*)
=> T ; justified by 19.2.2.2.2 paragraph 1, for example
(pathname-match-p (make-pathname :directory (:absolute "FOO" "BAR")
                                 :case :common
                                 :defaults *p*)
                  (make-pathname :directory (pathname-directory *p*)
                                 :defaults *p*))
=> NIL ; by 19.2.2.2.2 paragraph 4 and 19.2.2.4.3.

Next, pathnames constructed using such a pathname as the :DEFAULTS and
with no specified directory argument will inherit these merging and
matching properties.  So such directory components can infect
user-constructed pathnames, unless you're careful.

Finally, I can't find anywhere that says that a string str or :WILD in
the directory means that the pathname denotes the same filename or has
the same namestring representation as a pathname with (:ABSOLUTE str)
or (:ABSOLUTE :WILD) for the directory and all other components
equivalent.  So it's not clear what such pathnames are supposed to be
for, other than to give these brain-busting semantics to the pathname
operators (which might actually be their purpose, see [1]).

Consequently, if the implementation ever produces a pathname whose
directory is a string or :WILD, various generally desirable properties
don't hold for the pathname system on that implementation.
Nevertheless, portable programs are probably required to behave as if
all implementations did this, and so are required to check the
directory component of every pathname they come across, if they're to
have predictable merging and matching results everywhere.  (Of course
nobody does this, nor should anybody have to; I'm just noting some
absurd obstacles to writing ANSI-portable programs that work with
files.)

--
RmK

[1] Pathnames are sometimes constructed solely for use as operands to
pathname functions, so maybe pathnames with strings or :WILD in the
directory are supposed to be for that.  For example, one use for a
pathname with :WILD for the whole directory would be for
whole-component matching of directories on file systems that don't
support :WILD-INFERIORS.  But if I'm right that you can't standardly
construct such a pathname, then that an implementation might permit
these kinds of pathnames to exist is fairly pointless.  And in any
case, that still doesn't explain what good a string for the directory
does.
From: Barry Margolin
Subject: Re: Simple question about directories
Date: 
Message-ID: <barmar-F5545E.20260329082007@comcast.dca.giganews.com>
In article <··············@progn.net>,
 Richard M Kreuter <·······@progn.net> wrote:

> ISTM that allowing the directory component to be a non-list was
> probably a compatibility sop for some implementations of the day.

IIRC, directories as lists are for representing paths in hierarchical 
filesystems.  Back when CL was being designed, there were still quite a 
few popular operating systems with flat filesystems, and they were 
expected to use a single string as the directory.  The CL pathname 
system was adapted from the Lisp Machine pathname system, and this was 
probably how it represented those filesystems.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***