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