bbedac2506c3874ff112a2656607d5a0b181e6cd
[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 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 (int-char (+ #x2EFF i)))
69       (setq i (1+ i)))
70     (if (< (charset-iso-final-char (car (split-char (aref v 34)))) ?0)
71         (aset v 34 (make-char 'chinese-gb2312 #x62 #x3A)))
72     v))
73
74 (defun char-attribute-name< (ka kb)
75   (cond
76    ((find-charset ka)
77     (cond
78      ((find-charset kb)
79       (cond
80        ((= (charset-dimension ka)
81            (charset-dimension kb))
82         (cond ((= (charset-chars ka)(charset-chars kb))
83                (cond
84                 ((>= (charset-iso-final-char ka) ?@)
85                  (if (>= (charset-iso-final-char kb) ?@)
86                      (< (charset-iso-final-char ka)
87                         (charset-iso-final-char kb))
88                    t))
89                 ((>= (charset-iso-final-char ka) ?0)
90                  (cond
91                   ((>= (charset-iso-final-char kb) ?@)
92                    nil)
93                   ((>= (charset-iso-final-char kb) ?0)
94                    (< (charset-iso-final-char ka)
95                       (charset-iso-final-char kb)))
96                   (t)))
97                 (t (if (>= (charset-iso-final-char kb) ?0)
98                        nil
99                      (> (charset-id ka)(charset-id kb))))))
100               ((<= (charset-chars ka)(charset-chars kb)))))
101        (t
102         (< (charset-dimension ka)
103            (charset-dimension kb))
104         )))
105      ((symbolp kb)
106       nil)
107      (t
108       t)))
109    ((find-charset kb)
110     t)
111    ((symbolp ka)
112     (cond ((symbolp kb)
113            (string< (symbol-name ka)
114                     (symbol-name kb)))
115           (t)))
116    ((symbolp kb)
117     nil)))
118
119 (defun char-db-insert-char-spec (char &optional readable column)
120   (unless column
121     (setq column (current-column)))
122   (let (char-spec ret al cal key temp-char)
123     (cond ((characterp char)
124            (cond ((and (setq ret (get-char-attribute char 'ucs))
125                        (not (and (<= #xE000 ret)(<= ret #xF8FF))))
126                   (setq char-spec (list (cons 'ucs ret)))
127                   (if (setq ret (get-char-attribute char 'name))
128                       (setq char-spec (cons (cons 'name ret) char-spec)))
129                   )
130                  ((setq ret (split-char char))
131                   (setq char-spec (list ret))
132                   (dolist (ccs (delq (car ret) (charset-list)))
133                     (if (or (and (>= (charset-iso-final-char ccs) ?0)
134                                  (setq ret (get-char-attribute char ccs)))
135                             (eq ccs 'ideograph-daikanwa))
136                         (setq char-spec (cons (cons ccs ret) char-spec))))
137                   (if (setq ret (get-char-attribute char 'name))
138                       (setq char-spec (cons (cons 'name ret) char-spec)))
139                   )))
140           ((consp char)
141            (setq char-spec char)
142            (setq char nil)))
143     (unless (or char
144                 (condition-case nil
145                     (setq char (find-char char-spec))
146                   (error nil)))
147       ;; define temporary character
148       ;;   Current implementation is dirty.
149       (setq temp-char (define-char (cons '(ideograph-daikanwa . 0)
150                                          char-spec)))
151       (remove-char-attribute temp-char 'ideograph-daikanwa)
152       (setq char temp-char))
153     (setq al nil
154           cal nil)
155     (while char-spec
156       (setq key (car (car char-spec)))
157       (if (find-charset key)
158           (setq cal (cons key cal))
159         (setq al (cons key al)))
160       (setq char-spec (cdr char-spec)))
161     (insert-char-attributes char
162                             readable
163                             (or al 'none) cal)
164     (when temp-char
165       ;; undefine temporary character
166       ;;   Current implementation is dirty.
167       (setq char-spec (char-attribute-alist temp-char))
168       (while char-spec
169         (remove-char-attribute temp-char (car (car char-spec)))
170         (setq char-spec (cdr char-spec))))))
171
172 (defun char-db-insert-alist (alist &optional readable column)
173   (unless column
174     (setq column (current-column)))
175   (let ((line-breaking
176          (concat "\n" (make-string (1+ column) ?\ )))
177         name value
178         ret al cal key
179         lbs cell rest separator)
180     (insert "(")
181     (while alist
182       (setq name (car (car alist))
183             value (cdr (car alist)))
184       (cond ((eq name 'char)
185              (insert "(char . ")
186              (if (setq ret (condition-case nil
187                                (find-char value)
188                              (error nil)))
189                  (progn
190                    (setq al nil
191                          cal nil)
192                    (while value
193                      (setq key (car (car value)))
194                      (if (find-charset key)
195                          (setq cal (cons key cal))
196                        (setq al (cons key al)))
197                      (setq value (cdr value)))
198                    (insert-char-attributes ret
199                                            readable
200                                            (or al 'none) cal))
201                (insert (prin1-to-string value)))
202              (insert ")")
203              (insert line-breaking))
204             ((consp value)
205              (insert (format "(%-18s " name))
206              (setq lbs (concat "\n" (make-string (current-column) ?\ )))
207              (while (consp value)
208                (setq cell (car value))
209                (if (and (consp cell)
210                         (consp (car cell))
211                         (setq ret (condition-case nil
212                                       (find-char cell)
213                                     (error nil)))
214                         )
215                    (progn
216                      (setq rest cell
217                            al nil
218                            cal nil)
219                      (while rest
220                        (setq key (car (car rest)))
221                        (if (find-charset key)
222                            (setq cal (cons key cal))
223                          (setq al (cons key al)))
224                        (setq rest (cdr rest)))
225                      (if separator
226                          (insert lbs))
227                      (insert-char-attributes ret
228                                              readable
229                                              al cal)
230                      (setq separator lbs))
231                  (if separator
232                      (insert separator))
233                  (insert (prin1-to-string cell))
234                  (setq separator " "))
235                (setq value (cdr value)))
236              (insert ")")
237              (insert line-breaking))
238             (t
239              (insert (format "(%-18s . %S)%s"
240                              name value
241                              line-breaking))))
242       (setq alist (cdr alist))))
243   (insert ")"))
244
245 (defun char-db-insert-char-reference (plist &optional readable column)
246   (unless column
247     (setq column (current-column)))
248   (let ((line-breaking
249          (concat "\n" (make-string (1+ column) ?\ )))
250         name value)
251     (insert "(")
252     (while plist
253       (setq name (pop plist))
254       (setq value (pop plist))
255       (cond ((eq name :char)
256              (insert ":char\t")
257              (cond ((numberp value)
258                     (setq value (decode-char 'ucs value)))
259                    ;; ((consp value)
260                    ;;  (setq value (or (find-char value)
261                    ;;                  value)))
262                    )
263              (char-db-insert-char-spec value readable)
264              (insert line-breaking))
265             (t
266              (insert (format "%s\t%S%s"
267                              name value
268                              line-breaking))))
269       ))
270   (insert ")"))
271
272 (defun char-db-decode-isolated-char (ccs code-point)
273   (let (ret)
274     (setq ret
275           (cond ((eq ccs 'arabic-iso8859-6)
276                  (decode-char ccs code-point))
277                 ((and (memq ccs '(ideograph-gt-pj-1
278                                   ideograph-gt-pj-2
279                                   ideograph-gt-pj-3
280                                   ideograph-gt-pj-4
281                                   ideograph-gt-pj-5
282                                   ideograph-gt-pj-6
283                                   ideograph-gt-pj-7
284                                   ideograph-gt-pj-8
285                                   ideograph-gt-pj-9
286                                   ideograph-gt-pj-10
287                                   ideograph-gt-pj-11))
288                       (setq ret (decode-char ccs code-point))
289                       (setq ret (get-char-attribute ret 'ideograph-gt)))
290                  (decode-builtin-char 'ideograph-gt ret))
291                 (t
292                  (decode-builtin-char ccs code-point))))
293     (cond ((and (<= 0 (char-int ret))
294                 (<= (char-int ret) #x1F))
295            (decode-char 'ucs (+ #x2400 (char-int ret))))
296           ((= (char-int ret) #x7F)
297            ?\u2421)
298           (t ret))))
299
300 (defvar char-db-convert-obsolete-format t)
301
302 (defun insert-char-attributes (char &optional readable
303                                     attributes ccs-attributes
304                                     column)
305   (setq attributes
306         (sort (if attributes
307                   (if (consp attributes)
308                       (copy-sequence attributes))
309                 (char-attribute-list))
310               #'char-attribute-name<))
311   (setq ccs-attributes
312         (sort (if ccs-attributes
313                   (copy-sequence ccs-attributes)
314                 (charset-list))
315               #'char-attribute-name<))
316   (unless column
317     (setq column (current-column)))
318   (let (name value has-long-ccs-name rest
319         radical strokes
320         (line-breaking
321          (concat "\n" (make-string (1+ column) ?\ )))
322         lbs cell separator ret
323         key al cal)
324     (insert "(")
325     (when (and (memq 'name attributes)
326                (setq value (get-char-attribute char 'name)))
327       (insert (format
328                (if (> (+ (current-column) (length value)) 48)
329                    "(name . %S)%s"
330                  "(name               . %S)%s")
331                value line-breaking))
332       (setq attributes (delq 'name attributes))
333       )
334     (when (and (memq 'script attributes)
335                (setq value (get-char-attribute char 'script)))
336       (insert (format "(script\t\t%s)%s"
337                       (mapconcat (function prin1-to-string)
338                                  value " ")
339                       line-breaking))
340       (setq attributes (delq 'script attributes))
341       )
342     (when (and (memq '=>ucs attributes)
343                (setq value (get-char-attribute char '=>ucs)))
344       (insert (format "(=>ucs\t\t. #x%04X)\t; %c%s"
345                       value (decode-char 'ucs value)
346                       line-breaking))
347       (setq attributes (delq '=>ucs attributes))
348       )
349     (when (and (memq '->ucs attributes)
350                (setq value (get-char-attribute char '->ucs)))
351       (insert (format (if char-db-convert-obsolete-format
352                           "(=>ucs\t\t. #x%04X)\t; %c%s"
353                         "(->ucs\t\t. #x%04X)\t; %c%s")
354                       value (decode-char 'ucs value)
355                       line-breaking))
356       (setq attributes (delq '->ucs attributes))
357       )
358     (when (and (memq 'general-category attributes)
359                (setq value (get-char-attribute char 'general-category)))
360       (insert (format
361                "(general-category\t%s) ; %s%s"
362                (mapconcat (lambda (cell)
363                             (format "%S" cell))
364                           value " ")
365                (cond ((rassoc value unidata-normative-category-alist)
366                       "Normative Category")
367                      ((rassoc value unidata-informative-category-alist)
368                       "Informative Category")
369                      (t
370                       "Unknown Category"))
371                line-breaking))
372       (setq attributes (delq 'general-category attributes))
373       )
374     (when (and (memq 'bidi-category attributes)
375                (setq value (get-char-attribute char 'bidi-category)))
376       (insert (format "(bidi-category\t. %S)%s"
377                       value
378                       line-breaking))
379       (setq attributes (delq 'bidi-category attributes))
380       )
381     (unless (or (not (memq 'mirrored attributes))
382                 (eq (setq value (get-char-attribute char 'mirrored 'empty))
383                     'empty))
384       (insert (format "(mirrored\t\t. %S)%s"
385                       value
386                       line-breaking))
387       (setq attributes (delq 'mirrored attributes))
388       )
389     (cond
390      ((and (memq 'decimal-digit-value attributes)
391            (setq value (get-char-attribute char 'decimal-digit-value)))
392       (insert (format "(decimal-digit-value . %S)%s"
393                       value
394                       line-breaking))
395       (setq attributes (delq 'decimal-digit-value attributes))
396       (when (and (memq 'digit-value attributes)
397                  (setq value (get-char-attribute char 'digit-value)))
398         (insert (format "(digit-value\t . %S)%s"
399                         value
400                         line-breaking))
401         (setq attributes (delq 'digit-value attributes))
402         )
403       (when (and (memq 'numeric-value attributes)
404                  (setq value (get-char-attribute char 'numeric-value)))
405         (insert (format "(numeric-value\t . %S)%s"
406                         value
407                         line-breaking))
408         (setq attributes (delq 'numeric-value attributes))
409         )
410       )
411      (t
412       (when (and (memq 'digit-value attributes)
413                  (setq value (get-char-attribute char 'digit-value)))
414         (insert (format "(digit-value\t. %S)%s"
415                         value
416                         line-breaking))
417         (setq attributes (delq 'digit-value attributes))
418         )
419       (when (and (memq 'numeric-value attributes)
420                  (setq value (get-char-attribute char 'numeric-value)))
421         (insert (format "(numeric-value\t. %S)%s"
422                         value
423                         line-breaking))
424         (setq attributes (delq 'numeric-value attributes))
425         )))
426     (when (and (memq 'iso-10646-comment attributes)
427                (setq value (get-char-attribute char 'iso-10646-comment)))
428       (insert (format "(iso-10646-comment\t. %S)%s"
429                       value
430                       line-breaking))
431       (setq attributes (delq 'iso-10646-comment attributes))
432       )
433     (when (and (memq 'morohashi-daikanwa attributes)
434                (setq value (get-char-attribute char 'morohashi-daikanwa)))
435       (insert (format "(morohashi-daikanwa\t%s)%s"
436                       (mapconcat (function prin1-to-string) value " ")
437                       line-breaking))
438       (setq attributes (delq 'morohashi-daikanwa attributes))
439       )
440     (setq radical nil
441           strokes nil)
442     (when (and (memq 'ideographic-radical attributes)
443                (setq value (get-char-attribute char 'ideographic-radical)))
444       (setq radical value)
445       (insert (format "(ideographic-radical . %S)\t; %c%s"
446                       radical
447                       (aref ideographic-radicals radical)
448                       line-breaking))
449       (setq attributes (delq 'ideographic-radical attributes))
450       )
451     (when (and (memq 'ideographic-strokes attributes)
452                (setq value (get-char-attribute char 'ideographic-strokes)))
453       (setq strokes value)
454       (insert (format "(ideographic-strokes . %S)%s"
455                       strokes
456                       line-breaking))
457       (setq attributes (delq 'ideographic-strokes attributes))
458       )
459     (when (and (memq 'kangxi-radical attributes)
460                (setq value (get-char-attribute char 'kangxi-radical)))
461       (unless (eq value radical)
462         (insert (format "(kangxi-radical\t . %S)\t; %c%s"
463                         value
464                         (aref ideographic-radicals value)
465                         line-breaking))
466         (or radical
467             (setq radical value)))
468       (setq attributes (delq 'kangxi-radical attributes))
469       )
470     (when (and (memq 'kangxi-strokes attributes)
471                (setq value (get-char-attribute char 'kangxi-strokes)))
472       (unless (eq value strokes)
473         (insert (format "(kangxi-strokes\t . %S)%s"
474                         value
475                         line-breaking))
476         (or strokes
477             (setq strokes value)))
478       (setq attributes (delq 'kangxi-strokes attributes))
479       )
480     (when (and (memq 'japanese-radical attributes)
481                (setq value (get-char-attribute char 'japanese-radical)))
482       (unless (eq value radical)
483         (insert (format "(japanese-radical\t . %S)\t; %c%s"
484                         value
485                         (aref ideographic-radicals value)
486                         line-breaking))
487         (or radical
488             (setq radical value)))
489       (setq attributes (delq 'japanese-radical attributes))
490       )
491     (when (and (memq 'japanese-strokes attributes)
492                (setq value (get-char-attribute char 'japanese-strokes)))
493       (unless (eq value strokes)
494         (insert (format "(japanese-strokes\t . %S)%s"
495                         value
496                         line-breaking))
497         (or strokes
498             (setq strokes value)))
499       (setq attributes (delq 'japanese-strokes attributes))
500       )
501     (when (and (memq 'cns-radical attributes)
502                (setq value (get-char-attribute char 'cns-radical)))
503       (insert (format "(cns-radical\t . %S)\t; %c%s"
504                       value
505                       (aref ideographic-radicals value)
506                       line-breaking))
507       (setq attributes (delq 'cns-radical attributes))
508       )
509     (when (and (memq 'cns-strokes attributes)
510                (setq value (get-char-attribute char 'cns-strokes)))
511       (unless (eq value strokes)
512         (insert (format "(cns-strokes\t . %S)%s"
513                         value
514                         line-breaking))
515         (or strokes
516             (setq strokes value)))
517       (setq attributes (delq 'cns-strokes attributes))
518       )
519     (when (and (memq 'shinjigen-1-radical attributes)
520                (setq value (get-char-attribute char 'shinjigen-1-radical)))
521       (unless (eq value radical)
522         (insert (format "(shinjigen-1-radical . %S)\t; %c%s"
523                         value
524                         (aref ideographic-radicals value)
525                         line-breaking))
526         (or radical
527             (setq radical value)))
528       (setq attributes (delq 'shinjigen-1-radical attributes))
529       )
530     (when (and (memq 'total-strokes attributes)
531                (setq value (get-char-attribute char 'total-strokes)))
532       (insert (format "(total-strokes       . %S)%s"
533                       value
534                       line-breaking))
535       (setq attributes (delq 'total-strokes attributes))
536       )
537     (when (and (memq '->ideograph attributes)
538                (setq value (get-char-attribute char '->ideograph)))
539       (insert (format "(->ideograph\t%s)%s"
540                       (mapconcat (lambda (code)
541                                    (cond ((symbolp code)
542                                           (symbol-name code))
543                                          ((integerp code)
544                                           (format "#x%04X" code))
545                                          (t
546                                           (format "%s %S"
547                                                   line-breaking code))))
548                                  value " ")
549                       line-breaking))
550       (setq attributes (delq '->ideograph attributes))
551       )
552     (when (and (memq '->decomposition attributes)
553                (setq value (get-char-attribute char '->decomposition)))
554       (insert (format "(->decomposition\t%s)%s"
555                       (mapconcat (lambda (code)
556                                    (cond ((symbolp code)
557                                           (symbol-name code))
558                                          ((characterp code)
559                                           (if readable
560                                               (format "%S" code)
561                                             (format "#x%04X"
562                                                     (char-int code))
563                                             ))
564                                          ((integerp code)
565                                           (format "#x%04X" code))
566                                          (t
567                                           (format "%s%S" line-breaking code))))
568                                  value " ")
569                       line-breaking))
570       (setq attributes (delq '->decomposition attributes))
571       )
572     (if (equal (get-char-attribute char '->titlecase)
573                (get-char-attribute char '->uppercase))
574         (setq attributes (delq '->titlecase attributes)))
575     (when (and (memq '->mojikyo attributes)
576                (setq value (get-char-attribute char '->mojikyo)))
577       (insert (format "(->mojikyo\t\t. %06d)\t; %c%s"
578                       value (decode-char 'mojikyo value)
579                       line-breaking))
580       (setq attributes (delq '->mojikyo attributes))
581       )
582     (setq rest ccs-attributes)
583     (while (and rest
584                 (progn
585                   (setq value (get-char-attribute char (car rest)))
586                   (if value
587                       (if (>= (length (symbol-name (car rest))) 19)
588                           (progn
589                             (setq has-long-ccs-name t)
590                             nil)
591                         t)
592                     t)))
593       (setq rest (cdr rest)))
594     (while attributes
595       (setq name (car attributes))
596       (if (setq value (get-char-attribute char name))
597           (cond ((eq name 'jisx0208-1978/4X)
598                  (insert (format "(%-18s . #x%04X)%s"
599                                  name value
600                                  line-breaking)))
601                 ((memq name '(->lowercase
602                               ->uppercase ->titlecase
603                               ->fullwidth <-fullwidth
604                               ->vulgar-ideograph <-vulgar-ideograph
605                               ->ancient-ideograph <-ancient-ideograph
606                               ->original-ideograph <-original-ideograph
607                               ->simplified-ideograph <-simplified-ideograph
608                               ->wrong-ideograph <-wrong-ideograph
609                               ->same-ideograph
610                               ->ideographic-variants
611                               ->synonyms
612                               ->radical <-radical
613                               ->bopomofo <-bopomofo
614                               ->ideographic <-ideographic
615                               ideographic-structure))
616                  (insert (format "(%-18s%s " name line-breaking))
617                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
618                        separator nil)
619                  (while (consp value)
620                    (setq cell (car value))
621                    (if (integerp cell)
622                        (setq cell (decode-char 'ucs cell)))
623                    (cond ((characterp cell)
624                           (if separator
625                               (insert lbs))
626                           (char-db-insert-char-spec cell readable)
627                           (setq separator lbs))
628                          ((consp cell)
629                           (if separator
630                               (insert lbs))
631                           (if (consp (car cell))
632                               (char-db-insert-char-spec cell readable)
633                             (char-db-insert-char-reference cell readable))
634                           (setq separator lbs))
635                          (t
636                           (if separator
637                               (insert separator))
638                           (insert (prin1-to-string cell))
639                           (setq separator " ")))
640                    (setq value (cdr value)))
641                  (insert ")")
642                  (insert line-breaking))
643                 ((memq name '(ideograph=
644                               original-ideograph-of
645                               ancient-ideograph-of
646                               vulgar-ideograph-of
647                               wrong-ideograph-of
648                               simplified-ideograph-of
649                               ideographic-variants
650                               ideographic-different-form-of))
651                  (insert (format "(%-18s%s " name line-breaking))
652                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
653                        separator nil)
654                  (while (consp value)
655                    (setq cell (car value))
656                    (if (and (consp cell)
657                             (consp (car cell)))
658                        (progn
659                          (if separator
660                              (insert lbs))
661                          (char-db-insert-alist cell readable)
662                          (setq separator lbs))
663                      (if separator
664                          (insert separator))
665                      (insert (prin1-to-string cell))
666                      (setq separator " "))
667                    (setq value (cdr value)))
668                  (insert ")")
669                  (insert line-breaking))
670                 ((string-match "^->" (symbol-name name))
671                  (insert
672                   (format "(%-18s %s)%s"
673                           name
674                           (mapconcat (lambda (code)
675                                        (cond ((symbolp code)
676                                               (symbol-name code))
677                                              ((integerp code)
678                                               (format "#x%04X" code))
679                                              (t
680                                               (format "%s%S"
681                                                       line-breaking code))))
682                                      value " ")
683                           line-breaking)))
684                 ((consp value)
685                  (insert (format "(%-18s " name))
686                  (setq lbs (concat "\n" (make-string (current-column) ?\ ))
687                        separator nil)
688                  (while (consp value)
689                    (setq cell (car value))
690                    (if (and (consp cell)
691                             (consp (car cell))
692                             (setq ret (condition-case nil
693                                           (find-char cell)
694                                         (error nil))))
695                        (progn
696                          (setq rest cell
697                                al nil
698                                cal nil)
699                          (while rest
700                            (setq key (car (car rest)))
701                            (if (find-charset key)
702                                (setq cal (cons key cal))
703                              (setq al (cons key al)))
704                            (setq rest (cdr rest)))
705                          (if separator
706                              (insert lbs))
707                          (insert-char-attributes ret
708                                                  readable
709                                                  al cal)
710                          (setq separator lbs))
711                      (if separator
712                          (insert separator))
713                      (insert (prin1-to-string cell))
714                      (setq separator " "))
715                    (setq value (cdr value)))
716                  (insert ")")
717                  (insert line-breaking))
718                 (t
719                  (insert (format "(%-18s . %S)%s"
720                                  name value
721                                  line-breaking)))
722                 ))
723       (setq attributes (cdr attributes)))
724     (while ccs-attributes
725       (setq name (car ccs-attributes))
726       (if (and (eq name (charset-name name))
727                (setq value (get-char-attribute char name)))
728           (insert
729            (format
730             (cond ((memq name '(ideograph-daikanwa ideograph-gt
731                                                    ideograph-cbeta))
732                    (if has-long-ccs-name
733                        "(%-26s . %05d)\t; %c%s"
734                      "(%-18s . %05d)\t; %c%s"))
735                   ((eq name 'mojikyo)
736                    (if has-long-ccs-name
737                        "(%-26s . %06d)\t; %c%s"
738                      "(%-18s . %06d)\t; %c%s"))
739                   ((eq name 'ucs)
740                    (if has-long-ccs-name
741                        "(%-26s . #x%04X)\t; %c%s"
742                      "(%-18s . #x%04X)\t; %c%s"))
743                   (t
744                    (if has-long-ccs-name
745                        "(%-26s . #x%02X)\t; %c%s"
746                      "(%-18s . #x%02X)\t; %c%s")))
747             name
748             (if (= (charset-iso-graphic-plane name) 1)
749                 (logior value
750                         (cond ((= (charset-dimension name) 1)
751                                #x80)
752                               ((= (charset-dimension name) 2)
753                                #x8080)
754                               ((= (charset-dimension name) 3)
755                                #x808080)
756                               (t 0)))
757               value)
758             (char-db-decode-isolated-char name value)
759             line-breaking)))
760       (setq ccs-attributes (cdr ccs-attributes)))
761     (insert ")")))
762
763 (defun insert-char-data (char &optional readable
764                               attributes ccs-attributes)
765   (save-restriction
766     (narrow-to-region (point)(point))
767     (insert "(define-char
768   '")
769     (insert-char-attributes char readable
770                             attributes ccs-attributes)
771     (insert ")\n")
772     (goto-char (point-min))
773     (while (re-search-forward "[ \t]+$" nil t)
774       (replace-match ""))
775     (goto-char (point-max))
776     (tabify (point-min)(point-max))
777     ))
778
779 ;;;###autoload
780 (defun char-db-update-comment ()
781   (interactive)
782   (save-excursion
783     (goto-char (point-min))
784     (let (cdef table char)
785       (while (re-search-forward "^[ \t]*\\(([^.()]+)\\)" nil t)
786         (goto-char (match-beginning 1))
787         (setq cdef (read (current-buffer)))
788         (when (find-charset (car cdef))
789           (goto-char (match-end 0))
790           (setq char
791                 (if (and
792                      (not (eq (car cdef) 'ideograph-daikanwa))
793                      (or (memq (car cdef) '(ascii latin-viscii-upper
794                                                   latin-viscii-lower
795                                                   arabic-iso8859-6
796                                                   japanese-jisx0213-1
797                                                   japanese-jisx0213-2))
798                          (= (char-int (charset-iso-final-char (car cdef)))
799                             0)))
800                     (apply (function make-char) cdef)
801                   (if (setq table (charset-mapping-table (car cdef)))
802                       (set-charset-mapping-table (car cdef) nil))
803                   (prog1
804                       (apply (function make-char) cdef)
805                     (if table
806                         (set-charset-mapping-table (car cdef) table)))))
807           (when (not (or (< (char-int char) 32)
808                          (and (<= 128 (char-int char))
809                               (< (char-int char) 160))))
810             (delete-region (point) (point-at-eol))
811             (insert (format "\t; %c" char)))
812           )))))
813
814 (defun insert-char-data-with-variant (char &optional printable
815                                            no-ucs-variant
816                                            script excluded-script)
817   (insert-char-data char printable)
818   (let ((variants (or (char-variants char)
819                       (let ((ucs (get-char-attribute char '->ucs)))
820                         (if ucs
821                             (delete char (char-variants (int-char ucs)))))))
822         variant vs)
823     (setq variants (sort variants #'<))
824     (while variants
825       (setq variant (car variants))
826       (if (and (or (null script)
827                    (null (setq vs (get-char-attribute variant 'script)))
828                    (memq script vs))
829                (or (null excluded-script)
830                    (null (setq vs (get-char-attribute variant 'script)))
831                    (not (memq excluded-script vs))))
832           (or (and no-ucs-variant (get-char-attribute variant 'ucs))
833               (insert-char-data variant printable)))
834       (setq variants (cdr variants))
835       )))
836
837 (defun insert-char-range-data (min max &optional script excluded-script)
838   (let ((code min)
839         char)
840     (while (<= code max)
841       (setq char (decode-char 'ucs code))
842       (if (get-char-attribute char 'ucs)
843           (insert-char-data-with-variant char nil 'no-ucs-variant
844                                          script excluded-script))
845       (setq code (1+ code))
846       )))
847
848 (defun write-char-range-data-to-file (min max file
849                                           &optional script excluded-script)
850   (let ((coding-system-for-write 'utf-8))
851     (with-temp-buffer
852       (insert-char-range-data min max script excluded-script)
853       (write-region (point-min)(point-max) file))))
854
855 (defvar what-character-original-window-configuration)
856
857 ;;;###autoload
858 (defun what-char-definition (char)
859   (interactive (list (char-after)))
860   (let ((buf (get-buffer-create "*Character Description*"))
861         (the-buf (current-buffer))
862         (win-conf (current-window-configuration)))
863     (pop-to-buffer buf)
864     (make-local-variable 'what-character-original-window-configuration)
865     (setq what-character-original-window-configuration win-conf)
866     (setq buffer-read-only nil)
867     (erase-buffer)
868     (condition-case err
869         (progn
870           (insert-char-data-with-variant char 'printable)
871           ;; (char-db-update-comment)
872           (set-buffer-modified-p nil)
873           (view-mode the-buf (lambda (buf)
874                                (set-window-configuration
875                                 what-character-original-window-configuration)
876                                ))
877           (goto-char (point-min)))
878       (error (progn
879                (set-window-configuration
880                 what-character-original-window-configuration)
881                (signal (car err) (cdr err)))))))
882
883 (provide 'char-db-util)
884
885 ;;; char-db-util.el ends here