]> code.delx.au - gnu-emacs/blob - lisp/jka-cmpr-hook.el
198cd5ce680cec6e7486f184d28a7317dd512980
[gnu-emacs] / lisp / jka-cmpr-hook.el
1 ;;; jka-cmpr-hook.el --- preloaded code to enable jka-compr.el
2
3 ;; Copyright (C) 1993-1995, 1997, 1999-2000, 2002-2011 Free Software Foundation, Inc.
4
5 ;; Author: jka@ece.cmu.edu (Jay K. Adams)
6 ;; Maintainer: FSF
7 ;; Keywords: data
8 ;; Package: emacs
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software: you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation, either version 3 of the License, or
15 ;; (at your option) any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24
25 ;;; Commentary:
26
27 ;; This file contains the code to enable and disable Auto-Compression mode.
28 ;; It is preloaded. The guts of this mode are in jka-compr.el, which
29 ;; is loaded only when you really try to uncompress something.
30
31 ;;; Code:
32
33 (defgroup compression nil
34 "Data compression utilities."
35 :group 'data)
36
37 (defgroup jka-compr nil
38 "jka-compr customization."
39 :group 'compression)
40
41 ;; List of all the elements we actually added to file-coding-system-alist.
42 (defvar jka-compr-added-to-file-coding-system-alist nil)
43
44 (defvar jka-compr-file-name-handler-entry
45 nil
46 "`file-name-handler-alist' entry used by jka-compr I/O functions.")
47
48 ;; Compiler defvars. These three variables will be defined later with
49 ;; `defcustom' when everything used in the :set functions is defined.
50 (defvar jka-compr-compression-info-list)
51 (defvar jka-compr-mode-alist-additions)
52 (defvar jka-compr-load-suffixes)
53
54 (defvar jka-compr-compression-info-list--internal nil
55 "Stored value of `jka-compr-compression-info-list'.
56 If Auto Compression mode is enabled, this is the value of
57 `jka-compr-compression-info-list' when `jka-compr-install' was last called.
58 Otherwise, it is nil.")
59
60 (defvar jka-compr-mode-alist-additions--internal nil
61 "Stored value of `jka-compr-mode-alist-additions'.
62 If Auto Compression mode is enabled, this is the value of
63 `jka-compr-mode-alist-additions' when `jka-compr-install' was last called.
64 Otherwise, it is nil.")
65
66 (defvar jka-compr-load-suffixes--internal nil
67 "Stored value of `jka-compr-load-suffixes'.
68 If Auto Compression mode is enabled, this is the value of
69 `jka-compr-load-suffixes' when `jka-compr-install' was last called.
70 Otherwise, it is nil.")
71
72 \f
73 (defun jka-compr-build-file-regexp ()
74 (purecopy
75 (let ((re-anchored '())
76 (re-free '()))
77 (dolist (e jka-compr-compression-info-list)
78 (let ((re (jka-compr-info-regexp e)))
79 (if (string-match "\\\\'\\'" re)
80 (push (substring re 0 (match-beginning 0)) re-anchored)
81 (push re re-free))))
82 (concat
83 (if re-free (concat (mapconcat 'identity re-free "\\|") "\\|"))
84 "\\(?:"
85 (mapconcat 'identity re-anchored "\\|")
86 "\\)" file-name-version-regexp "?\\'"))))
87
88 ;; Functions for accessing the return value of jka-compr-get-compression-info
89 (defun jka-compr-info-regexp (info) (aref info 0))
90 (defun jka-compr-info-compress-message (info) (aref info 1))
91 (defun jka-compr-info-compress-program (info) (aref info 2))
92 (defun jka-compr-info-compress-args (info) (aref info 3))
93 (defun jka-compr-info-uncompress-message (info) (aref info 4))
94 (defun jka-compr-info-uncompress-program (info) (aref info 5))
95 (defun jka-compr-info-uncompress-args (info) (aref info 6))
96 (defun jka-compr-info-can-append (info) (aref info 7))
97 (defun jka-compr-info-strip-extension (info) (aref info 8))
98 (defun jka-compr-info-file-magic-bytes (info) (aref info 9))
99
100
101 (defun jka-compr-get-compression-info (filename)
102 "Return information about the compression scheme of FILENAME.
103 The determination as to which compression scheme, if any, to use is
104 based on the filename itself and `jka-compr-compression-info-list'."
105 (catch 'compression-info
106 (let ((case-fold-search nil))
107 (dolist (x jka-compr-compression-info-list)
108 (and (string-match (jka-compr-info-regexp x) filename)
109 (throw 'compression-info x)))
110 nil)))
111
112 (defun jka-compr-install ()
113 "Install jka-compr.
114 This adds entries to `file-name-handler-alist' and `auto-mode-alist'
115 and `inhibit-first-line-modes-suffixes'."
116
117 (setq jka-compr-file-name-handler-entry
118 (cons (jka-compr-build-file-regexp) 'jka-compr-handler))
119
120 (push jka-compr-file-name-handler-entry file-name-handler-alist)
121
122 (setq jka-compr-compression-info-list--internal
123 jka-compr-compression-info-list
124 jka-compr-mode-alist-additions--internal
125 jka-compr-mode-alist-additions
126 jka-compr-load-suffixes--internal
127 jka-compr-load-suffixes)
128
129 (dolist (x jka-compr-compression-info-list)
130 ;; Don't do multibyte encoding on the compressed files.
131 (let ((elt (cons (jka-compr-info-regexp x)
132 '(no-conversion . no-conversion))))
133 (push elt file-coding-system-alist)
134 (push elt jka-compr-added-to-file-coding-system-alist))
135
136 (and (jka-compr-info-strip-extension x)
137 ;; Make entries in auto-mode-alist so that modes
138 ;; are chosen right according to the file names
139 ;; sans `.gz'.
140 (push (list (jka-compr-info-regexp x) nil 'jka-compr) auto-mode-alist)
141 ;; Also add these regexps to
142 ;; inhibit-first-line-modes-suffixes, so that a
143 ;; -*- line in the first file of a compressed tar
144 ;; file doesn't override tar-mode.
145 (push (jka-compr-info-regexp x)
146 inhibit-first-line-modes-suffixes)))
147 (setq auto-mode-alist
148 (append auto-mode-alist jka-compr-mode-alist-additions))
149
150 ;; Make sure that (load "foo") will find /bla/foo.el.gz.
151 (setq load-file-rep-suffixes
152 (append load-file-rep-suffixes jka-compr-load-suffixes nil)))
153
154 (defun jka-compr-installed-p ()
155 "Return non-nil if jka-compr is installed.
156 The return value is the entry in `file-name-handler-alist' for jka-compr."
157
158 (let ((fnha file-name-handler-alist)
159 (installed nil))
160
161 (while (and fnha (not installed))
162 (and (eq (cdr (car fnha)) 'jka-compr-handler)
163 (setq installed (car fnha)))
164 (setq fnha (cdr fnha)))
165
166 installed))
167
168 (defun jka-compr-update ()
169 "Update Auto Compression mode for changes in option values.
170 If you change the options `jka-compr-compression-info-list',
171 `jka-compr-mode-alist-additions' or `jka-compr-load-suffixes'
172 outside Custom, while Auto Compression mode is already enabled
173 \(as it is by default), then you have to call this function
174 afterward to properly update other variables. Setting these
175 options through Custom does this automatically."
176 (when (jka-compr-installed-p)
177 (jka-compr-uninstall)
178 (jka-compr-install)))
179
180 (defun jka-compr-set (variable value)
181 "Internal Custom :set function."
182 (set-default variable value)
183 (jka-compr-update))
184
185 ;; I have this defined so that .Z files are assumed to be in unix
186 ;; compress format; and .gz files, in gzip format, and .bz2 files in bzip fmt.
187
188 ;; FIXME? It seems ugly that one has to add "\\(~\\|\\.~[0-9]+~\\)?" to
189 ;; all the regexps here, in order to match backup files etc.
190 ;; It's trivial to modify jka-compr-get-compression-info to match
191 ;; regexps against file-name-sans-versions, but this regexp is also
192 ;; used to build a file-name-handler-alist entry.
193 ;; find-file-name-handler does not use file-name-sans-versions.
194 ;; Perhaps it should,
195 ;; http://lists.gnu.org/archive/html/emacs-devel/2008-02/msg00812.html,
196 ;; but it's used all over the place and there are probably other ramifications.
197 ;; One could modify jka-compr-build-file-regexp to add the backup regexp,
198 ;; but jka-compr-compression-info-list is a defcustom to which
199 ;; anything could be added, so it's easiest to leave things as they are.
200 (defcustom jka-compr-compression-info-list
201 ;;[regexp
202 ;; compr-message compr-prog compr-args
203 ;; uncomp-message uncomp-prog uncomp-args
204 ;; can-append strip-extension-flag file-magic-bytes]
205 (mapcar 'purecopy
206 '(["\\.Z\\'"
207 "compressing" "compress" ("-c")
208 ;; gzip is more common than uncompress. It can only read, not write.
209 "uncompressing" "gzip" ("-c" "-q" "-d")
210 nil t "\037\235"]
211 ;; Formerly, these had an additional arg "-c", but that fails with
212 ;; "Version 0.1pl2, 29-Aug-97." (RedHat 5.1 GNU/Linux) and
213 ;; "Version 0.9.0b, 9-Sept-98".
214 ["\\.bz2\\'"
215 "bzip2ing" "bzip2" nil
216 "bunzip2ing" "bzip2" ("-d")
217 nil t "BZh"]
218 ["\\.tbz2?\\'"
219 "bzip2ing" "bzip2" nil
220 "bunzip2ing" "bzip2" ("-d")
221 nil nil "BZh"]
222 ["\\.\\(?:tgz\\|svgz\\|sifz\\)\\'"
223 "compressing" "gzip" ("-c" "-q")
224 "uncompressing" "gzip" ("-c" "-q" "-d")
225 t nil "\037\213"]
226 ["\\.g?z\\'"
227 "compressing" "gzip" ("-c" "-q")
228 "uncompressing" "gzip" ("-c" "-q" "-d")
229 t t "\037\213"]
230 ["\\.xz\\'"
231 "XZ compressing" "xz" ("-c" "-q")
232 "XZ uncompressing" "xz" ("-c" "-q" "-d")
233 t t "\3757zXZ\0"]
234 ;; dzip is gzip with random access. Its compression program can't
235 ;; read/write stdin/out, so .dz files can only be viewed without
236 ;; saving, having their contents decompressed with gzip.
237 ["\\.dz\\'"
238 nil nil nil
239 "uncompressing" "gzip" ("-c" "-q" "-d")
240 nil t "\037\213"]))
241
242 "List of vectors that describe available compression techniques.
243 Each element, which describes a compression technique, is a vector of
244 the form [REGEXP COMPRESS-MSG COMPRESS-PROGRAM COMPRESS-ARGS
245 UNCOMPRESS-MSG UNCOMPRESS-PROGRAM UNCOMPRESS-ARGS
246 APPEND-FLAG STRIP-EXTENSION-FLAG FILE-MAGIC-CHARS], where:
247
248 regexp is a regexp that matches filenames that are
249 compressed with this format
250
251 compress-msg is the message to issue to the user when doing this
252 type of compression (nil means no message)
253
254 compress-program is a program that performs this compression
255 (nil means visit file in read-only mode)
256
257 compress-args is a list of args to pass to the compress program
258
259 uncompress-msg is the message to issue to the user when doing this
260 type of uncompression (nil means no message)
261
262 uncompress-program is a program that performs this compression
263
264 uncompress-args is a list of args to pass to the uncompress program
265
266 append-flag is non-nil if this compression technique can be
267 appended
268
269 strip-extension-flag non-nil means strip the regexp from file names
270 before attempting to set the mode.
271
272 file-magic-chars is a string of characters that you would find
273 at the beginning of a file compressed in this way.
274
275 If you set this outside Custom while Auto Compression mode is
276 already enabled \(as it is by default), you have to call
277 `jka-compr-update' after setting it to properly update other
278 variables. Setting this through Custom does that automatically."
279 :type '(repeat (vector regexp
280 (choice :tag "Compress Message"
281 (string :format "%v")
282 (const :tag "No Message" nil))
283 (choice :tag "Compress Program"
284 (string)
285 (const :tag "None" nil))
286 (repeat :tag "Compress Arguments" string)
287 (choice :tag "Uncompress Message"
288 (string :format "%v")
289 (const :tag "No Message" nil))
290 (choice :tag "Uncompress Program"
291 (string)
292 (const :tag "None" nil))
293 (repeat :tag "Uncompress Arguments" string)
294 (boolean :tag "Append")
295 (boolean :tag "Strip Extension")
296 (string :tag "Magic Bytes")))
297 :set 'jka-compr-set
298 :group 'jka-compr)
299
300 (defcustom jka-compr-mode-alist-additions
301 (list (cons (purecopy "\\.tgz\\'") 'tar-mode) (cons (purecopy "\\.tbz2?\\'") 'tar-mode))
302 "List of pairs added to `auto-mode-alist' when installing jka-compr.
303 Uninstalling jka-compr removes all pairs from `auto-mode-alist' that
304 installing added.
305
306 If you set this outside Custom while Auto Compression mode is
307 already enabled \(as it is by default), you have to call
308 `jka-compr-update' after setting it to properly update other
309 variables. Setting this through Custom does that automatically."
310 :type '(repeat (cons string symbol))
311 :set 'jka-compr-set
312 :group 'jka-compr)
313
314 (defcustom jka-compr-load-suffixes (list (purecopy ".gz"))
315 "List of compression related suffixes to try when loading files.
316 Enabling Auto Compression mode appends this list to `load-file-rep-suffixes',
317 which see. Disabling Auto Compression mode removes all suffixes
318 from `load-file-rep-suffixes' that enabling added.
319
320 If you set this outside Custom while Auto Compression mode is
321 already enabled \(as it is by default), you have to call
322 `jka-compr-update' after setting it to properly update other
323 variables. Setting this through Custom does that automatically."
324 :type '(repeat string)
325 :set 'jka-compr-set
326 :group 'jka-compr)
327
328 (define-minor-mode auto-compression-mode
329 "Toggle automatic file compression and uncompression.
330 With prefix argument ARG, turn auto compression on if positive, else off.
331 Return the new status of auto compression (non-nil means on)."
332 :global t :init-value t :group 'jka-compr :version "22.1"
333 (let* ((installed (jka-compr-installed-p))
334 (flag auto-compression-mode))
335 (cond
336 ((and flag installed) t) ; already installed
337 ((and (not flag) (not installed)) nil) ; already not installed
338 (flag (jka-compr-install))
339 (t (jka-compr-uninstall)))))
340
341 (defmacro with-auto-compression-mode (&rest body)
342 "Evalute BODY with automatic file compression and uncompression enabled."
343 (declare (indent 0))
344 (let ((already-installed (make-symbol "already-installed")))
345 `(let ((,already-installed (jka-compr-installed-p)))
346 (unwind-protect
347 (progn
348 (unless ,already-installed
349 (jka-compr-install))
350 ,@body)
351 (unless ,already-installed
352 (jka-compr-uninstall))))))
353
354 ;; This is what we need to know about jka-compr-handler
355 ;; in order to decide when to call it.
356
357 (put 'jka-compr-handler 'safe-magic t)
358 (put 'jka-compr-handler 'operations '(byte-compiler-base-file-name
359 write-region insert-file-contents
360 file-local-copy load))
361
362 ;; Turn on the mode.
363 (when auto-compression-mode (auto-compression-mode 1))
364
365 (provide 'jka-cmpr-hook)
366
367 ;;; jka-cmpr-hook.el ends here