(ediff-files, ediff-files3, ediff-merge-files)
[bpt/emacs.git] / lisp / env.el
CommitLineData
55535639 1;;; env.el --- functions to manipulate environment variables
c88ab9ce 2
0d30b337 3;; Copyright (C) 1991, 1994, 2000, 2001, 2002, 2003, 2004,
aaef169d 4;; 2005, 2006 Free Software Foundation, Inc.
971571b9 5
e5167999 6;; Maintainer: FSF
d9ecc911 7;; Keywords: processes, unix
e5167999 8
b578f267 9;; This file is part of GNU Emacs.
6449c898 10
b578f267
EN
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
6449c898 15
b578f267
EN
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
6449c898 20
b578f267
EN
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
6449c898 25
d9ecc911
ER
26;;; Commentary:
27
b578f267
EN
28;; UNIX processes inherit a list of name-to-string associations from their
29;; parents called their `environment'; these are commonly used to control
30;; program options. This package permits you to set environment variables
31;; to be passed to any sub-process run under Emacs.
d9ecc911 32
1a90eae6
DL
33;; Note that the environment string `process-environment' is not
34;; decoded, but the args of `setenv' and `getenv' are normally
35;; multibyte text and get coding conversion.
36
e5167999
ER
37;;; Code:
38
99ac138a
RS
39;; History list for environment variable names.
40(defvar read-envvar-name-history nil)
41
42(defun read-envvar-name (prompt &optional mustmatch)
43 "Read environment variable name, prompting with PROMPT.
8b740009
RS
44Optional second arg MUSTMATCH, if non-nil, means require existing envvar name.
45If it is also not t, RET does not exit if it does non-null completion."
99ac138a 46 (completing-read prompt
1a90eae6
DL
47 (mapcar (lambda (enventry)
48 (list (if enable-multibyte-characters
49 (decode-coding-string
50 (substring enventry 0
51 (string-match "=" enventry))
52 locale-coding-system t)
53 (substring enventry 0
54 (string-match "=" enventry)))))
99ac138a
RS
55 process-environment)
56 nil mustmatch nil 'read-envvar-name-history))
57
58;; History list for VALUE argument to setenv.
59(defvar setenv-history nil)
60
a4a216c5
GM
61
62(defun substitute-env-vars (string)
63 "Substitute environment variables referred to in STRING.
64`$FOO' where FOO is an environment variable name means to substitute
65the value of that variable. The variable name should be terminated
66with a character not a letter, digit or underscore; otherwise, enclose
cccc806d
RS
67the entire variable name in braces. For instance, in `ab$cd-x',
68`$cd' is treated as an environment variable.
69
70Use `$$' to insert a single dollar sign."
a4a216c5 71 (let ((start 0))
71296446 72 (while (string-match
1a90eae6 73 (eval-when-compile
cccc806d 74 (rx (or (and "$" (submatch (1+ (regexp "[[:alnum:]_]"))))
1a90eae6
DL
75 (and "${" (submatch (minimal-match (0+ anything))) "}")
76 "$$")))
a4a216c5
GM
77 string start)
78 (cond ((match-beginning 1)
79 (let ((value (getenv (match-string 1 string))))
80 (setq string (replace-match (or value "") t t string)
81 start (+ (match-beginning 0) (length value)))))
82 ((match-beginning 2)
83 (let ((value (getenv (match-string 2 string))))
84 (setq string (replace-match (or value "") t t string)
85 start (+ (match-beginning 0) (length value)))))
86 (t
87 (setq string (replace-match "$" t t string)
88 start (+ (match-beginning 0) 1)))))
89 string))
90
1a90eae6 91;; Fixme: Should `process-environment' be recoded if LC_CTYPE &c is set?
a4a216c5 92
27bdc650 93(defun setenv (variable &optional value substitute-env-vars)
6449c898 94 "Set the value of the environment variable named VARIABLE to VALUE.
b71038b2 95VARIABLE should be a string. VALUE is optional; if not provided or
27bdc650 96nil, the environment variable VARIABLE will be removed.
cbfe666b
RS
97
98Interactively, a prefix argument means to unset the variable.
99ac138a
RS
99Interactively, the current value (if any) of the variable
100appears at the front of the history list when you type in the new value.
a4a216c5 101Interactively, always replace environment variables in the new value.
99ac138a 102
27bdc650
RS
103SUBSTITUTE-ENV-VARS, if non-nil, means to substitute environment
104variables in VALUE with `substitute-env-vars', which see.
105This is normally used only for interactive calls.
106
107The return value is the new value of VARIABLE, or nil if
108it was removed from the environment.
109
1a90eae6
DL
110This function works by modifying `process-environment'.
111
112As a special case, setting variable `TZ' calls `set-time-zone-rule' as
113a side-effect."
cbfe666b
RS
114 (interactive
115 (if current-prefix-arg
27bdc650 116 (list (read-envvar-name "Clear environment variable: " 'exact) nil)
2a5becfb
GM
117 (let* ((var (read-envvar-name "Set environment variable: " nil))
118 (value (getenv var)))
119 (when value
120 (push value setenv-history))
99ac138a 121 ;; Here finally we specify the args to give call setenv with.
71296446 122 (list var
a4a216c5
GM
123 (read-from-minibuffer (format "Set %s to value: " var)
124 nil nil nil 'setenv-history
125 value)
a4a216c5 126 t))))
1a90eae6 127 (if (and (multibyte-string-p variable) locale-coding-system)
1ebb05c4
KH
128 (let ((codings (find-coding-systems-string (concat variable value))))
129 (unless (or (eq 'undecided (car codings))
130 (memq (coding-system-base locale-coding-system) codings))
131 (error "Can't encode `%s=%s' with `locale-coding-system'"
132 variable (or value "")))))
27bdc650
RS
133 (and value
134 substitute-env-vars
135 (setq value (substitute-env-vars value)))
1a90eae6
DL
136 (if (multibyte-string-p variable)
137 (setq variable (encode-coding-string variable locale-coding-system)))
138 (if (and value (multibyte-string-p value))
139 (setq value (encode-coding-string value locale-coding-system)))
6449c898 140 (if (string-match "=" variable)
1bbda2d6 141 (error "Environment variable name `%s' contains `='" variable)
971571b9 142 (let ((pattern (concat "\\`" (regexp-quote (concat variable "="))))
7e68de56 143 (case-fold-search nil)
cbfe666b
RS
144 (scan process-environment)
145 found)
7fd81709
RS
146 (if (string-equal "TZ" variable)
147 (set-time-zone-rule value))
cbfe666b
RS
148 (while scan
149 (cond ((string-match pattern (car scan))
150 (setq found t)
151 (if (eq nil value)
1a90eae6
DL
152 (setq process-environment (delq (car scan)
153 process-environment))
cbfe666b
RS
154 (setcar scan (concat variable "=" value)))
155 (setq scan nil)))
156 (setq scan (cdr scan)))
157 (or found
158 (if value
a3cda273 159 (setq process-environment
cbfe666b 160 (cons (concat variable "=" value)
a4a216c5
GM
161 process-environment))))))
162 value)
49116ac0 163
b1e11b4f
GM
164(defun getenv (variable)
165 "Get the value of environment variable VARIABLE.
166VARIABLE should be a string. Value is nil if VARIABLE is undefined in
167the environment. Otherwise, value is a string.
168
169This function consults the variable `process-environment'
170for its value."
171 (interactive (list (read-envvar-name "Get environment variable: " t)))
1a90eae6
DL
172 (let ((value (getenv-internal (if (multibyte-string-p variable)
173 (encode-coding-string
174 variable locale-coding-system)
175 variable))))
176 (if (and enable-multibyte-characters value)
177 (setq value (decode-coding-string value locale-coding-system)))
b1e11b4f
GM
178 (when (interactive-p)
179 (message "%s" (if value value "Not set")))
180 value))
181
1bbda2d6
NF
182(provide 'env)
183
ab5796a9 184;;; arch-tag: b7d6a8f7-bc81-46db-8e39-8d721d4ed0b8
1bbda2d6 185;;; env.el ends here