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