[Openmcl-devel] Conformity and convenience problems with pathnames

Pascal J. Bourguignon pjb at informatimago.com
Sat Nov 20 19:31:35 PST 2010


Hello,

It is well known that implementations of CL pathnames have been greatly
implementation dependant.  However, the standard still specifies clear
behavior for logical pathnames, for one thing, and for the other, since
there are several implementations working on the same POSIX systems
(unix including linux and MacOSX; and MS-Windows), it is desirable that
all implementations converge in their handling of pathnames on these
plateforms.

Personnaly, I resolved to use logical pathnames and logical-pathname
translations as much as possible, and to use make-pathname to build
portably physical pathnames. 

However, most implementations have problems dealing with these two
aspects.   To improve the situation, I wrote a little script to check
the behavior of implementations in these two aspects.

The script can be found at:

ftp://ftp.informatimago.com/users/pjb/lisp/check-pathnames.lisp

Since I'm sending a similar message to most implementation  lists, it
might be better, if there is any need for 'language lawyer' discussions,
to direct them to news:comp.lang.lisp.


Here are the results for ccl 1.6 (note: including the patch I sent last week):
------------------------------------------------------------------------
[pjb at kuiper :0.0 lisp]$ ccl --no-init --load  check-pathnames.lisp
check-pathnames of Clozure Common Lisp (Version 1.6-RC1-r14432M  (LinuxX8664))

================================================================================

Test and probe conforming logical pathnames, and their translation to
unix physical pathnames.

We want to check the good working of logical pathnames, and the
translation of logical pathnames to physical pathnames, in a
semi-standard way on unix systems.

Namely, given the logical host and its translations:

  (setf (logical-pathname-translations "LOGICAL") nil)
  (setf (logical-pathname-translations "LOGICAL") 
        '((#P"LOGICAL:**;*.*" #P"/tmp/**/*.*")
          (#P"LOGICAL:**;*"   #P"/tmp/**/*")))

#P"LOGICAL:DIR;SUBDIR;NAME.TYPE.NEWEST"
must be the same as (make-pathname :host "LOGICAL"
                                   :directory '(:absolute "DIR" "SUBDIR")
                                   :name "NAME" :type "TYPE" :version :newest
                                   :case :common)
and must translate to: #P"/tmp/dir/subdir/name.type" on unix.



Merging physical pathnames specified with :case :common is also tested:

  (merge-pathnames (make-pathname :directory '(:relative "DIR" "SUBDIR")
                                  :name "NAME" :type "TYPE" :version :newest
                                  :case :common :default #1=#P"/tmp/")
                    #1# nil)

must give #P"/tmp/dir/subdir/name.type" on unix.

================================================================================



The customary case for the file system of Clozure Common Lisp (Version 
1.6-RC1-r14432M (LinuxX8664)) seems to be lower case.


*FEATURES* = (:PRIMARY-CLASSES :COMMON-LISP :OPENMCL :CCL :CCL-1.2 :CCL-1.3
              :CCL-1.4 :CCL-1.5 :CCL-1.6 :CLOZURE :CLOZURE-COMMON-LISP :ANSI-CL
              :UNIX :OPENMCL-UNICODE-STRINGS :OPENMCL-NATIVE-THREADS
              :OPENMCL-PARTIAL-MOP :MCL-COMMON-MOP-SUBSET :OPENMCL-MOP-2
              :OPENMCL-PRIVATE-HASH-TABLES :X86-64 :X86_64 :X86-TARGET
              :X86-HOST :X8664-TARGET :X8664-HOST :LINUX-HOST :LINUX-TARGET
              :LINUXX86-TARGET :LINUXX8664-TARGET :LINUXX8664-HOST
              :64-BIT-TARGET :64-BIT-HOST :LINUX :LITTLE-ENDIAN-TARGET
              :LITTLE-ENDIAN-HOST)





================================================================================
(MAKE-PATHNAME
  :HOST
  "LOGICAL"
  :DEVICE
  :UNSPECIFIC
  :DIRECTORY
  (:ABSOLUTE "DIR" "SUBDIR")
  :NAME
  "NAME"
  :TYPE
  "TYPE"
  :VERSION
  :NEWEST
  :CASE
  :COMMON)


LOGICAL-PATHNAME #P"LOGICAL:dir;subdir;name.type.newest"
--------------------  :case :local (default)
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "dir" "subdir")
Name      : "name"
Type      : "type"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  
--------------------------------------------------------------------------------
Failed assertion: ((LAMBDA (PRINTED EXPECTED-PRINTED)
                     (FIND-IF (LAMBDA (EXPECTED) (STRING= EXPECTED PRINTED))
                              EXPECTED-PRINTED))
                   #1=(PRIN1-TO-STRING PATH) EXPECTED-PRINTED)
   with: #1# = "#P\"LOGICAL:dir;subdir;name.type.newest\""
    and: EXPECTED-PRINTED = ("#P\"LOGICAL:DIR;SUBDIR;NAME.TYPE\""
                             "#P\"LOGICAL:DIR;SUBDIR;NAME.TYPE.NEWEST\"")

It would be better if logical pathnames were printed using upper case
letters, mostly because of 19.3.1.1.7, and because:

    22.1.1 Overview of The Lisp Printer

    Reading a printed representation typically produces an object that is
    equal to the originally printed object. 

and

    2.4.8.14 Sharpsign P

    #P reads a following object, which must be a string.

    #P<<expression>> is equivalent to #.(parse-namestring '<<expression>>),
    except that #P is not affected by *read-eval*.

and

    Function PARSE-NAMESTRING

    * If host is nil and thing is a syntactically valid logical pathname
      namestring containing an explicit host, then it is parsed as a
      logical pathname namestring.

and

    19.3.1.1.7 Lowercase Letters in a Logical Pathname Namestring
    When parsing words and wildcard-words, lowercase letters are translated to uppercase.

Notice that means that a logical pathname built with mixed cases (or
lower case), cannot be printed readably with a conforming syntax (but
it doesn't matter, since it's not a conforming logical pathname
anyways).
--------------------------------------------------------------------------------
Failed assertion: (STRING= #1=(PATHNAME-HOST PATH :CASE :LOCAL)
                           #2=(POP EXPECTED-VALUES))
   with: #1# = "LOGICAL"
    and: #2# = "logical"
19.2.2.1.2  makes no exception for pathname-host of logical pathnames.



================================================================================
(MAKE-PATHNAME
  :HOST
  "logical"
  :DEVICE
  :UNSPECIFIC
  :DIRECTORY
  (:ABSOLUTE "dir" "subdir")
  :NAME
  "name"
  :TYPE
  "type"
  :VERSION
  :NEWEST
  :CASE
  :LOCAL)


LOGICAL-PATHNAME #P"logical:dir;subdir;name.type.newest"
--------------------  :case :local (default)
Host      : "logical"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "dir" "subdir")
Name      : "name"
Type      : "type"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  
--------------------------------------------------------------------------------
Failed assertion: ((LAMBDA (PRINTED EXPECTED-PRINTED)
                     (FIND-IF (LAMBDA (EXPECTED) (STRING= EXPECTED PRINTED))
                              EXPECTED-PRINTED))
                   #1=(PRIN1-TO-STRING PATH) EXPECTED-PRINTED)
   with: #1# = "#P\"logical:dir;subdir;name.type.newest\""
    and: EXPECTED-PRINTED = ("#P\"LOGICAL:DIR;SUBDIR;NAME.TYPE\""
                             "#P\"LOGICAL:DIR;SUBDIR;NAME.TYPE.NEWEST\"")

It would be better if logical pathnames were printed using upper case
letters, mostly because of 19.3.1.1.7, and because:

    22.1.1 Overview of The Lisp Printer

    Reading a printed representation typically produces an object that is
    equal to the originally printed object. 

and

    2.4.8.14 Sharpsign P

    #P reads a following object, which must be a string.

    #P<<expression>> is equivalent to #.(parse-namestring '<<expression>>),
    except that #P is not affected by *read-eval*.

and

    Function PARSE-NAMESTRING

    * If host is nil and thing is a syntactically valid logical pathname
      namestring containing an explicit host, then it is parsed as a
      logical pathname namestring.

and

    19.3.1.1.7 Lowercase Letters in a Logical Pathname Namestring
    When parsing words and wildcard-words, lowercase letters are translated to uppercase.

Notice that means that a logical pathname built with mixed cases (or
lower case), cannot be printed readably with a conforming syntax (but
it doesn't matter, since it's not a conforming logical pathname
anyways).

--------------------------------------------------------------------------------
Failed assertion: (PATHNAME-EQUAL
                    #1=(LOGICAL-PATHNAME "LOGICAL:dir;subdir;name.type.newest")
                    #2=(LOGICAL-PATHNAME "LOGICAL:DIR;SUBDIR;NAME.TYPE.NEWEST"))
   with: #1# = #P"LOGICAL:dir;subdir;name.type.newest"
    and: #2# = #P"LOGICAL:DIR;SUBDIR;NAME.TYPE.newest"

    19.3.1.1.7 Lowercase Letters in a Logical Pathname Namestring
    When parsing words and wildcard-words, lowercase letters are translated to uppercase.

LOGICAL-PATHNAME #P"LOGICAL:dir;subdir;name.type.newest"
--------------------  :case :local (default)
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "dir" "subdir")
Name      : "name"
Type      : "type"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  

LOGICAL-PATHNAME #P"LOGICAL:DIR;SUBDIR;NAME.TYPE.newest"
--------------------  :case :local (default)
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  
--------------------------------------------------------------------------------
Failed assertion: (PATHNAME-EQUAL
                    #1=#P"LOGICAL:dir;subdir;name.type.newest"
                    #2=#P"LOGICAL:DIR;SUBDIR;NAME.TYPE.newest")
   with: #1# = #1#
    and: #2# = #2#

    2.4.8.14 Sharpsign P

    #P reads a following object, which must be a string.

    #P<<expression>> is equivalent to #.(parse-namestring '<<expression>>),
    except that #P is not affected by *read-eval*.

and

    Function PARSE-NAMESTRING

    * If host is nil and thing is a syntactically valid logical pathname
      namestring containing an explicit host, then it is parsed as a
      logical pathname namestring.

and

    19.3.1.1.7 Lowercase Letters in a Logical Pathname Namestring
    When parsing words and wildcard-words, lowercase letters are translated to uppercase.

LOGICAL-PATHNAME #P"LOGICAL:dir;subdir;name.type.newest"
--------------------  :case :local (default)
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "dir" "subdir")
Name      : "name"
Type      : "type"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  

LOGICAL-PATHNAME #P"LOGICAL:DIR;SUBDIR;NAME.TYPE.newest"
--------------------  :case :local (default)
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  
--------------------------------------------------------------------------------
Failed assertion: (PATHNAME-EQUAL
                    #1=#P"LOGICAL:DIR;SUBDIR;NAME.TYPE.newest"
                    #2=(MAKE-PATHNAME
                         :HOST
                         "LOGICAL"
                         :DEVICE
                         :UNSPECIFIC
                         :DIRECTORY
                         '(:ABSOLUTE "DIR" "SUBDIR")
                         :NAME
                         "NAME"
                         :TYPE
                         "TYPE"
                         :VERSION
                         :NEWEST
                         :CASE
                         :COMMON))
   with: #1# = #1#
    and: #2# = #P"LOGICAL:dir;subdir;name.type.newest"

LOGICAL-PATHNAME #P"LOGICAL:DIR;SUBDIR;NAME.TYPE.newest"
--------------------  :case :local (default)
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  

LOGICAL-PATHNAME #P"LOGICAL:dir;subdir;name.type.newest"
--------------------  :case :local (default)
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "dir" "subdir")
Name      : "name"
Type      : "type"
Version   : :NEWEST
--------------------  :case :common
Host      : "LOGICAL"
Device    : :UNSPECIFIC
Directory : (:ABSOLUTE "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  
--------------------------------------------------------------------------------
Failed assertion: (PATHNAME-EQUAL
                    #1=(TRANSLATE-LOGICAL-PATHNAME
                         #P"LOGICAL:DIR;SUBDIR;NAME.TYPE.newest")
                    #2=(TRANSLATE-LOGICAL-PATHNAME
                         (MAKE-PATHNAME
                           :HOST
                           "LOGICAL"
                           :DEVICE
                           :UNSPECIFIC
                           :DIRECTORY
                           '(:ABSOLUTE "DIR" "SUBDIR")
                           :NAME
                           "NAME"
                           :TYPE
                           "TYPE"
                           :VERSION
                           :NEWEST
                           :CASE
                           :COMMON)))
   with: #1# = #P"/tmp/DIR/SUBDIR/NAME.TYPE"
    and: #2# = #P"/tmp/dir/subdir/name.type"

PATHNAME #P"/tmp/DIR/SUBDIR/NAME.TYPE"
--------------------  :case :local (default)
Host      : :UNSPECIFIC
Device    : NIL
Directory : (:ABSOLUTE "tmp" "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  :case :common
Host      : :UNSPECIFIC
Device    : NIL
Directory : (:ABSOLUTE "TMP" "dir" "subdir")
Name      : "name"
Type      : "type"
Version   : :NEWEST
--------------------  

PATHNAME #P"/tmp/dir/subdir/name.type"
--------------------  :case :local (default)
Host      : :UNSPECIFIC
Device    : NIL
Directory : (:ABSOLUTE "tmp" "dir" "subdir")
Name      : "name"
Type      : "type"
Version   : :NEWEST
--------------------  :case :common
Host      : :UNSPECIFIC
Device    : NIL
Directory : (:ABSOLUTE "TMP" "DIR" "SUBDIR")
Name      : "NAME"
Type      : "TYPE"
Version   : :NEWEST
--------------------  
Welcome to Clozure Common Lisp Version 1.6-RC1-r14432M  (LinuxX8664)!
? (quit)
[pjb at kuiper :0.0 lisp]$ 
-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.




More information about the Openmcl-devel mailing list