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