Mercurial > emacs
changeset 46496:395e5c46761b
(utf-8-subst-table)
(utf-8-subst-rev-table, utf-8-translation-table-for-decode)
(utf-8-fragment-on-decoding, ccl-untranslated-to-ucs)
(utf-8-ccl-regs, utf-8-translate-cjk): New.
(ccl-encode-mule-utf-8): Use utf-8-subst-rev-table.
(ccl-decode-mule-utf-8, ccl-untranslated-to-ucs)
(utf-8-untranslated-to-ucs, utf-8-compose): Rewritten.
(mule-utf-8): Remove pre-write-conversion.
(utf-8-post-read-conversion): Comment out.
author | Dave Love <fx@gnu.org> |
---|---|
date | Wed, 17 Jul 2002 15:04:25 +0000 |
parents | fc51841e5d97 |
children | 4e525f71bb31 |
files | lisp/international/utf-8.el |
diffstat | 1 files changed, 400 insertions(+), 187 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/international/utf-8.el Wed Jul 17 14:39:54 2002 +0000 +++ b/lisp/international/utf-8.el Wed Jul 17 15:04:25 2002 +0000 @@ -1,10 +1,11 @@ -;;; utf-8.el --- limited UTF-8 decoding/encoding support -*- coding: iso-2022-7bit -*- +;;; utf-8.el --- UTF-8 decoding/encoding support -*- coding: iso-2022-7bit -*- ;; Copyright (C) 2001 Electrotechnical Laboratory, JAPAN. ;; Licensed to the Free Software Foundation. -;; Copyright (C) 2001 Free Software Foundation, Inc. +;; Copyright (C) 2001, 2002 Free Software Foundation, Inc. ;; Author: TAKAHASHI Naoto <ntakahas@m17n.org> +;; Maintainer: FSF ;; Keywords: multilingual, Unicode, UTF-8, i18n ;; This file is part of GNU Emacs. @@ -39,11 +40,18 @@ ;; On decoding, Unicode characters that do not fit into the above ;; character sets are handled as `eight-bit-control' or ;; `eight-bit-graphic' characters to retain the information about the -;; original byte sequence. +;; original byte sequence and text properties record the corresponding +;; unicode. +;; +;; Fixme: note that reading and writing invalid utf-8 may not be +;; idempotent -- to represent the bytes to fix that needs a new charset. ;; ;; Characters from other character sets can be encoded with ;; mule-utf-8 by populating the table `ucs-mule-to-mule-unicode' and -;; registering the translation with `register-char-codings'. +;; registering the translation with `register-char-codings'. Hash +;; tables `utf-8-subst-table' and `utf-8-subst-rev-table' are used to +;; support encoding and decoding of about a quarter of the CJK space +;; between U+3400 and U+DFFF. ;; UTF-8 is defined in RFC 2279. A sketch of the encoding is: @@ -60,7 +68,111 @@ "Translation table for encoding to `mule-utf-8'.") ;; Could have been done by ucs-tables loaded before. (unless (get 'ucs-mule-to-mule-unicode 'translation-table) - (define-translation-table 'ucs-mule-to-mule-unicode ucs-mule-to-mule-unicode)) + (define-translation-table 'ucs-mule-to-mule-unicode + ucs-mule-to-mule-unicode)) + +(defvar utf-8-subst-table (make-hash-table :test 'eq)) +(defvar utf-8-subst-rev-table (make-hash-table :test 'eq)) +(define-translation-hash-table 'utf-8-subst-table utf-8-subst-table) +(define-translation-hash-table 'utf-8-subst-rev-table utf-8-subst-rev-table) + +(defvar utf-8-translation-table-for-decode (make-translation-table) + "Translation table applied after decoding utf-8 to mule-unicode. +This is only actually applied to characters which would normally be +decoded into mule-unicode-0100-24ff.") +(define-translation-table 'utf-8-translation-table-for-decode + utf-8-translation-table-for-decode) + +;; Map Cyrillic and Greek to iso-8859 charsets, which take half the +;; space of mule-unicode. For Latin scripts this isn't very +;; important. Hebrew and Arabic might go here too when there's proper +;; support for them. +(mapc + (lambda (pair) + (aset utf-8-translation-table-for-decode (car pair) (cdr pair))) + '((?$,1&d(B . ?,F4(B) (?$,1&e(B . ?,F5(B) (?$,1&f(B . ?,F6(B) (?$,1&h(B . ?,F8(B) (?$,1&i(B . ?,F9(B) + (?$,1&j(B . ?,F:(B) (?$,1&l(B . ?,F<(B) (?$,1&n(B . ?,F>(B) (?$,1&o(B . ?,F?(B) (?$,1&p(B . ?,F@(B) + (?$,1&q(B . ?,FA(B) (?$,1&r(B . ?,FB(B) (?$,1&s(B . ?,FC(B) (?$,1&t(B . ?,FD(B) (?$,1&u(B . ?,FE(B) + (?$,1&v(B . ?,FF(B) (?$,1&w(B . ?,FG(B) (?$,1&x(B . ?,FH(B) (?$,1&y(B . ?,FI(B) (?$,1&z(B . ?,FJ(B) + (?$,1&{(B . ?,FK(B) (?$,1&|(B . ?,FL(B) (?$,1&}(B . ?,FM(B) (?$,1&~(B . ?,FN(B) (?$,1&(B . ?,FO(B) + (?$,1' (B . ?,FP(B) (?$,1'!(B . ?,FQ(B) (?$,1'#(B . ?,FS(B) (?$,1'$(B . ?,FT(B) (?$,1'%(B . ?,FU(B) + (?$,1'&(B . ?,FV(B) (?$,1''(B . ?,FW(B) (?$,1'((B . ?,FX(B) (?$,1')(B . ?,FY(B) (?$,1'*(B . ?,FZ(B) + (?$,1'+(B . ?,F[(B) (?$,1',(B . ?,F\(B) (?$,1'-(B . ?,F](B) (?$,1'.(B . ?,F^(B) (?$,1'/(B . ?,F_(B) + (?$,1'0(B . ?,F`(B) (?$,1'1(B . ?,Fa(B) (?$,1'2(B . ?,Fb(B) (?$,1'3(B . ?,Fc(B) (?$,1'4(B . ?,Fd(B) + (?$,1'5(B . ?,Fe(B) (?$,1'6(B . ?,Ff(B) (?$,1'7(B . ?,Fg(B) (?$,1'8(B . ?,Fh(B) (?$,1'9(B . ?,Fi(B) + (?$,1':(B . ?,Fj(B) (?$,1';(B . ?,Fk(B) (?$,1'<(B . ?,Fl(B) (?$,1'=(B . ?,Fm(B) (?$,1'>(B . ?,Fn(B) + (?$,1'?(B . ?,Fo(B) (?$,1'@(B . ?,Fp(B) (?$,1'A(B . ?,Fq(B) (?$,1'B(B . ?,Fr(B) (?$,1'C(B . ?,Fs(B) + (?$,1'D(B . ?,Ft(B) (?$,1'E(B . ?,Fu(B) (?$,1'F(B . ?,Fv(B) (?$,1'G(B . ?,Fw(B) (?$,1'H(B . ?,Fx(B) + (?$,1'I(B . ?,Fy(B) (?$,1'J(B . ?,Fz(B) (?$,1'K(B . ?,F{(B) (?$,1'L(B . ?,F|(B) (?$,1'M(B . ?,F}(B) + (?$,1'N(B . ?,F~(B) + + (?$,1(!(B . ?,L!(B) (?$,1("(B . ?,L"(B) (?$,1(#(B . ?,L#(B) (?$,1($(B . ?,L$(B) + (?$,1(%(B . ?,L%(B) (?$,1(&(B . ?,L&(B) (?$,1('(B . ?,L'(B) (?$,1(((B . ?,L((B) (?$,1()(B . ?,L)(B) + (?$,1(*(B . ?,L*(B) (?$,1(+(B . ?,L+(B) (?$,1(,(B . ?,L,(B) (?$,1(.(B . ?,L.(B) (?$,1(/(B . ?,L/(B) + (?$,1(0(B . ?,L0(B) (?$,1(1(B . ?,L1(B) (?$,1(2(B . ?,L2(B) (?$,1(3(B . ?,L3(B) (?$,1(4(B . ?,L4(B) + (?$,1(5(B . ?,L5(B) (?$,1(6(B . ?,L6(B) (?$,1(7(B . ?,L7(B) (?$,1(8(B . ?,L8(B) (?$,1(9(B . ?,L9(B) + (?$,1(:(B . ?,L:(B) (?$,1(;(B . ?,L;(B) (?$,1(<(B . ?,L<(B) (?$,1(=(B . ?,L=(B) (?$,1(>(B . ?,L>(B) + (?$,1(?(B . ?,L?(B) (?$,1(@(B . ?,L@(B) (?$,1(A(B . ?,LA(B) (?$,1(B(B . ?,LB(B) (?$,1(C(B . ?,LC(B) + (?$,1(D(B . ?,LD(B) (?$,1(E(B . ?,LE(B) (?$,1(F(B . ?,LF(B) (?$,1(G(B . ?,LG(B) (?$,1(H(B . ?,LH(B) + (?$,1(I(B . ?,LI(B) (?$,1(J(B . ?,LJ(B) (?$,1(K(B . ?,LK(B) (?$,1(L(B . ?,LL(B) (?$,1(M(B . ?,LM(B) + (?$,1(N(B . ?,LN(B) (?$,1(O(B . ?,LO(B) (?$,1(P(B . ?,LP(B) (?$,1(Q(B . ?,LQ(B) (?$,1(R(B . ?,LR(B) + (?$,1(S(B . ?,LS(B) (?$,1(T(B . ?,LT(B) (?$,1(U(B . ?,LU(B) (?$,1(V(B . ?,LV(B) (?$,1(W(B . ?,LW(B) + (?$,1(X(B . ?,LX(B) (?$,1(Y(B . ?,LY(B) (?$,1(Z(B . ?,LZ(B) (?$,1([(B . ?,L[(B) (?$,1(\(B . ?,L\(B) + (?$,1(](B . ?,L](B) (?$,1(^(B . ?,L^(B) (?$,1(_(B . ?,L_(B) (?$,1(`(B . ?,L`(B) (?$,1(a(B . ?,La(B) + (?$,1(b(B . ?,Lb(B) (?$,1(c(B . ?,Lc(B) (?$,1(d(B . ?,Ld(B) (?$,1(e(B . ?,Le(B) (?$,1(f(B . ?,Lf(B) + (?$,1(g(B . ?,Lg(B) (?$,1(h(B . ?,Lh(B) (?$,1(i(B . ?,Li(B) (?$,1(j(B . ?,Lj(B) (?$,1(k(B . ?,Lk(B) + (?$,1(l(B . ?,Ll(B) (?$,1(m(B . ?,Lm(B) (?$,1(n(B . ?,Ln(B) (?$,1(o(B . ?,Lo(B) (?$,1(q(B . ?,Lq(B) + (?$,1(r(B . ?,Lr(B) (?$,1(s(B . ?,Ls(B) (?$,1(t(B . ?,Lt(B) (?$,1(u(B . ?,Lu(B) (?$,1(v(B . ?,Lv(B) + (?$,1(w(B . ?,Lw(B) (?$,1(x(B . ?,Lx(B) (?$,1(y(B . ?,Ly(B) (?$,1(z(B . ?,Lz(B) (?$,1({(B . ?,L{(B) + (?$,1(|(B . ?,L|(B) (?$,1(~(B . ?,L~(B) (?$,1((B . ?,L(B))) + +(defcustom utf-8-fragment-on-decoding nil + "Whether or not to decode some scripts in UTF-8 text into 8-bit characters. +Setting this means that the relevant Cyrillic and Greek characters are +decoded into the iso8859 charsets rather than into +mule-unicode-0100-24ff. The 8-bit characters take half as much space +in the buffer, but using them may affect how the buffer can be re-encoded +and may require a different input method to search for them, for instance. +See `unify-8859-on-decoding-mode' and `unify-8859-on-encoding-mode' +for mechanisms to make this largely transparent." + :set (lambda (s v) + (if v + (define-translation-table 'utf-8-translation-table-for-decode + utf-8-translation-table-for-decode) + (define-translation-table 'utf-8-translation-table-for-decode)) + (set-default s v)) + :version "21.4" + :type 'boolean + :group 'mule) + +(defcustom utf-8-translate-cjk nil + "Whether the `mule-utf-8' coding system should encode many CJK characters. + +Enabling this loads tables which enable the coding system to encode +characters in the charsets `korean-ksc5601', `chinese-gb2312' and +`japanese-jisx0208', and to decode the corresponding unicodes into +such characters. This works by loading the library `utf-8-subst'; see +its commentary. The tables are fairly large (about 33000 entries), so this +option is not the default." + :link '(emacs-commentary-link "utf-8-subst") + :set (lambda (s v) + (when v + (require 'utf-8-subst) + (let ((table (make-char-table 'translation-table))) + (coding-system-put 'mule-utf-8 'safe-charsets + (append (coding-system-get 'mule-utf-8 + 'safe-charsets) + '(korean-ksc5601 chinese-gb2312 + japanese-jisx0208))) + (maphash (lambda (k v) + (aset table k v)) + utf-8-subst-rev-table) + (register-char-codings 'mule-utf-8 table))) + (set-default s v)) + :version "21.4" + :type 'boolean + :group 'mule) + (define-ccl-program ccl-decode-mule-utf-8 ;; ;; charset | bytes in utf-8 | bytes in emacs @@ -90,66 +202,16 @@ ;; 1byte encoding, i.e., ascii (if (r0 < #x80) (write r0) - - ;; 2 byte encoding 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx - (if (r0 < #xe0) - ((read r1) - - (if ((r1 & #b11000000) != #b10000000) - ;; Invalid 2-byte sequence - ((if (r0 < #xa0) - (write-multibyte-character r5 r0) - (write-multibyte-character r6 r0)) - (if (r1 < #x80) - (write r1) - (if (r1 < #xa0) - (write-multibyte-character r5 r1) - (write-multibyte-character r6 r1)))) - - ((r0 &= #x1f) - (r0 <<= 6) - (r1 &= #x3f) - (r1 += r0) - ;; Now r1 holds scalar value - - ;; eight-bit-control - (if (r1 < 160) - ((write-multibyte-character r5 r1)) + (if (r0 < #xc0) ; continuation byte (invalid here) + (if (r0 < #xa0) + (write-multibyte-character r5 r0) + (write-multibyte-character r6 r0)) + ;; 2 byte encoding 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + (if (r0 < #xe0) + ((read r1) - ;; latin-iso8859-1 - (if (r1 < 256) - ((r0 = ,(charset-id 'latin-iso8859-1)) - (r1 -= 128) - (write-multibyte-character r0 r1)) - - ;; mule-unicode-0100-24ff (< 0800) - ((r0 = ,(charset-id 'mule-unicode-0100-24ff)) - (r1 -= #x0100) - (r2 = (((r1 / 96) + 32) << 7)) - (r1 %= 96) - (r1 += (r2 + 32)) - (write-multibyte-character r0 r1))))))) - - ;; 3byte encoding - ;; zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx - (if (r0 < #xf0) - ((read r1 r2) - - ;; This is set to 1 if the encoding is invalid. - (r4 = 0) - - (r3 = (r1 & #b11000000)) - (r3 |= ((r2 >> 2) & #b00110000)) - (if (r3 != #b10100000) - (r4 = 1) - ((r3 = ((r0 & #x0f) << 12)) - (r3 += ((r1 & #x3f) << 6)) - (r3 += (r2 & #x3f)) - (if (r3 < #x0800) - (r4 = 1)))) - - (if (r4 != 0) - ;; Invalid 3-byte sequence + (if ((r1 & #b11000000) != #b10000000) + ;; Invalid 2-byte sequence ((if (r0 < #xa0) (write-multibyte-character r5 r0) (write-multibyte-character r6 r0)) @@ -157,75 +219,195 @@ (write r1) (if (r1 < #xa0) (write-multibyte-character r5 r1) - (write-multibyte-character r6 r1))) - (if (r2 < #x80) - (write r2) - (if (r2 < #xa0) - (write-multibyte-character r5 r2) - (write-multibyte-character r6 r2)))) + (write-multibyte-character r6 r1)))) + + ((r3 = r0) ; save in case of overlong sequence + (r2 = r1) + (r0 &= #x1f) + (r0 <<= 6) + (r2 = r1) ; save in case of overlong sequence + (r1 &= #x3f) + (r1 += r0) + ;; Now r1 holds scalar value + + (if (r1 < 128) ; `overlong sequence' + ((if (r3 < #xa0) + (write-multibyte-character r5 r3) + (write-multibyte-character r6 r3)) + (if (r2 < #x80) + (write r2) + (if (r2 < #xa0) + (write-multibyte-character r5 r2) + (write-multibyte-character r6 r2)))) + + ;; eight-bit-control + (if (r1 < 160) + ((write-multibyte-character r5 r1)) + + ;; latin-iso8859-1 + (if (r1 < 256) + ((r0 = ,(charset-id 'latin-iso8859-1)) + (r1 -= 128) + (write-multibyte-character r0 r1)) + + ;; mule-unicode-0100-24ff (< 0800) + ((r0 = ,(charset-id 'mule-unicode-0100-24ff)) + (r1 -= #x0100) + (r2 = (((r1 / 96) + 32) << 7)) + (r1 %= 96) + (r1 += (r2 + 32)) + (translate-character + utf-8-translation-table-for-decode r0 r1) + (write-multibyte-character r0 r1)))))))) + + ;; 3byte encoding + ;; zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + (if (r0 < #xf0) + ((read r1 r2) + + ;; This is set to 1 if the encoding is invalid. + (r4 = 0) + + (r3 = (r1 & #b11000000)) + (r3 |= ((r2 >> 2) & #b00110000)) + (if (r3 != #b10100000) + (r4 = 1) + ((r3 = ((r0 & #x0f) << 12)) + (r3 += ((r1 & #x3f) << 6)) + (r3 += (r2 & #x3f)) + (if (r3 < #x0800) + (r4 = 1)))) + + (if (r4 != 0) + ;; Invalid 3-byte sequence + ((if (r0 < #xa0) + (write-multibyte-character r5 r0) + (write-multibyte-character r6 r0)) + (if (r1 < #x80) + (write r1) + (if (r1 < #xa0) + (write-multibyte-character r5 r1) + (write-multibyte-character r6 r1))) + (if (r2 < #x80) + (write r2) + (if (r2 < #xa0) + (write-multibyte-character r5 r2) + (write-multibyte-character r6 r2)))) - ;; mule-unicode-0100-24ff (>= 0800) - ((if (r3 < #x2500) - ((r0 = ,(charset-id 'mule-unicode-0100-24ff)) - (r3 -= #x0100) - (r3 //= 96) - (r1 = (r7 + 32)) - (r1 += ((r3 + 32) << 7)) - (write-multibyte-character r0 r1)) - - ;; mule-unicode-2500-33ff - (if (r3 < #x3400) - ((r0 = ,(charset-id 'mule-unicode-2500-33ff)) - (r3 -= #x2500) + ;; mule-unicode-0100-24ff (>= 0800) + ((if (r3 < #x2500) + ((r0 = ,(charset-id 'mule-unicode-0100-24ff)) + (r3 -= #x0100) (r3 //= 96) (r1 = (r7 + 32)) (r1 += ((r3 + 32) << 7)) + (translate-character + utf-8-translation-table-for-decode r0 r1) (write-multibyte-character r0 r1)) - - ;; U+3400 .. U+DFFF - ;; keep those bytes as eight-bit-{control|graphic} - (if (r3 < #xe000) - ( ;; #xe0 <= r0 < #xf0, so r0 is eight-bit-graphic - (r3 = r6) - (write-multibyte-character r3 r0) - (if (r1 < #xa0) - (r3 = r5)) - (write-multibyte-character r3 r1) - (if (r2 < #xa0) - (r3 = r5) - (r3 = r6)) - (write-multibyte-character r3 r2)) + + ;; mule-unicode-2500-33ff + ;; Fixme: Perhaps allow translation via + ;; utf-8-subst-table for #x2e80 up, so that we use + ;; consistent charsets for all of CJK. Would need + ;; corresponding change to encoding tables. + (if (r3 < #x3400) + ((r0 = ,(charset-id 'mule-unicode-2500-33ff)) + (r3 -= #x2500) + (r3 //= 96) + (r1 = (r7 + 32)) + (r1 += ((r3 + 32) << 7)) + (write-multibyte-character r0 r1)) + + ;; U+3400 .. U+D7FF + ;; Try to convert to CJK chars, else keep + ;; them as eight-bit-{control|graphic}. + (if (r3 < #xd800) + ((r4 = r3) ; don't zap r3 + (lookup-integer utf-8-subst-table r4 r5) + (if r7 + ;; got a translation + ((write-multibyte-character r4 r5) + ;; Zapped through register starvation. + (r5 = ,(charset-id 'eight-bit-control))) + ;; #xe0 <= r0 < #xf0, so r0 is eight-bit-graphic + ((r3 = r6) + (write-multibyte-character r3 r0) + (if (r1 < #xa0) + (r3 = r5)) + (write-multibyte-character r3 r1) + (if (r2 < #xa0) + (r3 = r5) + (r3 = r6)) + (write-multibyte-character r3 r2)))) + + ;; Surrogates, U+D800 .. U+DFFF + ;; Fixme: process them properly. + (if (r3 < #xe000) + ((r3 = r6) + (write-multibyte-character r3 r0) ; eight-bit-graphic + (if (r1 < #xa0) + (r3 = r5)) + (write-multibyte-character r3 r1) + (if (r2 < #xa0) + (r3 = r5) + (r3 = r6)) + (write-multibyte-character r3 r2)) - ;; mule-unicode-e000-ffff - ((r0 = ,(charset-id 'mule-unicode-e000-ffff)) - (r3 -= #xe000) - (r3 //= 96) - (r1 = (r7 + 32)) - (r1 += ((r3 + 32) << 7)) - (write-multibyte-character r0 r1)))))))) + ;; mule-unicode-e000-ffff + ;; Fixme: fffe and ffff are invalid. + ((r0 = ,(charset-id 'mule-unicode-e000-ffff)) + (r3 -= #xe000) + (r3 //= 96) + (r1 = (r7 + 32)) + (r1 += ((r3 + 32) << 7)) + (write-multibyte-character r0 r1))))))))) - ;; 4byte encoding - ;; keep those bytes as eight-bit-{control|graphic} - ((read r1 r2 r3) - ;; r0 > #xf0, thus eight-bit-graphic - (write-multibyte-character r6 r0) - (if (r1 < #xa0) - (write-multibyte-character r5 r1) - (write-multibyte-character r6 r1)) - (if (r2 < #xa0) - (write-multibyte-character r5 r2) - (write-multibyte-character r6 r2)) - (if (r3 < #xa0) - (write-multibyte-character r5 r3) - (write-multibyte-character r6 r3)))))) - + (if (r0 < #xfe) + ;; 4byte encoding + ;; keep those bytes as eight-bit-{control|graphic} + ;; Fixme: allow lookup in utf-8-subst-table. + ((read r1 r2 r3) + ;; r0 > #xf0, thus eight-bit-graphic + (write-multibyte-character r6 r0) + (if (r1 < #xa0) + (if (r1 < #x80) ; invalid byte + (write r1) + (write-multibyte-character r5 r1)) + (write-multibyte-character r6 r1)) + (if (r2 < #xa0) + (if (r2 < #x80) ; invalid byte + (write r2) + (write-multibyte-character r5 r2)) + (write-multibyte-character r6 r2)) + (if (r3 < #xa0) + (if (r3 < #x80) ; invalid byte + (write r3) + (write-multibyte-character r5 r3)) + (write-multibyte-character r6 r3)) + (if (r0 >= #xf8) ; 5- or 6-byte encoding + ((read r1) + (if (r1 < #xa0) + (if (r1 < #x80) ; invalid byte + (write r1) + (write-multibyte-character r5 r1)) + (write-multibyte-character r6 r1)) + (if (r0 >= #xfc) ; 6-byte + ((read r1) + (if (r1 < #xa0) + (if (r1 < #x80) ; invalid byte + (write r1) + (write-multibyte-character r5 r1)) + (write-multibyte-character r6 r1))))))) + ;; else invalid byte >= #xfe + (write-multibyte-character r6 r0)))))) (repeat)))) "CCL program to decode UTF-8. Basic decoding is done into the charsets ascii, latin-iso8859-1 and -mule-unicode-*. Encodings of un-representable Unicode characters are -decoded asis into eight-bit-control and eight-bit-graphic -characters.") +mule-unicode-*, but see also `utf-8-translation-table-for-decode' and +`utf-8-subst-table'. +Encodings of un-representable Unicode characters are decoded asis into +eight-bit-control and eight-bit-graphic characters.") (define-ccl-program ccl-encode-mule-utf-8 `(1 @@ -288,7 +470,7 @@ (if (r0 == ,(charset-id 'mule-unicode-e000-ffff)) ((r0 = ((((r1 & #x3f80) >> 7) - 32) * 96)) (r1 &= #x7f) - (r1 += (r0 + 57312)) ; 57312 == -160 + #xe000 + (r1 += (r0 + 57312)) ; 57312 == -32 + #xe000 (r0 = (((r1 & #xf000) >> 12) | #xe0)) (r2 = ((r1 & #x3f) | #x80)) (r1 &= #x0fc0) @@ -329,11 +511,19 @@ ((write #xc2) (write r1))))))) - ;; Unsupported character. - ;; Output U+FFFD, which is `ef bf bd' in UTF-8. - ((write #xef) - (write #xbf) - (write #xbd))))))))) + ((lookup-character utf-8-subst-rev-table r0 r1) + (if r7 ; lookup succeeded + ((r1 = (((r0 & #xf000) >> 12) | #xe0)) + (r2 = ((r0 & #x3f) | #x80)) + (r0 &= #x0fc0) + (r0 >>= 6) + (r0 |= #x80) + (write r1 r0 r2)) + ;; Unsupported character. + ;; Output U+FFFD, which is `ef bf bd' in UTF-8. + ((write #xef) + (write #xbf) + (write #xbd))))))))))) (repeat))) (if (r1 >= #xa0) (write r1) @@ -341,69 +531,89 @@ ((write #xc2) (write r1))))) - "CCL program to encode into UTF-8. -Only characters from the charsets ascii, eight-bit-control, -eight-bit-graphic, latin-iso8859-1 and mule-unicode-* are recognized. -Others are encoded as U+FFFD.") + "CCL program to encode into UTF-8.") ;; Dummy definition so that the CCL can be checked correctly; the ;; actual data are loaded on demand. (unless (boundp 'ucs-mule-8859-to-mule-unicode) ; don't zap it (define-translation-table 'ucs-mule-8859-to-mule-unicode)) +(define-ccl-program ccl-untranslated-to-ucs + `(0 + (if (r0 < #xf0) ; 3-byte encoding, as above + ((r4 = 0) + (r3 = (r1 & #b11000000)) + (r3 |= ((r2 >> 2) & #b00110000)) + (if (r3 != #b10100000) + (r4 = 1) + ((r3 = ((r0 & #x0f) << 12)) + (r3 += ((r1 & #x3f) << 6)) + (r3 += (r2 & #x3f)) + (if (r3 < #x0800) + (r4 = 1)))) + (if (r4 != 0) + (r0 = 0) + (r0 = r3))) + (if (r0 < #xf8) ; 4-byte (Mule-UCS recipe) + ((r4 = (r1 >> 6)) + (if (r4 != #b10) + (r0 = 0) + ((r4 = (r2 >> 6)) + (if (r4 != #b10) + (r0 = 0) + ((r4 = (r3 >> 6)) + (if (r4 != #b10) + (r0 = 0) + ((r1 = ((r1 & #x3F) << 12)) + (r2 = ((r2 & #x3F) << 6)) + (r3 &= #x3F) + (r0 = (((((r0 & #x07) << 18) | r1) | r2) | r3))))))))) + (r0 = 0)))) + "Decode 3- or 4-byte sequences in r0, r1, r2 [,r3] to unicodes in r0. +r0 == 0 for invalid sequence.") + +(defvar utf-8-ccl-regs (make-vector 8 0)) + (defsubst utf-8-untranslated-to-ucs () - (let ((b1 (char-after)) - (b2 (char-after (1+ (point)))) - (b3 (char-after (+ 2 (point)))) - (b4 (char-after (+ 4 (point))))) - (if (and b1 b2 b3) - (cond ((< b1 ?\xf0) - (setq b2 (lsh (logand b2 ?\x3f) 6)) - (setq b3 (logand b3 ?\x3f)) - (logior b3 (logior b2 (lsh (logand b1 ?\x0f) 12)))) - (b4 - (setq b2 (lsh (logand b2 ?\x3f) 12)) - (setq b3 (lsh (logand b3 ?\x3f) 6)) - (setq b4 (logand b4 ?\x3f)) - (logior b4 (logior b3 (logior b2 (lsh (logand b1 ?\x07) - 18))))))))) + "Return the UCS code for an untranslated sequence of raw bytes t point. +Only for 3- or 4-byte sequences." + (aset utf-8-ccl-regs 0 (or (char-after) 0)) + (aset utf-8-ccl-regs 1 (or (char-after (1+ (point))) 0)) + (aset utf-8-ccl-regs 2 (or (char-after (+ 2 (point))) 0)) + (aset utf-8-ccl-regs 3 (or (char-after (+ 3 (point))) 0)) + (ccl-execute 'ccl-untranslated-to-ucs utf-8-ccl-regs) + (aref utf-8-ccl-regs 0)) (defun utf-8-help-echo (window object position) (format "Untranslated Unicode U+%04X" (get-char-property position 'untranslated-utf-8 object))) -(defvar utf-8-subst-table nil - "If non-nil, a hash table mapping `untranslatable utf-8' to Emacs characters.") - ;; We compose the untranslatable sequences into a single character. ;; This is infelicitous for editing, because there's currently no ;; mechanism for treating compositions as atomic, but is OK for -;; display. We try to compose an appropriate character from a hash -;; table of CJK characters to display correctly. Otherwise we use -;; U+FFFD. What we really should have is hash table lookup from CCL -;; so that we could do this properly. This function GCs too much. +;; display. They are composed to U+FFFD with help-echo which +;; indicates the unicodes they represent. This function GCs too much. (defsubst utf-8-compose () "Put a suitable composition on an untranslatable sequence. Return the sequence's length." (let* ((u (utf-8-untranslated-to-ucs)) - (l (and u (if (>= u ?\x10000) + (l (unless (zerop u) + (if (>= u #x10000) 4 - 3))) - (subst (and utf-8-subst-table (gethash u utf-8-subst-table)))) - (when u + 3)))) + (when l (put-text-property (point) (min (point-max) (+ l (point))) 'untranslated-utf-8 u) - (unless subst - (put-text-property (point) (min (point-max) (+ l (point))) - 'help-echo 'utf-8-help-echo) - (setq subst ?$,3u=(B)) - (compose-region (point) (+ l (point)) subst) + (put-text-property (point) (min (point-max) (+ l (point))) + 'help-echo 'utf-8-help-echo) + (compose-region (point) (+ l (point)) ?$,3u=(B) l))) (defcustom utf-8-compose-scripts nil - "*Non-nil means compose various scipts on decoding utf-8 text." + "*Non-nil means compose various scripts on decoding utf-8 text." :group 'mule - :type 'boolean) ; omitted in Emacs 21.1 + :version "21.4" + :type 'boolean) (defun utf-8-post-read-conversion (length) "Compose untranslated utf-8 sequences into single characters. @@ -412,38 +622,39 @@ ;; Can't do eval-when-compile to insert a multibyte constant ;; version of the string in the loop, since it's always loaded as ;; unibyte from a byte-compiled file. - (let ((range (string-as-multibyte "^\341-\377"))) - (while (and (skip-chars-forward - range) + (let ((range (string-as-multibyte "^\xe1-\xf7"))) + (while (and (skip-chars-forward range) (not (eobp))) (forward-char (utf-8-compose))))) - ;; Fixme: Takahashi-san implies it may not work this easily -- needs - ;; checking with him. + ;; Fixme: Takahashi-san implies it may not work this easily. I + ;; asked why but didn't get a reply. -- fx (when (and utf-8-compose-scripts (> length 1)) ;; These currently have definitions which cover the relevant - ;; Unicodes. We could avoid loading thai-util &c by checking + ;; unicodes. We could avoid loading thai-util &c by checking ;; whether the region contains any characters with the appropriate ;; categories. There aren't yet Unicode-based rules for Tibetan. (save-excursion (setq length (diacritic-post-read-conversion length))) (save-excursion (setq length (thai-post-read-conversion length))) (save-excursion (setq length (lao-post-read-conversion length))) - (save-excursion (setq length (devanagari-post-read-conversion length)))) + (save-excursion + (setq length (in-is13194-devanagari-post-read-conversion length)))) length) -(defun utf-8-pre-write-conversion (beg end) - "Semi-dummy pre-write function effectively to autoload ucs-tables." - ;; Ensure translation table is loaded. - (require 'ucs-tables) - ;; Don't do this again. - (coding-system-put 'mule-utf-8 'pre-write-conversion nil) - nil) +;; ucs-tables is preloaded +;; (defun utf-8-pre-write-conversion (beg end) +;; "Semi-dummy pre-write function effectively to autoload ucs-tables." +;; ;; Ensure translation table is loaded. +;; (require 'ucs-tables) +;; ;; Don't do this again. +;; (coding-system-put 'mule-utf-8 'pre-write-conversion nil) +;; nil) (make-coding-system 'mule-utf-8 4 ?u "UTF-8 encoding for Emacs-supported Unicode characters. -The supported Emacs character sets are the following, plus others -which may be included in the translation table -`ucs-mule-to-mule-unicode': +The supported Emacs character sets are the following, plus any other +characters included in the tables `ucs-mule-to-mule-unicode' and +`utf-8-subst-rev-table': ascii eight-bit-control eight-bit-graphic @@ -462,10 +673,12 @@ mule-unicode-e000-ffff Unicode characters out of the ranges U+0000-U+33FF and U+E200-U+FFFF -are decoded into sequences of eight-bit-control and eight-bit-graphic -characters to preserve their byte sequences and composed to display as -a single character. Emacs characters that can't be encoded to these -ranges are encoded as U+FFFD." +may be decoded into korean-ksc5601, chinese-gb2312, japanese-jisx0208 +\(see user option `utf-8-translate-cjk'); otherwise, sequences of +eight-bit-control and eight-bit-graphic characters are used to +preserve their byte sequences, and these are composed to display as a +single character. Emacs characters that otherwise can't be encoded +are encoded as U+FFFD." '(ccl-decode-mule-utf-8 . ccl-encode-mule-utf-8) '((safe-charsets @@ -497,7 +710,7 @@ (mime-charset . utf-8) (coding-category . coding-category-utf-8) (valid-codes (0 . 255)) - (pre-write-conversion . utf-8-pre-write-conversion) +;; (pre-write-conversion . utf-8-pre-write-conversion) (post-read-conversion . utf-8-post-read-conversion))) (define-coding-system-alias 'utf-8 'mule-utf-8)