Commit ee041f2d authored by Stefan Monnier's avatar Stefan Monnier
Browse files

* src/fileio.c (Fsubstitute_in_file_name): Use substitute-env-in-file-name.

(Qsubstitute_env_in_file_name): New var.
(syms_of_fileio): Define it.
* lisp/env.el (substitute-env-in-file-name): New function.
(substitute-env-vars): Extend the meaning of the optional arg.
parent 00036e1d
2013-10-10 Stefan Monnier <monnier@iro.umontreal.ca>
* env.el (substitute-env-in-file-name): New function.
(substitute-env-vars): Extend the meaning of the optional arg.
2013-10-10 Eli Zaretskii <eliz@gnu.org>
* term/w32-win.el (dynamic-library-alist): Define separate lists
......
;;; env.el --- functions to manipulate environment variables
;;; env.el --- functions to manipulate environment variables -*- lexical-binding:t -*-
;; Copyright (C) 1991, 1994, 2000-2013 Free Software Foundation, Inc.
......@@ -60,30 +60,46 @@ If it is also not t, RET does not exit if it does non-null completion."
(defconst env--substitute-vars-regexp
"\\$\\(?:\\(?1:[[:alnum:]_]+\\)\\|{\\(?1:[^{}]+\\)}\\|\\$\\)")
(defun substitute-env-vars (string &optional only-defined)
(defun substitute-env-vars (string &optional when-undefined)
"Substitute environment variables referred to in STRING.
`$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. For instance, in `ab$cd-x',
`$cd' is treated as an environment variable.
If ONLY-DEFINED is nil, references to undefined environment variables
are replaced by the empty string; if it is non-nil, they are left unchanged.
If WHEN-DEFINED is nil, references to undefined environment variables
are replaced by the empty string; if it is a function, the function is called
with the variable name as argument and should return the text with which
to replace it or nil to leave it unchanged.
If it is non-nil and not a function, references to undefined variables are
left unchanged.
Use `$$' to insert a single dollar sign."
(let ((start 0))
(while (string-match env--substitute-vars-regexp string start)
(cond ((match-beginning 1)
(let ((value (getenv (match-string 1 string))))
(if (and (null value) only-defined)
(let* ((var (match-string 1 string))
(value (getenv var)))
(if (and (null value)
(if (functionp when-undefined)
(null (setq value (funcall when-undefined var)))
when-undefined))
(setq start (match-end 0))
(setq string (replace-match (or value "") t t string)
(setq string (replace-match (or value "") t t string)
start (+ (match-beginning 0) (length value))))))
(t
(setq string (replace-match "$" t t string)
start (+ (match-beginning 0) 1)))))
string))
(defun substitute-env-in-file-name (filename)
(substitute-env-vars filename
;; How 'bout we lookup other tables than the env?
;; E.g. we could accept bookmark names as well!
(if (memq system-type '(windows-nt ms-dos))
(lambda (var) (getenv (upcase var)))
t)))
(defun setenv-internal (env variable value keep-empty)
"Set VARIABLE to VALUE in ENV, adding empty entries if KEEP-EMPTY.
......
2013-10-10 Stefan Monnier <monnier@iro.umontreal.ca>
* fileio.c (Fsubstitute_in_file_name): Use substitute-env-in-file-name.
(Qsubstitute_env_in_file_name): New var.
(syms_of_fileio): Define it.
2013-10-10 Eli Zaretskii <eliz@gnu.org>
* xdisp.c (deep_copy_glyph_row): Assert that the 'used' counts of
......
......@@ -143,6 +143,8 @@ static Lisp_Object Qcopy_directory;
/* Lisp function for recursively deleting directories. */
static Lisp_Object Qdelete_directory;
static Lisp_Object Qsubstitute_env_in_file_name;
#ifdef WINDOWSNT
#endif
......@@ -1664,10 +1666,8 @@ If `//' appears, everything up to and including the first of
those `/' is discarded. */)
(Lisp_Object filename)
{
char *nm, *s, *p, *o, *x, *endp;
char *target = NULL;
ptrdiff_t total = 0;
bool substituted = 0;
char *nm, *p, *x, *endp;
bool substituted = false;
bool multibyte;
char *xnm;
Lisp_Object handler;
......@@ -1708,66 +1708,19 @@ those `/' is discarded. */)
return Fsubstitute_in_file_name
(make_specified_string (p, -1, endp - p, multibyte));
/* See if any variables are substituted into the string
and find the total length of their values in `total'. */
for (p = nm; p != endp;)
if (*p != '$')
p++;
else
{
p++;
if (p == endp)
goto badsubst;
else if (*p == '$')
{
/* "$$" means a single "$". */
p++;
total -= 1;
substituted = 1;
continue;
}
else if (*p == '{')
{
o = ++p;
p = memchr (p, '}', endp - p);
if (! p)
goto missingclose;
s = p;
}
else
{
o = p;
while (p != endp && (c_isalnum (*p) || *p == '_')) p++;
s = p;
}
/* Copy out the variable name. */
target = alloca (s - o + 1);
memcpy (target, o, s - o);
target[s - o] = 0;
#ifdef DOS_NT
strupr (target); /* $home == $HOME etc. */
#endif /* DOS_NT */
/* See if any variables are substituted into the string. */
/* Get variable value. */
o = egetenv (target);
if (o)
{
/* Don't try to guess a maximum length - UTF8 can use up to
four bytes per character. This code is unlikely to run
in a situation that requires performance, so decoding the
env variables twice should be acceptable. Note that
decoding may cause a garbage collect. */
Lisp_Object orig, decoded;
orig = build_unibyte_string (o);
decoded = DECODE_FILE (orig);
total += SBYTES (decoded);
substituted = 1;
}
else if (*p == '}')
goto badvar;
}
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)
{
......@@ -1778,73 +1731,9 @@ those `/' is discarded. */)
return filename;
}
/* If substitution required, recopy the string and do it. */
/* Make space in stack frame for the new copy. */
xnm = alloca (SBYTES (filename) + total + 1);
x = xnm;
/* Copy the rest of the name through, replacing $ constructs with values. */
for (p = nm; *p;)
if (*p != '$')
*x++ = *p++;
else
{
p++;
if (p == endp)
goto badsubst;
else if (*p == '$')
{
*x++ = *p++;
continue;
}
else if (*p == '{')
{
o = ++p;
p = memchr (p, '}', endp - p);
if (! p)
goto missingclose;
s = p++;
}
else
{
o = p;
while (p != endp && (c_isalnum (*p) || *p == '_')) p++;
s = p;
}
/* Copy out the variable name. */
target = alloca (s - o + 1);
memcpy (target, o, s - o);
target[s - o] = 0;
/* Get variable value. */
o = egetenv (target);
if (!o)
{
*x++ = '$';
strcpy (x, target); x+= strlen (target);
}
else
{
Lisp_Object orig, decoded;
ptrdiff_t orig_length, decoded_length;
orig_length = strlen (o);
orig = make_unibyte_string (o, orig_length);
decoded = DECODE_FILE (orig);
decoded_length = SBYTES (decoded);
memcpy (x, SDATA (decoded), decoded_length);
x += decoded_length;
/* If environment variable needed decoding, return value
needs to be multibyte. */
if (decoded_length != orig_length
|| memcmp (SDATA (decoded), o, orig_length))
multibyte = 1;
}
}
*x = 0;
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
......@@ -1862,14 +1751,9 @@ those `/' is discarded. */)
}
else
#endif
return make_specified_string (xnm, -1, x - xnm, multibyte);
badsubst:
error ("Bad format environment-variable substitution");
missingclose:
error ("Missing \"}\" in environment-variable substitution");
badvar:
error ("Substituting nonexistent environment variable \"%s\"", target);
return (xnm == SSDATA (filename)
? filename
: make_specified_string (xnm, -1, x - xnm, multibyte));
}
/* A slightly faster and more convenient way to get
......@@ -6108,6 +5992,7 @@ This includes interactive calls to `delete-file' and
DEFSYM (Qmove_file_to_trash, "move-file-to-trash");
DEFSYM (Qcopy_directory, "copy-directory");
DEFSYM (Qdelete_directory, "delete-directory");
DEFSYM (Qsubstitute_env_in_file_name, "substitute-env-in-file-name");
defsubr (&Sfind_file_name_handler);
defsubr (&Sfile_name_directory);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment