1 ;;; uudecode.el -- elisp native uudecode
3 ;; Copyright (c) 1998, 1999, 2000 Free Software Foundation, Inc.
5 ;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
6 ;; Keywords: uudecode news
8 ;; This file is a part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
27 ;; Lots of codes are stolen from mm-decode.el, gnus-uu.el and
30 ;; This looks as though it could be made rather more efficient for
31 ;; internal working. Encoding could use a lookup table and decoding
32 ;; should presumably use a vector or list buffer for partial results
33 ;; rather than with-current-buffer. -- fx
37 (eval-when-compile (require 'cl
))
40 (defalias 'uudecode-char-int
41 (if (fboundp 'char-int
)
45 (if (featurep 'xemacs
)
46 (defalias 'uudecode-insert-char
'insert-char
)
47 (defun uudecode-insert-char (char &optional count ignored buffer
)
48 (if (or (null buffer
) (eq buffer
(current-buffer)))
49 (insert-char char count
)
50 (with-current-buffer buffer
51 (insert-char char count
))))))
53 (defcustom uudecode-decoder-program
"uudecode"
54 "*Non-nil value should be a string that names a uu decoder.
55 The program should expect to read uu data on its standard
56 input and write the converted data to its standard output."
60 (defcustom uudecode-decoder-switches nil
61 "*List of command line flags passed to `uudecode-decoder-program'."
63 :type
'(repeat string
))
65 (defconst uudecode-alphabet
"\040-\140")
67 (defconst uudecode-begin-line
"^begin[ \t]+[0-7][0-7][0-7][ \t]+\\(.*\\)$")
68 (defconst uudecode-end-line
"^end[ \t]*$")
70 (defconst uudecode-body-line
71 (let ((i 61) (str "^M"))
72 (while (> (setq i
(1- i
)) 0)
73 (setq str
(concat str
"[^a-z]")))
76 (defvar uudecode-temporary-file-directory
77 (cond ((fboundp 'temp-directory
) (temp-directory))
78 ((boundp 'temporary-file-directory
) temporary-file-directory
)
82 (defun uudecode-decode-region-external (start end
&optional file-name
)
83 "Uudecode region between START and END using external program.
84 If FILE-NAME is non-nil, save the result to FILE-NAME. The program
85 used is specified by `uudecode-decoder-program'."
87 (let ((cbuf (current-buffer)) tempfile firstline status
)
90 (when (re-search-forward uudecode-begin-line nil t
)
92 (setq firstline
(point))
93 (cond ((null file-name
))
96 (setq file-name
(read-file-name "File to Name:"
99 (setq tempfile
(if file-name
100 (expand-file-name file-name
)
101 (let ((temporary-file-directory
102 uudecode-temporary-file-directory
))
103 (make-temp-file "uu"))))
104 (let ((cdir default-directory
)
105 default-process-coding-system
)
108 (insert "begin 600 " (file-name-nondirectory tempfile
) "\n")
109 (insert-buffer-substring cbuf firstline end
)
110 (cd (file-name-directory tempfile
))
111 (apply 'call-process-region
114 uudecode-decoder-program
118 uudecode-decoder-switches
))
119 (cd cdir
) (set-buffer cbuf
)))
120 (if (file-exists-p tempfile
)
123 (delete-region start end
)
125 (insert-file-contents-literally tempfile
)))
126 (message "Can not uudecode")))
127 (ignore-errors (or file-name
(delete-file tempfile
))))))
130 (defun uudecode-decode-region (start end
&optional file-name
)
131 "Uudecode region between START and END without using an external program.
132 If FILE-NAME is non-nil, save the result to FILE-NAME."
134 (let ((work-buffer nil
)
140 (non-data-chars (concat "^" uudecode-alphabet
)))
144 (when (re-search-forward uudecode-begin-line nil t
)
145 (cond ((null file-name
))
146 ((stringp file-name
))
148 (setq file-name
(expand-file-name
149 (read-file-name "File to Name:"
151 (match-string 1))))))
152 (setq work-buffer
(generate-new-buffer " *uudecode-work*"))
154 (skip-chars-forward non-data-chars end
)
156 (setq inputpos
(point))
157 (setq remain
0 bits
0 counter
0)
159 ((> (skip-chars-forward uudecode-alphabet end
) 0)
162 (logand (- (uudecode-char-int (char-after inputpos
)) 32)
164 (setq inputpos
(1+ inputpos
))
165 (if (= remain
0) (setq done t
))
166 (while (and (< inputpos lim
) (> remain
0))
170 (uudecode-char-int (char-after inputpos
)) 32)
172 (if (/= counter
0) (setq remain
(1- remain
)))
173 (setq counter
(1+ counter
)
174 inputpos
(1+ inputpos
))
176 (uudecode-insert-char
177 (lsh bits -
16) 1 nil work-buffer
)
178 (uudecode-insert-char
179 (logand (lsh bits -
8) 255) 1 nil work-buffer
)
180 (uudecode-insert-char (logand bits
255) 1 nil
182 (setq bits
0 counter
0))
183 (t (setq bits
(lsh bits
6)))))))
187 (error "uucode line ends unexpectly")
189 ((and (= (point) end
) (not done
))
190 ;;(error "uucode ends unexpectly")
193 (uudecode-insert-char (logand (lsh bits -
16) 255) 1 nil
195 (uudecode-insert-char (logand (lsh bits -
8) 255) 1 nil
198 (uudecode-insert-char (logand (lsh bits -
10) 255) 1 nil
200 (skip-chars-forward non-data-chars end
))
203 (set-buffer work-buffer
)
204 (write-file file-name
))
205 (or (markerp end
) (setq end
(set-marker (make-marker) end
)))
207 (insert-buffer-substring work-buffer
)
208 (delete-region (point) end
))))
209 (and work-buffer
(kill-buffer work-buffer
)))))
213 ;;; uudecode.el ends here