Update years in copyright notice; nfc.
[bpt/emacs.git] / lisp / jka-compr.el
CommitLineData
be010748
RS
1;;; jka-compr.el --- reading/writing/loading compressed files
2
0d30b337 3;; Copyright (C) 1993, 1994, 1995, 1997, 1999, 2000, 2002, 2003,
aaef169d 4;; 2004, 2005, 2006 Free Software Foundation, Inc.
acd622cc
RS
5
6;; Author: jka@ece.cmu.edu (Jay K. Adams)
4228277d 7;; Maintainer: FSF
acd622cc
RS
8;; Keywords: data
9
f4454a14
RS
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 2, or (at your option)
15;; 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
b578f267 23;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
24;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25;; Boston, MA 02110-1301, USA.
f4454a14 26
55535639 27;;; Commentary:
acd622cc 28
b578f267
EN
29;; This package implements low-level support for reading, writing,
30;; and loading compressed files. It hooks into the low-level file
31;; I/O functions (including write-region and insert-file-contents) so
32;; that they automatically compress or uncompress a file if the file
33;; appears to need it (based on the extension of the file name).
34;; Packages like Rmail, VM, GNUS, and Info should be able to work
35;; with compressed files without modification.
36
37
38;; INSTRUCTIONS:
39;;
7391213d
MB
40;; To use jka-compr, invoke the command `auto-compression-mode' (which
41;; see), or customize the variable of the same name. Its operation
42;; should be transparent to the user (except for messages appearing when
43;; a file is being compressed or uncompressed).
b578f267
EN
44;;
45;; The variable, jka-compr-compression-info-list can be used to
46;; customize jka-compr to work with other compression programs.
47;; The default value of this variable allows jka-compr to work with
48;; Unix compress and gzip.
49;;
50;; If you are concerned about the stderr output of gzip and other
51;; compression/decompression programs showing up in your buffers, you
52;; should set the discard-error flag in the compression-info-list.
53;; This will cause the stderr of all programs to be discarded.
54;; However, it also causes emacs to call compression/uncompression
55;; programs through a shell (which is specified by jka-compr-shell).
56;; This may be a drag if, on your system, starting up a shell is
57;; slow.
58;;
59;; If you don't want messages about compressing and decompressing
60;; to show up in the echo area, you can set the compress-name and
61;; decompress-name fields of the jka-compr-compression-info-list to
62;; nil.
63
64
65;; APPLICATION NOTES:
66;;
67;; crypt++
5f320490 68;; jka-compr can coexist with crypt++ if you take all the decompression
b578f267
EN
69;; entries out of the crypt-encoding-list. Clearly problems will arise if
70;; you have two programs trying to compress/decompress files. jka-compr
71;; will not "work with" crypt++ in the following sense: you won't be able to
72;; decode encrypted compressed files--that is, files that have been
73;; compressed then encrypted (in that order). Theoretically, crypt++ and
74;; jka-compr could properly handle a file that has been encrypted then
75;; compressed, but there is little point in trying to compress an encrypted
76;; file.
77;;
78
79
80;; ACKNOWLEDGMENTS
f1180544 81;;
b578f267 82;; jka-compr is a V19 adaptation of jka-compr for V18 of Emacs. Many people
f1180544 83;; have made helpful suggestions, reported bugs, and even fixed bugs in
b578f267
EN
84;; jka-compr. I recall the following people as being particularly helpful.
85;;
86;; Jean-loup Gailly
87;; David Hughes
88;; Richard Pieri
89;; Daniel Quinlan
90;; Chris P. Ross
91;; Rick Sladkey
92;;
93;; Andy Norman's ange-ftp was the inspiration for the original jka-compr for
94;; Version 18 of Emacs.
95;;
96;; After I had made progress on the original jka-compr for V18, I learned of a
97;; package written by Kazushi Jam Marukawa, called jam-zcat, that did exactly
98;; what I was trying to do. I looked over the jam-zcat source code and
99;; probably got some ideas from it.
100;;
acd622cc
RS
101
102;;; Code:
103
f6cb7e0a
SM
104(require 'jka-cmpr-hook)
105
bbf5eb28 106(defcustom jka-compr-shell "sh"
acd622cc
RS
107 "*Shell to be used for calling compression programs.
108The value of this variable only matters if you want to discard the
109stderr of a compression/decompression program (see the documentation
bbf5eb28
RS
110for `jka-compr-compression-info-list')."
111 :type 'string
112 :group 'jka-compr)
acd622cc 113
f1180544 114(defvar jka-compr-use-shell
eb915452 115 (not (memq system-type '(ms-dos windows-nt))))
acd622cc 116
e073a356 117(defvar jka-compr-really-do-compress nil
dd83d95a
RS
118 "Non-nil in a buffer whose visited file was uncompressed on visiting it.
119This means compress the data on writing the file, even if the
120data appears to be compressed already.")
121(make-variable-buffer-local 'jka-compr-really-do-compress)
e073a356 122(put 'jka-compr-really-do-compress 'permanent-local t)
555235e6 123\f
acd622cc
RS
124
125(put 'compression-error 'error-conditions '(compression-error file-error error))
126
127
30c78e11 128(defvar jka-compr-acceptable-retval-list '(0 2 141))
acd622cc
RS
129
130
131(defun jka-compr-error (prog args infile message &optional errfile)
132
f6cb7e0a 133 (let ((errbuf (get-buffer-create " *jka-compr-error*")))
75e9c107
RS
134 (with-current-buffer errbuf
135 (widen) (erase-buffer)
136 (insert (format "Error while executing \"%s %s < %s\"\n\n"
137 prog
138 (mapconcat 'identity args " ")
139 infile))
140
141 (and errfile
142 (insert-file-contents errfile)))
acd622cc
RS
143 (display-buffer errbuf))
144
75e9c107
RS
145 (signal 'compression-error
146 (list "Opening input file" (format "error %s" message) infile)))
f1180544
JB
147
148
242d2673
RS
149(defcustom jka-compr-dd-program "/bin/dd"
150 "How to invoke `dd'."
151 :type 'string
152 :group 'jka-compr)
acd622cc
RS
153
154
dfe05fac 155(defvar jka-compr-dd-blocksize 256)
acd622cc
RS
156
157
158(defun jka-compr-partial-uncompress (prog message args infile beg len)
159 "Call program PROG with ARGS args taking input from INFILE.
160Fourth and fifth args, BEG and LEN, specify which part of the output
ee139ed3 161to keep: LEN chars starting BEG chars from the beginning."
242d2673
RS
162 (let ((start (point))
163 (prefix beg))
164 (if (and jka-compr-use-shell jka-compr-dd-program)
165 ;; Put the uncompression output through dd
166 ;; to discard the part we don't want.
167 (let ((skip (/ beg jka-compr-dd-blocksize))
168 (err-file (jka-compr-make-temp-name))
169 count)
170 ;; Update PREFIX based on the text that we won't read in.
171 (setq prefix (- beg (* skip jka-compr-dd-blocksize))
172 count (and len (1+ (/ (+ len prefix) jka-compr-dd-blocksize))))
173 (unwind-protect
174 (or (memq (call-process
175 jka-compr-shell infile t nil "-c"
176 (format
152e2693 177 "%s %s 2> %s | %s bs=%d skip=%d %s 2> %s"
242d2673
RS
178 prog
179 (mapconcat 'identity args " ")
180 err-file
181 jka-compr-dd-program
182 jka-compr-dd-blocksize
183 skip
184 ;; dd seems to be unreliable about
185 ;; providing the last block. So, always
186 ;; read one more than you think you need.
152e2693
EZ
187 (if count (format "count=%d" (1+ count)) "")
188 null-device))
242d2673
RS
189 jka-compr-acceptable-retval-list)
190 (jka-compr-error prog args infile message err-file))
191 (jka-compr-delete-temp-file err-file)))
192 ;; Run the uncompression program directly.
193 ;; We get the whole file and must delete what we don't want.
194 (jka-compr-call-process prog message infile t nil args))
acd622cc 195
ee139ed3 196 ;; Delete the stuff after what we want, if there is any.
acd622cc 197 (and
dfe05fac 198 len
ee139ed3 199 (< (+ start prefix len) (point))
dfe05fac 200 (delete-region (+ start prefix len) (point)))
acd622cc 201
ee139ed3 202 ;; Delete the stuff before what we want.
acd622cc
RS
203 (delete-region start (+ start prefix))))
204
205
206(defun jka-compr-call-process (prog message infile output temp args)
207 (if jka-compr-use-shell
208
a81635fc 209 (let ((err-file (jka-compr-make-temp-name))
baefb016 210 (coding-system-for-read (or coding-system-for-read 'undecided))
70c7850e 211 (coding-system-for-write 'no-conversion))
a81635fc 212
acd622cc
RS
213 (unwind-protect
214
215 (or (memq
216 (call-process jka-compr-shell infile
217 (if (stringp output) nil output)
218 nil
219 "-c"
220 (format "%s %s 2> %s %s"
221 prog
222 (mapconcat 'identity args " ")
223 err-file
224 (if (stringp output)
225 (concat "> " output)
226 "")))
227 jka-compr-acceptable-retval-list)
228
229 (jka-compr-error prog args infile message err-file))
230
231 (jka-compr-delete-temp-file err-file)))
232
15502042 233 (or (eq 0
acd622cc
RS
234 (apply 'call-process
235 prog
236 infile
237 (if (stringp output) temp output)
238 nil
239 args))
240 (jka-compr-error prog args infile message))
241
242 (and (stringp output)
75e9c107 243 (with-current-buffer temp
acd622cc 244 (write-region (point-min) (point-max) output)
75e9c107 245 (erase-buffer)))))
acd622cc
RS
246
247
f6cb7e0a
SM
248;; Support for temp files. Much of this was inspired if not lifted
249;; from ange-ftp.
acd622cc 250
bbf5eb28 251(defcustom jka-compr-temp-name-template
11757e2f 252 (expand-file-name "jka-com" temporary-file-directory)
362b539a 253 "Prefix added to all temp files created by jka-compr.
bbf5eb28
RS
254There should be no more than seven characters after the final `/'."
255 :type 'string
256 :group 'jka-compr)
acd622cc 257
acd622cc
RS
258(defun jka-compr-make-temp-name (&optional local-copy)
259 "This routine will return the name of a new file."
767d12f2
SM
260 (make-temp-file jka-compr-temp-name-template))
261
262(defalias 'jka-compr-delete-temp-file 'delete-file)
acd622cc
RS
263
264
265(defun jka-compr-write-region (start end file &optional append visit)
acd622cc
RS
266 (let* ((filename (expand-file-name file))
267 (visit-file (if (stringp visit) (expand-file-name visit) filename))
e073a356
RS
268 (info (jka-compr-get-compression-info visit-file))
269 (magic (and info (jka-compr-info-file-magic-bytes info))))
270
b6e8d238
RS
271 ;; If START is nil, use the whole buffer.
272 (if (null start)
273 (setq start 1 end (1+ (buffer-size))))
274
e073a356
RS
275 ;; If we uncompressed this file when visiting it,
276 ;; then recompress it when writing it
277 ;; even if the contents look compressed already.
278 (if (and jka-compr-really-do-compress
279 (eq start 1)
280 (eq end (1+ (buffer-size))))
281 (setq magic nil))
282
283 (if (and info
284 ;; If the contents to be written out
285 ;; are properly compressed already,
286 ;; don't try to compress them over again.
287 (not (and magic
288 (equal (if (stringp start)
289 (substring start 0 (min (length start)
290 (length magic)))
291 (buffer-substring start
292 (min end
293 (+ start (length magic)))))
294 magic))))
295 (let ((can-append (jka-compr-info-can-append info))
296 (compress-program (jka-compr-info-compress-program info))
297 (compress-message (jka-compr-info-compress-message info))
e073a356 298 (compress-args (jka-compr-info-compress-args info))
e073a356
RS
299 (base-name (file-name-nondirectory visit-file))
300 temp-file temp-buffer
301 ;; we need to leave `last-coding-system-used' set to its
302 ;; value after calling write-region the first time, so
303 ;; that `basic-save-buffer' sees the right value.
304 (coding-system-used last-coding-system-used))
305
cc8b577e
JL
306 (or compress-program
307 (error "No compression program defined"))
308
e073a356
RS
309 (setq temp-buffer (get-buffer-create " *jka-compr-wr-temp*"))
310 (with-current-buffer temp-buffer
311 (widen) (erase-buffer))
312
313 (if (and append
314 (not can-append)
315 (file-exists-p filename))
316
317 (let* ((local-copy (file-local-copy filename))
318 (local-file (or local-copy filename)))
319
320 (setq temp-file local-file))
321
322 (setq temp-file (jka-compr-make-temp-name)))
323
f1180544 324 (and
e073a356
RS
325 compress-message
326 (message "%s %s..." compress-message base-name))
327
328 (jka-compr-run-real-handler 'write-region
329 (list start end temp-file t 'dont))
330 ;; save value used by the real write-region
331 (setq coding-system-used last-coding-system-used)
332
333 ;; Here we must read the output of compress program as is
334 ;; without any code conversion.
335 (let ((coding-system-for-read 'no-conversion))
336 (jka-compr-call-process compress-program
337 (concat compress-message
338 " " base-name)
339 temp-file
340 temp-buffer
341 nil
342 compress-args))
343
344 (with-current-buffer temp-buffer
345 (let ((coding-system-for-write 'no-conversion))
346 (if (memq system-type '(ms-dos windows-nt))
347 (setq buffer-file-type t) )
348 (jka-compr-run-real-handler 'write-region
349 (list (point-min) (point-max)
350 filename
351 (and append can-append) 'dont))
352 (erase-buffer)) )
353
354 (jka-compr-delete-temp-file temp-file)
acd622cc 355
e073a356
RS
356 (and
357 compress-message
358 (message "%s %s...done" compress-message base-name))
359
360 (cond
361 ((eq visit t)
362 (setq buffer-file-name filename)
363 (setq jka-compr-really-do-compress t)
364 (set-visited-file-modtime))
365 ((stringp visit)
366 (setq buffer-file-name visit)
367 (let ((buffer-file-name filename))
368 (set-visited-file-modtime))))
369
370 (and (or (eq visit t)
371 (eq visit nil)
372 (stringp visit))
373 (message "Wrote %s" visit-file))
374
375 ;; ensure `last-coding-system-used' has an appropriate value
376 (setq last-coding-system-used coding-system-used)
377
378 nil)
f1180544 379
e073a356
RS
380 (jka-compr-run-real-handler 'write-region
381 (list start end filename append visit)))))
acd622cc
RS
382
383
54b2aa5c 384(defun jka-compr-insert-file-contents (file &optional visit beg end replace)
acd622cc
RS
385 (barf-if-buffer-read-only)
386
387 (and (or beg end)
388 visit
389 (error "Attempt to visit less than an entire file"))
390
391 (let* ((filename (expand-file-name file))
392 (info (jka-compr-get-compression-info filename)))
393
394 (if info
395
396 (let ((uncompress-message (jka-compr-info-uncompress-message info))
397 (uncompress-program (jka-compr-info-uncompress-program info))
398 (uncompress-args (jka-compr-info-uncompress-args info))
399 (base-name (file-name-nondirectory filename))
400 (notfound nil)
8fb1a583
RS
401 (local-copy
402 (jka-compr-run-real-handler 'file-local-copy (list filename)))
acd622cc 403 local-file
f54a7168 404 size start)
acd622cc
RS
405
406 (setq local-file (or local-copy filename))
407
408 (and
409 visit
410 (setq buffer-file-name filename))
411
412 (unwind-protect ; to make sure local-copy gets deleted
413
414 (progn
f1180544 415
acd622cc
RS
416 (and
417 uncompress-message
418 (message "%s %s..." uncompress-message base-name))
419
420 (condition-case error-code
421
f54a7168 422 (let ((coding-system-for-read 'no-conversion))
094cf604
RS
423 (if replace
424 (goto-char (point-min)))
acd622cc
RS
425 (setq start (point))
426 (if (or beg end)
427 (jka-compr-partial-uncompress uncompress-program
428 (concat uncompress-message
429 " " base-name)
430 uncompress-args
431 local-file
432 (or beg 0)
433 (if (and beg end)
434 (- end beg)
435 end))
ae849784
RS
436 ;; If visiting, bind off buffer-file-name so that
437 ;; file-locking will not ask whether we should
438 ;; really edit the buffer.
439 (let ((buffer-file-name
440 (if visit nil buffer-file-name)))
441 (jka-compr-call-process uncompress-program
442 (concat uncompress-message
443 " " base-name)
444 local-file
445 t
446 nil
447 uncompress-args)))
acd622cc 448 (setq size (- (point) start))
094cf604 449 (if replace
31b55e80 450 (delete-region (point) (point-max)))
094cf604 451 (goto-char start))
acd622cc 452 (error
7bbae30c
RS
453 ;; If the file we wanted to uncompress does not exist,
454 ;; handle that according to VISIT as `insert-file-contents'
455 ;; would, maybe signaling the same error it normally would.
acd622cc
RS
456 (if (and (eq (car error-code) 'file-error)
457 (eq (nth 3 error-code) local-file))
458 (if visit
459 (setq notfound error-code)
f1180544 460 (signal 'file-error
acd622cc
RS
461 (cons "Opening input file"
462 (nthcdr 2 error-code))))
7bbae30c
RS
463 ;; If the uncompression program can't be found,
464 ;; signal that as a non-file error
465 ;; so that find-file-noselect-1 won't handle it.
466 (if (and (eq (car error-code) 'file-error)
467 (equal (cadr error-code) "Searching for program"))
468 (error "Uncompression program `%s' not found"
469 (nth 3 error-code)))
acd622cc
RS
470 (signal (car error-code) (cdr error-code))))))
471
472 (and
473 local-copy
474 (file-exists-p local-copy)
475 (delete-file local-copy)))
476
8290faa3
AS
477 (unless notfound
478 (decode-coding-inserted-region
479 (point) (+ (point) size)
480 (jka-compr-byte-compiler-base-file-name file)
481 visit beg end replace))
f54a7168 482
acd622cc
RS
483 (and
484 visit
485 (progn
8fb1a583 486 (unlock-buffer)
acd622cc 487 (setq buffer-file-name filename)
e073a356 488 (setq jka-compr-really-do-compress t)
acd622cc 489 (set-visited-file-modtime)))
f1180544 490
acd622cc
RS
491 (and
492 uncompress-message
493 (message "%s %s...done" uncompress-message base-name))
494
495 (and
496 visit
497 notfound
498 (signal 'file-error
499 (cons "Opening input file" (nth 2 notfound))))
500
5c6f2f2a
RS
501 ;; This is done in insert-file-contents after we return.
502 ;; That is a little weird, but better to go along with it now
503 ;; than to change it now.
504
505;;; ;; Run the functions that insert-file-contents would.
506;;; (let ((p after-insert-file-functions)
507;;; (insval size))
508;;; (while p
509;;; (setq insval (funcall (car p) size))
510;;; (if insval
511;;; (progn
512;;; (or (integerp insval)
513;;; (signal 'wrong-type-argument
514;;; (list 'integerp insval)))
515;;; (setq size insval)))
516;;; (setq p (cdr p))))
094cf604 517
cc8b577e
JL
518 (or (jka-compr-info-compress-program info)
519 (message "You can't save this buffer because compression program is not defined"))
520
acd622cc
RS
521 (list filename size))
522
8fb1a583
RS
523 (jka-compr-run-real-handler 'insert-file-contents
524 (list file visit beg end replace)))))
acd622cc
RS
525
526
527(defun jka-compr-file-local-copy (file)
acd622cc
RS
528 (let* ((filename (expand-file-name file))
529 (info (jka-compr-get-compression-info filename)))
530
531 (if info
532
533 (let ((uncompress-message (jka-compr-info-uncompress-message info))
534 (uncompress-program (jka-compr-info-uncompress-program info))
535 (uncompress-args (jka-compr-info-uncompress-args info))
536 (base-name (file-name-nondirectory filename))
8fb1a583
RS
537 (local-copy
538 (jka-compr-run-real-handler 'file-local-copy (list filename)))
acd622cc 539 (temp-file (jka-compr-make-temp-name t))
30c78e11 540 (temp-buffer (get-buffer-create " *jka-compr-flc-temp*"))
acd622cc
RS
541 local-file)
542
543 (setq local-file (or local-copy filename))
544
545 (unwind-protect
546
75e9c107 547 (with-current-buffer temp-buffer
f1180544 548
acd622cc
RS
549 (and
550 uncompress-message
551 (message "%s %s..." uncompress-message base-name))
f1180544 552
baefb016
KH
553 ;; Here we must read the output of uncompress program
554 ;; and write it to TEMP-FILE without any code
555 ;; conversion. An appropriate code conversion (if
556 ;; necessary) is done by the later I/O operation
557 ;; (e.g. load).
558 (let ((coding-system-for-read 'no-conversion)
559 (coding-system-for-write 'no-conversion))
560
561 (jka-compr-call-process uncompress-program
562 (concat uncompress-message
563 " " base-name)
564 local-file
565 t
566 nil
567 uncompress-args)
568
569 (and
570 uncompress-message
571 (message "%s %s...done" uncompress-message base-name))
572
573 (write-region
574 (point-min) (point-max) temp-file nil 'dont)))
acd622cc
RS
575
576 (and
577 local-copy
578 (file-exists-p local-copy)
579 (delete-file local-copy))
580
acd622cc
RS
581 (kill-buffer temp-buffer))
582
583 temp-file)
f1180544 584
8fb1a583 585 (jka-compr-run-real-handler 'file-local-copy (list filename)))))
acd622cc
RS
586
587
f6cb7e0a 588;; Support for loading compressed files.
acd622cc
RS
589(defun jka-compr-load (file &optional noerror nomessage nosuffix)
590 "Documented as original."
591
592 (let* ((local-copy (jka-compr-file-local-copy file))
593 (load-file (or local-copy file)))
594
595 (unwind-protect
596
8fb1a583
RS
597 (let (inhibit-file-name-operation
598 inhibit-file-name-handlers)
acd622cc
RS
599 (or nomessage
600 (message "Loading %s..." file))
601
9b37d8a9
RS
602 (let ((load-force-doc-strings t))
603 (load load-file noerror t t))
acd622cc 604 (or nomessage
e645e77b
DL
605 (message "Loading %s...done." file))
606 ;; Fix up the load history to point at the right library.
607 (let ((l (assoc load-file load-history)))
608 ;; Remove .gz and .elc?.
609 (while (file-name-extension file)
610 (setq file (file-name-sans-extension file)))
611 (setcar l file)))
acd622cc 612
acd622cc
RS
613 (jka-compr-delete-temp-file local-copy))
614
615 t))
3068998d
RS
616
617(defun jka-compr-byte-compiler-base-file-name (file)
618 (let ((info (jka-compr-get-compression-info file)))
619 (if (and info (jka-compr-info-strip-extension info))
620 (save-match-data
621 (substring file 0 (string-match (jka-compr-info-regexp info) file)))
622 file)))
8fb1a583
RS
623\f
624(put 'write-region 'jka-compr 'jka-compr-write-region)
625(put 'insert-file-contents 'jka-compr 'jka-compr-insert-file-contents)
626(put 'file-local-copy 'jka-compr 'jka-compr-file-local-copy)
627(put 'load 'jka-compr 'jka-compr-load)
3068998d
RS
628(put 'byte-compiler-base-file-name 'jka-compr
629 'jka-compr-byte-compiler-base-file-name)
acd622cc 630
0e2846fb 631;;;###autoload
9fdf055b
KH
632(defvar jka-compr-inhibit nil
633 "Non-nil means inhibit automatic uncompression temporarily.
634Lisp programs can bind this to t to do that.
635It is not recommended to set this variable permanently to anything but nil.")
636
0e2846fb 637;;;###autoload
acd622cc 638(defun jka-compr-handler (operation &rest args)
8fb1a583
RS
639 (save-match-data
640 (let ((jka-op (get operation 'jka-compr)))
9fdf055b 641 (if (and jka-op (not jka-compr-inhibit))
8fb1a583
RS
642 (apply jka-op args)
643 (jka-compr-run-real-handler operation args)))))
acd622cc 644
99bee6a4
RS
645;; If we are given an operation that we don't handle,
646;; call the Emacs primitive for that operation,
647;; and manipulate the inhibit variables
648;; to prevent the primitive from calling our handler again.
649(defun jka-compr-run-real-handler (operation args)
650 (let ((inhibit-file-name-handlers
651 (cons 'jka-compr-handler
652 (and (eq inhibit-file-name-operation operation)
653 inhibit-file-name-handlers)))
654 (inhibit-file-name-operation operation))
655 (apply operation args)))
656
233c955d 657;;;###autoload
acd622cc
RS
658(defun jka-compr-uninstall ()
659 "Uninstall jka-compr.
99bee6a4 660This removes the entries in `file-name-handler-alist' and `auto-mode-alist'
919a07bb
RS
661and `inhibit-first-line-modes-suffixes' that were added
662by `jka-compr-installed'."
663 ;; Delete from inhibit-first-line-modes-suffixes
664 ;; what jka-compr-install added.
665 (mapcar
666 (function (lambda (x)
667 (and (jka-compr-info-strip-extension x)
668 (setq inhibit-first-line-modes-suffixes
669 (delete (jka-compr-info-regexp x)
670 inhibit-first-line-modes-suffixes)))))
671 jka-compr-compression-info-list)
acd622cc
RS
672
673 (let* ((fnha (cons nil file-name-handler-alist))
674 (last fnha))
675
676 (while (cdr last)
677 (if (eq (cdr (car (cdr last))) 'jka-compr-handler)
678 (setcdr last (cdr (cdr last)))
679 (setq last (cdr last))))
680
681 (setq file-name-handler-alist (cdr fnha)))
682
683 (let* ((ama (cons nil auto-mode-alist))
684 (last ama)
685 entry)
686
687 (while (cdr last)
688 (setq entry (car (cdr last)))
74b2c737
RS
689 (if (or (member entry jka-compr-mode-alist-additions)
690 (and (consp (cdr entry))
691 (eq (nth 2 entry) 'jka-compr)))
acd622cc
RS
692 (setcdr last (cdr (cdr last)))
693 (setq last (cdr last))))
f1180544 694
4eec33ae
RS
695 (setq auto-mode-alist (cdr ama)))
696
f6cb7e0a
SM
697 (while jka-compr-added-to-file-coding-system-alist
698 (setq file-coding-system-alist
699 (delq (car (member (pop jka-compr-added-to-file-coding-system-alist)
700 file-coding-system-alist))
701 file-coding-system-alist)))
aab8a6e3
SM
702
703 ;; Remove the suffixes that were added by jka-compr.
704 (let ((suffixes nil)
705 (re (jka-compr-build-file-regexp)))
706 (dolist (suffix load-suffixes)
707 (unless (string-match re suffix)
708 (push suffix suffixes)))
709 (setq load-suffixes (nreverse suffixes))))
acd622cc 710
acd622cc
RS
711(provide 'jka-compr)
712
f6cb7e0a 713;; arch-tag: 3f15b630-e9a7-46c4-a22a-94afdde86ebc
55535639 714;;; jka-compr.el ends here