Hey, all.
Trying to make sure my code was portable between ACL and CMUCL, I ran into
a question about rename-file behavior which is at slightly subtle. The
more I think about it, the more I think I know the answer, but I thought
I'd ask here.
In a nutshell, what should (rename-file "subdir/junk.txt" "subdir/gold.txt")
do?
Yes, in case you're wondering, I also wrote it as
(rename-file (make-pathname :directory '(:relative "subdir")
:name "junk"
:type "txt")
(make-pathname :directory '(:relative "subdir")
:name "gold"
:type "txt"))
I'm leaving out my conclusions, here, so I can see what other people think.
Michael
--
Michael Hannemann
Senior Programmer
I/NET Advanced Technologies, Inc.
Just to follow up to myself: Franz has declared the behavior I was seeing
to be a bug in ACL 6.1 and they'll fix it. What was happening was that
(rename-file "subdir/old.txt" "subdir/new.txt")
worked as one might intuitively expect, renaming old to new in subdir.
When I tried this under CMUCL, it complained that it couldn't create
"subdir/subdir/new.txt".
The spec says that the path for the new file is the result of calling
(merge-pathnames new-file old-path), and as merge-pathnames treats relative
directories specially, the CMUCL behavior, appending the directory
mentioned in new-file to the path in old-path, is correct.
My work-around for this is to say:
(rename-file (truename (pathname temp-path))
(merge-pathnames (pathname new-file)
(truename (pathname temp-path))))
This seems to be portable amongst ACL, CMUCL, and MCL.
Michael
--
Michael Hannemann
Senior Programmer
I/NET Advanced Technologies, Inc.
Michael Hannemann <····@pobox.com> writes:
> Just to follow up to myself: Franz has declared the behavior I was seeing
> to be a bug in ACL 6.1 and they'll fix it.
I can confirm that this has been fixed for the upcoming 6.2.beta release.
Kevin
+ Michael Hannemann <····@pobox.com>:
| In a nutshell, what should (rename-file "subdir/junk.txt" "subdir/gold.txt")
| do?
It should rename the file named "subdir/junk.txt" to the result of
(merge-pathnames "subdir/gold.txt" "subdir/junk.txt"), which
incidentally on CMUCL is #p"subdir/subdir/gold.txt".
Assuming that the implementation details are such that the above is
equivalent to
| (rename-file (make-pathname :directory '(:relative "subdir")
| :name "junk"
| :type "txt")
| (make-pathname :directory '(:relative "subdir")
| :name "gold"
| :type "txt"))
the CMUCL answer certainly seems correct to me, judging by this
section of the HyperSpec <HyperSpec/Body/fun_merge-pathnames.html>:
Pathname merging treats a relative directory specially. If
(pathname-directory pathname) is a list whose car is :relative, and
(pathname-directory default-pathname) is a list, then the merged
directory is the value of
(append (pathname-directory default-pathname)
(cdr ;remove :relative from the front
(pathname-directory pathname)))
Sure, this behaviour surprised the hell out of me when I first
encountered it last week, but after reading up on it in the HyperSpec,
I am (temporarily at least) unable to see any other interpretation.
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?