1 ;;; tramp-compat.el --- Tramp compatibility functions
3 ;; Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 ;; Author: Michael Albinus <michael.albinus@gmx.de>
6 ;; Keywords: comm, processes
9 ;; This file is part of GNU Emacs.
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 3 of the License, or
14 ;; (at your option) any later version.
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.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26 ;; Tramp's main Emacs version for development is GNU Emacs 24. This
27 ;; package provides compatibility functions for GNU Emacs 22, GNU
28 ;; Emacs 23 and XEmacs 21.4+.
34 ;; Pacify byte-compiler.
41 ;; Load the appropriate timer package.
42 (if (featurep 'xemacs
)
43 (require 'timer-funcs
)
46 (autoload 'tramp-tramp-file-p
"tramp")
47 (autoload 'tramp-file-name-handler
"tramp")
49 ;; We check whether `start-file-process' is bound.
50 (unless (fboundp 'start-file-process
)
52 ;; tramp-util offers integration into other (X)Emacs packages like
53 ;; compile.el, gud.el etc. Not necessary in Emacs 23.
54 (eval-after-load "tramp"
57 (add-hook 'tramp-unload-hook
59 (when (featurep 'tramp-util
)
60 (unload-feature 'tramp-util
'force
))))))
62 ;; Make sure that we get integration with the VC package. When it
63 ;; is loaded, we need to pull in the integration module. Not
64 ;; necessary in Emacs 23.
66 (eval-after-load "tramp"
69 (add-hook 'tramp-unload-hook
71 (when (featurep 'tramp-vc
)
72 (unload-feature 'tramp-vc
'force
))))))))
74 ;; Avoid byte-compiler warnings if the byte-compiler supports this.
75 ;; Currently, XEmacs supports this.
76 (when (featurep 'xemacs
)
77 (unless (boundp 'byte-compile-default-warnings
)
78 (defvar byte-compile-default-warnings nil
))
79 (delq 'unused-vars byte-compile-default-warnings
))
81 ;; `last-coding-system-used' is unknown in XEmacs.
82 (unless (boundp 'last-coding-system-used
)
83 (defvar last-coding-system-used nil
))
85 ;; `directory-sep-char' is an obsolete variable in Emacs. But it is
86 ;; used in XEmacs, so we set it here and there. The following is
87 ;; needed to pacify Emacs byte-compiler.
88 (unless (boundp 'byte-compile-not-obsolete-var
)
89 (defvar byte-compile-not-obsolete-var nil
))
90 (setq byte-compile-not-obsolete-var
'directory-sep-char
)
92 (unless (boundp 'byte-compile-not-obsolete-vars
)
93 (defvar byte-compile-not-obsolete-vars nil
))
94 (setq byte-compile-not-obsolete-vars
'(directory-sep-char))
96 ;; `with-temp-message' does not exists in XEmacs.
98 (with-temp-message (current-message) nil
)
99 (error (defmacro with-temp-message
(message &rest body
) `(progn ,@body
))))
101 ;; For not existing functions, or functions with a changed argument
102 ;; list, there are compiler warnings. We want to avoid them in
103 ;; cases we know what we do.
104 (defmacro tramp-compat-funcall
(function &rest arguments
)
105 (if (featurep 'xemacs
)
106 `(funcall (symbol-function ,function
) ,@arguments
)
107 `(when (or (subrp ,function
) (functionp ,function
))
108 (with-no-warnings (funcall ,function
,@arguments
)))))
110 ;; `set-buffer-multibyte' comes from Emacs Leim.
111 (unless (fboundp 'set-buffer-multibyte
)
112 (defalias 'set-buffer-multibyte
'ignore
))
114 ;; `font-lock-add-keywords' does not exist in XEmacs.
115 (unless (fboundp 'font-lock-add-keywords
)
116 (defalias 'font-lock-add-keywords
'ignore
))
118 ;; The following functions cannot be aliases of the corresponding
119 ;; `tramp-handle-*' functions, because this would bypass the locking
122 ;; `file-remote-p' has been introduced with Emacs 22. The version
123 ;; of XEmacs is not a magic file name function (yet); this is
124 ;; corrected in tramp-util.el. Here it is sufficient if the
126 (unless (fboundp 'file-remote-p
)
127 (defalias 'file-remote-p
128 (lambda (file &optional identification connected
)
129 (when (tramp-tramp-file-p file
)
130 (tramp-file-name-handler
131 'file-remote-p file identification connected
)))))
133 ;; `process-file' does not exist in XEmacs.
134 (unless (fboundp 'process-file
)
135 (defalias 'process-file
136 (lambda (program &optional infile buffer display
&rest args
)
137 (when (tramp-tramp-file-p default-directory
)
139 'tramp-file-name-handler
140 'process-file program infile buffer display args
)))))
142 ;; `start-file-process' is new in Emacs 23.
143 (unless (fboundp 'start-file-process
)
144 (defalias 'start-file-process
145 (lambda (name buffer program
&rest program-args
)
146 (when (tramp-tramp-file-p default-directory
)
148 'tramp-file-name-handler
149 'start-file-process name buffer program program-args
)))))
151 ;; `set-file-times' is also new in Emacs 23.
152 (unless (fboundp 'set-file-times
)
153 (defalias 'set-file-times
154 (lambda (filename &optional time
)
155 (when (tramp-tramp-file-p filename
)
156 (tramp-file-name-handler
157 'set-file-times filename time
)))))
159 ;; We currently use "[" and "]" in the filename format for IPv6
160 ;; hosts of GNU Emacs. This means, that Emacs wants to expand
161 ;; wildcards if `find-file-wildcards' is non-nil, and then barfs
162 ;; because no expansion could be found. We detect this situation
163 ;; and do something really awful: we have `file-expand-wildcards'
164 ;; return the original filename if it can't expand anything. Let's
165 ;; just hope that this doesn't break anything else.
166 ;; It is not needed anymore since GNU Emacs 23.2.
167 (unless (or (featurep 'xemacs
)
168 ;; `featurep' has only one argument in XEmacs.
169 (funcall 'featurep
'files
'remote-wildcards
))
170 (defadvice file-expand-wildcards
171 (around tramp-advice-file-expand-wildcards activate
)
172 (let ((name (ad-get-arg 0)))
173 ;; If it's a Tramp file, look if wildcards need to be expanded
176 (tramp-tramp-file-p name
)
178 "[[*?]" (tramp-compat-funcall
179 'file-remote-p name
'localname
))))
180 (setq ad-return-value
(list name
))
181 ;; Otherwise, just run the original function.
187 'file-expand-wildcards
'around
'tramp-advice-file-expand-wildcards
)
188 (ad-activate 'file-expand-wildcards
)))))
190 (defsubst tramp-compat-line-beginning-position
()
191 "Return point at beginning of line (compat function).
192 Calls `line-beginning-position' or `point-at-bol' if defined, else
195 ((fboundp 'line-beginning-position
)
196 (tramp-compat-funcall 'line-beginning-position
))
197 ((fboundp 'point-at-bol
) (tramp-compat-funcall 'point-at-bol
))
198 (t (save-excursion (beginning-of-line) (point)))))
200 (defsubst tramp-compat-line-end-position
()
201 "Return point at end of line (compat function).
202 Calls `line-end-position' or `point-at-eol' if defined, else
205 ((fboundp 'line-end-position
) (tramp-compat-funcall 'line-end-position
))
206 ((fboundp 'point-at-eol
) (tramp-compat-funcall 'point-at-eol
))
207 (t (save-excursion (end-of-line) (point)))))
209 (defsubst tramp-compat-temporary-file-directory
()
210 "Return name of directory for temporary files (compat function).
211 For Emacs, this is the variable `temporary-file-directory', for XEmacs
212 this is the function `temp-directory'."
214 ((boundp 'temporary-file-directory
) (symbol-value 'temporary-file-directory
))
215 ((fboundp 'temp-directory
) (tramp-compat-funcall 'temp-directory
))
216 ((let ((d (getenv "TEMP"))) (and d
(file-directory-p d
)))
217 (file-name-as-directory (getenv "TEMP")))
218 ((let ((d (getenv "TMP"))) (and d
(file-directory-p d
)))
219 (file-name-as-directory (getenv "TMP")))
220 ((let ((d (getenv "TMPDIR"))) (and d
(file-directory-p d
)))
221 (file-name-as-directory (getenv "TMPDIR")))
222 ((file-exists-p "c:/temp") (file-name-as-directory "c:/temp"))
223 (t (message (concat "Neither `temporary-file-directory' nor "
224 "`temp-directory' is defined -- using /tmp."))
225 (file-name-as-directory "/tmp"))))
227 ;; `make-temp-file' exists in Emacs only. On XEmacs, we use our own
228 ;; implementation with `make-temp-name', creating the temporary file
229 ;; immediately in order to avoid a security hole.
230 (defsubst tramp-compat-make-temp-file
(filename &optional dir-flag
)
231 "Create a temporary file (compat function).
232 Add the extension of FILENAME, if existing."
233 (let* (file-name-handler-alist
234 (prefix (expand-file-name
235 (symbol-value 'tramp-temp-name-prefix
)
236 (tramp-compat-temporary-file-directory)))
237 (extension (file-name-extension filename t
))
241 (tramp-compat-funcall 'make-temp-file prefix dir-flag extension
))
243 ;; We use our own implementation, taken from files.el.
247 (setq result
(concat (make-temp-name prefix
) extension
))
249 (make-directory result
)
250 (write-region "" nil result nil
'silent
))
252 (file-already-exists t
))
253 ;; The file was somehow created by someone else between
254 ;; `make-temp-name' and `write-region', let's try again.
258 ;; `most-positive-fixnum' does not exist in XEmacs.
259 (defsubst tramp-compat-most-positive-fixnum
()
260 "Return largest positive integer value (compat function)."
262 ((boundp 'most-positive-fixnum
) (symbol-value 'most-positive-fixnum
))
263 ;; Default value in XEmacs.
266 ;; ID-FORMAT does not exists in XEmacs.
267 (defun tramp-compat-file-attributes (filename &optional id-format
)
268 "Like `file-attributes' for Tramp files (compat function)."
270 ((or (null id-format
) (eq id-format
'integer
))
271 (file-attributes filename
))
272 ((tramp-tramp-file-p filename
)
273 (tramp-file-name-handler 'file-attributes filename id-format
))
274 (t (condition-case nil
275 (tramp-compat-funcall 'file-attributes filename id-format
)
276 (wrong-number-of-arguments (file-attributes filename
))))))
278 ;; PRESERVE-UID-GID has been introduced with Emacs 23. It does not
279 ;; hurt to ignore it for other (X)Emacs versions.
280 ;; PRESERVE-SELINUX-CONTEXT has been introduced with Emacs 24.
281 (defun tramp-compat-copy-file
282 (filename newname
&optional ok-if-already-exists keep-date
283 preserve-uid-gid preserve-selinux-context
)
284 "Like `copy-file' for Tramp files (compat function)."
286 (preserve-selinux-context
287 (tramp-compat-funcall
288 'copy-file filename newname ok-if-already-exists keep-date
289 preserve-uid-gid preserve-selinux-context
))
291 (tramp-compat-funcall
292 'copy-file filename newname ok-if-already-exists keep-date
295 (copy-file filename newname ok-if-already-exists keep-date
))))
297 ;; `copy-directory' is a new function in Emacs 23.2. Implementation
298 ;; is taken from there.
299 (defun tramp-compat-copy-directory
300 (directory newname
&optional keep-time parents
)
301 "Make a copy of DIRECTORY (compat function)."
302 (if (fboundp 'copy-directory
)
303 (tramp-compat-funcall 'copy-directory directory newname keep-time parents
)
305 ;; If `default-directory' is a remote directory, make sure we find
306 ;; its `copy-directory' handler.
307 (let ((handler (or (find-file-name-handler directory
'copy-directory
)
308 (find-file-name-handler newname
'copy-directory
))))
310 (funcall handler
'copy-directory directory newname keep-time parents
)
312 ;; Compute target name.
313 (setq directory
(directory-file-name (expand-file-name directory
))
314 newname
(directory-file-name (expand-file-name newname
)))
315 (if (and (file-directory-p newname
)
316 (not (string-equal (file-name-nondirectory directory
)
317 (file-name-nondirectory newname
))))
320 (file-name-nondirectory directory
) newname
)))
321 (if (not (file-directory-p newname
)) (make-directory newname parents
))
326 (if (file-directory-p file
)
327 (tramp-compat-copy-directory file newname keep-time parents
)
328 (copy-file file newname t keep-time
)))
329 ;; We do not want to delete "." and "..".
331 directory
'full
"^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))
333 ;; Set directory attributes.
334 (set-file-modes newname
(file-modes directory
))
336 (set-file-times newname
(nth 5 (file-attributes directory
))))))))
338 ;; TRASH has been introduced with Emacs 24.1.
339 (defun tramp-compat-delete-file (filename &optional trash
)
340 "Like `delete-file' for Tramp files (compat function)."
342 (tramp-compat-funcall 'delete-file filename trash
)
343 ;; This Emacs version does not support the TRASH flag.
344 (wrong-number-of-arguments
345 (let ((delete-by-moving-to-trash
346 (and (boundp 'delete-by-moving-to-trash
)
347 (symbol-value 'delete-by-moving-to-trash
)
349 (delete-file filename
)))))
351 ;; RECURSIVE has been introduced with Emacs 23.2.
352 (defun tramp-compat-delete-directory (directory &optional recursive
)
353 "Like `delete-directory' for Tramp files (compat function)."
355 (delete-directory directory
)
357 (tramp-compat-funcall 'delete-directory directory recursive
)
358 ;; This Emacs version does not support the RECURSIVE flag. We
359 ;; use the implementation from Emacs 23.2.
360 (wrong-number-of-arguments
361 (setq directory
(directory-file-name (expand-file-name directory
)))
362 (if (not (file-symlink-p directory
))
364 (if (eq t
(car (file-attributes file
)))
365 (tramp-compat-delete-directory file recursive
)
368 directory
'full
"^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*")))
369 (delete-directory directory
)))))
371 ;; `number-sequence' does not exist in XEmacs. Implementation is
372 ;; taken from Emacs 23.
373 (defun tramp-compat-number-sequence (from &optional to inc
)
374 "Return a sequence of numbers from FROM to TO as a list (compat function)."
375 (if (or (subrp 'number-sequence
) (symbol-file 'number-sequence
))
376 (tramp-compat-funcall 'number-sequence from to inc
)
377 (if (or (not to
) (= from to
))
379 (or inc
(setq inc
1))
380 (when (zerop inc
) (error "The increment can not be zero"))
381 (let (seq (n 0) (next from
))
384 (setq seq
(cons next seq
)
386 next
(+ from
(* n inc
))))
388 (setq seq
(cons next seq
)
390 next
(+ from
(* n inc
)))))
393 (defun tramp-compat-split-string (string pattern
)
394 "Like `split-string' but omit empty strings.
395 In Emacs, (split-string \"/foo/bar\" \"/\") returns (\"foo\" \"bar\").
396 This is, the first, empty, element is omitted. In XEmacs, the first
397 element is not omitted."
398 (delete "" (split-string string pattern
)))
400 (defun tramp-compat-process-running-p (process-name)
401 "Returns `t' if system process PROCESS-NAME is running for `user-login-name'."
402 (when (stringp process-name
)
404 ;; GNU Emacs 22 on w32.
405 ((fboundp 'w32-window-exists-p
)
406 (tramp-compat-funcall 'w32-window-exists-p process-name process-name
))
409 ((and (fboundp 'list-system-processes
) (fboundp 'process-attributes
))
411 (dolist (pid (tramp-compat-funcall 'list-system-processes
) result
)
412 (let ((attributes (tramp-compat-funcall 'process-attributes pid
)))
413 (when (and (string-equal
414 (cdr (assoc 'user attributes
)) (user-login-name))
415 (let ((comm (cdr (assoc 'comm attributes
))))
416 ;; The returned command name could be truncated
417 ;; to 15 characters. Therefore, we cannot check
418 ;; for `string-equal'.
419 (and comm
(string-match
420 (concat "^" (regexp-quote comm
))
424 ;; Fallback, if there is no Lisp support yet.
425 (t (let ((default-directory
426 (if (file-remote-p default-directory
)
427 (tramp-compat-temporary-file-directory)
429 (unix95 (getenv "UNIX95"))
431 (setenv "UNIX95" "1")
434 (tramp-compat-split-string
435 (shell-command-to-string
436 (format "ps -C %s -o user=" process-name
))
439 (setenv "UNIX95" unix95
)
442 (provide 'tramp-compat
)
446 ;; arch-tag: 0e724b18-6699-4f87-ad96-640b272e5c85
447 ;;; tramp-compat.el ends here