(Fx_create_frame): Make 1 the default for menu-bar-lines.
[bpt/emacs.git] / lisp / jka-compr.el
CommitLineData
acd622cc
RS
1;;; jka-compr.el - reading/writing/loading compressed files.
2;;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3
4;; Author: jka@ece.cmu.edu (Jay K. Adams)
dfe05fac 5;; Version: 0.11
acd622cc
RS
6;; Keywords: data
7
8;;; Commentary:
9
10;;; This package implements low-level support for reading, writing,
11;;; and loading compressed files. It hooks into the low-level file
12;;; I/O functions (including write-region and insert-file-contents) so
13;;; that they automatically compress or uncompress a file if the file
14;;; appears to need it (based on the extension of the file name).
dfe05fac 15;;; Packages like Rmail, VM, GNUS, and Info should be able to work
acd622cc
RS
16;;; with compressed files without modification.
17
18
19;;; INSTRUCTIONS:
20;;;
21;;; To use jka-compr, simply load this package, and edit as usual.
22;;; Its operation should be transparent to the user (except for
23;;; messages appearing when a file is being compressed or
24;;; uncompressed).
25;;;
26;;; The variable, jka-compr-compression-info-list can be used to
27;;; customize jka-compr to work with other compression programs.
28;;; The default value of this variable allows jka-compr to work with
29;;; Unix compress and gzip.
30;;;
31;;; If you are concerned about the stderr output of gzip and other
32;;; compression/decompression programs showing up in your buffers, you
33;;; should set the discard-error flag in the compression-info-list.
34;;; This will cause the stderr of all programs to be discarded.
35;;; However, it also causes emacs to call compression/uncompression
36;;; programs through a shell (which is specified by jka-compr-shell).
37;;; This may be a drag if, on your system, starting up a shell is
38;;; slow.
39;;;
40;;; If you don't want messages about compressing and decompressing
41;;; to show up in the echo area, you can set the compress-name and
42;;; decompress-name fields of the jka-compr-compression-info-list to
43;;; nil.
44
45
46;;; APPLICATION NOTES:
47;;;
48;;; rmail, vm, gnus, etc.
49;;; To use compressed mail folders, .newsrc files, etc., you need
50;;; only compress the file. Since jka-compr searches for .gz
51;;; versions of the files it's finding, you need not change
52;;; variables within rmail, gnus, etc.
53;;;
54;;;
55;;; crypt++
56;;; jka-compr can coexist with crpyt++ if you take all the decompression
57;;; entries out of the crypt-encoding-list. Clearly problems will arise if
58;;; you have two programs trying to compress/decompress files. jka-compr
59;;; will not "work with" crypt++ in the following sense: you won't be able to
60;;; decode encrypted compressed files--that is, files that have been
61;;; compressed then encrypted (in that order). Theoretically, crypt++ and
62;;; jka-compr could properly handle a file that has been encrypted then
63;;; compressed, but there is little point in trying to compress an encrypted
64;;; file.
65;;;
66;;;
67;;; tar-mode
68;;; Some people like to use extensions like .trz for compressed tar files.
69;;; To handle these sorts of files, you have to add an entry to
70;;; jka-compr-compression-info-list that looks something like this:
71;;;
72;;; ["\\.trz\\'" "\037\213"
73;;; "zip" "gzip" nil ("-q")
74;;; "unzip" "gzip" nil ("-q" "-d")
75;;; t
76;;; nil]
77;;;
78;;; The last nil in the vector (the "extension" field) prevents jka-compr
79;;; from attempting to add .trz to an ordinary file name when it is looking
80;;; for a compressed version of that file (i.e. don't look for things like
81;;; foobar.c.trz).
82;;;
83;;; Finally, to make tar-mode start up automatically, you have to add an
84;;; entry to auto-mode-alist that looks like this
85;;;
86;;; ("\\.trz\\'" . tar-mode)
87;;;
88
89
90;;; ACKNOWLEDGMENTS
91;;;
92;;; jka-compr is a V19 adaptation of jka-compr for V18 of Emacs. Many people
93;;; have made helpful suggestions, reported bugs, and even fixed bugs in
94;;; jka-compr. I recall the following people as being particularly helpful.
95;;;
96;;; Jean-loup Gailly
97;;; David Hughes
98;;; Richard Pieri
99;;; Daniel Quinlan
100;;; Chris P. Ross
101;;; Rick Sladkey
102;;;
103;;; Andy Norman's ange-ftp was the inspiration for the original jka-compr for
104;;; Version 18 of Emacs.
105;;;
106;;; After I had made progress on the original jka-compr for V18, I learned of a
107;;; package written by Kazushi Jam Marukawa, called jam-zcat, that did exactly
108;;; what I was trying to do. I looked over the jam-zcat source code and
109;;; probably got some ideas from it.
110;;;
111
112;;; Code:
113
114(defvar jka-compr-shell "sh"
115 "*Shell to be used for calling compression programs.
116The value of this variable only matters if you want to discard the
117stderr of a compression/decompression program (see the documentation
99bee6a4 118for `jka-compr-compression-info-list').")
acd622cc
RS
119
120
121(defvar jka-compr-use-shell t)
122
123
124;;; I have this defined so that .Z files are assumed to be in unix
125;;; compress format; and .gz files, in gzip format.
126(defvar jka-compr-compression-info-list
127 ;;[regexp
ede9c6a8
RS
128 ;; compr-message compr-prog compr-args
129 ;; uncomp-message uncomp-prog uncomp-args
acd622cc
RS
130 ;; can-append auto-mode-flag]
131 '(["\\.Z~?\\'"
132 "compressing" "compress" ("-c")
133 "uncompressing" "uncompress" ("-c")
134 nil t]
135 ["\\.gz~?\\'"
136 "zipping" "gzip" ("-c" "-q")
137 "unzipping" "gzip" ("-c" "-q" "-d")
138 t t])
139
140 "List of vectors that describe available compression techniques.
141Each element, which describes a compression technique, is a vector of
ede9c6a8
RS
142the form [REGEXP COMPRESS-MSG COMPRESS-PROGRAM COMPRESS-ARGS
143UNCOMPRESS-MSG UNCOMPRESS-PROGRAM UNCOMPRESS-ARGS
144APPEND-FLAG EXTENSION], where:
acd622cc
RS
145
146 regexp is a regexp that matches filenames that are
147 compressed with this format
148
ede9c6a8
RS
149 compress-msg is the message to issue to the user when doing this
150 type of compression (nil means no message)
151
acd622cc
RS
152 compress-program is a program that performs this compression
153
154 compress-args is a list of args to pass to the compress program
155
ede9c6a8
RS
156 uncompress-msg is the message to issue to the user when doing this
157 type of uncompression (nil means no message)
acd622cc
RS
158
159 uncompress-program is a program that performs this compression
160
161 uncompress-args is a list of args to pass to the uncompress program
162
163 append-flag is non-nil if this compression technique can be
164 appended
165
166 auto-mode flag non-nil means strip the regexp from file names
167 before attempting to set the mode.
168
8fb1a583 169Because of the way `call-process' is defined, discarding the stderr output of
acd622cc
RS
170a program adds the overhead of starting a shell each time the program is
171invoked.")
172
173
555235e6
RS
174(defvar jka-compr-file-name-handler-entry
175 nil
176 "The entry in `file-name-handler-alist' used by the jka-compr I/O functions.")
555235e6 177\f
acd622cc
RS
178;;; Functions for accessing the return value of jka-get-compression-info
179(defun jka-compr-info-regexp (info) (aref info 0))
180(defun jka-compr-info-compress-message (info) (aref info 1))
181(defun jka-compr-info-compress-program (info) (aref info 2))
182(defun jka-compr-info-compress-args (info) (aref info 3))
183(defun jka-compr-info-uncompress-message (info) (aref info 4))
184(defun jka-compr-info-uncompress-program (info) (aref info 5))
185(defun jka-compr-info-uncompress-args (info) (aref info 6))
186(defun jka-compr-info-can-append (info) (aref info 7))
187(defun jka-compr-info-strip-extension (info) (aref info 8))
188
189
190(defun jka-compr-get-compression-info (filename)
191 "Return information about the compression scheme of FILENAME.
192The determination as to which compression scheme, if any, to use is
99bee6a4 193based on the filename itself and `jka-compr-compression-info-list'."
acd622cc
RS
194 (catch 'compression-info
195 (let ((case-fold-search nil))
196 (mapcar
197 (function (lambda (x)
198 (and (string-match (jka-compr-info-regexp x) filename)
199 (throw 'compression-info x))))
200 jka-compr-compression-info-list)
201 nil)))
202
203
204(put 'compression-error 'error-conditions '(compression-error file-error error))
205
206
207(defvar jka-compr-acceptable-retval-list '(0 141))
208
209
210(defun jka-compr-error (prog args infile message &optional errfile)
211
212 (let ((errbuf (get-buffer-create " *jka-compr-error*"))
213 (curbuf (current-buffer)))
214 (set-buffer errbuf)
215 (widen) (erase-buffer)
216 (insert (format "Error while executing \"%s %s < %s\"\n\n"
217 prog
218 (mapconcat 'identity args " ")
219 infile))
220
221 (and errfile
222 (insert-file-contents errfile))
223
224 (set-buffer curbuf)
225 (display-buffer errbuf))
226
227 (signal 'compression-error (list "Opening input file" (format "error %s" message) infile)))
228
229
230(defvar jka-compr-dd-program
231 "/bin/dd")
232
233
dfe05fac 234(defvar jka-compr-dd-blocksize 256)
acd622cc
RS
235
236
237(defun jka-compr-partial-uncompress (prog message args infile beg len)
238 "Call program PROG with ARGS args taking input from INFILE.
239Fourth and fifth args, BEG and LEN, specify which part of the output
ee139ed3 240to keep: LEN chars starting BEG chars from the beginning."
acd622cc
RS
241 (let* ((skip (/ beg jka-compr-dd-blocksize))
242 (prefix (- beg (* skip jka-compr-dd-blocksize)))
243 (count (and len (1+ (/ (+ len prefix) jka-compr-dd-blocksize))))
244 (start (point))
acd622cc
RS
245 (err-file (jka-compr-make-temp-name))
246 (run-string (format "%s %s 2> %s | %s bs=%d skip=%d %s 2> /dev/null"
247 prog
248 (mapconcat 'identity args " ")
249 err-file
250 jka-compr-dd-program
251 jka-compr-dd-blocksize
252 skip
dfe05fac
RS
253 ;; dd seems to be unreliable about
254 ;; providing the last block. So, always
255 ;; read one more than you think you need.
256 (if count (concat "count=" (1+ count)) ""))))
acd622cc
RS
257
258 (unwind-protect
259 (or (memq (call-process jka-compr-shell
260 infile t nil "-c"
261 run-string)
262 jka-compr-acceptable-retval-list)
263
264 (jka-compr-error prog args infile message err-file))
265
266 (jka-compr-delete-temp-file err-file))
267
ee139ed3 268 ;; Delete the stuff after what we want, if there is any.
acd622cc 269 (and
dfe05fac 270 len
ee139ed3 271 (< (+ start prefix len) (point))
dfe05fac 272 (delete-region (+ start prefix len) (point)))
acd622cc 273
ee139ed3 274 ;; Delete the stuff before what we want.
acd622cc
RS
275 (delete-region start (+ start prefix))))
276
277
278(defun jka-compr-call-process (prog message infile output temp args)
279 (if jka-compr-use-shell
280
281 (let ((err-file (jka-compr-make-temp-name)))
282
283 (unwind-protect
284
285 (or (memq
286 (call-process jka-compr-shell infile
287 (if (stringp output) nil output)
288 nil
289 "-c"
290 (format "%s %s 2> %s %s"
291 prog
292 (mapconcat 'identity args " ")
293 err-file
294 (if (stringp output)
295 (concat "> " output)
296 "")))
297 jka-compr-acceptable-retval-list)
298
299 (jka-compr-error prog args infile message err-file))
300
301 (jka-compr-delete-temp-file err-file)))
302
303 (or (zerop
304 (apply 'call-process
305 prog
306 infile
307 (if (stringp output) temp output)
308 nil
309 args))
310 (jka-compr-error prog args infile message))
311
312 (and (stringp output)
313 (let ((cbuf (current-buffer)))
314 (set-buffer temp)
315 (write-region (point-min) (point-max) output)
316 (erase-buffer)
317 (set-buffer cbuf)))))
318
319
320;;; Support for temp files. Much of this was inspired if not lifted
321;;; from ange-ftp.
322
323(defvar jka-compr-temp-name-template
324 "/tmp/jka-com"
325 "Prefix added to all temp files created by jka-compr.
99bee6a4 326There should be no more than seven characters after the final `/'")
acd622cc
RS
327
328(defvar jka-compr-temp-name-table (make-vector 31 nil))
329
330(defun jka-compr-make-temp-name (&optional local-copy)
331 "This routine will return the name of a new file."
332 (let* ((lastchar ?a)
333 (prevchar ?a)
334 (template (concat jka-compr-temp-name-template "aa"))
335 (lastpos (1- (length template)))
336 (not-done t)
337 file
338 entry)
339
340 (while not-done
341 (aset template lastpos lastchar)
342 (setq file (concat (make-temp-name template) "#"))
343 (setq entry (intern file jka-compr-temp-name-table))
344 (if (or (get entry 'active)
345 (file-exists-p file))
346
347 (progn
348 (setq lastchar (1+ lastchar))
349 (if (> lastchar ?z)
350 (progn
351 (setq prevchar (1+ prevchar))
352 (setq lastchar ?a)
353 (if (> prevchar ?z)
354 (error "Can't allocate temp file.")
355 (aset template (1- lastpos) prevchar)))))
356
357 (put entry 'active (not local-copy))
358 (setq not-done nil)))
359
360 file))
361
362
363(defun jka-compr-delete-temp-file (temp)
364
365 (put (intern temp jka-compr-temp-name-table)
366 'active nil)
367
368 (condition-case ()
369 (delete-file temp)
370 (error nil)))
371
372
373(defun jka-compr-write-region (start end file &optional append visit)
acd622cc
RS
374 (let* ((filename (expand-file-name file))
375 (visit-file (if (stringp visit) (expand-file-name visit) filename))
376 (info (jka-compr-get-compression-info visit-file)))
377
378 (if info
379
380 (let ((can-append (jka-compr-info-can-append info))
381 (compress-program (jka-compr-info-compress-program info))
382 (compress-message (jka-compr-info-compress-message info))
383 (uncompress-program (jka-compr-info-uncompress-program info))
384 (uncompress-message (jka-compr-info-uncompress-message info))
385 (compress-args (jka-compr-info-compress-args info))
386 (uncompress-args (jka-compr-info-uncompress-args info))
387 (temp-file (jka-compr-make-temp-name))
388 (base-name (file-name-nondirectory visit-file))
389 cbuf temp-buffer)
390
391 (setq cbuf (current-buffer)
392 temp-buffer (get-buffer-create " *jka-compr-temp*"))
393 (set-buffer temp-buffer)
394 (widen) (erase-buffer)
395 (set-buffer cbuf)
396
397 (and append
398 (not can-append)
399 (file-exists-p filename)
400 (let* ((local-copy (file-local-copy filename))
401 (local-file (or local-copy filename)))
402
403 (unwind-protect
404
405 (progn
406
407 (and
408 uncompress-message
409 (message "%s %s..." uncompress-message base-name))
410
411 (jka-compr-call-process uncompress-program
412 (concat uncompress-message
413 " " base-name)
414 local-file
415 temp-file
416 temp-buffer
417 uncompress-args)
418 (and
419 uncompress-message
420 (message "%s %s...done" uncompress-message base-name)))
421
422 (and
423 local-copy
424 (file-exists-p local-copy)
425 (delete-file local-copy)))))
426
427 (and
428 compress-message
429 (message "%s %s..." compress-message base-name))
430
8fb1a583
RS
431 (jka-compr-run-real-handler 'write-region
432 (list start end temp-file t 'dont))
acd622cc
RS
433
434 (jka-compr-call-process compress-program
435 (concat compress-message
436 " " base-name)
437 temp-file
438 temp-buffer
439 nil
440 compress-args)
441
442 (set-buffer temp-buffer)
8fb1a583
RS
443 (jka-compr-run-real-handler 'write-region
444 (list (point-min) (point-max)
445 filename
446 (and append can-append) 'dont))
acd622cc
RS
447 (erase-buffer)
448 (set-buffer cbuf)
449
450 (jka-compr-delete-temp-file temp-file)
451
452 (and
453 compress-message
454 (message "%s %s...done" compress-message base-name))
455
456 (cond
457 ((eq visit t)
458 (setq buffer-file-name filename)
459 (set-visited-file-modtime))
460 ((stringp visit)
461 (setq buffer-file-name visit)
462 (let ((buffer-file-name filename))
463 (set-visited-file-modtime))))
464
465 (and (or (eq visit t)
466 (eq visit nil)
467 (stringp visit))
468 (message "Wrote %s" visit-file))
469
470 nil)
471
8fb1a583
RS
472 (jka-compr-run-real-handler 'write-region
473 (list start end filename append visit)))))
acd622cc
RS
474
475
54b2aa5c 476(defun jka-compr-insert-file-contents (file &optional visit beg end replace)
acd622cc
RS
477 (barf-if-buffer-read-only)
478
479 (and (or beg end)
480 visit
481 (error "Attempt to visit less than an entire file"))
482
483 (let* ((filename (expand-file-name file))
484 (info (jka-compr-get-compression-info filename)))
485
486 (if info
487
488 (let ((uncompress-message (jka-compr-info-uncompress-message info))
489 (uncompress-program (jka-compr-info-uncompress-program info))
490 (uncompress-args (jka-compr-info-uncompress-args info))
491 (base-name (file-name-nondirectory filename))
492 (notfound nil)
8fb1a583
RS
493 (local-copy
494 (jka-compr-run-real-handler 'file-local-copy (list filename)))
acd622cc
RS
495 local-file
496 size start)
497
498 (setq local-file (or local-copy filename))
499
500 (and
501 visit
502 (setq buffer-file-name filename))
503
504 (unwind-protect ; to make sure local-copy gets deleted
505
506 (progn
507
508 (and
509 uncompress-message
510 (message "%s %s..." uncompress-message base-name))
511
512 (condition-case error-code
513
514 (progn
515 (setq start (point))
516 (if (or beg end)
517 (jka-compr-partial-uncompress uncompress-program
518 (concat uncompress-message
519 " " base-name)
520 uncompress-args
521 local-file
522 (or beg 0)
523 (if (and beg end)
524 (- end beg)
525 end))
526 (jka-compr-call-process uncompress-program
527 (concat uncompress-message
528 " " base-name)
529 local-file
530 t
531 nil
532 uncompress-args))
533 (setq size (- (point) start))
b38fda68
RS
534 (goto-char start)
535 ;; Run the functions that insert-file-contents would.
536 (let ((list after-insert-file-functions)
537 (value size))
538 (while list
539 (setq value (funcall (car list) size))
540 (if value
541 (setq size value))
542 (setq list (cdr list)))))
acd622cc
RS
543
544 (error
545 (if (and (eq (car error-code) 'file-error)
546 (eq (nth 3 error-code) local-file))
547 (if visit
548 (setq notfound error-code)
549 (signal 'file-error
550 (cons "Opening input file"
551 (nthcdr 2 error-code))))
552 (signal (car error-code) (cdr error-code))))))
553
554 (and
555 local-copy
556 (file-exists-p local-copy)
557 (delete-file local-copy)))
558
559 (and
560 visit
561 (progn
8fb1a583 562 (unlock-buffer)
acd622cc
RS
563 (setq buffer-file-name filename)
564 (set-visited-file-modtime)))
565
566 (and
567 uncompress-message
568 (message "%s %s...done" uncompress-message base-name))
569
570 (and
571 visit
572 notfound
573 (signal 'file-error
574 (cons "Opening input file" (nth 2 notfound))))
575
576 (list filename size))
577
8fb1a583
RS
578 (jka-compr-run-real-handler 'insert-file-contents
579 (list file visit beg end replace)))))
acd622cc
RS
580
581
582(defun jka-compr-file-local-copy (file)
acd622cc
RS
583 (let* ((filename (expand-file-name file))
584 (info (jka-compr-get-compression-info filename)))
585
586 (if info
587
588 (let ((uncompress-message (jka-compr-info-uncompress-message info))
589 (uncompress-program (jka-compr-info-uncompress-program info))
590 (uncompress-args (jka-compr-info-uncompress-args info))
591 (base-name (file-name-nondirectory filename))
8fb1a583
RS
592 (local-copy
593 (jka-compr-run-real-handler 'file-local-copy (list filename)))
acd622cc
RS
594 (temp-file (jka-compr-make-temp-name t))
595 (temp-buffer (get-buffer-create " *jka-compr-temp*"))
596 (notfound nil)
597 (cbuf (current-buffer))
598 local-file)
599
600 (setq local-file (or local-copy filename))
601
602 (unwind-protect
603
604 (progn
605
606 (and
607 uncompress-message
608 (message "%s %s..." uncompress-message base-name))
609
610 (set-buffer temp-buffer)
611
612 (jka-compr-call-process uncompress-program
613 (concat uncompress-message
614 " " base-name)
615 local-file
616 t
617 nil
618 uncompress-args)
619
620 (and
621 uncompress-message
622 (message "%s %s...done" uncompress-message base-name))
623
624 (write-region
625 (point-min) (point-max) temp-file nil 'dont))
626
627 (and
628 local-copy
629 (file-exists-p local-copy)
630 (delete-file local-copy))
631
632 (set-buffer cbuf)
633 (kill-buffer temp-buffer))
634
635 temp-file)
636
8fb1a583 637 (jka-compr-run-real-handler 'file-local-copy (list filename)))))
acd622cc
RS
638
639
640;;; Support for loading compressed files.
641(defun jka-compr-load (file &optional noerror nomessage nosuffix)
642 "Documented as original."
643
644 (let* ((local-copy (jka-compr-file-local-copy file))
645 (load-file (or local-copy file)))
646
647 (unwind-protect
648
8fb1a583
RS
649 (let (inhibit-file-name-operation
650 inhibit-file-name-handlers)
acd622cc
RS
651 (or nomessage
652 (message "Loading %s..." file))
653
654 (load load-file noerror t t)
655
656 (or nomessage
657 (message "Loading %s...done." file)))
658
acd622cc
RS
659 (jka-compr-delete-temp-file local-copy))
660
661 t))
8fb1a583
RS
662\f
663(put 'write-region 'jka-compr 'jka-compr-write-region)
664(put 'insert-file-contents 'jka-compr 'jka-compr-insert-file-contents)
665(put 'file-local-copy 'jka-compr 'jka-compr-file-local-copy)
666(put 'load 'jka-compr 'jka-compr-load)
acd622cc 667
acd622cc 668(defun jka-compr-handler (operation &rest args)
8fb1a583
RS
669 (save-match-data
670 (let ((jka-op (get operation 'jka-compr)))
671 (if jka-op
672 (apply jka-op args)
673 (jka-compr-run-real-handler operation args)))))
acd622cc 674
99bee6a4
RS
675;; If we are given an operation that we don't handle,
676;; call the Emacs primitive for that operation,
677;; and manipulate the inhibit variables
678;; to prevent the primitive from calling our handler again.
679(defun jka-compr-run-real-handler (operation args)
680 (let ((inhibit-file-name-handlers
681 (cons 'jka-compr-handler
682 (and (eq inhibit-file-name-operation operation)
683 inhibit-file-name-handlers)))
684 (inhibit-file-name-operation operation))
685 (apply operation args)))
686
acd622cc
RS
687(defun toggle-auto-compression (arg)
688 "Toggle automatic file compression and decompression.
689With prefix argument ARG, turn auto compression on if positive, else off.
690Returns the new status of auto compression (non-nil means on)."
691 (interactive "P")
692 (let* ((installed (jka-compr-installed-p))
693 (flag (if (null arg)
694 (not installed)
695 (or (eq arg t) (listp arg) (and (integerp arg) (> arg 0))))))
696
697 (cond
698 ((and flag installed) t) ; already installed
699
700 ((and (not flag) (not installed)) nil) ; already not installed
701
702 (flag
703 (jka-compr-install))
704
705 (t
706 (jka-compr-uninstall)))
707
708
709 (and (interactive-p)
710 (if flag
711 (message "Automatic file (de)compression is now ON.")
712 (message "Automatic file (de)compression is now OFF.")))
713
714 flag))
715
716
717(defun jka-compr-build-file-regexp ()
718 (concat
719 "\\("
720 (mapconcat
721 'jka-compr-info-regexp
722 jka-compr-compression-info-list
723 "\\)\\|\\(")
724 "\\)"))
725
726
727(defun jka-compr-install ()
728 "Install jka-compr.
99bee6a4 729This adds entries to `file-name-handler-alist' and `auto-mode-alist'."
acd622cc
RS
730
731 (setq jka-compr-file-name-handler-entry
732 (cons (jka-compr-build-file-regexp) 'jka-compr-handler))
733
734 (setq file-name-handler-alist (cons jka-compr-file-name-handler-entry
735 file-name-handler-alist))
736
8fb1a583
RS
737 ;; Make entries in auto-mode-alist so that modes are chosen right
738 ;; according to the file names sans `.gz'.
acd622cc
RS
739 (mapcar
740 (function (lambda (x)
741 (and
742 (jka-compr-info-strip-extension x)
743 (setq auto-mode-alist (cons (list (jka-compr-info-regexp x)
744 nil 'jka-compr)
745 auto-mode-alist)))))
746
747 jka-compr-compression-info-list))
748
749
750(defun jka-compr-uninstall ()
751 "Uninstall jka-compr.
99bee6a4
RS
752This removes the entries in `file-name-handler-alist' and `auto-mode-alist'
753that were created by `jka-compr-installed'."
acd622cc
RS
754
755 (let* ((fnha (cons nil file-name-handler-alist))
756 (last fnha))
757
758 (while (cdr last)
759 (if (eq (cdr (car (cdr last))) 'jka-compr-handler)
760 (setcdr last (cdr (cdr last)))
761 (setq last (cdr last))))
762
763 (setq file-name-handler-alist (cdr fnha)))
764
765 (let* ((ama (cons nil auto-mode-alist))
766 (last ama)
767 entry)
768
769 (while (cdr last)
770 (setq entry (car (cdr last)))
771 (if (and (consp (cdr entry))
772 (eq (nth 2 entry) 'jka-compr))
773 (setcdr last (cdr (cdr last)))
774 (setq last (cdr last))))
775
776 (setq auto-mode-alist (cdr ama))))
777
778
779(defun jka-compr-installed-p ()
780 "Return non-nil if jka-compr is installed.
99bee6a4 781The return value is the entry in `file-name-handler-alist' for jka-compr."
acd622cc
RS
782
783 (let ((fnha file-name-handler-alist)
784 (installed nil))
785
786 (while (and fnha (not installed))
787 (and (eq (cdr (car fnha)) 'jka-compr-handler)
788 (setq installed (car fnha)))
789 (setq fnha (cdr fnha)))
790
791 installed))
792
793
794;;; Add the file I/O hook if it does not already exist.
795;;; Make sure that jka-compr-file-name-handler-entry is eq to the
796;;; entry for jka-compr in file-name-handler-alist.
797(and (jka-compr-installed-p)
798 (jka-compr-uninstall))
799
800(jka-compr-install)
801
802
803(provide 'jka-compr)
804
805;; jka-compr.el ends here.