Subject: Re: bug#76023: 31.0.50; Observed behavior for substitute-in-file-name different from the doc string

From: Eli Zaretskii <[email-masked]>
Date: Mon, 03 Feb 2025 19:59:56 +0200

> From: arthur miller <[email-masked]>
> CC: "[email-masked]" <[email-masked]>
> Date: Mon, 3 Feb 2025 15:34:48 +0000
> 
> > > (substitute-in-file-name "some-string/~$HOME") => some-string/~C:\Users\arthur
> > >
> > > However:
> > >
> > > (substitute-in-file-name "some-string~/$HOME") => C:\Users\arthur
> >
> > Yes.  Emacs on MS-Windows doesn't support the "~foo" notation, which
> 
> Actually, is seems you do support that notation on Windows :-). It works here:
> 
> ~/repos/emsrc/emacs/src $ (expand-file-name "~")
> c:/Users/Arthur
> ~/repos/emsrc/emacs/src $ (expand-file-name "~arthur")
> c:/Users/Arthur

Yes, if "foo" is your user name, then we do support "~foo" (because
it's easy and expected).  But not for any other "foo".

> ~/repos/emsrc/emacs/src $ (expand-file-name "~/test")
> c:/Users/Arthur/test
> ~/repos/emsrc/emacs/src $
> 
> It seems that you are thinking of the wrong function here, or haven't looked at
> the implementation. That would be expand-file-name that supports "~foo"
> notation, not substitute-in-file-name.

The function is different, but the reason is the same: Emacs doesn't
support ~foo on MS-Windows, even if the user "foo" does exist on the
system:

  (substitute-in-file-name "some-string/~Administrator")
   => "some-string/~Administrator"
  (substitute-in-file-name "some-string/~SYSTEM")
   => "some-string/~SYSTEM"

> We are speaking about substitute-in-file-name, which supports "$foo" to
> substitute an env variable in the string. Furthermore, it also supports "/~" and
> "//" which means that everything before those two strings should be
> discarded. As described in the bug report, "~/" does what the doc string
> states.

Yes.  Once again, Emacs on MS-Windows supports ~ and ~/ and ~user when
"user" is the name of the current session's user.  In any other case
the "~" is interpreted literally on MS-Windows, and "~SOMETHING" is
*not* supposed to cause this function discard everything, because then
it will be inconsistent with how other primitives treat ~foo on
MS-Windows.

> Observe that substitute-in-file-name never calls expand-file-name; so
> that expansion of tilde you seem to speak about, should never take place there.

I know.  But observe that it calls user_homedir, which in Emacs on
MS-Windows works as I described above.

> In short: everything is supported, the docs just display a bad string.

No, that's an incorrect conclusion, for the reasons I explained.

> I think you are confused by my example. I choose "HOME" because the result
> string is shorter. I could have used "$PATH" in those examples, or "$UserProfile".

Yes, because the name of the current session's user is unlikely to be
the expansion of $PATH.  But try this:

  (substitute-in-file-name "some-string/~$LOGNAME")
   => "~eliz"

(My user name on this system is "eliz".)

So I don't think I'm confused, no.

> > It isn't a typo in the doc string, because on Posix systems Emacs
> > behaves like the doc string says.  It is a common trait in
> > documentation Emacs not to describe too many details about the
> > idiosyncrasies of MS-Windows, especially in dark corners such as this
> > one.
> 
> Why does "~/" works as described in the doc string of substitute-in-file-name,
> but the doc says "/~"?

Both work here:

  (substitute-in-file-name "some-string/~")
   => "~"
  (substitute-in-file-name "some-string/~/")
   => "~/"

> > That shouldn't matter, since Emacs can use both forward and
> > backslashes in file names.
> 
> Yes, I understand that, I have seen it. It is not that it matters to Emacs per
> se, or if the user types at the prompt interactively. It matters if someone
> passes a result of that function to some other function which is not Emacs
> built-in namestring manipulation function. Than that person can not assume
> platform-independent namestrings, which I don't think would be unreasonable to
> assume. Also, it is not very difficult to implement it either.

What would that person do with this file name?  All the Emacs
primitives that accept file names support both flavors of slashes.
Example:

  (file-name-nondirectory "d:\\foo/bar\\baz")
   => "baz"

So the only case where a Lisp program will fail for such file names is
if that Lisp program manually analyzes the file name, instead of using
Emacs primitives.  In which case I'd say the Lisp program has a bug.

But we digress, I think?

> The only two functions that has this different behavior are
> substitute-in-file-name and concat-path-name. The reason is probably because
> they don't expand file name as others functions in fileio.c do, but do their own
> thing with string concatenations.
> 
> As regression: (file-name-concat "foo" "bar\\" "baz") => "foo/bar\\baz"

And why is that a problem?  (Of course, one should almost never use
file-name-concat, it exists for a small number of very special cases;
everything else should use expand-file-name.)

> > It is a feature, but I don't think we want to mention it, because it's
> > Windows-specific, and because "~$HOME" makes very little sense on
> > Windows.
> 
> I am not sure why "~$HOME" makes sense anywhere? Do you perhaps mean "~$USER"?

No, I meant ~$HOME.  Since ~ is the same as $HOME, why double it?