Function: substitute-in-file-name
substitute-in-file-name is a function defined in fileio.c.
Signature
(substitute-in-file-name FILENAME)
Documentation
Substitute environment variables referred to in FILENAME.
$FOO where FOO is an environment variable name means to substitute
the value of that variable. The variable name should be terminated
with a character not a letter, digit or underscore; otherwise, enclose
the entire variable name in braces.
If FOO is not defined in the environment, $FOO is left unchanged in
the value of this function.
If /~ appears, all of FILENAME through that / is discarded.
If // appears, everything up to and including the first of
those / is discarded.
Other relevant functions are documented in the file-name group.
Probably introduced at or before Emacs version 1.6.
Shortdoc
;; file-name
(substitute-in-file-name "$HOME/foo")
=> "/root/foo"
Source Code
// Defined in /usr/src/emacs/src/fileio.c
{
char *nm, *p, *x, *endp;
bool substituted = false;
bool multibyte;
char *xnm;
Lisp_Object handler;
CHECK_STRING (filename);
multibyte = STRING_MULTIBYTE (filename);
/* If the file name has special constructs in it,
call the corresponding file name handler. */
handler = Ffind_file_name_handler (filename, Qsubstitute_in_file_name);
if (!NILP (handler))
{
Lisp_Object handled_name = call2 (handler, Qsubstitute_in_file_name,
filename);
if (STRINGP (handled_name))
return handled_name;
error ("Invalid handler in `file-name-handler-alist'");
}
/* Always work on a copy of the string, in case GC happens during
decode of environment variables, causing the original Lisp_String
data to be relocated. */
USE_SAFE_ALLOCA;
SAFE_ALLOCA_STRING (nm, filename);
#ifdef DOS_NT
dostounix_filename (nm);
substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
#endif
endp = nm + SBYTES (filename);
/* If /~ or // appears, discard everything through first slash. */
p = search_embedded_absfilename (nm, endp);
if (p)
/* Start over with the new string, so we check the file-name-handler
again. Important with filenames like "/home/foo//:/hello///there"
which would substitute to "/:/hello///there" rather than "/there". */
{
Lisp_Object result
= (Fsubstitute_in_file_name
(make_specified_string (p, -1, endp - p, multibyte)));
SAFE_FREE ();
return result;
}
/* See if any variables are substituted into the string. */
if (!NILP (Ffboundp (Qsubstitute_env_in_file_name)))
{
Lisp_Object name
= (!substituted ? filename
: make_specified_string (nm, -1, endp - nm, multibyte));
Lisp_Object tmp = call1 (Qsubstitute_env_in_file_name, name);
CHECK_STRING (tmp);
if (!EQ (tmp, name))
substituted = true;
filename = tmp;
}
if (!substituted)
{
#ifdef WINDOWSNT
if (!NILP (Vw32_downcase_file_names))
filename = Fdowncase (filename);
#endif
SAFE_FREE ();
return filename;
}
xnm = SSDATA (filename);
x = xnm + SBYTES (filename);
/* If /~ or // appears, discard everything through first slash. */
while ((p = search_embedded_absfilename (xnm, x)) != NULL)
/* This time we do not start over because we've already expanded envvars
and replaced $$ with $. Maybe we should start over as well, but we'd
need to quote some $ to $$ first. */
xnm = p;
#ifdef WINDOWSNT
if (!NILP (Vw32_downcase_file_names))
{
Lisp_Object xname = make_specified_string (xnm, -1, x - xnm, multibyte);
filename = Fdowncase (xname);
}
else
#endif
if (xnm != SSDATA (filename))
filename = make_specified_string (xnm, -1, x - xnm, multibyte);
SAFE_FREE ();
return filename;
}