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