- Don't require `alist'.
[chise/xemacs-chise.git-] / lisp / utf-2000 / char-db-util.el
1 ;;; char-db-util.el --- Character Database utility -*- coding: utf-8-er; -*-
2
3 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4 ;;   2007, 2008, 2009, 2010 MORIOKA Tomohiko.
5
6 ;; Author: MORIOKA Tomohiko <tomo@kanji.zinbun.kyoto-u.ac.jp>
7 ;; Keywords: CHISE, Character Database, ISO/IEC 10646, UCS, Unicode, MULE.
8
9 ;; This file is part of XEmacs CHISE.
10
11 ;; XEmacs CHISE is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or (at
14 ;; your option) any later version.
15
16 ;; XEmacs CHISE is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 ;; General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with XEmacs CHISE; see the file COPYING.  If not, write to
23 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25
26 ;;; Code:
27
28 (require 'chise-subr)
29 (require 'ideograph-subr)
30
31 (defconst unidata-normative-category-alist
32   '(("Lu" letter        uppercase)
33     ("Ll" letter        lowercase)
34     ("Lt" letter        titlecase)
35     ("Mn" mark          non-spacing)
36     ("Mc" mark          spacing-combining)
37     ("Me" mark          enclosing)
38     ("Nd" number        decimal-digit)
39     ("Nl" number        letter)
40     ("No" number        other)
41     ("Zs" separator     space)
42     ("Zl" separator     line)
43     ("Zp" separator     paragraph)
44     ("Cc" other         control)
45     ("Cf" other         format)
46     ("Cs" other         surrogate)
47     ("Co" other         private-use)
48     ("Cn" other         not-assigned)))
49
50 (defconst unidata-informative-category-alist
51   '(("Lm" letter        modifier)
52     ("Lo" letter        other)
53     ("Pc" punctuation   connector)
54     ("Pd" punctuation   dash)
55     ("Ps" punctuation   open)
56     ("Pe" punctuation   close)
57     ("Pi" punctuation   initial-quote)
58     ("Pf" punctuation   final-quote)
59     ("Po" punctuation   other)
60     ("Sm" symbol        math)
61     ("Sc" symbol        currency)
62     ("Sk" symbol        modifier)
63     ("So" symbol        other)
64     ))
65
66 (defconst shuowen-radicals
67   [?一 ?上 ?示 ?三 ?王 ?玉 ?玨 ?气 ?士 ?丨 ; 010
68    ?屮 ?艸 ?蓐 ?茻 ?小 ?八 ?釆 ?半 ?牛 ?犛 ; 020
69    ?告 ?口 ?凵 ?吅 ?哭 ?走 ?止 ?癶 ?步 ?此 ; 030
70    ?正 ?是 ?辵 ?彳 ?廴 ?㢟 ?行 ?齒 ?牙 ?足 ; 040
71    ?疋 ?品 ?龠 ?冊 ?㗊 ?舌 ?干 ?谷 ?只 ?㕯 ; 050
72    ?句 ?丩 ?古 ?十 ?卅 ?言 ?誩 ?音 ?䇂 ?丵 ; 060
73    ?菐 ?𠬞 ?廾 ?共 ?異 ?舁 ?𦥑 ?䢅 ?爨 ?革 ; 070
74    ?鬲 ?䰜 ?爪 ?𠃨 ?鬥 ?又 ?𠂇 ?㕜 ?支 ?𦘒 ; 080
75    ?聿 ?畫 ?隶 ?臤 ?臣 ?殳 ?殺 ?𠘧 ?寸 ?皮 ; 090
76    ?㼱 ?攴 ?敎 ?卜 ?用 ?爻 ?㸚 ?𥄎 ?目 ?䀠 ; 100
77    ?眉 ?盾 ?自 ?白 ?鼻 ?皕 ?習 ?羽 ?隹 ?奞 ; 110
78    ?萑 ?𦫳 ?苜 ?羊 ?羴 ?瞿 ?雔 ?雥 ?鳥 ?烏 ; 120
79    ?𠦒 ?冓 ?幺 ?𢆶 ?叀 ?玄 ?予 ?放 ?𠬪 ?𣦼 ; 130
80    ?歺 ?死 ?冎 ?骨 ?肉 ?筋 ?刀 ?刃 ?㓞 ?丰 ; 140
81    ?耒 ?𧢲 ?竹 ?箕 ?丌 ?左 ?工 ?㠭 ?巫 ?甘 ; 150
82    ?曰 ?乃 ?丂 ?可 ?兮 ?号 ?亏 ?旨 ?喜 ?壴 ; 160
83    ?鼓 ?豈 ?豆 ?豊 ?豐 ?䖒 ?虍 ?虎 ?虤 ?皿 ; 170
84    ?𠙴 ?去 ?血 ?丶 ?丹 ?青 ?井 ?皀 ?鬯 ?食 ; 180
85    ?亼 ?會 ?倉 ?入 ?缶 ?矢 ?高 ?冂 ?𩫏 ?京 ; 190
86    ?亯 ?𣆪 ?畗 ?㐭 ?嗇 ?來 ?麥 ?夊 ?舛 ?䑞 ; 200
87    ?韋 ?弟 ?夂 ?久 ?桀 ?木 ?東 ?林 ?才 ?叒 ; 210
88    ?之 ?帀 ?出 ?𣎵 ?生 ?乇 ?𠂹 ?𠌶 ?華 ?𥝌 ; 220
89    ?稽 ?巢 ?桼 ?束 ?㯻 ?囗 ?員 ?貝 ?邑 ?𨛜 ; 230
90    ?日 ?旦 ?倝 ?㫃 ?冥 ?晶 ?月 ?有 ?明 ?囧 ; 240
91    ?夕 ?多 ?毌 ?𢎘 ?𣐺 ?卣 ?齊 ?朿 ?片 ?鼎 ; 250
92    ?克 ?彔 ?禾 ?秝 ?黍 ?香 ?米 ?毇 ?臼 ?凶 ; 260
93    ?𣎳 ?林 ?麻 ?尗 ?耑 ?韭 ?瓜 ?瓠 ?宀 ?宮 ; 270
94    ?呂 ?穴 ?㝱 ?𤕫 ?冖 ?𠔼 ?冃 ?㒳 ?网 ?襾 ; 280
95    ?巾 ?巿 ?帛 ?白 ?㡀 ?黹 ?人 ?𠤎 ?匕 ?从 ; 290
96    ])
97
98 (defun shuowen-radical (number)
99   (aref shuowen-radicals (1- number)))
100
101 (defvar char-db-file-coding-system 'utf-8-mcs-er)
102
103 (defvar char-db-feature-domains
104   '(ucs ucs/compat daikanwa cns gt jis jis/alt jis/a jis/b
105         jis-x0212 jis-x0213 cdp shinjigen misc unknown))
106
107 (defvar char-db-ignored-attributes '(ideographic-products))
108
109 (defvar char-db-coded-charset-priority-list
110   '(ascii
111     control-1
112     latin-iso8859-1
113     latin-iso8859-2
114     latin-iso8859-3
115     latin-iso8859-4
116     latin-iso8859-9
117     latin-jisx0201
118     cyrillic-iso8859-5
119     greek-iso8859-7
120     thai-tis620
121     =jis-x0208
122     =jis-x0208@1978
123     =jis-x0208@1983
124     japanese-jisx0212
125     chinese-gb2312
126     =jis-x0208@1990
127     chinese-cns11643-1
128     chinese-cns11643-2
129     chinese-cns11643-3
130     chinese-cns11643-4
131     chinese-cns11643-5
132     chinese-cns11643-6
133     chinese-cns11643-7
134     =jis-x0213-1
135     =jis-x0213-1@2000
136     =jis-x0213-1@2004
137     =jis-x0213-2
138     korean-ksc5601
139     chinese-isoir165
140     katakana-jisx0201
141     hebrew-iso8859-8
142     chinese-gb12345
143     latin-viscii
144     ethiopic-ucs
145     =big5-cdp
146     =gt
147     =>>gt
148     =>gt
149     ideograph-daikanwa-2
150     ideograph-daikanwa
151     =cbeta
152     ideograph-hanziku-1
153     ideograph-hanziku-2
154     ideograph-hanziku-3
155     ideograph-hanziku-4
156     ideograph-hanziku-5
157     ideograph-hanziku-6
158     ideograph-hanziku-7
159     ideograph-hanziku-8
160     ideograph-hanziku-9
161     ideograph-hanziku-10
162     ideograph-hanziku-11
163     ideograph-hanziku-12
164     =gt-k
165     =ucs@iso
166     =ucs@unicode
167     =>>ucs@unicode
168     =>>jis-x0208
169     =>>jis-x0213-1
170     =>>jis-x0213-1@2000
171     =>>jis-x0213-1@2004
172     =>>jis-x0213-2
173     =>>jis-x0208@1978
174     =>jis-x0208
175     =>jis-x0208@1997
176     =>jis-x0213-1
177     =>jis-x0213-1@2000
178     =>jis-x0213-1@2004
179     =>jis-x0213-2
180     =big5
181     =big5-eten
182     =zinbun-oracle
183     =>zinbun-oracle
184     =ruimoku-v6
185     =jef-china3
186     =shinjigen))
187
188
189 ;;; @ char-db formatters
190 ;;;
191
192 (defun char-db-make-char-spec (char)
193   (let (ret char-spec)
194     (cond ((characterp char)
195            (cond ((and (setq ret (encode-char char '=ucs 'defined-only))
196                        (not (and (<= #xE000 ret)(<= ret #xF8FF))))
197                   (setq char-spec (list (cons '=ucs ret)))
198                   (cond ((setq ret (get-char-attribute char 'name))
199                          (setq char-spec (cons (cons 'name ret) char-spec))
200                          )
201                         ((setq ret (get-char-attribute char 'name*))
202                          (setq char-spec (cons (cons 'name* ret) char-spec))
203                          ))
204                   )
205                  ((setq ret
206                         (catch 'tag
207                           (let ((rest char-db-coded-charset-priority-list)
208                                 ccs)
209                             (while rest
210                               (setq ccs (charset-name
211                                          (find-charset (car rest))))
212                               (if (setq ret
213                                         (encode-char char ccs
214                                                      'defined-only))
215                                   (throw 'tag (cons ccs ret)))
216                               (setq rest (cdr rest))))))
217                   (setq char-spec (list ret))
218                   (dolist (ccs (delq (car ret) (charset-list)))
219                     (if (and (or (charset-iso-final-char ccs)
220                                  (memq ccs
221                                        '(=daikanwa
222                                          =daikanwa@rev2
223                                          ;; =gt-k
224                                          =jis-x0208@1997
225                                          ))
226                                  (string-match "=ucs@" (symbol-name ccs)))
227                              (setq ccs (charset-name ccs))
228                              (null (assq ccs char-spec))
229                              (setq ret (encode-char char ccs 'defined-only)))
230                         (setq char-spec (cons (cons ccs ret) char-spec))))
231                   (if (null char-spec)
232                       (setq char-spec (split-char char)))
233                   (cond ((setq ret (get-char-attribute char 'name))
234                          (setq char-spec (cons (cons 'name ret) char-spec))
235                          )
236                         ((setq ret (get-char-attribute char 'name*))
237                          (setq char-spec (cons (cons 'name* ret) char-spec))
238                          ))
239                   )
240                  ((setq ret (get-char-attribute
241                              char 'ideographic-combination))
242                   (setq char-spec
243                         (cons (cons 'ideographic-combination ret)
244                               char-spec))
245                   ))
246            char-spec)
247           ((consp char)
248            char))))
249     
250 (defun char-db-insert-char-spec (char &optional readable column
251                                       required-features)
252   (unless column
253     (setq column (current-column)))
254   (let (char-spec temp-char)
255     (setq char-spec (char-db-make-char-spec char))
256     (unless (or (characterp char) ; char
257                 (condition-case nil
258                     (setq char (find-char char-spec))
259                   (error nil)))
260       ;; define temporary character
261       ;;   Current implementation is dirty.
262       (setq temp-char (define-char (cons '(ideograph-daikanwa . 0)
263                                          char-spec)))
264       (remove-char-attribute temp-char 'ideograph-daikanwa)
265       (setq char temp-char))
266     (insert-char-attributes char
267                             readable
268                             (union (mapcar #'car char-spec)
269                                    required-features))
270     (when temp-char
271       ;; undefine temporary character
272       ;;   Current implementation is dirty.
273       (setq char-spec (char-attribute-alist temp-char))
274       (while char-spec
275         (remove-char-attribute temp-char (car (car char-spec)))
276         (setq char-spec (cdr char-spec))))))
277
278 (defun char-db-insert-alist (alist &optional readable column)
279   (unless column
280     (setq column (current-column)))
281   (let ((line-breaking
282          (concat "\n" (make-string (1+ column) ?\ )))
283         name value
284         ret al ; cal
285         key
286         lbs cell rest separator)
287     (insert "(")
288     (while alist
289       (setq name (car (car alist))
290             value (cdr (car alist)))
291       (cond ((eq name 'char)
292              (insert "(char . ")
293              (if (setq ret (condition-case nil
294                                (find-char value)
295                              (error nil)))
296                  (progn
297                    (setq al nil
298                          ;; cal nil
299                          )
300                    (while value
301                      (setq key (car (car value)))
302                      ;; (if (find-charset key)
303                      ;;     (setq cal (cons key cal))
304                      (setq al (cons key al))
305                      ;; )
306                      (setq value (cdr value)))
307                    (insert-char-attributes ret
308                                            readable
309                                            (or al 'none) ; cal
310                                            ))
311                (insert (prin1-to-string value)))
312              (insert ")")
313              (insert line-breaking))
314             ((consp value)
315              (insert (format "(%-18s " name))
316              (setq lbs (concat "\n" (make-string (current-column) ?\ )))
317              (while (consp value)
318                (setq cell (car value))
319                (if (and (consp cell)
320                         (consp (car cell))
321                         (setq ret (condition-case nil
322                                       (find-char cell)
323                                     (error nil)))
324                         )
325                    (progn
326                      (setq rest cell
327                            al nil
328                            ;; cal nil
329                            )
330                      (while rest
331                        (setq key (car (car rest)))
332                        ;; (if (find-charset key)
333                        ;;     (setq cal (cons key cal))
334                        (setq al (cons key al))
335                        ;; )
336                        (setq rest (cdr rest)))
337                      (if separator
338                          (insert lbs))
339                      (insert-char-attributes ret
340                                              readable
341                                              al ; cal
342                                              )
343                      (setq separator lbs))
344                  (if separator
345                      (insert separator))
346                  (insert (prin1-to-string cell))
347                  (setq separator " "))
348                (setq value (cdr value)))
349              (insert ")")
350              (insert line-breaking))
351             (t
352              (insert (format "(%-18s . %S)%s"
353                              name value
354                              line-breaking))))
355       (setq alist (cdr alist))))
356   (insert ")"))
357
358 (defun char-db-insert-char-reference (plist &optional readable column)
359   (unless column
360     (setq column (current-column)))
361   (let ((line-breaking
362          (concat "\n" (make-string (1+ column) ?\ )))
363         (separator "")
364         name value)
365     (insert "(")
366     (while plist
367       (setq name (pop plist))
368       (setq value (pop plist))
369       (cond ((eq name :char)
370              (insert separator)
371              (insert ":char\t")
372              (cond ((numberp value)
373                     (setq value (decode-char '=ucs value)))
374                    ;; ((consp value)
375                    ;;  (setq value (or (find-char value)
376                    ;;                  value)))
377                    )
378              (char-db-insert-char-spec value readable)
379              (insert line-breaking)
380              (setq separator ""))
381             ((eq name :radical)
382              (insert (format "%s%s\t%d ; %c%s"
383                              separator
384                              name value
385                              (ideographic-radical value)
386                              line-breaking))
387              (setq separator ""))
388             (t
389              (insert (format "%s%s\t%S" separator name value))
390              (setq separator line-breaking)))
391       ))
392   (insert ")"))
393
394 (defun char-db-decode-isolated-char (ccs code-point)
395   (let (ret)
396     (setq ret
397           (cond ((eq ccs 'arabic-iso8859-6)
398                  (decode-char ccs code-point))
399                 ((and (memq ccs '(=gt-pj-1
400                                   =gt-pj-2
401                                   =gt-pj-3
402                                   =gt-pj-4
403                                   =gt-pj-5
404                                   =gt-pj-6
405                                   =gt-pj-7
406                                   =gt-pj-8
407                                   =gt-pj-9
408                                   =gt-pj-10
409                                   =gt-pj-11))
410                       (setq ret (decode-char ccs code-point))
411                       (setq ret (encode-char ret '=gt 'defined-only)))
412                  (decode-builtin-char '=gt ret))
413                 (t
414                  (decode-builtin-char ccs code-point))))
415     (cond ((and (<= 0 (char-int ret))
416                 (<= (char-int ret) #x1F))
417            (decode-char '=ucs (+ #x2400 (char-int ret))))
418           ((= (char-int ret) #x7F)
419            ?\u2421)
420           (t ret))))
421
422 (defvar char-db-convert-obsolete-format t)
423
424 (defun char-db-insert-ccs-feature (name value line-breaking)
425   (insert
426    (format
427     (cond ((memq name '(=shinjigen
428                         =shinjigen@1ed
429                         =shinjigen@rev =shinjigen/+p@rev))
430            "(%-18s .  %04d)\t; %c")
431           ((eq name '=shinjigen@1ed/24pr)
432            "(%-18s . %04d)\t; %c")
433           ((or (memq name '(=daikanwa
434                             =daikanwa@rev1 =daikanwa@rev2
435                             =gt =>>gt =>gt =gt-k =cbeta
436                             =zinbun-oracle =>zinbun-oracle))
437                (string-match "^=adobe-" (symbol-name name)))
438            "(%-18s . %05d)\t; %c")
439           ((eq name 'mojikyo)
440            "(%-18s . %06d)\t; %c")
441           ((>= (charset-dimension name) 2)
442            "(%-18s . #x%04X)\t; %c")
443           (t
444            "(%-18s . #x%02X)\t; %c"))
445     name
446     (if (= (charset-iso-graphic-plane name) 1)
447         (logior value
448                 (cond ((= (charset-dimension name) 1)
449                        #x80)
450                       ((= (charset-dimension name) 2)
451                        #x8080)
452                       ((= (charset-dimension name) 3)
453                        #x808080)
454                       (t 0)))
455       value)
456     (char-db-decode-isolated-char name value)))
457   (if (and (= (charset-chars name) 94)
458            (= (charset-dimension name) 2))
459       (insert (format " [%02d-%02d]"
460                       (- (lsh value -8) 32)
461                       (- (logand value 255) 32))))
462   (insert line-breaking))
463
464 (defun char-db-insert-relation-feature (char name value line-breaking
465                                              ccss readable)
466   (insert (format "(%-18s%s " name line-breaking))
467   (let ((lbs (concat "\n" (make-string (current-column) ?\ )))
468         separator cell sources required-features
469         ret)
470     (while (consp value)
471       (setq cell (car value))
472       (if (integerp cell)
473           (setq cell (decode-char '=ucs cell)))
474       (cond
475        ((eq name '->subsumptive)
476         (when (or (not (some (lambda (atr)
477                                (get-char-attribute cell atr))
478                              char-db-ignored-attributes))
479                   (some (lambda (ccs)
480                           (encode-char cell ccs 'defined-only))
481                         ccss))
482           (if separator
483               (insert lbs))
484           (let ((char-db-ignored-attributes
485                  (cons '<-subsumptive
486                        char-db-ignored-attributes)))
487             (insert-char-attributes cell readable))
488           (setq separator lbs))
489         )
490        ((characterp cell)
491         (setq sources
492               (get-char-attribute
493                char (intern (format "%s*sources" name))))
494         (setq required-features nil)
495         (dolist (source sources)
496           (cond
497            ((memq source '(JP
498                            JP/Jouyou
499                            shinjigen shinjigen@1ed shinjigen@rev))
500             (setq required-features
501                   (union required-features
502                          '(=jis-x0208
503                            =jis-x0208@1990
504                            =jis-x0213-1-2000
505                            =jis-x0213-2-2000
506                            =jis-x0212
507                            =jis-x0208@1983
508                            =jis-x0208@1978
509                            =shinjigen))))
510            ((eq source 'CN)
511             (setq required-features
512                   (union required-features
513                          '(=gb2312
514                            =gb12345
515                            =iso-ir165)))))
516           (cond
517            ((find-charset (setq ret (intern (format "=%s" source))))
518             (setq required-features
519                   (cons ret required-features)))
520            (t (setq required-features
521                     (cons source required-features)))))
522         (cond ((string-match "@JP" (symbol-name name))
523                (setq required-features
524                      (union required-features
525                             '(=jis-x0208
526                               =jis-x0208@1990
527                               =jis-x0213-1-2000
528                               =jis-x0213-2-2000
529                               =jis-x0212
530                               =jis-x0208@1983
531                               =jis-x0208@1978))))
532               ((string-match "@CN" (symbol-name name))
533                (setq required-features
534                      (union required-features
535                             '(=gb2312
536                               =gb12345
537                               =iso-ir165)))))
538         (if separator
539             (insert lbs))
540         (if readable
541             (insert (format "%S" cell))
542           (char-db-insert-char-spec cell readable
543                                     nil
544                                     required-features))
545         (setq separator lbs))
546        ((consp cell)
547         (if separator
548             (insert lbs))
549         (if (consp (car cell))
550             (char-db-insert-char-spec cell readable)
551           (char-db-insert-char-reference cell readable))
552         (setq separator lbs))
553        (t
554         (if separator
555             (insert separator))
556         (insert (prin1-to-string cell))
557         (setq separator " ")))
558       (setq value (cdr value)))
559     (insert ")")
560     (insert line-breaking)))
561
562 (defun insert-char-attributes (char &optional readable attributes column)
563   (unless column
564     (setq column (current-column)))
565   (let (name value ; has-long-ccs-name
566         rest
567         radical strokes
568         (line-breaking
569          (concat "\n" (make-string (1+ column) ?\ )))
570         lbs cell separator ret
571         key al cal
572         dest-ccss ; sources required-features
573         ccss)
574     (let (atr-d)
575       (setq attributes
576             (sort (if attributes
577                       (if (consp attributes)
578                           (progn
579                             (dolist (name attributes)
580                               (unless (memq name char-db-ignored-attributes)
581                                 (if (find-charset name)
582                                     (push name ccss))
583                                 (push name atr-d)))
584                             atr-d))
585                     (dolist (name (char-attribute-list))
586                       (unless (memq name char-db-ignored-attributes)
587                         (if (find-charset name)
588                             (push name ccss))
589                         (push name atr-d)))
590                     atr-d)
591                   #'char-attribute-name<)))
592     (insert "(")
593     (when (memq '<-subsumptive attributes)
594       (when readable
595         (when (setq value (get-char-attribute char '<-subsumptive))
596           (char-db-insert-relation-feature char '<-subsumptive value
597                                            line-breaking
598                                            ccss readable)))
599       (setq attributes (delq '<-subsumptive attributes)))
600     (when (and (memq '<-denotational attributes)
601                (setq value (get-char-attribute char '<-denotational)))
602       (char-db-insert-relation-feature char '<-denotational value
603                                        line-breaking
604                                        ccss readable)
605       (setq attributes (delq '<-denotational attributes)))
606     (when (and (memq 'name attributes)
607                (setq value (get-char-attribute char 'name)))
608       (insert (format
609                (if (> (+ (current-column) (length value)) 48)
610                    "(name . %S)%s"
611                  "(name               . %S)%s")
612                value line-breaking))
613       (setq attributes (delq 'name attributes))
614       )
615     (when (and (memq 'name* attributes)
616                (setq value (get-char-attribute char 'name*)))
617       (insert (format
618                (if (> (+ (current-column) (length value)) 48)
619                    "(name* . %S)%s"
620                  "(name*              . %S)%s")
621                value line-breaking))
622       (setq attributes (delq 'name* attributes))
623       )
624     (when (and (memq 'script attributes)
625                (setq value (get-char-attribute char 'script)))
626       (insert (format "(script\t\t%s)%s"
627                       (mapconcat (function prin1-to-string)
628                                  value " ")
629                       line-breaking))
630       (setq attributes (delq 'script attributes))
631       )
632     (dolist (name '(=>ucs =>ucs*))
633       (when (and (memq name attributes)
634                  (setq value (get-char-attribute char name)))
635         (insert (format "(%-18s . #x%04X)\t; %c%s"
636                         name value (decode-char '=ucs value)
637                         line-breaking))
638         (setq attributes (delq name attributes))))
639     (dolist (name '(=>ucs@gb =>ucs@cns =>ucs@jis =>ucs@ks =>ucs@big5))
640       (when (and (memq name attributes)
641                  (setq value (get-char-attribute char name)))
642         (insert (format "(%-18s . #x%04X)\t; %c%s"
643                         name value
644                         (decode-char (intern
645                                       (concat "="
646                                               (substring
647                                                (symbol-name name) 2)))
648                                      value)
649                         line-breaking))
650         (setq attributes (delq name attributes))
651         ))
652     (dolist (name '(=>daikanwa))
653       (when (and (memq name attributes)
654                  (setq value (get-char-attribute char name)))
655         (insert
656          (if (integerp value)
657              (format "(%-18s . %05d)\t; %c%s"
658                      name value (decode-char '=daikanwa value)
659                      line-breaking)
660            (format "(%-18s %s)\t; %c%s"
661                    name
662                    (mapconcat (function prin1-to-string)
663                               value " ")
664                    (char-representative-of-daikanwa char)
665                    line-breaking)))
666         (setq attributes (delq name attributes))))
667     (when (and (memq 'general-category attributes)
668                (setq value (get-char-attribute char 'general-category)))
669       (insert (format
670                "(general-category\t%s) ; %s%s"
671                (mapconcat (lambda (cell)
672                             (format "%S" cell))
673                           value " ")
674                (cond ((rassoc value unidata-normative-category-alist)
675                       "Normative Category")
676                      ((rassoc value unidata-informative-category-alist)
677                       "Informative Category")
678                      (t
679                       "Unknown Category"))
680                line-breaking))
681       (setq attributes (delq 'general-category attributes))
682       )
683     (when (and (memq 'bidi-category attributes)
684                (setq value (get-char-attribute char 'bidi-category)))
685       (insert (format "(bidi-category\t. %S)%s"
686                       value
687                       line-breaking))
688       (setq attributes (delq 'bidi-category attributes))
689       )
690     (unless (or (not (memq 'mirrored attributes))
691                 (eq (setq value (get-char-attribute char 'mirrored 'empty))
692                     'empty))
693       (insert (format "(mirrored\t\t. %S)%s"
694                       value
695                       line-breaking))
696       (setq attributes (delq 'mirrored attributes))
697       )
698     (cond
699      ((and (memq 'decimal-digit-value attributes)
700            (setq value (get-char-attribute char 'decimal-digit-value)))
701       (insert (format "(decimal-digit-value . %S)%s"
702                       value
703                       line-breaking))
704       (setq attributes (delq 'decimal-digit-value attributes))
705       (when (and (memq 'digit-value attributes)
706                  (setq value (get-char-attribute char 'digit-value)))
707         (insert (format "(digit-value\t . %S)%s"
708                         value
709                         line-breaking))
710         (setq attributes (delq 'digit-value attributes))
711         )
712       (when (and (memq 'numeric-value attributes)
713                  (setq value (get-char-attribute char 'numeric-value)))
714         (insert (format "(numeric-value\t . %S)%s"
715                         value
716                         line-breaking))
717         (setq attributes (delq 'numeric-value attributes))
718         )
719       )
720      (t
721       (when (and (memq 'digit-value attributes)
722                  (setq value (get-char-attribute char 'digit-value)))
723         (insert (format "(digit-value\t. %S)%s"
724                         value
725                         line-breaking))
726         (setq attributes (delq 'digit-value attributes))
727         )
728       (when (and (memq 'numeric-value attributes)
729                  (setq value (get-char-attribute char 'numeric-value)))
730         (insert (format "(numeric-value\t. %S)%s"
731                         value
732                         line-breaking))
733         (setq attributes (delq 'numeric-value attributes))
734         )))
735     (when (and (memq 'iso-10646-comment attributes)
736                (setq value (get-char-attribute char 'iso-10646-comment)))
737       (insert (format "(iso-10646-comment\t. %S)%s"
738                       value
739                       line-breaking))
740       (setq attributes (delq 'iso-10646-comment attributes))
741       )
742     (when (and (memq 'morohashi-daikanwa attributes)
743                (setq value (get-char-attribute char 'morohashi-daikanwa)))
744       (insert (format "(morohashi-daikanwa\t%s)%s"
745                       (mapconcat (function prin1-to-string) value " ")
746                       line-breaking))
747       (setq attributes (delq 'morohashi-daikanwa attributes))
748       )
749     (setq radical nil
750           strokes nil)
751     (when (and (memq 'ideographic-radical attributes)
752                (setq value (get-char-attribute char 'ideographic-radical)))
753       (setq radical value)
754       (insert (format "(ideographic-radical . %S)\t; %c%s"
755                       radical
756                       (ideographic-radical radical)
757                       line-breaking))
758       (setq attributes (delq 'ideographic-radical attributes))
759       )
760     (when (and (memq 'shuowen-radical attributes)
761                (setq value (get-char-attribute char 'shuowen-radical)))
762       (insert (format "(shuowen-radical\t. %S)\t; %c%s"
763                       value
764                       (shuowen-radical value)
765                       line-breaking))
766       (setq attributes (delq 'shuowen-radical attributes))
767       )
768     (let (key)
769       (dolist (domain
770                (append
771                 char-db-feature-domains
772                 (let (dest domain)
773                   (dolist (feature (char-attribute-list))
774                     (setq feature (symbol-name feature))
775                     (when (string-match
776                            "\\(radical\\|strokes\\)@\\([^@*]+\\)\\(\\*\\|$\\)"
777                            feature)
778                       (setq domain (intern (match-string 2 feature)))
779                      (unless (memq domain dest)
780                        (setq dest (cons domain dest)))))
781                   (sort dest #'string<))))
782         (setq key (intern (format "%s@%s" 'ideographic-radical domain)))
783         (when (and (memq key attributes)
784                    (setq value (get-char-attribute char key)))
785           (setq radical value)
786           (insert (format "(%s . %S)\t; %c%s"
787                           key
788                           radical
789                           (ideographic-radical radical)
790                           line-breaking))
791           (setq attributes (delq key attributes))
792           )
793         (setq key (intern (format "%s@%s" 'ideographic-strokes domain)))
794         (when (and (memq key attributes)
795                    (setq value (get-char-attribute char key)))
796           (setq strokes value)
797           (insert (format "(%s . %S)%s"
798                           key
799                           strokes
800                           line-breaking))
801           (setq attributes (delq key attributes))
802           )
803         (setq key (intern (format "%s@%s" 'total-strokes domain)))
804         (when (and (memq key attributes)
805                    (setq value (get-char-attribute char key)))
806           (insert (format "(%s       . %S)%s"
807                           key
808                           value
809                           line-breaking))
810           (setq attributes (delq key attributes))
811           )
812         (dolist (feature '(ideographic-radical
813                            ideographic-strokes
814                            total-strokes))
815           (setq key (intern (format "%s@%s*sources" feature domain)))
816           (when (and (memq key attributes)
817                      (setq value (get-char-attribute char key)))
818             (insert (format "(%s%s" key line-breaking))
819             (dolist (cell value)
820               (insert (format " %s" cell)))
821             (insert ")")
822             (insert line-breaking)
823             (setq attributes (delq key attributes))
824             ))
825         ))
826     (when (and (memq 'ideographic-strokes attributes)
827                (setq value (get-char-attribute char 'ideographic-strokes)))
828       (setq strokes value)
829       (insert (format "(ideographic-strokes . %S)%s"
830                       strokes
831                       line-breaking))
832       (setq attributes (delq 'ideographic-strokes attributes))
833       )
834     (when (and (memq 'kangxi-radical attributes)
835                (setq value (get-char-attribute char 'kangxi-radical)))
836       (unless (eq value radical)
837         (insert (format "(kangxi-radical\t . %S)\t; %c%s"
838                         value
839                         (ideographic-radical value)
840                         line-breaking))
841         (or radical
842             (setq radical value)))
843       (setq attributes (delq 'kangxi-radical attributes))
844       )
845     (when (and (memq 'kangxi-strokes attributes)
846                (setq value (get-char-attribute char 'kangxi-strokes)))
847       (unless (eq value strokes)
848         (insert (format "(kangxi-strokes\t . %S)%s"
849                         value
850                         line-breaking))
851         (or strokes
852             (setq strokes value)))
853       (setq attributes (delq 'kangxi-strokes attributes))
854       )
855     (when (and (memq 'japanese-radical attributes)
856                (setq value (get-char-attribute char 'japanese-radical)))
857       (unless (eq value radical)
858         (insert (format "(japanese-radical\t . %S)\t; %c%s"
859                         value
860                         (ideographic-radical value)
861                         line-breaking))
862         (or radical
863             (setq radical value)))
864       (setq attributes (delq 'japanese-radical attributes))
865       )
866     (when (and (memq 'japanese-strokes attributes)
867                (setq value (get-char-attribute char 'japanese-strokes)))
868       (unless (eq value strokes)
869         (insert (format "(japanese-strokes\t . %S)%s"
870                         value
871                         line-breaking))
872         (or strokes
873             (setq strokes value)))
874       (setq attributes (delq 'japanese-strokes attributes))
875       )
876     (when (and (memq 'cns-radical attributes)
877                (setq value (get-char-attribute char 'cns-radical)))
878       (insert (format "(cns-radical\t . %S)\t; %c%s"
879                       value
880                       (ideographic-radical value)
881                       line-breaking))
882       (setq attributes (delq 'cns-radical attributes))
883       )
884     (when (and (memq 'cns-strokes attributes)
885                (setq value (get-char-attribute char 'cns-strokes)))
886       (unless (eq value strokes)
887         (insert (format "(cns-strokes\t . %S)%s"
888                         value
889                         line-breaking))
890         (or strokes
891             (setq strokes value)))
892       (setq attributes (delq 'cns-strokes attributes))
893       )
894     (when (and (memq 'shinjigen-1-radical attributes)
895                (setq value (get-char-attribute char 'shinjigen-1-radical)))
896       (unless (eq value radical)
897         (insert (format "(shinjigen-1-radical . %S)\t; %c%s"
898                         value
899                         (ideographic-radical value)
900                         line-breaking))
901         (or radical
902             (setq radical value)))
903       (setq attributes (delq 'shinjigen-1-radical attributes))
904       )
905     (when (and (memq 'ideographic- attributes)
906                (setq value (get-char-attribute char 'ideographic-)))
907       (insert "(ideographic-       ")
908       (setq lbs (concat "\n" (make-string (current-column) ?\ ))
909             separator nil)
910       (while (consp value)
911         (setq cell (car value))
912         (if (integerp cell)
913             (setq cell (decode-char '=ucs cell)))
914         (cond ((characterp cell)
915                (if separator
916                    (insert lbs))
917                (if readable
918                    (insert (format "%S" cell))
919                  (char-db-insert-char-spec cell readable))
920                (setq separator lbs))
921               ((consp cell)
922                (if separator
923                    (insert lbs))
924                (if (consp (car cell))
925                    (char-db-insert-char-spec cell readable)
926                  (char-db-insert-char-reference cell readable))
927                (setq separator lbs))
928               (t
929                (if separator
930                    (insert separator))
931                (insert (prin1-to-string cell))
932                (setq separator " ")))
933         (setq value (cdr value)))
934       (insert ")")
935       (insert line-breaking)
936       (setq attributes (delq 'ideographic- attributes)))
937     (when (and (memq 'total-strokes attributes)
938                (setq value (get-char-attribute char 'total-strokes)))
939       (insert (format "(total-strokes       . %S)%s"
940                       value
941                       line-breaking))
942       (setq attributes (delq 'total-strokes attributes))
943       )
944     (when (and (memq '->ideograph attributes)
945                (setq value (get-char-attribute char '->ideograph)))
946       (insert (format "(->ideograph\t%s)%s"
947                       (mapconcat (lambda (code)
948                                    (cond ((symbolp code)
949                                           (symbol-name code))
950                                          ((integerp code)
951                                           (format "#x%04X" code))
952                                          (t
953                                           (format "%s %S"
954                                                   line-breaking code))))
955                                  value " ")
956                       line-breaking))
957       (setq attributes (delq '->ideograph attributes))
958       )
959     ;; (when (and (memq '->decomposition attributes)
960     ;;            (setq value (get-char-attribute char '->decomposition)))
961     ;;   (insert (format "(->decomposition\t%s)%s"
962     ;;                   (mapconcat (lambda (code)
963     ;;                                (cond ((symbolp code)
964     ;;                                       (symbol-name code))
965     ;;                                      ((characterp code)
966     ;;                                       (if readable
967     ;;                                           (format "%S" code)
968     ;;                                         (format "#x%04X"
969     ;;                                                 (char-int code))
970     ;;                                         ))
971     ;;                                      ((integerp code)
972     ;;                                       (format "#x%04X" code))
973     ;;                                      (t
974     ;;                                       (format "%s%S" line-breaking code))))
975     ;;                              value " ")
976     ;;                   line-breaking))
977     ;;   (setq attributes (delq '->decomposition attributes))
978     ;;   )
979     (if (equal (get-char-attribute char '->titlecase)
980                (get-char-attribute char '->uppercase))
981         (setq attributes (delq '->titlecase attributes)))
982     (when (and (memq '->mojikyo attributes)
983                (setq value (get-char-attribute char '->mojikyo)))
984       (insert (format "(->mojikyo\t\t. %06d)\t; %c%s"
985                       value (decode-char 'mojikyo value)
986                       line-breaking))
987       (setq attributes (delq '->mojikyo attributes))
988       )
989     (when (and (memq 'hanyu-dazidian-vol attributes)
990                (setq value (get-char-attribute char 'hanyu-dazidian-vol)))
991       (insert (format "(hanyu-dazidian-vol  . %d)%s"
992                       value line-breaking))
993       (setq attributes (delq 'hanyu-dazidian-vol attributes))
994       )
995     (when (and (memq 'hanyu-dazidian-page attributes)
996                (setq value (get-char-attribute char 'hanyu-dazidian-page)))
997       (insert (format "(hanyu-dazidian-page . %d)%s"
998                       value line-breaking))
999       (setq attributes (delq 'hanyu-dazidian-page attributes))
1000       )
1001     (when (and (memq 'hanyu-dazidian-char attributes)
1002                (setq value (get-char-attribute char 'hanyu-dazidian-char)))
1003       (insert (format "(hanyu-dazidian-char . %d)%s"
1004                       value line-breaking))
1005       (setq attributes (delq 'hanyu-dazidian-char attributes))
1006       )
1007     (unless readable
1008       (dolist (ignored '(composition
1009                          ->denotational <-subsumptive ->ucs-unified
1010                          ->ideographic-component-forms))
1011         (setq attributes (delq ignored attributes))))
1012     (while attributes
1013       (setq name (car attributes))
1014       (if (setq value (get-char-attribute char name))
1015           (cond ((setq ret (find-charset name))
1016                  (setq name (charset-name ret))
1017                  (if (and (not (memq name dest-ccss))
1018                           (prog1
1019                               (setq value (get-char-attribute char name))
1020                             (setq dest-ccss (cons name dest-ccss))))
1021                      (char-db-insert-ccs-feature name value line-breaking))
1022                  )
1023                 ((string-match "^=>ucs@" (symbol-name name))
1024                  (insert (format "(%-18s . #x%04X)\t; %c%s"
1025                                  name value (decode-char '=ucs value)
1026                                  line-breaking))
1027                  )
1028                 ((eq name 'jisx0208-1978/4X)
1029                  (insert (format "(%-18s . #x%04X)%s"
1030                                  name value
1031                                  line-breaking))
1032                  )
1033                 ((and
1034                   (not readable)
1035                   (not (eq name '->subsumptive))
1036                   (not (eq name '->uppercase))
1037                   (not (eq name '->lowercase))
1038                   (not (eq name '->titlecase))
1039                   (not (eq name '->canonical))
1040                   (not (eq name '->Bopomofo))
1041                   (not (eq name '->mistakable))
1042                   (not (eq name '->ideographic-variants))
1043                   (null (get-char-attribute
1044                          char (intern (format "%s*sources" name))))
1045                   (not (string-match "\\*sources$" (symbol-name name)))
1046                   (null (get-char-attribute
1047                          char (intern (format "%s*note" name))))
1048                   (not (string-match "\\*note$" (symbol-name name)))
1049                   (or (eq name '<-identical)
1050                       (eq name '<-uppercase)
1051                       (eq name '<-lowercase)
1052                       (eq name '<-titlecase)
1053                       (eq name '<-canonical)
1054                       (eq name '<-ideographic-variants)
1055                       ;; (eq name '<-synonyms)
1056                       (string-match "^<-synonyms" (symbol-name name))
1057                       (eq name '<-mistakable)
1058                       (when (string-match "^->" (symbol-name name))
1059                         (cond
1060                          ((string-match "^->fullwidth" (symbol-name name))
1061                           (not (and (consp value)
1062                                     (characterp (car value))
1063                                     (encode-char
1064                                      (car value) '=ucs 'defined-only)))
1065                           )
1066                          (t)))
1067                       ))
1068                  )
1069                 ((or (eq name 'ideographic-structure)
1070                      (eq name 'ideographic-combination)
1071                      (eq name 'ideographic-)
1072                      (eq name '=decomposition)
1073                      (string-match "^=>decomposition" (symbol-name name))
1074                      (string-match "^\\(->\\|<-\\)[^*]*$" (symbol-name name))
1075                      (string-match "^\\(->\\|<-\\)[^*]*\\*sources$"
1076                                    (symbol-name name))
1077                      )
1078                  (char-db-insert-relation-feature char name value
1079                                                   line-breaking
1080                                                   ccss readable))
1081                 ((memq name '(ideograph=
1082                               original-ideograph-of
1083                               ancient-ideograph-of
1084                               vulgar-ideograph-of
1085                               wrong-ideograph-of
1086                               ;; simplified-ideograph-of
1087                               ideographic-variants
1088                               ;; ideographic-different-form-of
1089                               ))
1090                  (insert (format "(%-18s%s " name line-breaking))
1091                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
1092                        separator nil)
1093                  (while (consp value)
1094                    (setq cell (car value))
1095                    (if (and (consp cell)
1096                             (consp (car cell)))
1097                        (progn
1098                          (if separator
1099                              (insert lbs))
1100                          (char-db-insert-alist cell readable)
1101                          (setq separator lbs))
1102                      (if separator
1103                          (insert separator))
1104                      (insert (prin1-to-string cell))
1105                      (setq separator " "))
1106                    (setq value (cdr value)))
1107                  (insert ")")
1108                  (insert line-breaking))
1109                 ((consp value)
1110                  (insert (format "(%-18s " name))
1111                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
1112                        separator nil)
1113                  (while (consp value)
1114                    (setq cell (car value))
1115                    (if (and (consp cell)
1116                             (consp (car cell))
1117                             (setq ret (condition-case nil
1118                                           (find-char cell)
1119                                         (error nil))))
1120                        (progn
1121                          (setq rest cell
1122                                al nil
1123                                cal nil)
1124                          (while rest
1125                            (setq key (car (car rest)))
1126                            (if (find-charset key)
1127                                (setq cal (cons key cal))
1128                              (setq al (cons key al)))
1129                            (setq rest (cdr rest)))
1130                          (if separator
1131                              (insert lbs))
1132                          (insert-char-attributes ret
1133                                                  readable
1134                                                  al cal)
1135                          (setq separator lbs))
1136                      (setq ret (prin1-to-string cell))
1137                      (if separator
1138                          (if (< (+ (current-column)
1139                                    (length ret)
1140                                    (length separator))
1141                                 76)
1142                              (insert separator)
1143                            (insert lbs)))
1144                      (insert ret)
1145                      (setq separator " "))
1146                    (setq value (cdr value)))
1147                  (insert ")")
1148                  (insert line-breaking))
1149                 (t
1150                  (insert (format "(%-18s" name))
1151                  (setq ret (prin1-to-string value))
1152                  (unless (< (+ (current-column)
1153                                (length ret)
1154                                3)
1155                             76)
1156                    (insert line-breaking))
1157                  (insert " . " ret ")" line-breaking)
1158                  ;; (insert (format "(%-18s . %S)%s"
1159                  ;;                 name value
1160                  ;;                 line-breaking))
1161                  )
1162                 ))
1163       (setq attributes (cdr attributes)))
1164     (insert ")")))
1165
1166 (defun insert-char-data (char &optional readable
1167                               attributes)
1168   (save-restriction
1169     (narrow-to-region (point)(point))
1170     (insert "(define-char
1171   '")
1172     (insert-char-attributes char readable attributes)
1173     (insert ")\n")
1174     (goto-char (point-min))
1175     (while (re-search-forward "[ \t]+$" nil t)
1176       (replace-match ""))
1177     ;; from tabify.
1178     (goto-char (point-min))
1179     (while (re-search-forward "[ \t][ \t][ \t]*" nil t)
1180       (let ((column (current-column))
1181             (indent-tabs-mode t))
1182         (delete-region (match-beginning 0) (point))
1183         (indent-to column)))
1184     (goto-char (point-max))
1185     ;; (tabify (point-min)(point-max))
1186     ))
1187
1188 (defun insert-char-data-with-variant (char &optional printable
1189                                            no-ucs-unified
1190                                            script excluded-script)
1191   (insert-char-data char printable)
1192   (let ((variants (char-variants char))
1193         rest
1194         variant vs ret)
1195     (setq variants (sort variants #'<))
1196     (setq rest variants)
1197     (setq variants (cons char variants))
1198     (while rest
1199       (setq variant (car rest))
1200       (unless (get-char-attribute variant '<-subsumptive)
1201         (if (and (or (null script)
1202                      (null (setq vs (get-char-attribute variant 'script)))
1203                      (memq script vs))
1204                  (or (null excluded-script)
1205                      (null (setq vs (get-char-attribute variant 'script)))
1206                      (not (memq excluded-script vs))))
1207             (unless (and no-ucs-unified (get-char-attribute variant '=ucs))
1208               (insert-char-data variant printable)
1209               (if (setq ret (char-variants variant))
1210                   (while ret
1211                     (or (memq (car ret) variants)
1212                         ;; (get-char-attribute (car ret) '<-subsumptive)
1213                         (setq rest (nconc rest (list (car ret)))))
1214                     (setq ret (cdr ret)))))))
1215       (setq rest (cdr rest)))))
1216
1217 (defun insert-char-range-data (min max &optional script excluded-script)
1218   (let ((code min)
1219         char)
1220     (while (<= code max)
1221       (setq char (decode-char '=ucs code))
1222       (if (encode-char char '=ucs 'defined-only)
1223           (insert-char-data-with-variant char nil 'no-ucs-unified
1224                                          script excluded-script))
1225       (setq code (1+ code)))))
1226
1227 (defun write-char-range-data-to-file (min max file
1228                                           &optional script excluded-script)
1229   (let ((coding-system-for-write char-db-file-coding-system))
1230     (with-temp-buffer
1231       (insert (format ";; -*- coding: %s -*-\n"
1232                       char-db-file-coding-system))
1233       (insert-char-range-data min max script excluded-script)
1234       (write-region (point-min)(point-max) file))))
1235
1236 (defvar what-character-original-window-configuration)
1237
1238 ;;;###autoload
1239 (defun what-char-definition (char)
1240   (interactive (list (char-after)))
1241   (let ((buf (get-buffer-create "*Character Description*"))
1242         (the-buf (current-buffer))
1243         (win-conf (current-window-configuration)))
1244     (pop-to-buffer buf)
1245     (make-local-variable 'what-character-original-window-configuration)
1246     (setq what-character-original-window-configuration win-conf)
1247     (setq buffer-read-only nil)
1248     (erase-buffer)
1249     (condition-case err
1250         (progn
1251           (insert-char-data-with-variant char 'printable)
1252           (unless (char-attribute-alist char)
1253             (insert (format ";; = %c\n"
1254                             (let* ((rest (split-char char))
1255                                    (ccs (pop rest))
1256                                    (code (pop rest)))
1257                               (while rest
1258                                 (setq code (logior (lsh code 8)
1259                                                    (pop rest))))
1260                               (decode-char ccs code)))))
1261           ;; (char-db-update-comment)
1262           (set-buffer-modified-p nil)
1263           (view-mode the-buf (lambda (buf)
1264                                (set-window-configuration
1265                                 what-character-original-window-configuration)
1266                                ))
1267           (goto-char (point-min)))
1268       (error (progn
1269                (set-window-configuration
1270                 what-character-original-window-configuration)
1271                (signal (car err) (cdr err)))))))
1272
1273
1274 ;;; @ end
1275 ;;;
1276
1277 (provide 'char-db-util)
1278
1279 ;;; char-db-util.el ends here