1 ;;; utf-8.el --- UTF-8 decoding/encoding support -*- coding: iso-2022-7bit -*-
3 ;; Copyright (C) 2001, 2004 Electrotechnical Laboratory, JAPAN.
4 ;; Licensed to the Free Software Foundation.
5 ;; Copyright (C) 2001, 2002 Free Software Foundation, Inc.
7 ;; Author: TAKAHASHI Naoto <ntakahas@m17n.org>
9 ;; Keywords: multilingual, Unicode, UTF-8, i18n
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
30 ;; The coding-system `mule-utf-8' basically supports encoding/decoding
31 ;; of the following character sets to and from UTF-8:
36 ;; mule-unicode-0100-24ff
37 ;; mule-unicode-2500-33ff
38 ;; mule-unicode-e000-ffff
40 ;; On decoding, Unicode characters that do not fit into the above
41 ;; character sets are handled as `eight-bit-control' or
42 ;; `eight-bit-graphic' characters to retain the information about the
43 ;; original byte sequence and text properties record the corresponding
46 ;; Fixme: note that reading and writing invalid utf-8 may not be
47 ;; idempotent -- to represent the bytes to fix that needs a new charset.
49 ;; Characters from other character sets can be encoded with mule-utf-8
50 ;; by populating the translation table
51 ;; `utf-translation-table-for-encode'. Hash tables
52 ;; `utf-subst-table-for-decode' and `utf-subst-table-for-encode' are
53 ;; used to support encoding and decoding of about a quarter of the CJK
54 ;; space between U+3400 and U+DFFF.
56 ;; UTF-8 is defined in RFC 3629. A sketch of the encoding is:
59 ;; value | 1st byte | 2nd byte | 3rd byte
60 ;; --------------------+-----------+-----------+----------
61 ;; 0000 0000 0xxx xxxx | 0xxx xxxx | |
62 ;; 0000 0yyy yyxx xxxx | 110y yyyy | 10xx xxxx |
63 ;; zzzz yyyy yyxx xxxx | 1110 zzzz | 10yy yyyy | 10xx xxxx
67 (defvar ucs-mule-to-mule-unicode
(make-char-table 'translation-table nil
)
68 "Char table mapping characters to latin-iso8859-1 or mule-unicode-*.
70 If `unify-8859-on-encoding-mode' is non-nil, this table populates the
71 translation-table named `utf-translation-table-for-encode'.")
73 (define-translation-table 'utf-translation-table-for-encode
)
76 ;; Map Cyrillic and Greek to iso-8859 charsets, which take half the
77 ;; space of mule-unicode. For Latin scripts this isn't very
78 ;; important. Hebrew and Arabic might go here too when there's proper
81 (defvar utf-fragmentation-table
(make-char-table 'translation-table nil
)
82 "Char-table normally mapping non-Latin mule-unicode-* chars to iso-8859-*.
84 If `utf-fragment-on-decoding' is non-nil, this table populates the
85 translation-table named `utf-translation-table-for-decode'")
87 (defvar utf-defragmentation-table
(make-char-table 'translation-table nil
)
88 "Char-table for reverse mapping of `utf-fragmentation-table'.
90 If `utf-fragment-on-decoding' is non-nil and
91 `unify-8859-on-encoding-mode' is nil, this table populates the
92 translation-table named `utf-translation-table-for-encode'")
94 (define-translation-table 'utf-translation-table-for-decode
)
97 (defvar ucs-mule-cjk-to-unicode
(make-hash-table :test
'eq
)
98 "Hash table mapping Emacs CJK character sets to Unicode code points.
100 If `utf-translate-cjk-mode' is non-nil, this table populates the
101 translation-hash-table named `utf-subst-table-for-encode'.")
103 (define-translation-hash-table 'utf-subst-table-for-encode
104 ucs-mule-cjk-to-unicode
)
106 (defvar ucs-unicode-to-mule-cjk
(make-hash-table :test
'eq
)
107 "Hash table mapping Unicode code points to Emacs CJK character sets.
109 If `utf-translate-cjk-mode' is non-nil, this table populates the
110 translation-hash-table named `utf-subst-table-for-decode'.")
112 (define-translation-hash-table 'utf-subst-table-for-decode
113 ucs-unicode-to-mule-cjk
)
117 (aset utf-fragmentation-table
(car pair
) (cdr pair
))
118 (aset utf-defragmentation-table
(cdr pair
) (car pair
)))
119 '((?
\e$
,1&d
\e(B . ?
\e,F4
\e(B) (?
\e$
,1&e
\e(B . ?
\e,F5
\e(B) (?
\e$
,1&f
\e(B . ?
\e,F6
\e(B) (?
\e$
,1&h
\e(B . ?
\e,F8
\e(B) (?
\e$
,1&i
\e(B . ?
\e,F9
\e(B)
120 (?
\e$
,1&j
\e(B . ?
\e,F
:\e(B) (?
\e$
,1&l
\e(B . ?
\e,F
<\e(B) (?
\e$
,1&n
\e(B . ?
\e,F
>\e(B) (?
\e$
,1&o
\e(B . ?
\e,F?
\e(B) (?
\e$
,1&p
\e(B . ?
\e,F
@\e(B)
121 (?
\e$
,1&q
\e(B . ?
\e,FA
\e(B) (?
\e$
,1&r
\e(B . ?
\e,FB
\e(B) (?
\e$
,1&s
\e(B . ?
\e,FC
\e(B) (?
\e$
,1&t
\e(B . ?
\e,FD
\e(B) (?
\e$
,1&u
\e(B . ?
\e,FE
\e(B)
122 (?
\e$
,1&v
\e(B . ?
\e,FF
\e(B) (?
\e$
,1&w
\e(B . ?
\e,FG
\e(B) (?
\e$
,1&x
\e(B . ?
\e,FH
\e(B) (?
\e$
,1&y
\e(B . ?
\e,FI
\e(B) (?
\e$
,1&z
\e(B . ?
\e,FJ
\e(B)
123 (?
\e$
,1&{\e(B . ?
\e,FK
\e(B) (?
\e$
,1&|
\e(B . ?
\e,FL
\e(B) (?
\e$
,1&}\e(B . ?
\e,FM
\e(B) (?
\e$
,1&~
\e(B . ?
\e,FN
\e(B) (?
\e$
,1&\7f\e(B . ?
\e,FO
\e(B)
124 (?
\e$
,1' \e(B . ?
\e,FP
\e(B) (?
\e$
,1'!\e(B . ?
\e,FQ
\e(B) (?
\e$
,1'#\e(B . ?
\e,FS
\e(B) (?
\e$
,1'$
\e(B . ?
\e,FT
\e(B) (?
\e$
,1'%
\e(B . ?
\e,FU
\e(B)
125 (?
\e$
,1'&\e(B . ?
\e,FV
\e(B) (?
\e$
,1''\e(B . ?
\e,FW
\e(B) (?
\e$
,1'(\e(B . ?
\e,FX
\e(B) (?
\e$
,1')\e(B . ?
\e,FY
\e(B) (?
\e$
,1'*\e(B . ?
\e,FZ
\e(B)
126 (?
\e$
,1'+\e(B . ?
\e,F
[\e(B) (?
\e$
,1',\e(B . ?
\e,F\
\e(B) (?
\e$
,1'-
\e(B . ?
\e,F
]\e(B) (?
\e$
,1'.
\e(B . ?
\e,F^
\e(B) (?
\e$
,1'/\e(B . ?
\e,F_
\e(B)
127 (?
\e$
,1'0\e(B . ?
\e,F
`\e(B) (?
\e$
,1'1\e(B . ?
\e,Fa
\e(B) (?
\e$
,1'2\e(B . ?
\e,Fb
\e(B) (?
\e$
,1'3\e(B . ?
\e,Fc
\e(B) (?
\e$
,1'4\e(B . ?
\e,Fd
\e(B)
128 (?
\e$
,1'5\e(B . ?
\e,Fe
\e(B) (?
\e$
,1'6\e(B . ?
\e,Ff
\e(B) (?
\e$
,1'7\e(B . ?
\e,Fg
\e(B) (?
\e$
,1'8\e(B . ?
\e,Fh
\e(B) (?
\e$
,1'9\e(B . ?
\e,Fi
\e(B)
129 (?
\e$
,1':\e(B . ?
\e,Fj
\e(B) (?
\e$
,1';\e(B . ?\e,Fk\e(B) (?\e$,1'<\e(B . ?\e,Fl\e(B) (?\e$,1'=\e(B . ?\e,Fm\e(B) (?\e$,1'>\e(B . ?\e,Fn\e(B)
130 (?
\e$
,1'?
\e(B . ?
\e,Fo
\e(B) (?
\e$
,1'@\e(B . ?
\e,Fp
\e(B) (?
\e$
,1'A
\e(B . ?
\e,Fq
\e(B) (?
\e$
,1'B
\e(B . ?
\e,Fr
\e(B) (?
\e$
,1'C
\e(B . ?
\e,Fs
\e(B)
131 (?
\e$
,1'D
\e(B . ?
\e,Ft
\e(B) (?
\e$
,1'E
\e(B . ?
\e,Fu
\e(B) (?
\e$
,1'F
\e(B . ?
\e,Fv
\e(B) (?
\e$
,1'G
\e(B . ?
\e,Fw
\e(B) (?
\e$
,1'H
\e(B . ?
\e,Fx
\e(B)
132 (?
\e$
,1'I
\e(B . ?
\e,Fy
\e(B) (?
\e$
,1'J
\e(B . ?
\e,Fz
\e(B) (?
\e$
,1'K
\e(B . ?
\e,F
{\e(B) (?
\e$
,1'L
\e(B . ?
\e,F|
\e(B) (?
\e$
,1'M
\e(B . ?
\e,F
}\e(B)
133 (?
\e$
,1'N
\e(B . ?
\e,F~
\e(B)
135 (?
\e$
,1(!\e(B . ?
\e,L
!\e(B) (?
\e$
,1("\e(B . ?\e,L"\e(B) (?
\e$
,1(#\e(B . ?
\e,L
#\e(B) (?
\e$
,1($
\e(B . ?
\e,L$
\e(B)
136 (?
\e$
,1(%
\e(B . ?
\e,L%
\e(B) (?
\e$
,1(&\e(B . ?
\e,L
&\e(B) (?
\e$
,1('\e(B . ?
\e,L
'\e(B) (?
\e$
,1((\e(B . ?
\e,L
(\e(B) (?
\e$
,1()\e(B . ?
\e,L
)\e(B)
137 (?
\e$
,1(*\e(B . ?
\e,L
*\e(B) (?
\e$
,1(+\e(B . ?
\e,L
+\e(B) (?
\e$
,1(,\e(B . ?
\e,L
,\e(B) (?
\e$
,1(.
\e(B . ?
\e,L.
\e(B) (?
\e$
,1(/\e(B . ?
\e,L
/\e(B)
138 (?
\e$
,1(0\e(B . ?
\e,L0
\e(B) (?
\e$
,1(1\e(B . ?
\e,L1
\e(B) (?
\e$
,1(2\e(B . ?
\e,L2
\e(B) (?
\e$
,1(3\e(B . ?
\e,L3
\e(B) (?
\e$
,1(4\e(B . ?
\e,L4
\e(B)
139 (?
\e$
,1(5\e(B . ?
\e,L5
\e(B) (?
\e$
,1(6\e(B . ?
\e,L6
\e(B) (?
\e$
,1(7\e(B . ?
\e,L7
\e(B) (?
\e$
,1(8\e(B . ?
\e,L8
\e(B) (?
\e$
,1(9\e(B . ?
\e,L9
\e(B)
140 (?
\e$
,1(:\e(B . ?
\e,L
:\e(B) (?
\e$
,1(;\e(B . ?\e,L;\e(B) (?\e$,1(<\e(B . ?\e,L<\e(B) (?\e$,1(=\e(B . ?\e,L=\e(B) (?\e$,1(>\e(B . ?\e,L>\e(B)
141 (?
\e$
,1(?
\e(B . ?
\e,L?
\e(B) (?
\e$
,1(@\e(B . ?
\e,L
@\e(B) (?
\e$
,1(A\e(B . ?
\e,LA
\e(B) (?
\e$
,1(B\e(B . ?
\e,LB
\e(B) (?
\e$
,1(C\e(B . ?
\e,LC
\e(B)
142 (?
\e$
,1(D\e(B . ?
\e,LD
\e(B) (?
\e$
,1(E\e(B . ?
\e,LE
\e(B) (?
\e$
,1(F\e(B . ?
\e,LF
\e(B) (?
\e$
,1(G\e(B . ?
\e,LG
\e(B) (?
\e$
,1(H\e(B . ?
\e,LH
\e(B)
143 (?
\e$
,1(I\e(B . ?
\e,LI
\e(B) (?
\e$
,1(J\e(B . ?
\e,LJ
\e(B) (?
\e$
,1(K\e(B . ?
\e,LK
\e(B) (?
\e$
,1(L\e(B . ?
\e,LL
\e(B) (?
\e$
,1(M\e(B . ?
\e,LM
\e(B)
144 (?
\e$
,1(N\e(B . ?
\e,LN
\e(B) (?
\e$
,1(O\e(B . ?
\e,LO
\e(B) (?
\e$
,1(P\e(B . ?
\e,LP
\e(B) (?
\e$
,1(Q\e(B . ?
\e,LQ
\e(B) (?
\e$
,1(R\e(B . ?
\e,LR
\e(B)
145 (?
\e$
,1(S\e(B . ?
\e,LS
\e(B) (?
\e$
,1(T\e(B . ?
\e,LT
\e(B) (?
\e$
,1(U\e(B . ?
\e,LU
\e(B) (?
\e$
,1(V\e(B . ?
\e,LV
\e(B) (?
\e$
,1(W\e(B . ?
\e,LW
\e(B)
146 (?
\e$
,1(X\e(B . ?
\e,LX
\e(B) (?
\e$
,1(Y\e(B . ?
\e,LY
\e(B) (?
\e$
,1(Z\e(B . ?
\e,LZ
\e(B) (?
\e$
,1([\e(B . ?
\e,L
[\e(B) (?
\e$
,1(\
\e(B . ?
\e,L\
\e(B)
147 (?
\e$
,1(]\e(B . ?
\e,L
]\e(B) (?
\e$
,1(^
\e(B . ?
\e,L^
\e(B) (?
\e$
,1(_\e(B . ?
\e,L_
\e(B) (?
\e$
,1(`\e(B . ?
\e,L
`\e(B) (?
\e$
,1(a\e(B . ?
\e,La
\e(B)
148 (?
\e$
,1(b\e(B . ?
\e,Lb
\e(B) (?
\e$
,1(c\e(B . ?
\e,Lc
\e(B) (?
\e$
,1(d\e(B . ?
\e,Ld
\e(B) (?
\e$
,1(e\e(B . ?
\e,Le
\e(B) (?
\e$
,1(f\e(B . ?
\e,Lf
\e(B)
149 (?
\e$
,1(g\e(B . ?
\e,Lg
\e(B) (?
\e$
,1(h\e(B . ?
\e,Lh
\e(B) (?
\e$
,1(i\e(B . ?
\e,Li
\e(B) (?
\e$
,1(j\e(B . ?
\e,Lj
\e(B) (?
\e$
,1(k\e(B . ?
\e,Lk
\e(B)
150 (?
\e$
,1(l\e(B . ?
\e,Ll
\e(B) (?
\e$
,1(m\e(B . ?
\e,Lm
\e(B) (?
\e$
,1(n\e(B . ?
\e,Ln
\e(B) (?
\e$
,1(o\e(B . ?
\e,Lo
\e(B) (?
\e$
,1(q\e(B . ?
\e,Lq
\e(B)
151 (?
\e$
,1(r\e(B . ?
\e,Lr
\e(B) (?
\e$
,1(s\e(B . ?
\e,Ls
\e(B) (?
\e$
,1(t\e(B . ?
\e,Lt
\e(B) (?
\e$
,1(u\e(B . ?
\e,Lu
\e(B) (?
\e$
,1(v\e(B . ?
\e,Lv
\e(B)
152 (?
\e$
,1(w\e(B . ?
\e,Lw
\e(B) (?
\e$
,1(x\e(B . ?
\e,Lx
\e(B) (?
\e$
,1(y\e(B . ?
\e,Ly
\e(B) (?
\e$
,1(z\e(B . ?
\e,Lz
\e(B) (?
\e$
,1({\e(B . ?
\e,L
{\e(B)
153 (?
\e$
,1(|
\e(B . ?
\e,L|
\e(B) (?
\e$
,1(~
\e(B . ?
\e,L~
\e(B) (?
\e$
,1(\7f\e(B . ?
\e,L
\7f\e(B)))
156 (defcustom utf-fragment-on-decoding nil
157 "Whether or not to decode some chars in UTF-8/16 text into iso8859 charsets.
158 Setting this means that the relevant Cyrillic and Greek characters are
159 decoded into the iso8859 charsets rather than into
160 mule-unicode-0100-24ff. The iso8859 charsets take half as much space
161 in the buffer, but using them may affect how the buffer can be re-encoded
162 and may require a different input method to search for them, for instance.
163 See `unify-8859-on-decoding-mode' and `unify-8859-on-encoding-mode'
164 for mechanisms to make this largely transparent.
166 Setting this variable outside customize has no effect."
170 (define-translation-table 'utf-translation-table-for-decode
171 utf-fragmentation-table
)
172 ;; Even if unify-8859-on-encoding-mode is off, make
173 ;; mule-utf-* encode characters in
174 ;; utf-fragmentation-table.
175 (unless (eq (get 'utf-translation-table-for-encode
177 ucs-mule-to-mule-unicode
)
178 (define-translation-table 'utf-translation-table-for-encode
179 utf-defragmentation-table
)))
180 (define-translation-table 'utf-translation-table-for-decode
)
181 ;; When unify-8859-on-encoding-mode is off, be sure to make
182 ;; mule-utf-* disabled for characters in
183 ;; utf-fragmentation-table.
184 (unless (eq (get 'utf-translation-table-for-encode
186 ucs-mule-to-mule-unicode
)
187 (define-translation-table 'utf-translation-table-for-encode
)))
194 (defconst utf-translate-cjk-charsets
'(chinese-gb2312
195 chinese-big5-1 chinese-big5-2
196 japanese-jisx0208 japanese-jisx0212
199 "List of charsets supported by `utf-translate-cjk-mode'.")
201 (defvar utf-translate-cjk-lang-env nil
202 "Language environment in which tables for `utf-translate-cjk-mode' is loaded.
203 The value nil means that the tables are not yet loaded.")
205 (defvar utf-translate-cjk-unicode-range
)
207 ;; String generated from utf-translate-cjk-unicode-range. It is
208 ;; suitable for an argument to skip-chars-forward.
209 (defvar utf-translate-cjk-unicode-range-string nil
)
211 (defun utf-translate-cjk-set-unicode-range (range)
212 (setq utf-translate-cjk-unicode-range range
)
213 (setq utf-translate-cjk-unicode-range-string
214 (let ((decode-char-no-trans
216 (cond ((< x
#x100
) (make-char 'latin-iso8859-1 x
))
219 (make-char 'mule-unicode-0100-24ff
220 (+ (/ x
96) 32) (+ (% x
96) 32)))
222 (setq x
(- x
#x2500
))
223 (make-char 'mule-unicode-2500-33ff
224 (+ (/ x
96) 32) (+ (% x
96) 32)))
226 (setq x
(- x
#xe000
))
227 (make-char 'mule-unicode-e000-ffff
228 (+ (/ x
96) 32) (+ (% x
96) 32))))))
231 (setq from
(max #xA0
(car elt
)) to
(min #xffff
(cdr elt
)))
232 (if (and (>= to
#x3400
) (< to
#xE000
))
234 (cond ((< from
#x100
)
236 (setq ranges
(cons (cons #xE000 to
) ranges
)
239 (setq ranges
(cons (cons #x2500 to
) ranges
)
242 (setq ranges
(cons (cons #x100 to
) ranges
)
246 (setq ranges
(cons (cons #xE000 to
) ranges
)
249 (setq ranges
(cons (cons #x2500 to
) ranges
)
253 (setq ranges
(cons (cons #xE000 to
) ranges
)
256 (setq ranges
(cons (cons from to
) ranges
))))
257 (mapconcat #'(lambda (x)
259 (funcall decode-char-no-trans
(car x
))
260 (funcall decode-char-no-trans
(cdr x
))))
262 ;; These forces loading and settting tables for
263 ;; utf-translate-cjk-mode.
264 (setq utf-translate-cjk-lang-env nil
265 ucs-mule-cjk-to-unicode
(make-hash-table :test
'eq
)
266 ucs-unicode-to-mule-cjk
(make-hash-table :test
'eq
)))
268 (defcustom utf-translate-cjk-unicode-range
'((#x2e80 .
#xd7a3
)
270 "List of Unicode code ranges supported by `utf-translate-cjk-mode'.
271 Setting this variable directly does not take effect;
272 use either \\[customize] or the function
273 `utf-translate-cjk-set-unicode-range'."
275 :type
'(repeat (cons integer integer
))
276 :set
(lambda (symbol value
)
277 (utf-translate-cjk-set-unicode-range value
))
280 ;; Return non-nil if CODE-POINT is in `utf-translate-cjk-unicode-range'.
281 (defsubst utf-translate-cjk-substitutable-p
(code-point)
282 (let ((tail utf-translate-cjk-unicode-range
)
285 (setq elt
(car tail
) tail
(cdr tail
))
286 (if (and (>= code-point
(car elt
)) (<= code-point
(cdr elt
)))
291 (defun utf-translate-cjk-load-tables ()
292 "Load tables for `utf-translate-cjk-mode'."
293 ;; Fixme: Allow the use of the CJK charsets to be
294 ;; customized by reordering and possible omission.
295 (let ((redefined (< (hash-table-size ucs-mule-cjk-to-unicode
) 43000)))
297 ;; Redefine them with realistic initial sizes and a
298 ;; smallish rehash size to avoid wasting significant
299 ;; space after they're built.
300 (setq ucs-mule-cjk-to-unicode
301 (make-hash-table :test
'eq
:size
43000 :rehash-size
1000)
302 ucs-unicode-to-mule-cjk
303 (make-hash-table :test
'eq
:size
21500 :rehash-size
1000)))
305 ;; Load the files explicitly, to avoid having to keep
306 ;; around the large tables they contain (as well as the
307 ;; ones which get built).
308 ;; Here we bind coding-system-for-read to nil so that coding tags
309 ;; in the files are respected even if the files are not yet
311 (let ((coding-system-for-read nil
))
312 (cond ((string= "Korean" current-language-environment
)
315 (load "subst-gb2312")
317 ((string= "Chinese-BIG5" current-language-environment
)
320 (load "subst-gb2312")
322 ((string= "Chinese-GB" current-language-environment
)
326 (load "subst-gb2312"))
329 (load "subst-gb2312")
331 (load "subst-jis")))) ; jis covers as much as big5, gb2312
334 (define-translation-hash-table 'utf-subst-table-for-decode
335 ucs-unicode-to-mule-cjk
)
336 (define-translation-hash-table 'utf-subst-table-for-encode
337 ucs-mule-cjk-to-unicode
)
338 (set-char-table-extra-slot (get 'utf-translation-table-for-encode
340 1 ucs-mule-cjk-to-unicode
))
342 (setq utf-translate-cjk-lang-env current-language-environment
)))
344 (defun utf-lookup-subst-table-for-decode (code-point)
345 (if (and utf-translate-cjk-mode
346 (not utf-translate-cjk-lang-env
)
347 (utf-translate-cjk-substitutable-p code-point
))
348 (utf-translate-cjk-load-tables))
350 (get 'utf-subst-table-for-decode
'translation-hash-table
)))
353 (defun utf-lookup-subst-table-for-encode (char)
354 (if (and utf-translate-cjk-mode
355 (not utf-translate-cjk-lang-env
)
356 (memq (char-charset char
) utf-translate-cjk-charsets
))
357 (utf-translate-cjk-load-tables))
359 (get 'utf-subst-table-for-encode
'translation-hash-table
)))
361 (define-minor-mode utf-translate-cjk-mode
362 "Toggle whether UTF based coding systems de/encode CJK characters.
363 If ARG is an integer, enable if ARG is positive and disable if
364 zero or negative. This is a minor mode.
365 Enabling this allows the coding systems mule-utf-8,
366 mule-utf-16le and mule-utf-16be to encode characters in the charsets
367 `korean-ksc5601', `chinese-gb2312', `chinese-big5-1',
368 `chinese-big5-2', `japanese-jisx0208' and `japanese-jisx0212', and to
369 decode the corresponding unicodes into such characters.
371 Where the charsets overlap, the one preferred for decoding is chosen
372 according to the language environment in effect when this option is
373 turned on: ksc5601 for Korean, gb2312 for Chinese-GB, big5 for
374 Chinese-Big5 and jisx for other environments.
376 This mode is on by default. If you are not interested in CJK
377 characters and want to avoid some overhead on encoding/decoding
378 by the above coding systems, you can customize the user option
379 `utf-translate-cjk-mode' to nil."
385 (if utf-translate-cjk-mode
387 (define-translation-hash-table 'utf-subst-table-for-decode
388 ucs-unicode-to-mule-cjk
)
389 (define-translation-hash-table 'utf-subst-table-for-encode
390 ucs-mule-cjk-to-unicode
)
391 (set-char-table-extra-slot (get 'utf-translation-table-for-encode
393 1 ucs-mule-cjk-to-unicode
))
394 (define-translation-hash-table 'utf-subst-table-for-decode
395 (make-hash-table :test
'eq
))
396 (define-translation-hash-table 'utf-subst-table-for-encode
397 (make-hash-table :test
'eq
))
398 (set-char-table-extra-slot (get 'utf-translation-table-for-encode
402 ;; Update safe-chars of mule-utf-* coding systems.
403 (dolist (elt (coding-system-list t
))
404 (if (string-match "^mule-utf" (symbol-name elt
))
405 (let ((safe-charsets (coding-system-get elt
'safe-charsets
))
406 (safe-chars (coding-system-get elt
'safe-chars
))
408 (dolist (charset utf-translate-cjk-charsets
)
409 (unless (eq utf-translate-cjk-mode
(memq charset safe-charsets
))
411 (if utf-translate-cjk-mode
412 (cons charset safe-charsets
)
413 (delq charset safe-charsets
))
415 (aset safe-chars
(make-char charset
) utf-translate-cjk-mode
)))
417 (coding-system-put elt
'safe-charsets safe-charsets
)
418 (define-coding-system-internal elt
))))))
420 (define-ccl-program ccl-mule-utf-untrans
421 ;; R0 is an untranslatable Unicode code-point (U+3500..U+DFFF or
422 ;; U+10000..U+10FFFF) or an invaid byte (#x00..#xFF). Write
423 ;; eight-bit-control/graphic sequence (2 to 4 chars) representing
424 ;; UTF-8 sequence of r0. Registers r4, r5, r6 are modified.
426 ;; This is a subrountine because we assume that this is called very
427 ;; rarely (so we don't have to worry about the overhead of the
430 ((r5 = ,(charset-id 'eight-bit-control
))
431 (r6 = ,(charset-id 'eight-bit-graphic
))
433 ((r4 = ((r0 >> 6) |
#xC0
))
434 (write-multibyte-character r6 r4
))
436 ((r4 = ((r0 >> 12) |
#xE0
))
437 (write-multibyte-character r6 r4
))
438 ((r4 = ((r0 >> 18) |
#xF0
))
439 (write-multibyte-character r6 r4
)
440 (r4 = (((r0 >> 12) & #x3F
) |
#x80
))
442 (write-multibyte-character r5 r4
)
443 (write-multibyte-character r6 r4
))))
444 (r4 = (((r0 >> 6) & #x3F
) |
#x80
))
446 (write-multibyte-character r5 r4
)
447 (write-multibyte-character r6 r4
))))
448 (r4 = ((r0 & #x3F
) |
#x80
))
450 (write-multibyte-character r5 r4
)
451 (write-multibyte-character r6 r4
)))))
453 (define-ccl-program ccl-decode-mule-utf-8
455 ;; charset | bytes in utf-8 | bytes in emacs
456 ;; -----------------------+----------------+---------------
458 ;; -----------------------+----------------+---------------
459 ;; eight-bit-control | 2 | 2
460 ;; eight-bit-graphic | 2 | 1
461 ;; latin-iso8859-1 | 2 | 2
462 ;; -----------------------+----------------+---------------
463 ;; mule-unicode-0100-24ff | 2 | 4
465 ;; -----------------------+----------------+---------------
466 ;; mule-unicode-0100-24ff | 3 | 4
468 ;; mule-unicode-2500-33ff | 3 | 4
469 ;; mule-unicode-e000-ffff | 3 | 4
470 ;; -----------------------+----------------+---------------
471 ;; invalid byte | 1 | 2
473 ;; Thus magnification factor is two.
476 ((r6 = ,(charset-id 'latin-iso8859-1
))
480 ;; 1-byte encoding, i.e., ascii
481 (write-read-repeat r0
))
483 ;; continuation byte (invalid here) or 1st byte of overlong
485 ((call ccl-mule-utf-untrans
)
486 (r6 = ,(charset-id 'latin-iso8859-1
))
490 ;; Read the 2nd byte.
492 (if ((r1 & #b11000000
) != #b10000000
) ; Invalid 2nd byte
493 ((call ccl-mule-utf-untrans
)
494 (r6 = ,(charset-id 'latin-iso8859-1
))
495 ;; Handle it in the next loop.
500 ;; 2-byte encoding 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
502 (r1 |
= ((r0 & #x1F
) << 6))
503 ;; Now r1 holds scalar value. We don't have to check
504 ;; `overlong sequence' because r0 >= 0xC2.
507 ;; mule-unicode-0100-24ff (< 0800)
509 (lookup-integer utf-subst-table-for-decode r0 r1
)
511 ((r0 = ,(charset-id 'mule-unicode-0100-24ff
))
513 (r2 = (((r1 / 96) + 32) << 7))
517 utf-translation-table-for-decode r0 r1
)))
518 (write-multibyte-character r0 r1
)
524 (lookup-integer utf-subst-table-for-decode r0 r1
)
527 (write-multibyte-character r6 r1
))
528 ((write-multibyte-character r0 r1
)))
532 ((r0 = ,(charset-id 'eight-bit-control
))
533 (write-multibyte-character r0 r1
)
537 ;; Read the 3rd bytes.
539 (if ((r2 & #b11000000
) != #b10000000
) ; Invalid 3rd byte
540 ((call ccl-mule-utf-untrans
)
542 (call ccl-mule-utf-untrans
)
543 (r6 = ,(charset-id 'latin-iso8859-1
))
544 ;; Handle it in the next loop.
550 ;; zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
551 ((r3 = ((r0 & #xF
) << 12))
552 (r3 |
= ((r1 & #x3F
) << 6))
555 (if (r3 < #x800
) ; `overlong sequence'
556 ((call ccl-mule-utf-untrans
)
558 (call ccl-mule-utf-untrans
)
560 (call ccl-mule-utf-untrans
)
561 (r6 = ,(charset-id 'latin-iso8859-1
))
566 ;; mule-unicode-0100-24ff (>= 0800)
568 (lookup-integer utf-subst-table-for-decode r0 r1
)
570 ((r0 = ,(charset-id 'mule-unicode-0100-24ff
))
574 (r1 += ((r3 + 32) << 7))
576 utf-translation-table-for-decode r0 r1
)))
577 (write-multibyte-character r0 r1
)
582 ;; mule-unicode-2500-33ff
583 ((r0 = r3
) ; don't zap r3
584 (lookup-integer utf-subst-table-for-decode r0 r1
)
586 ((r0 = ,(charset-id 'mule-unicode-2500-33ff
))
590 (r1 += ((r3 + 32) << 7))))
591 (write-multibyte-character r0 r1
)
596 ;; Try to convert to CJK chars, else
597 ;; keep them as eight-bit-{control|graphic}.
599 (lookup-integer utf-subst-table-for-decode r3 r1
)
602 ((write-multibyte-character r3 r1
)
605 ((call ccl-mule-utf-untrans
)
606 (r6 = ,(charset-id 'latin-iso8859-1
))
610 ;; mule-unicode-e000-ffff
611 ;; Fixme: fffe and ffff are invalid.
612 (r0 = r3
) ; don't zap r3
613 (lookup-integer utf-subst-table-for-decode r0 r1
)
615 ((r0 = ,(charset-id 'mule-unicode-e000-ffff
))
619 (r1 += ((r3 + 32) << 7))))
620 (write-multibyte-character r0 r1
)
624 ;; Read the 4th bytes.
626 (if ((r3 & #b11000000
) != #b10000000
) ; Invalid 4th byte
627 ((call ccl-mule-utf-untrans
)
629 (call ccl-mule-utf-untrans
)
631 (call ccl-mule-utf-untrans
)
632 (r6 = ,(charset-id 'latin-iso8859-1
))
633 ;; Handle it in the next loop.
639 ;; wwwzzzzzzyyyyyyxxxxxx = 11110www 10zzzzzz 10yyyyyy 10xxxxxx
640 ;; keep those bytes as eight-bit-{control|graphic}
641 ;; Fixme: allow lookup in utf-subst-table-for-decode.
642 ((r4 = ((r0 & #x7
) << 18))
643 (r4 |
= ((r1 & #x3F
) << 12))
644 (r4 |
= ((r2 & #x3F
) << 6))
647 (if (r4 < #x10000
) ; `overlong sequence'
648 ((call ccl-mule-utf-untrans
)
650 (call ccl-mule-utf-untrans
)
652 (call ccl-mule-utf-untrans
)
654 (call ccl-mule-utf-untrans
))
656 (call ccl-mule-utf-untrans
))))
658 ;; Unsupported sequence.
659 ((call ccl-mule-utf-untrans
)
661 (call ccl-mule-utf-untrans
)
663 (call ccl-mule-utf-untrans
)
665 (call ccl-mule-utf-untrans
)))
666 (r6 = ,(charset-id 'latin-iso8859-1
))
674 ((call ccl-mule-utf-untrans
)
677 (call ccl-mule-utf-untrans
)
680 (call ccl-mule-utf-untrans
)
683 (call ccl-mule-utf-untrans
))))))))))
685 "CCL program to decode UTF-8.
686 Basic decoding is done into the charsets ascii, latin-iso8859-1 and
687 mule-unicode-*, but see also `utf-fragmentation-table' and
688 `ucs-mule-cjk-to-unicode'.
689 Encodings of un-representable Unicode characters are decoded asis into
690 eight-bit-control and eight-bit-graphic characters.")
692 (define-ccl-program ccl-mule-utf-8-encode-untrans
693 ;; UTF-8 decoder generates an UTF-8 sequence represented by a
694 ;; sequence eight-bit-control/graphic chars for an untranslatable
695 ;; character and an invalid byte.
697 ;; This CCL parses that sequence (the first byte is already in r1),
698 ;; writes out the original bytes of that sequence, and sets r5 to
701 ;; If the eight-bit-control/graphic sequence is shorter than what r1
702 ;; suggests, it sets r5 and r6 to the last character read that
703 ;; should be handled by the next loop of a caller.
705 ;; Note: For UTF-8 validation, we only check if a character is
706 ;; eight-bit-control/graphic or not. It may result in incorrect
707 ;; handling of random binary data, but such a data can't be encoded
708 ;; by UTF-8 anyway. At least, UTF-8 decoders doesn't generate such
709 ;; a sequence even if a source contains invalid byte-sequence.
711 (;; Read the 2nd byte.
712 (read-multibyte-character r5 r6
)
713 (r0 = (r5 != ,(charset-id 'eight-bit-control
)))
714 (if ((r5 != ,(charset-id 'eight-bit-graphic
)) & r0
)
715 ((write r1
) ; invalid UTF-8
720 ;; 2-byte sequence for an originally invalid byte.
722 (r6 |
= ((r1 & #x1F
) << 6))
730 ;; Read the 3rd byte.
731 (read-multibyte-character r5 r6
)
732 (r0 = (r5 != ,(charset-id 'eight-bit-control
)))
733 (if ((r5 != ,(charset-id 'eight-bit-graphic
)) & r0
)
734 (end)) ; invalid UTF-8
737 ;; 3-byte sequence for an untranslated character.
740 ;; Read the 4th byte.
741 (read-multibyte-character r5 r6
)
742 (r0 = (r5 != ,(charset-id 'eight-bit-control
)))
743 (if ((r5 != ,(charset-id 'eight-bit-graphic
)) & r0
)
744 (end)) ; invalid UTF-8
745 ;; 4-byte sequence for an untranslated character.
755 (define-ccl-program ccl-encode-mule-utf-8
760 (read-multibyte-character r0 r1
)
761 ;; Pre-read character is in r5 (charset-ID) and r6 (code-point).
765 (translate-character utf-translation-table-for-encode r0 r1
)
767 (if (r0 == ,(charset-id 'ascii
))
770 (if (r0 == ,(charset-id 'latin-iso8859-1
))
772 ;; 0000 0yyy yyxx xxxx 110y yyyy 10xx xxxx
773 ;; 20 0000 0000 1010 0000 1100 0010 1010 0000
774 ;; 7f 0000 0000 1111 1111 1100 0011 1011 1111
775 ((write ((r1 >> 6) |
#xc2
))
780 (if (r0 == ,(charset-id 'mule-unicode-0100-24ff
))
781 ((r0 = ((((r1 & #x3f80
) >> 7) -
32) * 96))
782 ;; #x3f80 == (0011 1111 1000 0000)b
784 (r1 += (r0 + 224)) ; 240 == -32 + #x0100
785 ;; now r1 holds scalar value
788 ((write ((r1 >> 6) |
#xC0
))
793 ((write ((r1 >> 12) |
#xE0
))
794 (write (((r1 & #x0FC0
) >> 6) |
#x80
))
797 (write-repeat r1
)))))
799 (if (r0 == ,(charset-id 'mule-unicode-2500-33ff
))
800 ((r0 = ((((r1 & #x3f80
) >> 7) -
32) * 96))
802 (r1 += (r0 + 9440)) ; 9440 == -32 + #x2500
803 ;; now r1 holds scalar value
804 (write ((r1 >> 12) |
#xE0
))
805 (write (((r1 & #x0FC0
) >> 6) |
#x80
))
810 (if (r0 == ,(charset-id 'mule-unicode-e000-ffff
))
811 ((r0 = ((((r1 & #x3f80
) >> 7) -
32) * 96))
813 (r1 += (r0 + 57312)) ; 57312 == -32 + #xe000
814 ;; now r1 holds scalar value
815 (write ((r1 >> 12) |
#xE0
))
816 (write (((r1 & #x0FC0
) >> 6) |
#x80
))
821 (if (r0 == ,(charset-id 'eight-bit-control
))
823 ;; 0000 0yyy yyxx xxxx 110y yyyy 10xx xxxx
824 ;; 80 0000 0000 1000 0000 1100 0010 1000 0000
825 ;; 9f 0000 0000 1001 1111 1100 0010 1001 1111
829 (if (r0 == ,(charset-id 'eight-bit-graphic
))
831 ;; 0000 0yyy yyxx xxxx 110y yyyy 10xx xxxx
832 ;; a0 0000 0000 1010 0000 1100 0010 1010 0000
833 ;; ff 0000 0000 1111 1111 1101 1111 1011 1111
840 ((call ccl-mule-utf-8-encode-untrans
)
844 (lookup-character utf-subst-table-for-encode r0 r1
)
845 (if r7
; lookup succeeded
848 ((write ((r0 >> 6) |
#xC0
))
849 (r0 = ((r0 & #x3F
) |
#x80
))
852 ((write ((r0 >> 12) |
#xE0
))
853 (write (((r0 & #x0FC0
) >> 6) |
#x80
))
854 (r0 = ((r0 & #x3F
) |
#x80
))
857 ;; Unsupported character.
858 ;; Output U+FFFD, which is `ef bf bd' in UTF-8.
861 (write-repeat #xbd
))))
862 "CCL program to encode into UTF-8.")
865 (define-ccl-program ccl-untranslated-to-ucs
869 (if (r0 <= #xC3
) ; 2-byte encoding
870 ((r0 = ((r0 & #x3
) << 6))
875 (if (r0 < #xF0
) ; 3-byte encoding, as above
876 ((r0 = ((r0 & #xF
) << 12))
877 (r0 |
= ((r1 & #x3F
) << 6))
882 ((r0 = ((r0 & #x7
) << 18))
883 (r0 |
= ((r1 & #x3F
) << 12))
884 (r0 |
= ((r2 & #x3F
) << 6))
887 "Decode 2-, 3-, or 4-byte sequences in r0, r1, r2 [,r3] to unicodes in r0.
888 Set r1 to the byte length. r0 == 0 for invalid sequence.")
890 (defvar utf-8-ccl-regs
(make-vector 8 0))
892 (defsubst utf-8-untranslated-to-ucs
()
893 "Return the UCS code for an untranslated sequence of raw bytes t point.
894 Only for 3- or 4-byte sequences."
895 (aset utf-8-ccl-regs
0 (or (char-after) 0))
896 (aset utf-8-ccl-regs
1 (or (char-after (1+ (point))) 0))
897 (aset utf-8-ccl-regs
2 (or (char-after (+ 2 (point))) 0))
898 (aset utf-8-ccl-regs
3 (or (char-after (+ 3 (point))) 0))
899 (ccl-execute 'ccl-untranslated-to-ucs utf-8-ccl-regs
))
901 (defun utf-8-help-echo (window object position
)
902 (format "Untranslated Unicode U+%04X"
903 (get-char-property position
'untranslated-utf-8 object
)))
905 ;; We compose the untranslatable sequences into a single character,
906 ;; and move point to the next character.
907 ;; This is infelicitous for editing, because there's currently no
908 ;; mechanism for treating compositions as atomic, but is OK for
909 ;; display. They are composed to U+FFFD with help-echo which
910 ;; indicates the unicodes they represent. This function GCs too much.
912 ;; If utf-translate-cjk-mode is non-nil, this function is called with
913 ;; HASH-TABLE which translates CJK characters into some of CJK
916 (defsubst utf-8-compose
(hash-table)
917 "Put a suitable composition on an untranslatable sequence at point.
918 If HASH-TABLE is non-nil, try to translate CJK characters by it at first.
919 Move point to the end of the sequence."
920 (utf-8-untranslated-to-ucs)
921 (let ((l (aref utf-8-ccl-regs
1))
925 (setq ch
(gethash (aref utf-8-ccl-regs
0) hash-table
)))
928 (delete-region (point) (min (point-max) (+ l
(point)))))
929 (setq ch
(aref utf-8-ccl-regs
0))
930 (put-text-property (point) (min (point-max) (+ l
(point)))
931 'untranslated-utf-8 ch
)
932 (put-text-property (point) (min (point-max) (+ l
(point)))
933 'help-echo
'utf-8-help-echo
)
935 (put-text-property (point) (min (point-max) (+ l
(point)))
936 'display
(format "\\%03o" ch
))
937 (compose-region (point) (+ l
(point)) ?
\e$
,3u=\e(B))
941 (defcustom utf-8-compose-scripts nil
942 "*Non-nil means compose various scripts on decoding utf-8 text."
947 (defun utf-8-post-read-conversion (length)
948 "Compose untranslated utf-8 sequences into single characters.
949 If `utf-translate-cjk-mode' is non-nil, tries to translate CJK characters.
950 Also compose particular scripts if `utf-8-compose-scripts' is non-nil."
953 (narrow-to-region (point) (+ (point) length
))
954 ;; Can't do eval-when-compile to insert a multibyte constant
955 ;; version of the string in the loop, since it's always loaded as
956 ;; unibyte from a byte-compiled file.
957 (let ((range (string-as-multibyte "^\xc0-\xc3\xe1-\xf7"))
958 (buffer-multibyte enable-multibyte-characters
)
960 (set-buffer-multibyte t
)
961 (when utf-translate-cjk-mode
962 (unless utf-translate-cjk-lang-env
963 ;; Check these characters in utf-translate-cjk-range.
964 ;; We may have to translate them to CJK charsets.
966 (concat range utf-translate-cjk-unicode-range-string
))
968 (utf-translate-cjk-load-tables)
970 (concat range utf-translate-cjk-unicode-range-string
)))
971 (setq hash-table
(get 'utf-subst-table-for-decode
972 'translation-hash-table
))))
973 (while (and (skip-chars-forward range
)
975 (setq ch
(following-char))
977 (utf-8-compose hash-table
)
979 (setq ch
(gethash (encode-char ch
'ucs
) hash-table
)))
985 (set-buffer-multibyte nil
)))
987 (when (and utf-8-compose-scripts
(> length
1))
988 ;; These currently have definitions which cover the relevant
989 ;; unicodes. We could avoid loading thai-util &c by checking
990 ;; whether the region contains any characters with the appropriate
991 ;; categories. There aren't yet Unicode-based rules for Tibetan.
992 (diacritic-compose-region (point-max) (point-min))
993 (thai-compose-region (point-max) (point-min))
994 (lao-compose-region (point-max) (point-min))
995 (devanagari-compose-region (point-max) (point-min))
996 (malayalam-compose-region (point-max) (point-min))
997 (tamil-compose-region (point-max) (point-min)))
998 (- (point-max) (point-min)))))
1000 (defun utf-8-pre-write-conversion (beg end
)
1001 "Prepare for `utf-translate-cjk-mode' to encode text between BEG and END.
1002 This is used as a post-read-conversion of utf-8 coding system."
1003 (if (and utf-translate-cjk-mode
1004 (not utf-translate-cjk-lang-env
)
1007 (re-search-forward "\\cc\\|\\cj\\|\\ch" end t
)))
1008 (utf-translate-cjk-load-tables))
1013 "UTF-8 encoding for Emacs-supported Unicode characters.
1014 It supports Unicode characters of these ranges:
1015 U+0000..U+33FF, U+E000..U+FFFF.
1016 They correspond to these Emacs character sets:
1017 ascii, latin-iso8859-1, mule-unicode-0100-24ff,
1018 mule-unicode-2500-33ff, mule-unicode-e000-ffff
1020 On decoding (e.g. reading a file), Unicode characters not in the above
1021 ranges are decoded into sequences of eight-bit-control and
1022 eight-bit-graphic characters to preserve their byte sequences. The
1023 byte sequence is preserved on i/o for valid utf-8, but not necessarily
1026 On encoding (e.g. writing a file), Emacs characters not belonging to
1027 any of the character sets listed above are encoded into the UTF-8 byte
1028 sequence representing U+FFFD (REPLACEMENT CHARACTER)."
1030 '(ccl-decode-mule-utf-8 . ccl-encode-mule-utf-8
)
1036 mule-unicode-0100-24ff
1037 mule-unicode-2500-33ff
1038 mule-unicode-e000-ffff
1039 ,@(if utf-translate-cjk-mode
1040 utf-translate-cjk-charsets
))
1041 (mime-charset . utf-8
)
1042 (coding-category . coding-category-utf-8
)
1043 (valid-codes (0 .
255))
1044 (pre-write-conversion . utf-8-pre-write-conversion
)
1045 (post-read-conversion . utf-8-post-read-conversion
)
1046 (translation-table-for-encode . utf-translation-table-for-encode
)
1047 (dependency unify-8859-on-encoding-mode
1048 unify-8859-on-decoding-mode
1049 utf-fragment-on-decoding
1050 utf-translate-cjk-mode
)))
1052 (define-coding-system-alias 'utf-8
'mule-utf-8
)
1054 ;; I think this needs special private charsets defined for the
1055 ;; untranslated sequences, if it's going to work well.
1057 ;;; (defun utf-8-compose-function (pos to pattern &optional string)
1058 ;;; (let* ((prop (get-char-property pos 'composition string))
1059 ;;; (l (and prop (- (cadr prop) (car prop)))))
1060 ;;; (cond ((and l (> l (- to pos)))
1061 ;;; (delete-region pos to))
1062 ;;; ((and (> (char-after pos) 224)
1063 ;;; (< (char-after pos) 256)
1064 ;;; (save-restriction
1065 ;;; (narrow-to-region pos to)
1066 ;;; (utf-8-compose)))
1070 ;;; (aset composition-function-table
1072 ;;; `((,(string-as-multibyte "[\200-\237\240-\377]")
1073 ;;; . utf-8-compose-function))))
1075 ;;; arch-tag: b08735b7-753b-4ae6-b754-0f3efe4515c5
1076 ;;; utf-8.el ends here