Importing pgnus-0.71
[elisp/gnus.git-] / lisp / mm-util.el
1 ;;; mm-util.el --- Utility functions for MIME things
2 ;; Copyright (C) 1998,99 Free Software Foundation, Inc.
3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
5 ;;      MORIOKA Tomohiko <morioka@jaist.ac.jp>
6 ;; This file is part of GNU Emacs.
7
8 ;; GNU Emacs is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
11 ;; any later version.
12
13 ;; GNU Emacs is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
20 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
22
23 ;;; Commentary:
24
25 ;;; Code:
26
27 (defvar mm-running-xemacs (string-match "XEmacs" emacs-version))
28
29 (defvar mm-running-ntemacs 
30   (and (not mm-running-xemacs) 
31        (string-match "nt" system-configuration)))
32
33 (defvar mm-binary-coding-system 
34   (if mm-running-xemacs
35       'binary 'no-conversion)
36   "100% binary coding system.")   
37
38 (defvar mm-text-coding-system 
39   (cond 
40    ((not (fboundp 'coding-system-p)) nil)
41    (mm-running-xemacs  ;; XEmacs
42     (and (coding-system-p 'no-conversion) 'no-conversion))
43    (mm-running-ntemacs ;; NTEmacs
44     (and (coding-system-p 'raw-text-dos) 'raw-text-dos))
45    ((coding-system-p 'raw-text) 'raw-text) ;; Emacs
46    (t nil))
47   "100% text coding system, for removing ^M.")
48
49 (defvar mm-mime-mule-charset-alist
50   '((us-ascii ascii)
51     (iso-8859-1 latin-iso8859-1)
52     (iso-8859-2 latin-iso8859-2)
53     (iso-8859-3 latin-iso8859-3)
54     (iso-8859-4 latin-iso8859-4)
55     (iso-8859-5 cyrillic-iso8859-5)
56     (koi8-r cyrillic-iso8859-5)
57     (iso-8859-6 arabic-iso8859-6)
58     (iso-8859-7 greek-iso8859-7)
59     (iso-8859-8 hebrew-iso8859-8)
60     (iso-8859-9 latin-iso8859-9)
61     (iso-2022-jp-2 japanese-jisx0208)
62     (iso-2022-jp latin-jisx0201
63                  japanese-jisx0208-1978)
64     (euc-kr korean-ksc5601)
65     (cn-gb-2312 chinese-gb2312)
66     (cn-big5 chinese-big5-1 chinese-big5-2)
67     (iso-2022-jp-2 latin-iso8859-1 greek-iso8859-7
68                    latin-jisx0201 japanese-jisx0208-1978
69                    chinese-gb2312 japanese-jisx0208
70                    korean-ksc5601 japanese-jisx0212)
71     (iso-2022-int-1 latin-iso8859-1 greek-iso8859-7
72                     latin-jisx0201 japanese-jisx0208-1978
73                     chinese-gb2312 japanese-jisx0208
74                     korean-ksc5601 japanese-jisx0212
75                     chinese-cns11643-1 chinese-cns11643-2)
76     (iso-2022-int-1 latin-iso8859-1 latin-iso8859-2
77                     cyrillic-iso8859-5 greek-iso8859-7
78                     latin-jisx0201 japanese-jisx0208-1978
79                     chinese-gb2312 japanese-jisx0208
80                     korean-ksc5601 japanese-jisx0212
81                     chinese-cns11643-1 chinese-cns11643-2
82                     chinese-cns11643-3 chinese-cns11643-4
83                     chinese-cns11643-5 chinese-cns11643-6
84                     chinese-cns11643-7))
85   "Alist of MIME-charset/MULE-charsets.")
86
87
88 (eval-and-compile
89   (mapcar
90    (lambda (elem)
91      (let ((nfunc (intern (format "mm-%s" (car elem)))))
92        (if (fboundp (car elem))
93            (fset nfunc (car elem))
94          (fset nfunc (cdr elem)))))
95    '((decode-coding-string . (lambda (s a) s))
96      (encode-coding-string . (lambda (s a) s))
97      (encode-coding-region . ignore)
98      (coding-system-list . ignore)
99      (decode-coding-region . ignore)
100      (char-int . identity)
101      (device-type . ignore)
102      (coding-system-equal . equal)
103      (annotationp . ignore)
104      (set-buffer-file-coding-system . ignore)
105      (make-char
106       . (lambda (charset int)
107           (int-to-char int)))
108      (read-coding-system
109       . (lambda (prompt)
110           "Prompt the user for a coding system."
111           (completing-read
112            prompt (mapcar (lambda (s) (list (symbol-name (car s))))
113                           mm-mime-mule-charset-alist)))))))
114
115 (defvar mm-coding-system-list nil)
116 (defun mm-get-coding-system-list ()
117   "Get the coding system list."
118   (or mm-coding-system-list
119       (setq mm-coding-system-list (mm-coding-system-list))))
120
121 (defvar mm-charset-coding-system-alist
122   (let ((rest
123          '((gb2312 . cn-gb-2312)
124            (iso-2022-jp-2 . iso-2022-7bit-ss2)
125            (x-ctext . ctext)))
126         (systems (mm-get-coding-system-list))
127         dest)
128     (while rest
129       (let ((pair (car rest)))
130         (unless (memq (car pair) systems)
131           (setq dest (cons pair dest))))
132       (setq rest (cdr rest)))
133     dest)
134   "Charset/coding system alist.")
135
136 ;;; Internal variables:
137
138 ;;; Functions:
139
140 (defun mm-mule-charset-to-mime-charset (charset)
141   "Return the MIME charset corresponding to MULE CHARSET."
142   (let ((alist mm-mime-mule-charset-alist)
143         out)
144     (while alist
145       (when (memq charset (cdar alist))
146         (setq out (caar alist)
147               alist nil))
148       (pop alist))
149     out))
150
151 (defun mm-charset-to-coding-system (charset &optional lbt)
152   "Return coding-system corresponding to CHARSET.
153 CHARSET is a symbol naming a MIME charset.
154 If optional argument LBT (`unix', `dos' or `mac') is specified, it is
155 used as the line break code type of the coding system."
156   (when (stringp charset)
157     (setq charset (intern (downcase charset))))
158   (setq charset
159         (or (cdr (assq charset mm-charset-coding-system-alist))
160             charset))
161   (when lbt
162     (setq charset (intern (format "%s-%s" charset lbt))))
163   (cond
164    ;; Running in a non-MULE environment.
165    ((null (mm-get-coding-system-list))
166     charset)
167    ;; ascii
168    ((eq charset 'us-ascii)
169     'ascii)
170    ;; Check to see whether we can handle this charset.
171    ((memq charset (mm-get-coding-system-list))
172     charset)
173    ;; Nope.
174    (t
175     nil)))
176
177 (defun mm-replace-chars-in-string (string from to)
178   "Replace characters in STRING from FROM to TO."
179   (let ((string (substring string 0))   ;Copy string.
180         (len (length string))
181         (idx 0))
182     ;; Replace all occurrences of FROM with TO.
183     (while (< idx len)
184       (when (= (aref string idx) from)
185         (aset string idx to))
186       (setq idx (1+ idx)))
187     string))
188
189 (defsubst mm-enable-multibyte ()
190   "Enable multibyte in the current buffer."
191   (when (and (fboundp 'set-buffer-multibyte)
192              (default-value 'enable-multibyte-characters))
193     (set-buffer-multibyte t)))
194
195 (defsubst mm-disable-multibyte ()
196   "Disable multibyte in the current buffer."
197   (when (fboundp 'set-buffer-multibyte)
198     (set-buffer-multibyte nil)))
199
200 (defun mm-mime-charset (charset b e)
201   (if (fboundp 'coding-system-get)
202       (or
203        (coding-system-get
204         (get-charset-property charset 'prefered-coding-system)
205         'mime-charset)
206        (car (memq charset (find-coding-systems-region
207                            (point-min) (point-max)))))
208     (mm-mule-charset-to-mime-charset charset)))
209
210 (defsubst mm-multibyte-p ()
211   "Say whether multibyte is enabled."
212   (and (boundp 'enable-multibyte-characters)
213        enable-multibyte-characters))
214
215 (defmacro mm-with-unibyte-buffer (&rest forms)
216   "Create a temporary buffer, and evaluate FORMS there like `progn'.
217 See also `with-temp-file' and `with-output-to-string'."
218   (let ((temp-buffer (make-symbol "temp-buffer"))
219         (multibyte (make-symbol "multibyte")))
220     `(if (not (boundp 'enable-multibyte-characters))
221          (with-temp-buffer ,@forms)
222        (let ((,multibyte (default-value 'enable-multibyte-characters))
223              ,temp-buffer)
224          (unwind-protect
225              (progn
226                (setq-default enable-multibyte-characters nil)
227                (setq ,temp-buffer
228                      (get-buffer-create (generate-new-buffer-name " *temp*")))
229                (unwind-protect
230                    (with-current-buffer ,temp-buffer
231                      (let ((buffer-file-coding-system mm-binary-coding-system)
232                            (coding-system-for-read mm-binary-coding-system)
233                            (coding-system-for-write mm-binary-coding-system))
234                        ,@forms))
235                  (and (buffer-name ,temp-buffer)
236                       (kill-buffer ,temp-buffer))))
237            (setq-default enable-multibyte-characters ,multibyte))))))
238 (put 'mm-with-unibyte-buffer 'lisp-indent-function 0)
239 (put 'mm-with-unibyte-buffer 'edebug-form-spec '(body))
240
241 (defun mm-find-charset-region (b e)
242   "Return a list of charsets in the region."
243   (cond
244    ((and (boundp 'enable-multibyte-characters)
245          enable-multibyte-characters
246          (fboundp 'find-charset-region))
247     (find-charset-region b e))
248    ((not (boundp 'current-language-environment))
249     (save-excursion
250       (save-restriction
251         (narrow-to-region b e)
252         (goto-char (point-min))
253         (skip-chars-forward "\0-\177")
254         (if (eobp)
255             '(ascii)
256           ;;;!!!bogus
257           (list 'ascii 'latin-iso8859-1)))))
258    (t
259     ;; We are in a unibyte buffer, so we futz around a bit.
260     (save-excursion
261       (save-restriction
262         (narrow-to-region b e)
263         (goto-char (point-min))
264         (let ((entry (assoc (capitalize current-language-environment)
265                             language-info-alist)))
266           (skip-chars-forward "\0-\177")
267           (if (eobp)
268               '(ascii)
269             (list 'ascii (car (last (assq 'charset entry)))))))))))
270
271 (defun mm-read-charset (prompt)
272   "Return a charset."
273   (completing-read prompt mm-mime-mule-charset-alist nil t))
274
275 (provide 'mm-util)
276
277 ;;; mm-util.el ends here