summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2013-10-10 17:42:38 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2013-10-10 17:42:38 -0400
commitee041f2d07b6ed485dc34c115588f973f046c9d4 (patch)
tree8152e54e2d2552d52629c7455837f85d07ee9503
parent00036e1dd2f2194fbc7938076defbe2d7228c8a3 (diff)
downloademacs-ee041f2d07b6ed485dc34c115588f973f046c9d4.tar.gz
* 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.
-rw-r--r--lisp/ChangeLog5
-rw-r--r--lisp/env.el30
-rw-r--r--src/ChangeLog6
-rw-r--r--src/fileio.c161
4 files changed, 57 insertions, 145 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index a06055ddb9b..1a312606ee0 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,8 @@
+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
diff --git a/lisp/env.el b/lisp/env.el
index 5618404cb67..044673d5e68 100644
--- a/lisp/env.el
+++ b/lisp/env.el
@@ -1,4 +1,4 @@
-;;; 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.
diff --git a/src/ChangeLog b/src/ChangeLog
index 4bd46642f43..39d576f2c40 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+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
diff --git a/src/fileio.c b/src/fileio.c
index c7125534e63..a80145ae42c 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -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);