Subject: bug#7617: 24.0.50; `expand-file-name': removal of slashes

From: "Drew Adams" <[email-masked]>
Date: Sat, 11 Dec 2010 13:53:38 -0800

emacs -Q
 
(expand-file-name "share/" "~/today//usr/") ->
c:/today/usr/share/.

(On my Windows laptop, `~' is just `c:/'.)

IOW, multiple consecutive slashes are collapsed to one.  This is not the
behavior I want.  This behavior started in Emacs 21; in Emacs 20 no such
removal of slashes occurs.

I would consider this loss of slashes a bug.  But I see that comments in
the current C code indicate that it is intentional (but not _why_).  I'm
not great at reading C code, but I see these comments in the Emacs 24 code:
 
/* We want to replace multiple `/' in a row with a single
   slash.  */
else if (p > nm
         && IS_DIRECTORY_SEP (p[0])
         && IS_DIRECTORY_SEP (p[1]))
 
And later on:
 
/* Now canonicalize by removing `//', `/.' and `/foo/..' if they
   appear.  */
...
/* Collapse multiple `/' in a row.  */
 
In the Emacs 20 C code the equivalent comment says only this:
 
/* Now canonicalize by removing /. and /foo/.. if they appear.  */
 
I don't have C source for Emacs 21, but the behavior of 21 indicates that
that is when the change was made, presumably intentionally.  I searched
the change logs but found no mention of this change or why it was made.
 
Given that the change was presumably intentional (but why?), you might
not be disposed to consider this a bug.  I imagine you might argue that
the second arg to `expand-file-name' in this case is not a valid
directory name, so all bets are off wrt the behavior - or something like
that.  Or perhaps you will argue that `expand*' is supposed to give you
a canonicalized file name, and a name such as "c:/today//usr/share/"
cannot be said to be canonicalized.
 
IOW, I imagine there can be arguments that defend the current (Emacs
21+) behavior.
 
But shouldn't `expand-file-name' do the right thing if the second arg is
in fact `file-directory-p'?

For a user on GNU/Linux with $HOME = /home/toto":
(file-directory-p "~/today//usr") -> nil, but
(file-directory-p "~//usr/") --> t, and we have the same problem:
(expand-file-name "foo" "~//usr/") -> "/home/toto/usr/foo"
 
Surely the behavior here is buggy, no?  The result should be
"/home/toto//usr/foo", I would think.

It seems like any special treatment of double slashes should only
be an interactive treatment (e.g. ignore or remove everything up
to the second consecutive slash).  _Why should_ `expand-file-name'
collapse multiple consecutive slashes into a single slash?
 
I would start with that questiom.  What is the rationale for that
Emacs 21 change wrt Emacs 20.
 
In case it helps, I've attached the Emacs 20 code for `expand-file-name'.

Finally, I need the Emacs 20 behavior for this for some of my code.  If you
decide not to change the behavior for this in Emacs, can you suggest a good way
(in Lisp) to get the behavior I want - i.e., the Emacs 20 behavior?

I can try to work around this by substituting something for multiple consecutive
slashes, so that `expand*' won't collapse them, and then substituting back again
to get the slashes, but that is a truly gross and fragile hack.  I'm open to
better suggestions.  Thanks.

Oh, and another thing.  This behavior of `expand-file-name' is not documented.
If the decision is to keep this behavior, then the doc should let users know
that the function does this.  See the doc string - it describes everything the
function does (including `.' removal etc.) - except this.

In GNU Emacs 24.0.50.1 (i386-mingw-nt5.1.2600)
 of 2010-12-06 on 3249CTO
Windowing system distributor `Microsoft Corp.', version 5.1.2600
configured using `configure --with-gcc (4.4) --no-opt --cflags
-Ic:/imagesupport/include'