MEL 1.8.
[elisp/flim.git] / mel-q.el
1 ;;;
2 ;;; $Id: mel-q.el,v 1.8 1995/08/27 19:29:17 morioka Exp $
3 ;;;
4
5 ;;; @ constants
6 ;;;
7
8 (defconst quoted-printable-hex-chars "0123456789ABCDEF")
9 (defconst quoted-printable-octet-regexp
10   (concat "=[" quoted-printable-hex-chars
11           "][" quoted-printable-hex-chars "]"))
12
13
14 ;;; @ variables
15 ;;;
16
17 (defvar quoted-printable-external-encoder '("mmencode" "-q")
18   "*list of quoted-printable encoder program name and its arguments.")
19
20 (defvar quoted-printable-external-decoder '("mmencode" "-q" "-u")
21   "*list of quoted-printable decoder program name and its arguments.")
22
23 (defvar quoted-printable-internal-encoding-limit 10000
24   "*limit size to use internal quoted-printable encoder.
25 If size of input to encode is larger than this limit,
26 external encoder is called.")
27
28 (defvar quoted-printable-internal-decoding-limit nil
29   "*limit size to use internal quoted-printable decoder.
30 If size of input to decode is larger than this limit,
31 external decoder is called.")
32
33
34 ;;; @ Quoted-Printable (Q-encode) encoder/decoder
35 ;;;
36
37 (defun quoted-printable-quote-char (chr)
38   (concat "="
39           (char-to-string (elt quoted-printable-hex-chars (ash chr -4)))
40           (char-to-string (elt quoted-printable-hex-chars (logand chr 15)))
41           ))
42
43
44 ;;; @@ Quoted-Printable encode/decode string
45 ;;;
46
47 (defun quoted-printable-encode-string (str)
48   (let ((i 0))
49     (mapconcat (function
50                 (lambda (chr)
51                   (cond ((or (< chr 32) (< 126 chr) (eq chr ?=))
52                          (if (>= i 73)
53                              (progn
54                                (setq i 0)
55                                (concat "=\n" (quoted-printable-quote-char chr))
56                                )
57                            (progn
58                              (setq i (+ i 3))
59                              (quoted-printable-quote-char chr)
60                              )))
61                         (t (if (>= i 75)
62                                (progn
63                                  (setq i 0)
64                                  (concat "=\n" (char-to-string chr))
65                                  )
66                              (progn
67                                (setq i (1+ i))
68                                (char-to-string chr)
69                                )))
70                         )))
71                str "")))
72
73 (defun quoted-printable-decode-string (str)
74   (let (q h l)
75     (mapconcat (function
76                 (lambda (chr)
77                   (cond ((eq chr ?=)
78                          (setq q t)
79                          "")
80                         (q (setq h
81                                  (cond ((<= ?a chr) (+ (- chr ?a) 10))
82                                        ((<= ?A chr) (+ (- chr ?A) 10))
83                                        ((<= ?0 chr) (- chr ?0))
84                                        ))
85                            (setq q nil)
86                            "")
87                         (h (setq l (cond ((<= ?a chr) (+ (- chr ?a) 10))
88                                          ((<= ?A chr) (+ (- chr ?A) 10))
89                                          ((<= ?0 chr) (- chr ?0))
90                                          ))
91                            (prog1
92                                (char-to-string (logior (ash h 4) l))
93                              (setq h nil)
94                              )
95                            )
96                         (t (char-to-string chr))
97                         )))
98                str "")))
99
100
101 ;;; @@ Quoted-Printable encode/decode region
102 ;;;
103
104 (defun quoted-printable-internal-encode-region (beg end)
105   (save-excursion
106     (save-restriction
107       (narrow-to-region beg end)
108       (goto-char (point-min))
109       (while (re-search-forward "^.*$" nil t)
110         (replace-match
111          (quoted-printable-encode-string
112           (buffer-substring (match-beginning 0)(match-end 0))
113           ))
114         ))))
115
116 (defun quoted-printable-internal-decode-region (beg end)
117   (save-excursion
118     (save-restriction
119       (narrow-to-region beg end)
120       (goto-char (point-min))
121       (while (re-search-forward "=\n" nil t)
122         (replace-match "")
123         )
124       (goto-char (point-min))
125       (let (b e str)
126         (while (re-search-forward quoted-printable-octet-regexp nil t)
127           (setq b (match-beginning 0))
128           (setq e (match-end 0))
129           (setq str (buffer-substring b e))
130           (delete-region b e)
131           (insert (quoted-printable-decode-string str))
132           ))
133       )))
134
135 (cond ((boundp 'MULE)
136        (define-program-coding-system
137          nil (car quoted-printable-external-encoder) *noconv*)
138        (define-program-coding-system
139          nil (car quoted-printable-external-decoder) *noconv*)
140        )
141       ((boundp 'NEMACS)
142        (define-program-kanji-code
143          nil (car quoted-printable-external-encoder) 0)
144        (define-program-kanji-code
145          nil (car quoted-printable-external-decoder) 0)
146        ))
147
148 (defun quoted-printable-external-encode-region (beg end)
149   (save-excursion
150     (apply (function call-process-region)
151            beg end (car quoted-printable-external-encoder)
152            t t nil (cdr quoted-printable-external-encoder))
153     ))
154
155 (defun quoted-printable-external-decode-region (beg end)
156   (save-excursion
157     (apply (function call-process-region)
158            beg end (car quoted-printable-external-decoder)
159            t t nil (cdr quoted-printable-external-decoder))
160     ))
161
162 (defun quoted-printable-encode-region (beg end)
163   (interactive "r")
164   (if (and quoted-printable-internal-encoding-limit
165            (> (- end beg) quoted-printable-internal-encoding-limit))
166       (quoted-printable-external-encode-region beg end)
167     (quoted-printable-internal-encode-region beg end)
168     ))
169
170 (defun quoted-printable-decode-region (beg end)
171   (interactive "r")
172   (if (and quoted-printable-internal-decoding-limit
173            (> (- end beg) quoted-printable-internal-decoding-limit))
174       (quoted-printable-external-decode-region beg end)
175     (quoted-printable-internal-decode-region beg end)
176     ))
177
178
179 ;;; @ Q-encoding encode/decode string
180 ;;;
181
182 (defun q-encoding-encode-string-for-text (str)
183   (mapconcat (function
184               (lambda (chr)
185                 (cond ((eq chr 32) "_")
186                       ((or (< chr 32) (< 126 chr) (eq chr ?=))
187                        (quoted-printable-quote-char chr)
188                        )
189                       (t (char-to-string chr))
190                       )))
191              str ""))
192
193 (defun q-encoding-encode-string-for-comment (str)
194   (mapconcat (function
195               (lambda (chr)
196                 (cond ((eq chr 32) "_")
197                       ((or (< chr 32) (< 126 chr)
198                            (memq chr '(?= ?\( ?\) ?\\))
199                            )
200                        (quoted-printable-quote-char chr)
201                        )
202                       (t (char-to-string chr))
203                       )))
204              str ""))
205
206 (defun q-encoding-encode-string-for-phrase (str)
207   (mapconcat (function
208               (lambda (chr)
209                 (cond ((eq chr 32) "_")
210                       ((or (and (<= ?A chr)(<= chr ?Z))
211                            (and (<= ?a chr)(<= chr ?z))
212                            (and (<= ?0 chr)(<= chr ?9))
213                            (memq chr '(?! ?* ?+ ?- ?/))
214                            )
215                        (char-to-string chr)
216                        )
217                       (t (quoted-printable-quote-char chr))
218                       )))
219              str ""))
220
221 (defun q-encoding-encode-string (str &optional mode)
222   (cond ((eq mode 'text)
223          (q-encoding-encode-string-for-text str)
224          )
225         ((eq mode 'comment)
226          (q-encoding-encode-string-for-comment str)
227          )
228         (t
229          (q-encoding-encode-string-for-phrase str)
230          )))
231
232 (defun q-encoding-decode-string (str)
233   (let (q h l)
234     (mapconcat (function
235                 (lambda (chr)
236                   (cond ((eq chr ?_) " ")
237                         ((eq chr ?=)
238                          (setq q t)
239                          "")
240                         (q (setq h (cond ((<= ?a chr) (+ (- chr ?a) 10))
241                                          ((<= ?A chr) (+ (- chr ?A) 10))
242                                          ((<= ?0 chr) (- chr ?0))
243                                          ))
244                            (setq q nil)
245                            "")
246                         (h (setq l (cond ((<= ?a chr) (+ (- chr ?a) 10))
247                                          ((<= ?A chr) (+ (- chr ?A) 10))
248                                          ((<= ?0 chr) (- chr ?0))
249                                          ))
250                            (prog1
251                                (char-to-string (logior (ash h 4) l))
252                              (setq h nil)
253                              )
254                            )
255                         (t (char-to-string chr))
256                         )))
257                str "")))
258
259
260 ;;; @@ etc
261 ;;;
262
263 (defun q-encoding-encoded-length (string &optional mode)
264   (let ((l 0)(i 0)(len (length string)) chr)
265     (while (< i len)
266       (setq chr (elt string i))
267       (if (string-match "[A-Za-z0-9!*+/=_---]" (char-to-string chr))
268           (setq l (+ l 1))
269         (setq l (+ l 3))
270         )
271       (setq i (+ i 1)) )
272     l))
273
274
275 ;;; @ end
276 ;;;
277
278 (provide 'mel-q)