env.el 7.9 KB

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