Sync up with r21-4-11-chise-0_21-pre8.
[chise/xemacs-chise.git] / lisp / utf-2000 / char-db-util.el
1 ;;; char-db-util.el --- Character Database utility
2
3 ;; Copyright (C) 1998,1999,2000,2001,2002,2003 MORIOKA Tomohiko.
4
5 ;; Author: MORIOKA Tomohiko <tomo@kanji.zinbun.kyoto-u.ac.jp>
6 ;; Keywords: UTF-2000, ISO/IEC 10646, Unicode, UCS-4, MULE.
7
8 ;; This file is part of XEmacs UTF-2000.
9
10 ;; XEmacs UTF-2000 is free software; you can redistribute it and/or
11 ;; modify it under the terms of the GNU General Public License as
12 ;; published by the Free Software Foundation; either version 2, or (at
13 ;; your option) any later version.
14
15 ;; XEmacs UTF-2000 is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 ;; General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with XEmacs UTF-2000; see the file COPYING.  If not, write to
22 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Code:
26
27 (require 'alist)
28
29 (defconst unidata-normative-category-alist
30   '(("Lu" letter        uppercase)
31     ("Ll" letter        lowercase)
32     ("Lt" letter        titlecase)
33     ("Mn" mark          non-spacing)
34     ("Mc" mark          spacing-combining)
35     ("Me" mark          enclosing)
36     ("Nd" number        decimal-digit)
37     ("Nl" number        letter)
38     ("No" number        other)
39     ("Zs" separator     space)
40     ("Zl" separator     line)
41     ("Zp" separator     paragraph)
42     ("Cc" other         control)
43     ("Cf" other         format)
44     ("Cs" other         surrogate)
45     ("Co" other         private-use)
46     ("Cn" other         not-assigned)))
47
48 (defconst unidata-informative-category-alist
49   '(("Lm" letter        modifier)
50     ("Lo" letter        other)
51     ("Pc" punctuation   connector)
52     ("Pd" punctuation   dash)
53     ("Ps" punctuation   open)
54     ("Pe" punctuation   close)
55     ("Pi" punctuation   initial-quote)
56     ("Pf" punctuation   final-quote)
57     ("Po" punctuation   other)
58     ("Sm" symbol        math)
59     ("Sc" symbol        currency)
60     ("Sk" symbol        modifier)
61     ("So" symbol        other)
62     ))
63
64 (defconst ideographic-radicals
65   (let ((v (make-vector 215 nil))
66         (i 1))
67     (while (< i 215)
68       (aset v i (decode-char '=ucs (+ #x2EFF i)))
69       (setq i (1+ i)))
70     v))
71
72 (defvar char-db-ignored-attributes nil)
73
74 ;;;###autoload
75 (defun char-ref= (cr1 cr2)
76   (cond ((char-ref-p cr1)
77          (if (char-ref-p cr2)
78              (char-spec= (plist-get cr1 :char)
79                          (plist-get cr2 :char))
80            (char-spec= (plist-get cr1 :char) cr2)))
81         (t
82          (char-spec= cr1
83                      (if (char-ref-p cr2)
84                          (plist-get cr2 :char)
85                        cr2)))))
86
87 ;;;###autoload
88 (defun char-spec= (cs1 cs2)
89   (if (characterp cs1)
90       (if (characterp cs2)
91           (eq cs1 cs2)
92         (eq cs1 (find-char cs2)))
93     (if (characterp cs2)
94         (eq (find-char cs1) cs2)
95       (eq (find-char cs1) (find-char cs2)))))
96
97 (defun char-attribute-name< (ka kb)
98   (cond
99    ((find-charset ka)
100     (cond
101      ((find-charset kb)
102       (cond
103        ((= (charset-dimension ka)
104            (charset-dimension kb))
105         (cond ((= (charset-chars ka)(charset-chars kb))
106                (if (charset-iso-final-char ka)
107                    (cond
108                     ((>= (charset-iso-final-char ka) ?@)
109                      (if (and (charset-iso-final-char kb)
110                               (>= (charset-iso-final-char kb) ?@))
111                          (< (charset-iso-final-char ka)
112                             (charset-iso-final-char kb))
113                        t))
114                     (t
115                      (if (charset-iso-final-char kb)
116                          (if (>= (charset-iso-final-char kb) ?@)
117                              nil
118                            (< (charset-iso-final-char ka)
119                               (charset-iso-final-char kb)))
120                        t)))
121                  (if (charset-iso-final-char kb)
122                      nil
123                    (< (charset-id ka)(charset-id kb)))))
124               ((<= (charset-chars ka)(charset-chars kb)))))
125        (t
126         (< (charset-dimension ka)
127            (charset-dimension kb))
128         )))
129      ((symbolp kb)
130       nil)
131      (t
132       t)))
133    ((find-charset kb)
134     t)
135    ((symbolp ka)
136     (cond ((symbolp kb)
137            (string< (symbol-name ka)
138                     (symbol-name kb)))
139           (t)))
140    ((symbolp kb)
141     nil)))
142
143 (defvar char-db-coded-charset-priority-list
144   '(ascii
145     control-1
146     latin-iso8859-1
147     latin-iso8859-2
148     latin-iso8859-3
149     latin-iso8859-4
150     latin-iso8859-9
151     latin-jisx0201
152     cyrillic-iso8859-5
153     greek-iso8859-7
154     thai-tis620
155     =jis-x0208
156     japanese-jisx0208
157     japanese-jisx0212
158     japanese-jisx0208-1978
159     chinese-gb2312
160     =cns11643-1
161     chinese-cns11643-2
162     chinese-cns11643-3
163     chinese-cns11643-4
164     chinese-cns11643-5
165     chinese-cns11643-6
166     chinese-cns11643-7
167     =jis-x0208-1990
168     =jis-x0213-1-2000
169     =jis-x0213-2-2000
170     korean-ksc5601
171     chinese-isoir165
172     katakana-jisx0201
173     hebrew-iso8859-8
174     chinese-gb12345
175     latin-viscii
176     ethiopic-ucs
177     =gt
178     ideograph-daikanwa-2
179     ideograph-daikanwa
180     =cbeta
181     ideograph-hanziku-1
182     ideograph-hanziku-2
183     ideograph-hanziku-3
184     ideograph-hanziku-4
185     ideograph-hanziku-5
186     ideograph-hanziku-6
187     ideograph-hanziku-7
188     ideograph-hanziku-8
189     ideograph-hanziku-9
190     ideograph-hanziku-10
191     ideograph-hanziku-11
192     ideograph-hanziku-12
193     =big5
194     =big5-eten
195     =big5-cdp
196     =gt-k
197     =jef-china3))
198
199 (defun char-db-make-char-spec (char)
200   (let (ret char-spec)
201     (cond ((characterp char)
202            (cond ((and (setq ret (encode-char char '=ucs 'defined-only))
203                        (not (and (<= #xE000 ret)(<= ret #xF8FF))))
204                   (setq char-spec (list (cons '=ucs ret)))
205                   (cond ((setq ret (get-char-attribute char 'name))
206                          (setq char-spec (cons (cons 'name ret) char-spec))
207                          )
208                         ((setq ret (get-char-attribute char 'name*))
209                          (setq char-spec (cons (cons 'name* ret) char-spec))
210                          ))
211                   )
212                  ((setq ret
213                         (catch 'tag
214                           (let ((rest char-db-coded-charset-priority-list)
215                                 ccs)
216                             (while rest
217                               (setq ccs (charset-name
218                                          (find-charset (car rest))))
219                               (if (setq ret
220                                         (encode-char char ccs
221                                                      'defined-only))
222                                   (throw 'tag (cons ccs ret)))
223                               (setq rest (cdr rest))))))
224                   (setq char-spec (list ret))
225                   (dolist (ccs (delq (car ret) (charset-list)))
226                     (if (and (or (charset-iso-final-char ccs)
227                                  (memq ccs
228                                        '(ideograph-daikanwa
229                                          =daikanwa-rev2
230                                          ;; =gt-k
231                                          )))
232                              (setq ret (encode-char char ccs 'defined-only)))
233                         (setq char-spec (cons (cons ccs ret) char-spec))))
234                   (if (null char-spec)
235                       (setq char-spec (split-char char)))
236                   (cond ((setq ret (get-char-attribute char 'name))
237                          (setq char-spec (cons (cons 'name ret) char-spec))
238                          )
239                         ((setq ret (get-char-attribute char 'name*))
240                          (setq char-spec (cons (cons 'name* ret) char-spec))
241                          ))
242                   ))
243            char-spec)
244           ((consp char)
245            char))))
246     
247 (defun char-db-insert-char-spec (char &optional readable column)
248   (unless column
249     (setq column (current-column)))
250   (let (char-spec ret al cal key temp-char)
251     (setq char-spec (char-db-make-char-spec char))
252     (unless (or (characterp char) ; char
253                 (condition-case nil
254                     (setq char (find-char char-spec))
255                   (error nil)))
256       ;; define temporary character
257       ;;   Current implementation is dirty.
258       (setq temp-char (define-char (cons '(ideograph-daikanwa . 0)
259                                          char-spec)))
260       (remove-char-attribute temp-char 'ideograph-daikanwa)
261       (setq char temp-char))
262     (setq al nil
263           cal nil)
264     (while char-spec
265       (setq key (car (car char-spec)))
266       (unless (memq key char-db-ignored-attributes)
267         (if (find-charset key)
268             (if (encode-char char key 'defined-only)
269                 (setq cal (cons key cal)))
270           (setq al (cons key al))))
271       (setq char-spec (cdr char-spec)))
272     (unless cal
273       (setq char-spec (char-db-make-char-spec char))
274       (while char-spec
275         (setq key (car (car char-spec)))
276         (unless (memq key char-db-ignored-attributes)
277           (if (find-charset key)
278               (setq cal (cons key cal))
279             (setq al (cons key al))))
280         (setq char-spec (cdr char-spec)))
281       )
282     (unless (or cal
283                 (memq 'ideographic-structure al))
284       (push 'ideographic-structure al))
285     (insert-char-attributes char
286                             readable
287                             (or al 'none) cal)
288     (when temp-char
289       ;; undefine temporary character
290       ;;   Current implementation is dirty.
291       (setq char-spec (char-attribute-alist temp-char))
292       (while char-spec
293         (remove-char-attribute temp-char (car (car char-spec)))
294         (setq char-spec (cdr char-spec))))))
295
296 (defun char-db-insert-alist (alist &optional readable column)
297   (unless column
298     (setq column (current-column)))
299   (let ((line-breaking
300          (concat "\n" (make-string (1+ column) ?\ )))
301         name value
302         ret al cal key
303         lbs cell rest separator)
304     (insert "(")
305     (while alist
306       (setq name (car (car alist))
307             value (cdr (car alist)))
308       (cond ((eq name 'char)
309              (insert "(char . ")
310              (if (setq ret (condition-case nil
311                                (find-char value)
312                              (error nil)))
313                  (progn
314                    (setq al nil
315                          cal nil)
316                    (while value
317                      (setq key (car (car value)))
318                      (if (find-charset key)
319                          (setq cal (cons key cal))
320                        (setq al (cons key al)))
321                      (setq value (cdr value)))
322                    (insert-char-attributes ret
323                                            readable
324                                            (or al 'none) cal))
325                (insert (prin1-to-string value)))
326              (insert ")")
327              (insert line-breaking))
328             ((consp value)
329              (insert (format "(%-18s " name))
330              (setq lbs (concat "\n" (make-string (current-column) ?\ )))
331              (while (consp value)
332                (setq cell (car value))
333                (if (and (consp cell)
334                         (consp (car cell))
335                         (setq ret (condition-case nil
336                                       (find-char cell)
337                                     (error nil)))
338                         )
339                    (progn
340                      (setq rest cell
341                            al nil
342                            cal nil)
343                      (while rest
344                        (setq key (car (car rest)))
345                        (if (find-charset key)
346                            (setq cal (cons key cal))
347                          (setq al (cons key al)))
348                        (setq rest (cdr rest)))
349                      (if separator
350                          (insert lbs))
351                      (insert-char-attributes ret
352                                              readable
353                                              al cal)
354                      (setq separator lbs))
355                  (if separator
356                      (insert separator))
357                  (insert (prin1-to-string cell))
358                  (setq separator " "))
359                (setq value (cdr value)))
360              (insert ")")
361              (insert line-breaking))
362             (t
363              (insert (format "(%-18s . %S)%s"
364                              name value
365                              line-breaking))))
366       (setq alist (cdr alist))))
367   (insert ")"))
368
369 (defun char-db-insert-char-reference (plist &optional readable column)
370   (unless column
371     (setq column (current-column)))
372   (let ((line-breaking
373          (concat "\n" (make-string (1+ column) ?\ )))
374         (separator "")
375         name value)
376     (insert "(")
377     (while plist
378       (setq name (pop plist))
379       (setq value (pop plist))
380       (cond ((eq name :char)
381              (insert separator)
382              (insert ":char\t")
383              (cond ((numberp value)
384                     (setq value (decode-char '=ucs value)))
385                    ;; ((consp value)
386                    ;;  (setq value (or (find-char value)
387                    ;;                  value)))
388                    )
389              (char-db-insert-char-spec value readable)
390              (insert line-breaking)
391              (setq separator ""))
392             ((eq name :radical)
393              (insert (format "%s%s\t%d ; %c%s"
394                              separator
395                              name value
396                              (aref ideographic-radicals value)
397                              line-breaking))
398              (setq separator ""))
399             (t
400              (insert (format "%s%s\t%S" separator name value))
401              (setq separator line-breaking)))
402       ))
403   (insert ")"))
404
405 (defun char-db-decode-isolated-char (ccs code-point)
406   (let (ret)
407     (setq ret
408           (cond ((eq ccs 'arabic-iso8859-6)
409                  (decode-char ccs code-point))
410                 ((and (memq ccs '(=gt-pj-1
411                                   =gt-pj-2
412                                   =gt-pj-3
413                                   =gt-pj-4
414                                   =gt-pj-5
415                                   =gt-pj-6
416                                   =gt-pj-7
417                                   =gt-pj-8
418                                   =gt-pj-9
419                                   =gt-pj-10
420                                   =gt-pj-11))
421                       (setq ret (decode-char ccs code-point))
422                       (setq ret (encode-char ret '=gt 'defined-only)))
423                  (decode-builtin-char '=gt ret))
424                 (t
425                  (decode-builtin-char ccs code-point))))
426     (cond ((and (<= 0 (char-int ret))
427                 (<= (char-int ret) #x1F))
428            (decode-char '=ucs (+ #x2400 (char-int ret))))
429           ((= (char-int ret) #x7F)
430            ?\u2421)
431           (t ret))))
432
433 (defvar char-db-convert-obsolete-format t)
434
435 (defun insert-char-attributes (char &optional readable
436                                     attributes ccs-attributes
437                                     column)
438   (let (atr-d ccs-d)
439     (setq attributes
440           (sort (if attributes
441                     (if (consp attributes)
442                         (progn
443                           (dolist (name attributes)
444                             (unless (memq name char-db-ignored-attributes)
445                               (push name atr-d)))
446                           atr-d))
447                   (dolist (name (char-attribute-list))
448                     (unless (memq name char-db-ignored-attributes)
449                       (if (find-charset name)
450                           (push name ccs-d)
451                         (push name atr-d))))
452                   atr-d)
453                 #'char-attribute-name<))
454     (setq ccs-attributes
455           (sort (if ccs-attributes
456                     (progn
457                       (setq ccs-d nil)
458                       (dolist (name ccs-attributes)
459                         (unless (memq name char-db-ignored-attributes)
460                           (push name ccs-d)))
461                       ccs-d)
462                   (or ccs-d
463                       (progn
464                         (dolist (name (charset-list))
465                           (unless (memq name char-db-ignored-attributes)
466                             (push name ccs-d)))
467                         ccs-d)))
468                 #'char-attribute-name<)))
469   (unless column
470     (setq column (current-column)))
471   (let (name value has-long-ccs-name rest
472         radical strokes
473         (line-breaking
474          (concat "\n" (make-string (1+ column) ?\ )))
475         lbs cell separator ret
476         key al cal
477         dest-ccss)
478     (insert "(")
479     (when (and (memq 'name attributes)
480                (setq value (get-char-attribute char 'name)))
481       (insert (format
482                (if (> (+ (current-column) (length value)) 48)
483                    "(name . %S)%s"
484                  "(name               . %S)%s")
485                value line-breaking))
486       (setq attributes (delq 'name attributes))
487       )
488     (when (and (memq 'name* attributes)
489                (setq value (get-char-attribute char 'name*)))
490       (insert (format
491                (if (> (+ (current-column) (length value)) 48)
492                    "(name* . %S)%s"
493                  "(name*              . %S)%s")
494                value line-breaking))
495       (setq attributes (delq 'name* attributes))
496       )
497     (when (and (memq 'script attributes)
498                (setq value (get-char-attribute char 'script)))
499       (insert (format "(script\t\t%s)%s"
500                       (mapconcat (function prin1-to-string)
501                                  value " ")
502                       line-breaking))
503       (setq attributes (delq 'script attributes))
504       )
505     (dolist (name '(=>ucs =>ucs*))
506       (when (and (memq name attributes)
507                  (setq value (get-char-attribute char name)))
508         (insert (format "(%-18s . #x%04X)\t; %c%s"
509                         name value (decode-char '=ucs value)
510                         line-breaking))
511         (setq attributes (delq name attributes))))
512     (dolist (name '(=>ucs@gb =>ucs@cns =>ucs@jis =>ucs@ks =>ucs@big5))
513       (when (and (memq name attributes)
514                  (setq value (get-char-attribute char name)))
515         (insert (format "(%-18s . #x%04X)\t; %c%s"
516                         name value
517                         (decode-char (intern
518                                       (concat "="
519                                               (substring
520                                                (symbol-name name) 2)))
521                                      value)
522                         line-breaking))
523         (setq attributes (delq name attributes))
524         ))
525     (dolist (name '(=>ucs-gb =>ucs-cns =>ucs-jis =>ucs-ks =>ucs-big5))
526       (when (and (memq name attributes)
527                  (setq value (get-char-attribute char name)))
528         (insert (format "(%-18s . #x%04X)\t; %c%s"
529                         (intern
530                          (concat "=>ucs@"
531                                  (substring (symbol-name name) 6)))
532                         value
533                         (decode-char (intern
534                                       (concat "=ucs@"
535                                               (substring
536                                                (symbol-name name) 6)))
537                                      value)
538                         line-breaking))
539         (setq attributes (delq name attributes))))
540     (when (and (memq '->ucs attributes)
541                (setq value (get-char-attribute char '->ucs)))
542       (insert (format (if char-db-convert-obsolete-format
543                           "(=>ucs\t\t. #x%04X)\t; %c%s"
544                         "(->ucs\t\t. #x%04X)\t; %c%s")
545                       value (decode-char '=ucs value)
546                       line-breaking))
547       (setq attributes (delq '->ucs attributes))
548       )
549     (when (and (memq 'general-category attributes)
550                (setq value (get-char-attribute char 'general-category)))
551       (insert (format
552                "(general-category\t%s) ; %s%s"
553                (mapconcat (lambda (cell)
554                             (format "%S" cell))
555                           value " ")
556                (cond ((rassoc value unidata-normative-category-alist)
557                       "Normative Category")
558                      ((rassoc value unidata-informative-category-alist)
559                       "Informative Category")
560                      (t
561                       "Unknown Category"))
562                line-breaking))
563       (setq attributes (delq 'general-category attributes))
564       )
565     (when (and (memq 'bidi-category attributes)
566                (setq value (get-char-attribute char 'bidi-category)))
567       (insert (format "(bidi-category\t. %S)%s"
568                       value
569                       line-breaking))
570       (setq attributes (delq 'bidi-category attributes))
571       )
572     (unless (or (not (memq 'mirrored attributes))
573                 (eq (setq value (get-char-attribute char 'mirrored 'empty))
574                     'empty))
575       (insert (format "(mirrored\t\t. %S)%s"
576                       value
577                       line-breaking))
578       (setq attributes (delq 'mirrored attributes))
579       )
580     (cond
581      ((and (memq 'decimal-digit-value attributes)
582            (setq value (get-char-attribute char 'decimal-digit-value)))
583       (insert (format "(decimal-digit-value . %S)%s"
584                       value
585                       line-breaking))
586       (setq attributes (delq 'decimal-digit-value attributes))
587       (when (and (memq 'digit-value attributes)
588                  (setq value (get-char-attribute char 'digit-value)))
589         (insert (format "(digit-value\t . %S)%s"
590                         value
591                         line-breaking))
592         (setq attributes (delq 'digit-value attributes))
593         )
594       (when (and (memq 'numeric-value attributes)
595                  (setq value (get-char-attribute char 'numeric-value)))
596         (insert (format "(numeric-value\t . %S)%s"
597                         value
598                         line-breaking))
599         (setq attributes (delq 'numeric-value attributes))
600         )
601       )
602      (t
603       (when (and (memq 'digit-value attributes)
604                  (setq value (get-char-attribute char 'digit-value)))
605         (insert (format "(digit-value\t. %S)%s"
606                         value
607                         line-breaking))
608         (setq attributes (delq 'digit-value attributes))
609         )
610       (when (and (memq 'numeric-value attributes)
611                  (setq value (get-char-attribute char 'numeric-value)))
612         (insert (format "(numeric-value\t. %S)%s"
613                         value
614                         line-breaking))
615         (setq attributes (delq 'numeric-value attributes))
616         )))
617     (when (and (memq 'iso-10646-comment attributes)
618                (setq value (get-char-attribute char 'iso-10646-comment)))
619       (insert (format "(iso-10646-comment\t. %S)%s"
620                       value
621                       line-breaking))
622       (setq attributes (delq 'iso-10646-comment attributes))
623       )
624     (when (and (memq 'morohashi-daikanwa attributes)
625                (setq value (get-char-attribute char 'morohashi-daikanwa)))
626       (insert (format "(morohashi-daikanwa\t%s)%s"
627                       (mapconcat (function prin1-to-string) value " ")
628                       line-breaking))
629       (setq attributes (delq 'morohashi-daikanwa attributes))
630       )
631     (setq radical nil
632           strokes nil)
633     (let (key)
634       (dolist (domain '(ucs daikanwa cns))
635         (setq key (intern (format "%s@%s" 'ideographic-radical domain)))
636         (when (and (memq key attributes)
637                    (setq value (get-char-attribute char key)))
638           (setq radical value)
639           (insert (format "(%s . %S)\t; %c%s"
640                           key
641                           radical
642                           (aref ideographic-radicals radical)
643                           line-breaking))
644           (setq attributes (delq key attributes))
645           )
646         (setq key (intern (format "%s@%s" 'ideographic-strokes domain)))
647         (when (and (memq key attributes)
648                    (setq value (get-char-attribute char key)))
649           (setq strokes value)
650           (insert (format "(%s . %S)%s"
651                           key
652                           strokes
653                           line-breaking))
654           (setq attributes (delq key attributes))
655           )
656         (setq key (intern (format "%s@%s*sources"
657                                   'ideographic-radical domain)))
658         (when (and (memq key attributes)
659                    (setq value (get-char-attribute char key)))
660           (insert (format "(%s%s" key line-breaking))
661           (dolist (cell value)
662             (insert (format " %s" cell)))
663           (insert ")")
664           (insert line-breaking)
665           (setq attributes (delq key attributes))
666           )
667         ))
668     (when (and (memq 'ideographic-radical attributes)
669                (setq value (get-char-attribute char 'ideographic-radical)))
670       (setq radical value)
671       (insert (format "(ideographic-radical . %S)\t; %c%s"
672                       radical
673                       (aref ideographic-radicals radical)
674                       line-breaking))
675       (setq attributes (delq 'ideographic-radical attributes))
676       )
677     (when (and (memq 'ideographic-strokes attributes)
678                (setq value (get-char-attribute char 'ideographic-strokes)))
679       (setq strokes value)
680       (insert (format "(ideographic-strokes . %S)%s"
681                       strokes
682                       line-breaking))
683       (setq attributes (delq 'ideographic-strokes attributes))
684       )
685     (when (and (memq 'kangxi-radical attributes)
686                (setq value (get-char-attribute char 'kangxi-radical)))
687       (unless (eq value radical)
688         (insert (format "(kangxi-radical\t . %S)\t; %c%s"
689                         value
690                         (aref ideographic-radicals value)
691                         line-breaking))
692         (or radical
693             (setq radical value)))
694       (setq attributes (delq 'kangxi-radical attributes))
695       )
696     (when (and (memq 'kangxi-strokes attributes)
697                (setq value (get-char-attribute char 'kangxi-strokes)))
698       (unless (eq value strokes)
699         (insert (format "(kangxi-strokes\t . %S)%s"
700                         value
701                         line-breaking))
702         (or strokes
703             (setq strokes value)))
704       (setq attributes (delq 'kangxi-strokes attributes))
705       )
706     (when (and (memq 'japanese-radical attributes)
707                (setq value (get-char-attribute char 'japanese-radical)))
708       (unless (eq value radical)
709         (insert (format "(japanese-radical\t . %S)\t; %c%s"
710                         value
711                         (aref ideographic-radicals value)
712                         line-breaking))
713         (or radical
714             (setq radical value)))
715       (setq attributes (delq 'japanese-radical attributes))
716       )
717     (when (and (memq 'japanese-strokes attributes)
718                (setq value (get-char-attribute char 'japanese-strokes)))
719       (unless (eq value strokes)
720         (insert (format "(japanese-strokes\t . %S)%s"
721                         value
722                         line-breaking))
723         (or strokes
724             (setq strokes value)))
725       (setq attributes (delq 'japanese-strokes attributes))
726       )
727     (when (and (memq 'cns-radical attributes)
728                (setq value (get-char-attribute char 'cns-radical)))
729       (insert (format "(cns-radical\t . %S)\t; %c%s"
730                       value
731                       (aref ideographic-radicals value)
732                       line-breaking))
733       (setq attributes (delq 'cns-radical attributes))
734       )
735     (when (and (memq 'cns-strokes attributes)
736                (setq value (get-char-attribute char 'cns-strokes)))
737       (unless (eq value strokes)
738         (insert (format "(cns-strokes\t . %S)%s"
739                         value
740                         line-breaking))
741         (or strokes
742             (setq strokes value)))
743       (setq attributes (delq 'cns-strokes attributes))
744       )
745     (when (and (memq 'shinjigen-1-radical attributes)
746                (setq value (get-char-attribute char 'shinjigen-1-radical)))
747       (unless (eq value radical)
748         (insert (format "(shinjigen-1-radical . %S)\t; %c%s"
749                         value
750                         (aref ideographic-radicals value)
751                         line-breaking))
752         (or radical
753             (setq radical value)))
754       (setq attributes (delq 'shinjigen-1-radical attributes))
755       )
756     (when (and (memq 'ideographic- attributes)
757                (setq value (get-char-attribute char 'ideographic-)))
758       (insert "(ideographic-       ")
759       (setq lbs (concat "\n" (make-string (current-column) ?\ ))
760             separator nil)
761       (while (consp value)
762         (setq cell (car value))
763         (if (integerp cell)
764             (setq cell (decode-char '=ucs cell)))
765         (cond ((characterp cell)
766                (if separator
767                    (insert lbs))
768                (if readable
769                    (insert (format "%S" cell))
770                  (char-db-insert-char-spec cell readable))
771                (setq separator lbs))
772               ((consp cell)
773                (if separator
774                    (insert lbs))
775                (if (consp (car cell))
776                    (char-db-insert-char-spec cell readable)
777                  (char-db-insert-char-reference cell readable))
778                (setq separator lbs))
779               (t
780                (if separator
781                    (insert separator))
782                (insert (prin1-to-string cell))
783                (setq separator " ")))
784         (setq value (cdr value)))
785       (insert ")")
786       (insert line-breaking)
787       (setq attributes (delq 'ideographic- attributes)))
788     (when (and (memq 'total-strokes attributes)
789                (setq value (get-char-attribute char 'total-strokes)))
790       (insert (format "(total-strokes       . %S)%s"
791                       value
792                       line-breaking))
793       (setq attributes (delq 'total-strokes attributes))
794       )
795     (when (and (memq '->ideograph attributes)
796                (setq value (get-char-attribute char '->ideograph)))
797       (insert (format "(->ideograph\t%s)%s"
798                       (mapconcat (lambda (code)
799                                    (cond ((symbolp code)
800                                           (symbol-name code))
801                                          ((integerp code)
802                                           (format "#x%04X" code))
803                                          (t
804                                           (format "%s %S"
805                                                   line-breaking code))))
806                                  value " ")
807                       line-breaking))
808       (setq attributes (delq '->ideograph attributes))
809       )
810     (when (and (memq '->decomposition attributes)
811                (setq value (get-char-attribute char '->decomposition)))
812       (insert (format "(->decomposition\t%s)%s"
813                       (mapconcat (lambda (code)
814                                    (cond ((symbolp code)
815                                           (symbol-name code))
816                                          ((characterp code)
817                                           (if readable
818                                               (format "%S" code)
819                                             (format "#x%04X"
820                                                     (char-int code))
821                                             ))
822                                          ((integerp code)
823                                           (format "#x%04X" code))
824                                          (t
825                                           (format "%s%S" line-breaking code))))
826                                  value " ")
827                       line-breaking))
828       (setq attributes (delq '->decomposition attributes))
829       )
830     (if (equal (get-char-attribute char '->titlecase)
831                (get-char-attribute char '->uppercase))
832         (setq attributes (delq '->titlecase attributes)))
833     (when (and (memq '->mojikyo attributes)
834                (setq value (get-char-attribute char '->mojikyo)))
835       (insert (format "(->mojikyo\t\t. %06d)\t; %c%s"
836                       value (decode-char 'mojikyo value)
837                       line-breaking))
838       (setq attributes (delq '->mojikyo attributes))
839       )
840     (when (and (memq 'hanyu-dazidian-vol attributes)
841                (setq value (get-char-attribute char 'hanyu-dazidian-vol)))
842       (insert (format "(hanyu-dazidian-vol  . %d)%s"
843                       value line-breaking))
844       (setq attributes (delq 'hanyu-dazidian-vol attributes))
845       )
846     (when (and (memq 'hanyu-dazidian-page attributes)
847                (setq value (get-char-attribute char 'hanyu-dazidian-page)))
848       (insert (format "(hanyu-dazidian-page . %d)%s"
849                       value line-breaking))
850       (setq attributes (delq 'hanyu-dazidian-page attributes))
851       )
852     (when (and (memq 'hanyu-dazidian-char attributes)
853                (setq value (get-char-attribute char 'hanyu-dazidian-char)))
854       (insert (format "(hanyu-dazidian-char . %d)%s"
855                       value line-breaking))
856       (setq attributes (delq 'hanyu-dazidian-char attributes))
857       )
858     (setq rest ccs-attributes)
859     (while (and rest
860                 (progn
861                   (setq value (get-char-attribute char (car rest)))
862                   (if value
863                       (if (>= (length (symbol-name (car rest))) 19)
864                           (progn
865                             (setq has-long-ccs-name t)
866                             nil)
867                         t)
868                     t)))
869       (setq rest (cdr rest)))
870     (while attributes
871       (setq name (car attributes))
872       (if (setq value (get-char-attribute char name))
873           (cond ((string-match "^=>ucs@" (symbol-name name))
874                  (insert (format "(%-18s . #x%04X)\t; %c%s"
875                                  name value (decode-char '=ucs value)
876                                  line-breaking))
877                  )
878                 ((eq name 'jisx0208-1978/4X)
879                  (insert (format "(%-18s . #x%04X)%s"
880                                  name value
881                                  line-breaking)))
882                 ((or (eq name 'ideographic-structure)
883                      (eq name 'ideographic-)
884                      (string-match "^\\(->\\|<-\\)" (symbol-name name)))
885                  (insert (format "(%-18s%s " name line-breaking))
886                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
887                        separator nil)
888                  (while (consp value)
889                    (setq cell (car value))
890                    (if (integerp cell)
891                        (setq cell (decode-char '=ucs cell)))
892                    (cond ((characterp cell)
893                           (if separator
894                               (insert lbs))
895                           (if readable
896                               (insert (format "%S" cell))
897                             (char-db-insert-char-spec cell readable))
898                           (setq separator lbs))
899                          ((consp cell)
900                           (if separator
901                               (insert lbs))
902                           (if (consp (car cell))
903                               (char-db-insert-char-spec cell readable)
904                             (char-db-insert-char-reference cell readable))
905                           (setq separator lbs))
906                          (t
907                           (if separator
908                               (insert separator))
909                           (insert (prin1-to-string cell))
910                           (setq separator " ")))
911                    (setq value (cdr value)))
912                  (insert ")")
913                  (insert line-breaking))
914                 ((memq name '(ideograph=
915                               original-ideograph-of
916                               ancient-ideograph-of
917                               vulgar-ideograph-of
918                               wrong-ideograph-of
919                               simplified-ideograph-of
920                               ideographic-variants
921                               ideographic-different-form-of))
922                  (insert (format "(%-18s%s " name line-breaking))
923                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
924                        separator nil)
925                  (while (consp value)
926                    (setq cell (car value))
927                    (if (and (consp cell)
928                             (consp (car cell)))
929                        (progn
930                          (if separator
931                              (insert lbs))
932                          (char-db-insert-alist cell readable)
933                          (setq separator lbs))
934                      (if separator
935                          (insert separator))
936                      (insert (prin1-to-string cell))
937                      (setq separator " "))
938                    (setq value (cdr value)))
939                  (insert ")")
940                  (insert line-breaking))
941                 ;; ((string-match "^->" (symbol-name name))
942                 ;;  (insert
943                 ;;   (format "(%-18s %s)%s"
944                 ;;           name
945                 ;;           (mapconcat (lambda (code)
946                 ;;                        (cond ((symbolp code)
947                 ;;                               (symbol-name code))
948                 ;;                              ((integerp code)
949                 ;;                               (format "#x%04X" code))
950                 ;;                              (t
951                 ;;                               (format "%s%S"
952                 ;;                                       line-breaking code))))
953                 ;;                      value " ")
954                 ;;           line-breaking)))
955                 ((consp value)
956                  (insert (format "(%-18s " name))
957                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
958                        separator nil)
959                  (while (consp value)
960                    (setq cell (car value))
961                    (if (and (consp cell)
962                             (consp (car cell))
963                             (setq ret (condition-case nil
964                                           (find-char cell)
965                                         (error nil))))
966                        (progn
967                          (setq rest cell
968                                al nil
969                                cal nil)
970                          (while rest
971                            (setq key (car (car rest)))
972                            (if (find-charset key)
973                                (setq cal (cons key cal))
974                              (setq al (cons key al)))
975                            (setq rest (cdr rest)))
976                          (if separator
977                              (insert lbs))
978                          (insert-char-attributes ret
979                                                  readable
980                                                  al cal)
981                          (setq separator lbs))
982                      (if separator
983                          (insert separator))
984                      (insert (prin1-to-string cell))
985                      (setq separator " "))
986                    (setq value (cdr value)))
987                  (insert ")")
988                  (insert line-breaking))
989                 (t
990                  (insert (format "(%-18s . %S)%s"
991                                  name value
992                                  line-breaking)))
993                 ))
994       (setq attributes (cdr attributes)))
995     (while ccs-attributes
996       (setq name (charset-name (car ccs-attributes)))
997       (if (and (not (memq name dest-ccss))
998                (prog1
999                    (setq value (get-char-attribute char name))
1000                  (setq dest-ccss (cons name dest-ccss))))
1001           (insert
1002            (format
1003             (cond ((memq name '(=daikanwa
1004                                 =daikanwa-rev1 =daikanwa-rev2
1005                                 =gt =gt-k =cbeta))
1006                    (if has-long-ccs-name
1007                        "(%-26s . %05d)\t; %c%s"
1008                      "(%-18s . %05d)\t; %c%s"))
1009                   ((eq name 'mojikyo)
1010                    (if has-long-ccs-name
1011                        "(%-26s . %06d)\t; %c%s"
1012                      "(%-18s . %06d)\t; %c%s"))
1013                   ((>= (charset-dimension name) 2)
1014                    (if has-long-ccs-name
1015                        "(%-26s . #x%04X)\t; %c%s"
1016                      "(%-18s . #x%04X)\t; %c%s"))
1017                   (t
1018                    (if has-long-ccs-name
1019                        "(%-26s . #x%02X)\t; %c%s"
1020                      "(%-18s . #x%02X)\t; %c%s")))
1021             name
1022             (if (= (charset-iso-graphic-plane name) 1)
1023                 (logior value
1024                         (cond ((= (charset-dimension name) 1)
1025                                #x80)
1026                               ((= (charset-dimension name) 2)
1027                                #x8080)
1028                               ((= (charset-dimension name) 3)
1029                                #x808080)
1030                               (t 0)))
1031               value)
1032             (char-db-decode-isolated-char name value)
1033             line-breaking)))
1034       (setq ccs-attributes (cdr ccs-attributes)))
1035     (insert ")")))
1036
1037 (defun insert-char-data (char &optional readable
1038                               attributes ccs-attributes)
1039   (save-restriction
1040     (narrow-to-region (point)(point))
1041     (insert "(define-char
1042   '")
1043     (insert-char-attributes char readable
1044                             attributes ccs-attributes)
1045     (insert ")\n")
1046     (goto-char (point-min))
1047     (while (re-search-forward "[ \t]+$" nil t)
1048       (replace-match ""))
1049     ;; from tabify.
1050     (goto-char (point-min))
1051     (while (re-search-forward "[ \t][ \t][ \t]*" nil t)
1052       (let ((column (current-column))
1053             (indent-tabs-mode t))
1054         (delete-region (match-beginning 0) (point))
1055         (indent-to column)))
1056     (goto-char (point-max))
1057     ;; (tabify (point-min)(point-max))
1058     ))
1059
1060 (defun insert-char-data-with-variant (char &optional printable
1061                                            no-ucs-variant
1062                                            script excluded-script)
1063   (insert-char-data char printable)
1064   (let ((variants (or (char-variants char)
1065                       (let ((ucs (get-char-attribute char '->ucs)))
1066                         (if ucs
1067                             (delete char (char-variants (int-char ucs)))))))
1068         variant vs)
1069     (setq variants (sort variants #'<))
1070     (while variants
1071       (setq variant (car variants))
1072       (if (and (or (null script)
1073                    (null (setq vs (get-char-attribute variant 'script)))
1074                    (memq script vs))
1075                (or (null excluded-script)
1076                    (null (setq vs (get-char-attribute variant 'script)))
1077                    (not (memq excluded-script vs))))
1078           (or (and no-ucs-variant (get-char-attribute variant '=ucs))
1079               (insert-char-data variant printable)))
1080       (setq variants (cdr variants))
1081       )))
1082
1083 (defun insert-char-range-data (min max &optional script excluded-script)
1084   (let ((code min)
1085         char)
1086     (while (<= code max)
1087       (setq char (decode-char '=ucs code))
1088       (if (encode-char char '=ucs 'defined-only)
1089           (insert-char-data-with-variant char nil 'no-ucs-variant
1090                                          script excluded-script))
1091       (setq code (1+ code)))))
1092
1093 (defun write-char-range-data-to-file (min max file
1094                                           &optional script excluded-script)
1095   (let ((coding-system-for-write 'utf-8))
1096     (with-temp-buffer
1097       (insert-char-range-data min max script excluded-script)
1098       (write-region (point-min)(point-max) file))))
1099
1100 (defvar what-character-original-window-configuration)
1101
1102 ;;;###autoload
1103 (defun what-char-definition (char)
1104   (interactive (list (char-after)))
1105   (let ((buf (get-buffer-create "*Character Description*"))
1106         (the-buf (current-buffer))
1107         (win-conf (current-window-configuration)))
1108     (pop-to-buffer buf)
1109     (make-local-variable 'what-character-original-window-configuration)
1110     (setq what-character-original-window-configuration win-conf)
1111     (setq buffer-read-only nil)
1112     (erase-buffer)
1113     (condition-case err
1114         (progn
1115           (insert-char-data-with-variant char 'printable)
1116           (unless (char-attribute-alist char)
1117             (insert (format ";; = %c\n"
1118                             (let* ((rest (split-char char))
1119                                    (ccs (pop rest))
1120                                    (code (pop rest)))
1121                               (while rest
1122                                 (setq code (logior (lsh code 8)
1123                                                    (pop rest))))
1124                               (decode-char ccs code)))))
1125           ;; (char-db-update-comment)
1126           (set-buffer-modified-p nil)
1127           (view-mode the-buf (lambda (buf)
1128                                (set-window-configuration
1129                                 what-character-original-window-configuration)
1130                                ))
1131           (goto-char (point-min)))
1132       (error (progn
1133                (set-window-configuration
1134                 what-character-original-window-configuration)
1135                (signal (car err) (cdr err)))))))
1136
1137 (provide 'char-db-util)
1138
1139 ;;; char-db-util.el ends here