Commit f35ca2fe authored by Karoly Lorentey's avatar Karoly Lorentey

Reimplement and extend support for terminal-local environment variables.

* lisp/termdev.el: New file.  Move terminal parameter-related functions
  here from frame.el.
  (terminal-getenv, with-terminal-environment): Reimplement and extend.
  (terminal-setenv, terminal-setenv-internal): New functions.

* lisp/frame.el (make-frame-on-tty, framep-on-display, suspend-frame):
  Extend doc string, update parameter names.
  (terminal-id, terminal-parameter-alist, terminal-parameters)
  (terminal-parameter-p, terminal-parameter, set-terminal-parameter)
  (terminal-handle-delete-frame, terminal-getenv, terminal-getenv)
  (with-terminal-environment): Move to termdev.el.

* lisp/loadup.el: Load termdev as well.
* lisp/Makefile.in (lisp, shortlisp): Add termdev.elc.
* lisp/makefile.MPW (shortlisp): Ditto.

* lisp/ebuff-menu.el (electric-buffer-menu-mode-map): Bind C-z to
  `suspend-frame', not `suspend-emacs'.
* lisp/echistory.el (electric-history-map): Ditto.
* lisp/ebrowse.el (ebrowse-electric-list-mode-map): Ditto.
* lisp/ebrowse.el (ebrowse-electric-position-mode-map): Ditto.

* lisp/startup.el (normal-splash-screen): Use `save-buffers-kill-display'
  instead of `save-buffers-kill-emacs'.

* lisp/x-win.el (x-initialize-window-system): Add 'global-ok option to
  `terminal-getenv'.

* src/term.c (suspend-tty): Update doc string.

git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-456
parent a18b8cb5
......@@ -89,7 +89,7 @@ frames. It has been changed open new Emacs frames by default.
The multi-tty branch has been scheduled for inclusion in the next
major release of Emacs (version 23). I expect the merge into the
development trunk to occur sometime during next year (2005), after the
development trunk to occur sometime during next year (2006), after the
merge of the Unicode branch.
Tested on GNU/Linux, Solaris 8, FreeBSD and OpenBSD. Please let me
......@@ -140,36 +140,36 @@ Known problems:
system-dependent source files need to be adapted
accordingly. The changes are mostly trivial, so almost
anyone can help, if only by compiling the branch and
reporting the compiler errors. (It is not worth to do this
yet, though.)
reporting the compiler errors.
HOW TO GET THE BRANCH
---------------------
The branch uses GNU Arch (http://www.gnuarch.org) for version control.
The branch uses Bazaar 1 (http://bazaar.canonical.com) for version control.
Retrieving the latest version of the branch:
tla register-archive -f http://lorentey.hu/arch/2004/
tla get lorentey@elte.hu--2004/emacs--multi-tty <directory>
baz register-archive -f http://aszt.inf.elte.hu/~lorentey/mirror/arch/2004
baz get lorentey@elte.hu--2004/emacs--multi-tty <directory>
This incantation uses my private archive mirror that is hosted on a
relatively low-bandwidth site; if you are outside Hungary, you will
probably want to you use my secondary mirror: (Note that the -f option
will overwrite the archive location if you have previously registered
the Hungarian one.)
This incantation uses an archive mirror that is hosted on a
high-bandwidth site. Please note that on average there is a two-hour
delay for commits to arrive on this mirror. My primary mirror is on the
low-bandwidth http://lorentey.hu/ site:
tla register-archive -f http://aszt.inf.elte.hu/~lorentey/mirror/arch/2004
tla get lorentey@elte.hu--2004/emacs--multi-tty <directory>
baz register-archive -f http://lorentey.hu/arch/2004/
baz get lorentey@elte.hu--2004/emacs--multi-tty <directory>
http://aszt.inf.elte.hu/~lorentey/mirror/arch/2004
This is "instantly" updated, but very slow from outside Hungary.
(By "instantly" I mean as soon as I connect the notebook I work on to
a network. It could take days.)
The Arch supermirror provides mirroring services for all public Arch
repositories. We have a mirror there, too, if you prefer.
tla register-archive -f http://mirrors.sourcecontrol.net/lorentey%40elte.hu--2004
tla get lorentey@elte.hu--2004/emacs--multi-tty <directory>
baz register-archive -f http://mirrors.sourcecontrol.net/lorentey%40elte.hu--2004
baz get lorentey@elte.hu--2004/emacs--multi-tty <directory>
My GPG key id is 0FB27A3F; it is available from
hkp://wwwkeys.eu.pgp.net/, or from my homepage at
......@@ -179,16 +179,20 @@ Don't worry if the above checkout takes a few minutes to complete;
once you have a source tree, updating it to the latest revision will
be _much_ faster. Use the following command for the update:
tla replay
baz replay
You can find more information about Arch on http://wiki.gnuarch.org/.
It's a wonderful source control system, I highly recommend it.
You can find more information about Bazaar on
http://bazaar.canonical.com/. It's a distributed source control
system that is somewhat less broken than competing projects.
If you don't have tla, the branch has a homepage from which you can
If you don't have Bazaar, the branch has a homepage from which you can
download conventional patches against Emacs CVS HEAD:
http://lorentey.hu/project/emacs.html
I suggest you use Bazaar whenever feasible.
DEBIAN PACKAGES
---------------
......@@ -244,9 +248,10 @@ finish editing the specified files (C-x #), but delete-frame (C-x 5 0)
also works. Of course, you can create frames on more than two tty
devices.
Creating new frames on the same tty with C-x 5 2 works, and they
behave the same way as in previous Emacs versions. If you exit emacs,
all terminals should be restored to their previous states.
Creating new frames on the same tty with C-x 5 2 (make-frame-command)
works, and they behave the same way as in previous Emacs versions. If
you exit emacs, all terminals should be restored to their previous
states.
This is work in progress, and probably full of bugs. It is a good
idea to run emacs from gdb, so that you'll have a live instance to
......@@ -384,6 +389,8 @@ For the NEWS file: (Needs much, much work)
*** talk.el has been extended for multiple tty support.
*** C-z now invokes `suspend-frame', C-x C-c now invokes
`save-buffers-kill-frame'.
* * *
......@@ -393,6 +400,10 @@ is probably not very interesting for anyone else.)
THINGS TO DO
------------
** Search for `suspend-emacs' references and replace them with
`suspend-frame', if necessary. Ditto for `save-buffers-kill-emacs'
vs. `save-buffers-kill-display'.
** Emacs crashes when a tty frame is resized so that there is no space
for all its windows. (Tom Schutzer-Weissmann)
......
......@@ -175,7 +175,7 @@ Entry to this mode via command `electric-buffer-list' calls the value of
(let ((map (make-keymap)))
(fillarray (car (cdr map)) 'Electric-buffer-menu-undefined)
(define-key map "\e" nil)
(define-key map "\C-z" 'suspend-emacs)
(define-key map "\C-z" 'suspend-frame)
(define-key map "v" 'Electric-buffer-menu-mode-view-buffer)
(define-key map (char-to-string help-char) 'Helper-help)
(define-key map "?" 'Helper-describe-bindings)
......
......@@ -65,7 +65,7 @@ With prefix arg NOCONFIRM, execute current line as-is without editing."
(define-key electric-history-map "\C-c" nil)
(define-key electric-history-map "\C-c\C-c" 'Electric-history-quit)
(define-key electric-history-map "\C-]" 'Electric-history-quit)
(define-key electric-history-map "\C-z" 'suspend-emacs)
(define-key electric-history-map "\C-z" 'suspend-frame)
(define-key electric-history-map (char-to-string help-char) 'Helper-help)
(define-key electric-history-map "?" 'Helper-describe-bindings)
(define-key electric-history-map "\e>" 'end-of-buffer)
......
......@@ -598,15 +598,18 @@ The optional second argument PARAMETERS specifies additional frame parameters."
(x-initialize-window-system))
(make-frame `((window-system . x) (display . ,display) . ,parameters)))
(defun make-frame-on-tty (device type &optional parameters)
"Make a frame on terminal DEVICE which is of type TYPE (e.g., \"xterm\").
The optional third argument PARAMETERS specifies additional frame parameters."
(defun make-frame-on-tty (tty type &optional parameters)
"Make a frame on terminal device TTY.
TTY should be the file name of the tty device to use. TYPE
should be the terminal type string of TTY, for example \"xterm\"
or \"vt100\". The optional third argument PARAMETERS specifies
additional frame parameters."
(interactive "fOpen frame on tty device: \nsTerminal type of %s: ")
(unless device
(unless tty
(error "Invalid terminal device"))
(unless type
(error "Invalid terminal type"))
(make-frame `((window-system . nil) (tty . ,device) (tty-type . ,type) . ,parameters)))
(make-frame `((window-system . nil) (tty . ,tty) (tty-type . ,type) . ,parameters)))
(defun make-frame-command ()
"Make a new frame, and select it if the terminal displays only one frame."
......@@ -710,15 +713,15 @@ frame's terminal device."
(eq (frame-display frame) terminal))))
(filtered-frame-list func)))
(defun framep-on-display (&optional display)
"Return the type of frames on DISPLAY.
DISPLAY may be a display id, a display name or a frame. If it is
a frame, its type is returned.
If DISPLAY is omitted or nil, it defaults to the selected frame's display.
All frames on a given display are of the same type."
(or (display-live-p display)
(framep display)
(framep (car (frames-on-display-list display)))))
(defun framep-on-display (&optional terminal)
"Return the type of frames on TERMINAL.
TERMINAL may be a terminal id, a display name or a frame. If it
is a frame, its type is returned. If TERMINAL is omitted or nil,
it defaults to the selected frame's terminal device. All frames
on a given display are of the same type."
(or (display-live-p terminal)
(framep terminal)
(framep (car (frames-on-display-list terminal)))))
(defun frame-remove-geometry-params (param-list)
"Return the parameter list PARAM-LIST, but with geometry specs removed.
......@@ -796,8 +799,8 @@ Otherwise, that variable should be nil."
(defun suspend-frame ()
"Do whatever is right to suspend the current frame.
Calls `suspend-emacs' if invoked from the controlling terminal,
`suspend-tty' from a secondary terminal, and
Calls `suspend-emacs' if invoked from the controlling tty device,
`suspend-tty' from a secondary tty device, and
`iconify-or-deiconify-frame' from an X frame."
(interactive)
(let ((type (framep (selected-frame))))
......@@ -809,7 +812,6 @@ Calls `suspend-emacs' if invoked from the controlling terminal,
(suspend-tty)))
(t (suspend-emacs)))))
(defun make-frame-names-alist ()
(let* ((current-frame (selected-frame))
(falist
......@@ -1425,146 +1427,6 @@ Use Custom to set this variable to get the display updated."
(define-key ctl-x-5-map "0" 'delete-frame)
(define-key ctl-x-5-map "o" 'other-frame)
(substitute-key-definition 'suspend-emacs 'suspend-frame global-map)
(defun terminal-id (terminal)
"Return the numerical id of terminal TERMINAL.
TERMINAL can be a terminal id (an integer), a frame, or
nil (meaning the selected frame's terminal). Alternatively,
TERMINAL may be the name of an X display
device (HOST.SERVER.SCREEN) or a tty device file."
(cond
((integerp terminal)
(if (display-live-p terminal)
terminal
(signal 'wrong-type-argument (list 'display-live-p terminal))))
((or (null terminal) (framep terminal))
(frame-display terminal))
((stringp terminal)
(let ((f (car (filtered-frame-list (lambda (frame)
(or (equal (frame-parameter frame 'display) terminal)
(equal (frame-parameter frame 'tty) terminal)))))))
(or f (error "Display %s does not exist" terminal))
(frame-display f)))
(t
(error "Invalid argument %s in `terminal-id'" terminal))))
(defvar terminal-parameter-alist nil
"An alist of terminal parameter alists.")
(defun terminal-parameters (&optional terminal)
"Return the paramater-alist of terminal TERMINAL.
It is a list of elements of the form (PARM . VALUE), where PARM is a symbol.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(cdr (assq (terminal-id terminal) terminal-parameter-alist)))
(defun terminal-parameter-p (terminal parameter)
"Return non-nil if PARAMETER is a terminal parameter on TERMINAL.
The actual value returned in that case is a cell (PARAMETER . VALUE),
where VALUE is the current value of PARAMETER.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(assq parameter (cdr (assq (terminal-id terminal) terminal-parameter-alist))))
(defun terminal-parameter (terminal parameter)
"Return TERMINAL's value for parameter PARAMETER.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(cdr (terminal-parameter-p terminal parameter)))
(defun set-terminal-parameter (terminal parameter value)
"Set TERMINAL's value for parameter PARAMETER to VALUE.
Returns the previous value of PARAMETER.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(setq terminal (terminal-id terminal))
(let* ((alist (assq terminal terminal-parameter-alist))
(pair (assq parameter (cdr alist)))
(result (cdr pair)))
(cond
(pair (setcdr pair value))
(alist (setcdr alist (cons (cons parameter value) (cdr alist))))
(t (setq terminal-parameter-alist
(cons (cons terminal
(cons (cons parameter value)
nil))
terminal-parameter-alist))))
result))
(defun terminal-handle-delete-frame (frame)
"Clean up terminal parameters of FRAME, if it's the last frame on its terminal."
;; XXX We assume that the display is closed immediately after the
;; last frame is deleted on it. It would be better to create a hook
;; called `delete-display-functions', and use it instead.
(when (and (frame-live-p frame)
(= 1 (length (frames-on-display-list (frame-display frame)))))
(setq terminal-parameter-alist
(assq-delete-all (frame-display frame) terminal-parameter-alist))))
(add-hook 'delete-frame-functions 'terminal-handle-delete-frame)
(defun terminal-getenv (variable &optional terminal)
"Get the value of VARIABLE in the client environment of TERMINAL.
VARIABLE should be a string. Value is nil if VARIABLE is undefined in
the environment. Otherwise, value is a string.
If TERMINAL was created by an emacsclient invocation, then the
variable is looked up in the environment of the emacsclient
process; otherwise the function consults the environment of the
Emacs process.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(setq terminal (terminal-id terminal))
(if (not (terminal-parameter-p terminal 'environment))
(getenv variable)
(let ((env (terminal-parameter terminal 'environment))
result entry)
(while (and env (null result))
(setq entry (car env)
env (cdr env))
(if (and (> (length entry) (length variable))
(eq ?= (aref entry (length variable)))
(equal variable (substring entry 0 (length variable))))
(setq result (substring entry (+ (length variable) 1)))))
(if (null result)
(getenv variable)
result))))
(defmacro with-terminal-environment (terminal vars &rest body)
"Evaluate BODY with environment variables VARS set to those of TERMINAL.
The environment variables are then restored to their previous values.
VARS should be a list of strings.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal).
See also `terminal-getenv'."
(declare (indent 2))
(let ((oldvalues (make-symbol "oldvalues"))
(var (make-symbol "var"))
(value (make-symbol "value"))
(pair (make-symbol "pair")))
`(let (,oldvalues)
(dolist (,var ,vars)
(let ((,value (terminal-getenv ,var ,terminal)))
(setq ,oldvalues (cons (cons ,var (getenv ,var)) ,oldvalues))
(setenv ,var ,value)))
(unwind-protect
(progn ,@body)
(dolist (,pair ,oldvalues)
(setenv (car ,pair) (cdr ,pair)))))))
(provide 'frame)
;; arch-tag: 82979c70-b8f2-4306-b2ad-ddbd6b328b56
......
......@@ -132,6 +132,7 @@
(load "indent")
(load "window")
(load "frame")
(load "termdev")
(load "term/tty-colors")
(load "font-core")
;; facemenu must be loaded before font-lock, because `facemenu-keymap'
......
......@@ -2004,7 +2004,7 @@ COLLAPSE non-nil means collapse the branch."
(fillarray (car (cdr map)) 'ebrowse-electric-list-undefined)
(fillarray (car (cdr submap)) 'ebrowse-electric-list-undefined)
(define-key map "\e" submap)
(define-key map "\C-z" 'suspend-emacs)
(define-key map "\C-z" 'suspend-frame)
(define-key map "\C-h" 'Helper-help)
(define-key map "?" 'Helper-describe-bindings)
(define-key map "\C-c" nil)
......@@ -3964,7 +3964,7 @@ Prefix arg ARG says how much."
(fillarray (car (cdr map)) 'ebrowse-electric-position-undefined)
(fillarray (car (cdr submap)) 'ebrowse-electric-position-undefined)
(define-key map "\e" submap)
(define-key map "\C-z" 'suspend-emacs)
(define-key map "\C-z" 'suspend-frame)
(define-key map "\C-h" 'Helper-help)
(define-key map "?" 'Helper-describe-bindings)
(define-key map "\C-c" nil)
......
......@@ -1429,7 +1429,7 @@ Copyright (C) 2005 Free Software Foundation, Inc."))
;; use precomputed string to save lots of time.
(if (and (eq (key-binding "\C-h") 'help-command)
(eq (key-binding "\C-xu") 'advertised-undo)
(eq (key-binding "\C-x\C-c") 'save-buffers-kill-emacs)
(eq (key-binding "\C-x\C-c") 'save-buffers-kill-display)
(eq (key-binding "\C-ht") 'help-with-tutorial)
(eq (key-binding "\C-hi") 'info)
(eq (key-binding "\C-hr") 'info-emacs-manual)
......@@ -1446,7 +1446,7 @@ Browse manuals C-h i")
Get help %s
Emacs manual \\[info-emacs-manual]
Emacs tutorial \\[help-with-tutorial]\tUndo changes\t\\[advertised-undo]
Buy manuals \\[view-order-manuals]\tExit Emacs\t\\[save-buffers-kill-emacs]
Buy manuals \\[view-order-manuals]\tExit Emacs\t\\[save-buffers-kill-display]
Browse manuals \\[info]"
(let ((where (where-is-internal
'help-command nil t)))
......
......@@ -2407,7 +2407,7 @@ order until succeed.")
(aset x-resource-name i ?-))))
(x-open-connection (or x-display-name
(setq x-display-name (terminal-getenv "DISPLAY")))
(setq x-display-name (terminal-getenv "DISPLAY" nil 'global-ok)))
x-command-line-resources
;; Exit Emacs with fatal error if this fails and we
;; are the initial display.
......
;;; termdev.el --- functions for dealing with terminals
;; Copyright (C) 2005 Free Software Foundation, Inc.
;; Author: Karoly Lorentey <karoly@lorentey.hu>
;; Created: 2005-12-22
;; Keywords: internal
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
(substitute-key-definition 'suspend-emacs 'suspend-frame global-map)
(defun terminal-id (terminal)
"Return the numerical id of terminal TERMINAL.
TERMINAL can be a terminal id (an integer), a frame, or
nil (meaning the selected frame's terminal). Alternatively,
TERMINAL may be the name of an X display
device (HOST.SERVER.SCREEN) or a tty device file."
(cond
((integerp terminal)
(if (display-live-p terminal)
terminal
(signal 'wrong-type-argument (list 'display-live-p terminal))))
((or (null terminal) (framep terminal))
(frame-display terminal))
((stringp terminal)
(let ((f (car (filtered-frame-list (lambda (frame)
(or (equal (frame-parameter frame 'display) terminal)
(equal (frame-parameter frame 'tty) terminal)))))))
(or f (error "Display %s does not exist" terminal))
(frame-display f)))
(t
(error "Invalid argument %s in `terminal-id'" terminal))))
(defvar terminal-parameter-alist nil
"An alist of terminal parameter alists.")
(defun terminal-parameters (&optional terminal)
"Return the paramater-alist of terminal TERMINAL.
It is a list of elements of the form (PARM . VALUE), where PARM is a symbol.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(cdr (assq (terminal-id terminal) terminal-parameter-alist)))
(defun terminal-parameter-p (terminal parameter)
"Return non-nil if PARAMETER is a terminal parameter on TERMINAL.
The actual value returned in that case is a cell (PARAMETER . VALUE),
where VALUE is the current value of PARAMETER.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(assq parameter (cdr (assq (terminal-id terminal) terminal-parameter-alist))))
(defun terminal-parameter (terminal parameter)
"Return TERMINAL's value for parameter PARAMETER.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(cdr (terminal-parameter-p terminal parameter)))
(defun set-terminal-parameter (terminal parameter value)
"Set TERMINAL's value for parameter PARAMETER to VALUE.
Returns the previous value of PARAMETER.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(setq terminal (terminal-id terminal))
(let* ((alist (assq terminal terminal-parameter-alist))
(pair (assq parameter (cdr alist)))
(result (cdr pair)))
(cond
(pair (setcdr pair value))
(alist (setcdr alist (cons (cons parameter value) (cdr alist))))
(t (setq terminal-parameter-alist
(cons (cons terminal
(cons (cons parameter value)
nil))
terminal-parameter-alist))))
result))
(defun terminal-handle-delete-frame (frame)
"Clean up terminal parameters of FRAME, if it's the last frame on its terminal."
;; XXX We assume that the display is closed immediately after the
;; last frame is deleted on it. It would be better to create a hook
;; called `delete-display-functions', and use it instead.
(when (and (frame-live-p frame)
(= 1 (length (frames-on-display-list (frame-display frame)))))
(setq terminal-parameter-alist
(assq-delete-all (frame-display frame) terminal-parameter-alist))))
(add-hook 'delete-frame-functions 'terminal-handle-delete-frame)
(defun terminal-getenv (variable &optional terminal global-ok)
"Get the value of VARIABLE in the client environment of TERMINAL.
VARIABLE should be a string. Value is nil if VARIABLE is undefined in
the environment. Otherwise, value is a string.
If TERMINAL has an associated emacsclient process, then
`terminal-getenv' looks up VARIABLE in the environment of that
process; otherwise the function consults the global environment,
i.e., the environment of the Emacs process itself.
If GLOBAL-OK is non-nil, and VARIABLE is not defined in the
terminal-local environment, then `terminal-getenv' will return
its value in the global environment instead.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(setq terminal (terminal-id terminal))
(if (not (terminal-parameter-p terminal 'environment))
(getenv variable)
(if (multibyte-string-p variable)
(setq variable (encode-coding-string variable locale-coding-system)))
(let ((env (terminal-parameter terminal 'environment))
result entry)
(while (and env (null result))
(setq entry (car env)
env (cdr env))
(if (and (> (length entry) (length variable))
(eq ?= (aref entry (length variable)))
(equal variable (substring entry 0 (length variable))))
(setq result (substring entry (+ (length variable) 1)))))
(if (and global-ok (null result))
(getenv variable)
(and result (decode-coding-string result locale-coding-system))))))
(defun terminal-setenv (variable &optional value terminal)
"Set the value of VARIABLE in the environment of TERMINAL.
VARIABLE should be string. VALUE is optional; if not provided or
nil, the environment variable VARIABLE is removed. Returned
value is the new value of VARIABLE, or nil if it was removed from
the environment.
If TERMINAL was created by an emacsclient invocation, then the
variable is set in the environment of the emacsclient process;
otherwise the function changes the environment of the Emacs
process itself.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal)."
(if (not (terminal-parameter-p terminal 'environment))
(setenv variable value)
(with-terminal-environment terminal variable
(setenv variable value))))
(defun terminal-setenv-internal (variable value terminal)
"Set the value of VARIABLE in the environment of TERMINAL.
The caller is responsible to ensure that both VARIABLE and VALUE
are usable in environment variables and that TERMINAL is a
remote terminal."
(if (multibyte-string-p variable)
(setq variable (encode-coding-string variable locale-coding-system)))
(if (and value (multibyte-string-p value))
(setq value (encode-coding-string value locale-coding-system)))
(let ((env (terminal-parameter terminal 'environment))
found)
(while (and env (not found))
(if (and (> (length (car env)) (length variable))
(eq ?= (aref (car env) (length variable)))
(equal variable (substring (car env) 0 (length variable))))
(progn
(if value
(setcar env (concat variable "=" value))
(set-terminal-parameter terminal 'environment
(delq (car env)
(terminal-parameter terminal
'environment))))
(setq found t))
(setq env (cdr env))))
(cond
((and value found)
(setcar env (concat variable "=" value)))
((and value (not found))
(set-terminal-parameter terminal 'environment
(cons (concat variable "=" value)
(terminal-parameter terminal
'environment))))
((and (not value) found)
(set-terminal-parameter terminal 'environment
(delq (car env)
(terminal-parameter terminal
'environment)))))))
(defmacro with-terminal-environment (terminal vars &rest body)
"Evaluate BODY with environment variables VARS set to those of TERMINAL.
The environment variables are then restored to their previous values.
VARS should be a single string, a list of strings, or t for all
environment variables.
TERMINAL can be a terminal id, a frame, or nil (meaning the
selected frame's terminal).
If BODY uses `setenv' to change environment variables in VARS,
then the new variable values will be remembered for TERMINAL, and
`terminal-getenv' will return them even outside BODY."
(declare (indent 2))
(let ((var (make-symbol "var"))
(term (make-symbol "term"))
(v (make-symbol "v"))