22
|
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
2 ;;
|
|
3 ;; File: dired-cmpr.el
|
116
|
4 ;; Dired Version: #Revision: 7.9 $
|
22
|
5 ;; RCS:
|
|
6 ;; Description: Commands for compressing marked files.
|
|
7 ;;
|
|
8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
9
|
|
10 ;;; Requirements and provisions
|
|
11 (provide 'dired-cmpr)
|
|
12 (require 'dired)
|
|
13
|
|
14 ;;; Entry points.
|
|
15
|
|
16 (defun dired-do-compress (&optional arg files)
|
|
17 "Compress or uncompress marked (or next ARG) files.
|
|
18 With a zero prefix, prompts for a new value of `dired-compression-method'."
|
|
19 (interactive
|
|
20 (let ((arg (prefix-numeric-value current-prefix-arg))
|
|
21 files)
|
|
22 (if (zerop arg)
|
|
23 (let ((new (completing-read
|
|
24 (format "Set compression method (currently %s): "
|
|
25 dired-compression-method)
|
|
26 (mapcar
|
|
27 (function
|
|
28 (lambda (x)
|
|
29 (cons (symbol-name (car x)) nil)))
|
|
30 dired-compression-method-alist)
|
|
31 nil t)))
|
|
32 (or (string-equal new "")
|
|
33 (setq dired-compression-method (intern new))))
|
|
34 (setq files (dired-get-marked-files nil current-prefix-arg))
|
|
35 (or (memq 'compress dired-no-confirm)
|
|
36 (let* ((dir (dired-current-directory))
|
|
37 (rfiles (mapcar (function
|
|
38 (lambda (fn)
|
|
39 (dired-make-relative fn dir t)))
|
|
40 files))
|
|
41 (prompt "")
|
|
42 (comp 0)
|
|
43 (uncomp nil)
|
|
44 (total (length files))
|
|
45 elt)
|
|
46 (mapcar (function
|
|
47 (lambda (fn)
|
|
48 (if (listp (setq elt
|
|
49 (dired-make-compressed-filename fn)))
|
|
50 (let* ((method (car (nth 3 elt)))
|
|
51 (count (assoc method uncomp)))
|
|
52 (if count
|
|
53 (setcdr count (1+ (cdr count)))
|
|
54 (setq uncomp (cons (cons method 1) uncomp))))
|
|
55 (setq comp (1+ comp)))))
|
|
56 files)
|
|
57 (if (/= comp 0)
|
|
58 (setq prompt
|
|
59 (format "%s %d"
|
|
60 (car
|
|
61 (nth 2
|
|
62 (assq dired-compression-method
|
|
63 dired-compression-method-alist)))
|
|
64 comp)))
|
|
65 (if uncomp
|
|
66 (let ((case-fold-search t)
|
|
67 method)
|
|
68 (or (string-equal prompt "")
|
|
69 (setq prompt (concat prompt "; ")))
|
|
70 (setq uncomp
|
|
71 (sort
|
|
72 (mapcar
|
|
73 (function
|
|
74 (lambda (elt)
|
|
75 (setq method (car elt))
|
|
76 (if (string-equal method "gzip")
|
|
77 (setq method "gunzip")
|
|
78 (or (string-match "^un" method)
|
|
79 (setq method (concat "un" method))))
|
|
80 (setcar elt method)
|
|
81 elt))
|
|
82 uncomp)
|
|
83 (function
|
|
84 (lambda (x y)
|
|
85 (string< (car x) (car y))))))
|
|
86 (setq prompt
|
|
87 (concat prompt
|
|
88 (mapconcat
|
|
89 (function
|
|
90 (lambda (elt)
|
|
91 (format "%s %d" (car elt) (cdr elt))))
|
|
92 uncomp ", ")))))
|
|
93 (cond
|
|
94 ((= (length rfiles) 1)
|
|
95 (setq prompt (format "%s %s? "
|
|
96 ;; Don't need the number 1
|
|
97 (substring prompt 0 -2)
|
|
98 (car rfiles))))
|
|
99 ((or (> (length uncomp) 1) (and (/= 0 comp) uncomp))
|
|
100 (setq prompt (format "%s? Total: %d file%s " prompt total
|
|
101 (dired-plural-s total))))
|
|
102 ((setq prompt (format "%s file%s? " prompt
|
|
103 (dired-plural-s total)))))
|
|
104 (or (dired-mark-pop-up nil 'compress rfiles 'y-or-n-p prompt)
|
|
105 (setq arg 0)))))
|
|
106 (list arg files)))
|
|
107
|
|
108 (if (not (zerop arg))
|
|
109 (dired-create-files
|
|
110 'dired-compress-file
|
|
111 "Compress or Uncompress"
|
|
112 files
|
|
113 (function
|
|
114 (lambda (fn)
|
|
115 (let ((cfn (dired-make-compressed-filename fn)))
|
|
116 (if (stringp cfn)
|
|
117 cfn
|
|
118 (substring fn 0 (- (length (nth 1 cfn))))))))
|
|
119 dired-keep-marker-compress nil t)))
|
|
120
|
|
121 (defun dired-compress-subdir-files (&optional uncompress)
|
|
122 "Compress all uncompressed files in the current subdirectory.
|
|
123 With a prefix argument uncompresses all compressed files."
|
|
124 (interactive "P")
|
|
125 (let ((dir (dired-current-directory))
|
|
126 files methods uncomp elt)
|
|
127 (save-excursion
|
|
128 (save-restriction
|
|
129 (narrow-to-region (dired-subdir-min) (dired-subdir-max))
|
|
130 (dired-map-dired-file-lines
|
|
131 (function
|
|
132 (lambda (f)
|
|
133 (if uncompress
|
|
134 (and (listp (setq uncomp (dired-make-compressed-filename f)))
|
|
135 (let ((program (car (nth 3 uncomp))))
|
|
136 (setq files (cons f files))
|
|
137 (if (setq elt (assoc program methods))
|
|
138 (setcdr elt (1+ (cdr elt)))
|
|
139 (setq methods (cons (cons program 1) methods)))))
|
|
140 (and (stringp (dired-make-compressed-filename f))
|
|
141 (setq files (cons f files)))))))))
|
|
142 (if files
|
|
143 (let ((total (length files))
|
|
144 (rfiles (mapcar
|
|
145 (function
|
|
146 (lambda (fn)
|
|
147 (dired-make-relative fn dir t)))
|
|
148 files))
|
|
149 prompt)
|
|
150 (if uncompress
|
|
151 (progn
|
|
152 (setq prompt (mapconcat
|
|
153 (function
|
|
154 (lambda (x)
|
|
155 (format "%s %d"
|
|
156 (if (string-equal (car x) "gzip")
|
|
157 "gunzip"
|
|
158 (if (string-match "^un" (car x))
|
|
159 (car x)
|
|
160 (concat "un" (car x))))
|
|
161 (cdr x))))
|
|
162 methods ", "))
|
|
163 (cond
|
|
164 ((= total 1)
|
|
165 (setq prompt
|
|
166 (concat (substring prompt 0 -1) (car rfiles) "? ")))
|
|
167 ((= (length methods) 1)
|
|
168 (setq prompt
|
|
169 (format "%s file%s? " prompt (dired-plural-s total))))
|
|
170 (t
|
|
171 (setq prompt (format "%s? Total: %d file%s " prompt total
|
|
172 (dired-plural-s total))))))
|
|
173 (setq prompt
|
|
174 (if (= total 1)
|
|
175 (format "%s %s? " dired-compression-method (car rfiles))
|
|
176 (format "%s %d file%s? "
|
|
177 dired-compression-method total
|
|
178 (dired-plural-s total)))))
|
|
179 (if (dired-mark-pop-up nil 'compress rfiles 'y-or-n-p prompt)
|
|
180 (dired-create-files
|
|
181 'dired-compress-file
|
|
182 "Compress or Uncompress"
|
|
183 files
|
|
184 (function
|
|
185 (lambda (fn)
|
|
186 (let ((cfn (dired-make-compressed-filename fn)))
|
|
187 (if (stringp cfn)
|
|
188 cfn
|
|
189 (substring fn 0 (- (length (nth 1 cfn))))))))
|
|
190 dired-keep-marker-compress nil t)))
|
|
191 (message "No files need %scompressing in %s."
|
|
192 (if uncompress "un" "")
|
|
193 (dired-abbreviate-file-name dir)))))
|
|
194
|
|
195 (defun dired-compress-file (file ok-flag)
|
|
196 ;; Compress or uncompress FILE.
|
|
197 ;; If ok-flag is non-nil, it is OK to overwrite an existing
|
|
198 ;; file. How well this actually works may depend on the compression
|
|
199 ;; program.
|
|
200 ;; Return the name of the compressed or uncompressed file.
|
|
201 (let ((handler (find-file-name-handler file 'dired-compress-file)))
|
|
202 (if handler
|
|
203 (funcall handler 'dired-compress-file file ok-flag)
|
|
204 (let ((compressed-fn (dired-make-compressed-filename file))
|
|
205 (err-buff (get-buffer-create " *dired-check-process output*")))
|
|
206 (save-excursion
|
|
207 (set-buffer err-buff)
|
|
208 (erase-buffer)
|
|
209 (cond ((file-symlink-p file)
|
|
210 (signal 'file-error (list "Error compressing file"
|
|
211 file "a symbolic link")))
|
|
212 ((listp compressed-fn)
|
|
213 (message "Uncompressing %s..." file)
|
|
214 (let* ((data (nth 3 compressed-fn))
|
|
215 (ret
|
|
216 (apply 'call-process
|
|
217 (car data) file t nil
|
|
218 (append (cdr data)
|
|
219 (and ok-flag
|
|
220 (list (nth 4 compressed-fn)))
|
|
221 (list file)))))
|
|
222 (if (or (and (integerp ret) (/= ret 0))
|
|
223 (not (bobp)))
|
|
224 (signal 'file-error
|
|
225 (nconc
|
|
226 (list "Error uncompressing file"
|
|
227 file)
|
|
228 (and (not (bobp))
|
|
229 (list
|
|
230 (progn
|
|
231 (goto-char (point-min))
|
|
232 (buffer-substring
|
|
233 (point) (progn (end-of-line)
|
|
234 (point))))))))))
|
|
235 (message "Uncompressing %s...done" file)
|
|
236 (dired-remove-file file)
|
|
237 (let ((to (substring file 0
|
|
238 (- (length (nth 1 compressed-fn))))))
|
|
239 ;; rename any buffers
|
|
240 (and (get-file-buffer file)
|
|
241 (save-excursion
|
|
242 (set-buffer (get-file-buffer file))
|
|
243 (let ((modflag (buffer-modified-p)))
|
|
244 ;; kills write-file-hooks
|
|
245 (set-visited-file-name to)
|
|
246 (set-buffer-modified-p modflag))))
|
|
247 to))
|
|
248 ((stringp compressed-fn)
|
|
249 (message "Compressing %s..." file)
|
|
250 (let* ((data (assq dired-compression-method
|
|
251 dired-compression-method-alist))
|
|
252 (compr-args (nth 2 data))
|
|
253 (ret
|
|
254 (apply 'call-process
|
|
255 (car compr-args) file t nil
|
|
256 (append (cdr compr-args)
|
|
257 (and ok-flag
|
|
258 (list (nth 4 data)))
|
|
259 (list file)))))
|
|
260 (if (or (and (integerp ret) (/= ret 0))
|
|
261 (not (bobp)))
|
|
262 (signal 'file-error
|
|
263 (nconc
|
|
264 (list "Error compressing file"
|
|
265 file)
|
|
266 (and (not (bobp))
|
|
267 (list
|
|
268 (progn
|
|
269 (goto-char (point-min))
|
|
270 (buffer-substring
|
|
271 (point) (progn (end-of-line)
|
|
272 (point))))))))))
|
|
273 (message "Compressing %s...done" file)
|
|
274 (dired-remove-file file)
|
|
275 ;; rename any buffers
|
|
276 (and (get-file-buffer file)
|
|
277 (save-excursion
|
|
278 (set-buffer (get-file-buffer file))
|
|
279 (let ((modflag (buffer-modified-p)))
|
|
280 ;; kills write-file-hooks
|
|
281 (set-visited-file-name compressed-fn)
|
|
282 (set-buffer-modified-p modflag))))
|
|
283 compressed-fn)
|
|
284 (t (error "Strange error in dired-compress-file."))))))))
|
|
285
|
|
286 (defun dired-make-compressed-filename (name &optional method)
|
|
287 ;; If NAME is in the syntax of a compressed file (according to
|
|
288 ;; dired-compression-method-alist), return the data (a list) from this
|
|
289 ;; alist on how to uncompress it. Otherwise, return a string, the
|
|
290 ;; compressed form of this file name. This is computed using the optional
|
|
291 ;; argument METHOD (a symbol). If METHOD is nil, the ambient value of
|
|
292 ;; dired-compression-method is used.
|
|
293 (let ((handler (find-file-name-handler
|
|
294 name 'dired-make-compressed-filename)))
|
|
295 (if handler
|
|
296 (funcall handler 'dired-make-compressed-filename name method)
|
|
297 (let ((alist dired-compression-method-alist)
|
|
298 (len (length name))
|
|
299 ext ext-len result)
|
|
300 (while alist
|
|
301 (if (and (> len
|
|
302 (setq ext-len (length (setq ext (nth 1 (car alist))))))
|
|
303 (string-equal ext (substring name (- ext-len))))
|
|
304 (setq result (car alist)
|
|
305 alist nil)
|
|
306 (setq alist (cdr alist))))
|
|
307 (or result
|
|
308 (concat name
|
|
309 (nth 1 (or (assq (or method dired-compression-method)
|
|
310 dired-compression-method-alist)
|
|
311 (error "Unknown compression method: %s"
|
|
312 (or method dired-compression-method))))))
|
|
313 ))))
|
|
314
|
|
315 ;;; end of dired-cmpr.el
|