+;; History list for environment variable names.
+(defvar read-envvar-name-history nil)
+
+(defun read-envvar-name (prompt &optional mustmatch)
+ "Read environment variable name, prompting with PROMPT.
+Optional second arg MUSTMATCH, if non-nil, means require existing envvar name.
+If it is also not t, RET does not exit if it does non-null completion."
+ (completing-read prompt
+ (mapcar (lambda (enventry)
+ (list (if enable-multibyte-characters
+ (decode-coding-string
+ (substring enventry 0
+ (string-match "=" enventry))
+ locale-coding-system t)
+ (substring enventry 0
+ (string-match "=" enventry)))))
+ process-environment)
+ nil mustmatch nil 'read-envvar-name-history))
+
+;; History list for VALUE argument to setenv.
+(defvar setenv-history nil)
+
+
+(defun substitute-env-vars (string)
+ "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.
+
+Use `$$' to insert a single dollar sign."
+ (let ((start 0))
+ (while (string-match
+ (eval-when-compile
+ (rx (or (and "$" (submatch (1+ (regexp "[[:alnum:]_]"))))
+ (and "${" (submatch (minimal-match (0+ anything))) "}")
+ "$$")))
+ string start)
+ (cond ((match-beginning 1)
+ (let ((value (getenv (match-string 1 string))))
+ (setq string (replace-match (or value "") t t string)
+ start (+ (match-beginning 0) (length value)))))
+ ((match-beginning 2)
+ (let ((value (getenv (match-string 2 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))
+
+;; Fixme: Should `process-environment' be recoded if LC_CTYPE &c is set?
+
+(defun setenv (variable &optional value unset substitute-env-vars)