(char-daikanwa-radical): New function.
[chise/xemacs-chise.git.1] / lisp / utf-2000 / ideograph-util.el
1 ;;; ideograph-util.el --- Ideographic Character Database utility
2
3 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
4 ;;   2009, 2010, 2012 MORIOKA Tomohiko.
5
6 ;; Author: MORIOKA Tomohiko <tomo@kanji.zinbun.kyoto-u.ac.jp>
7 ;; Keywords: CHISE, Chaon model, ISO/IEC 10646, Unicode, UCS-4, MULE.
8
9 ;; This file is part of XEmacs CHISE.
10
11 ;; XEmacs CHISE is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or (at
14 ;; your option) any later version.
15
16 ;; XEmacs CHISE is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 ;; General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with XEmacs CHISE; see the file COPYING.  If not, write to
23 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25
26 ;;; Code:
27
28 (require 'chise-subr)
29 (require 'ideograph-subr)
30 (require 'char-db-util)
31
32
33 (defvar ideograph-radical-chars-vector
34   (make-vector 215 nil))
35
36
37 ;;;###autoload
38 (defun update-ideograph-radical-table ()
39   (interactive)
40   (let (ret rret radical script dest)
41     (dolist (feature
42              (cons 'ideographic-radical
43                    (progn
44                      (dolist (feature (char-attribute-list))
45                        (if (string-match "^ideographic-radical@[^@*]+$"
46                                          (symbol-name feature))
47                            (setq dest (cons feature dest))))
48                      dest)))
49       (map-char-attribute
50        (lambda (chr radical)
51          (dolist (char (append
52                         (if (setq ret
53                                   (get-char-attribute chr '<-subsumptive))
54                             (progn
55                               (setq dest nil)
56                               (dolist (pc ret)
57                                 (unless (eq (get-char-attribute
58                                              pc 'ideographic-radical)
59                                             radical)
60                                   (if (setq rret
61                                             (get-char-attribute
62                                              pc '<-subsumptive))
63                                       (setq ret (append ret rret))
64                                     (setq dest (cons pc dest)))))
65                               dest)
66                           (list chr))
67                         (let ((rest (append
68                                      (get-char-attribute chr '<-identical)
69                                      (get-char-attribute chr '->denotational)))
70                               pc)
71                           (setq dest nil)
72                           (while rest
73                             (setq pc (car rest))
74                             (if (memq pc dest)
75                                 (setq rest (cdr rest))
76                               (setq dest (cons pc dest))
77                               (setq rest
78                                     (append (cdr rest)
79                                             (get-char-attribute
80                                              pc '<-identical)
81                                             (get-char-attribute
82                                              pc '->denotational)))))
83                           dest)))
84            (when (and radical
85                       (or (eq radical
86                               (or (get-char-attribute
87                                    char 'ideographic-radical)
88                                   (char-ideographic-radical char radical)))
89                           (null (char-ideographic-radical char)))
90                       (or (null (setq script
91                                       (get-char-attribute char 'script)))
92                           (memq 'Ideograph script)))
93              (unless (memq char
94                            (setq ret
95                                  (aref ideograph-radical-chars-vector
96                                        radical)))
97                (char-ideographic-strokes char)
98                (aset ideograph-radical-chars-vector radical
99                      (cons char ret)))))
100          nil)
101        feature))
102     (map-char-attribute
103      (lambda (char data)
104        (dolist (cell data)
105          (setq radical (plist-get cell :radical))
106          (when (and radical
107                     (or (null (setq script (get-char-attribute char 'script)))
108                         (memq 'Ideograph script)))
109            (unless (memq char
110                          (setq ret
111                                (aref ideograph-radical-chars-vector radical)))
112              (char-ideographic-strokes char)
113              (aset ideograph-radical-chars-vector radical
114                    (cons char ret))))))
115      'ideographic-)))
116
117
118 (defun int-list< (a b)
119   (if (numberp (car a))
120       (if (numberp (car b))
121           (if (= (car a) (car b))
122               (int-list< (cdr a)(cdr b))
123             (< (car a) (car b)))
124         (if (= (car a) 0)
125             nil
126           (< (car a) 0)))
127     (if (numberp (car b))
128         (if (= (car b) 0)
129             t
130           (< 0 (car b)))
131       )))
132
133 (defun morohashi-daikanwa< (a b)
134   (if (integerp a)
135       (setq a (list a)))
136   (if (integerp b)
137       (setq b (list b)))
138   (cond ((eq (car-safe a) 'ho)
139          (if (eq (car-safe b) 'ho)
140              (int-list< (cdr-safe a)(cdr-safe b))
141            nil))
142         ((or (integerp a)
143              (integerp (car a)))
144          (if (eq (car b) 'ho)
145              t
146            (int-list< a b)))
147         (t
148          (if (eq (car-safe b) 'ho)
149              t
150            (int-list< a b)))))
151
152 ;; (defun nil=-int< (a b)
153 ;;   (cond ((null a) nil)
154 ;;         ((null b) nil)
155 ;;         (t (< a b))))
156
157 ;; (defun nil>-int< (a b)
158 ;;   (cond ((null a) nil)
159 ;;         ((null b) t)
160 ;;         (t (< a b))))
161
162 (defvar ideographic-radical nil)
163
164 ;;;###autoload
165 (defun char-representative-of-daikanwa (char &optional radical
166                                              ignore-default checked)
167   (unless radical
168     (setq radical ideographic-radical))
169   (if (or (null radical)
170           (eq (or (get-char-attribute char 'ideographic-radical)
171                   (char-ideographic-radical char radical t))
172               radical))
173       (let ((ret (or (encode-char char '=daikanwa@rev2 'defined-only)
174                      (encode-char char '=daikanwa/+p 'defined-only)
175                      (encode-char char '=daikanwa/+2p 'defined-only)
176                      (encode-char char '=daikanwa/ho 'defined-only)
177                      )))
178         (or (and ret char)
179             (if (setq ret (get-char-attribute char 'morohashi-daikanwa))
180                 (let ((m-m (car ret))
181                       (m-s (nth 1 ret))
182                       pat)
183                   (if (= m-s 0)
184                       (or (decode-char '=daikanwa@rev2 m-m 'defined-only)
185                           (decode-char '=daikanwa m-m))
186                     (or (cond ((eq m-m 'ho)
187                                (decode-char '=daikanwa/ho m-s))
188                               ((eq m-s 1)
189                                (decode-char '=daikanwa/+p m-m))
190                               ((eq m-s 2)
191                                (decode-char '=daikanwa/+2p m-m)))
192                         (progn
193                           (setq pat (list m-m m-s))
194                           (map-char-attribute (lambda (c v)
195                                                 (if (equal pat v)
196                                                     c))
197                                               'morohashi-daikanwa))))))
198             (and (setq ret (get-char-attribute char '=>daikanwa))
199                  (if (numberp ret)
200                      (or (decode-char '=daikanwa@rev2 ret 'defined-only)
201                          (decode-char '=daikanwa ret))
202                    (map-char-attribute (lambda (c v)
203                                          (if (equal ret v)
204                                              char))
205                                        'morohashi-daikanwa)))
206             (unless (memq char checked)
207               (catch 'tag
208                 (let ((rest
209                        (append (get-char-attribute char '->subsumptive)
210                                (get-char-attribute char '->denotational)))
211                       (i 0)
212                       sc)
213                   (setq checked (cons char checked))
214                   (while rest
215                     (setq sc (car rest))
216                     (if (setq ret (char-representative-of-daikanwa
217                                    sc radical t checked))
218                         (throw 'tag ret))
219                     (setq checked (cons sc checked)
220                           rest (cdr rest)
221                           i (1+ i)))
222                   (setq rest (get-char-attribute char '->identical))
223                   (while rest
224                     (setq sc (car rest))
225                     (when (setq ret (char-representative-of-daikanwa
226                                      sc radical t checked))
227                       (throw 'tag ret))
228                     (setq checked (cons sc checked)
229                           rest (cdr rest)))
230                   (setq rest
231                         (append (get-char-attribute char '<-subsumptive)
232                                 (get-char-attribute char '<-denotational)))
233                   (while rest
234                     (setq sc (car rest))
235                     (when (setq ret (char-representative-of-daikanwa
236                                      sc radical t checked))
237                       (throw 'tag ret))
238                     (setq checked (cons sc checked)
239                           rest (cdr rest))))))
240             (unless ignore-default
241               char)))))
242
243 (defun char-attributes-poly< (c1 c2 accessors testers defaulters)
244   (catch 'tag
245     (let (a1 a2 accessor tester dm)
246       (while (and accessors testers)
247         (setq accessor (car accessors)
248               tester (car testers)
249               dm (car defaulters))
250         (when (and accessor tester)
251           (setq a1 (funcall accessor c1)
252                 a2 (funcall accessor c2))
253           (cond ((null a1)
254                  (if a2
255                      (cond ((eq dm '<)
256                             (throw 'tag t))
257                            ((eq dm '>)
258                             (throw 'tag nil)))))
259                 ((null a2)
260                  (cond ((eq dm '<)
261                         (throw 'tag nil))
262                        ((eq dm '>)
263                         (throw 'tag t))))
264                 (t
265                  (cond ((funcall tester a1 a2)
266                         (throw 'tag t))
267                        ((funcall tester a2 a1)
268                         (throw 'tag nil))))))
269         (setq accessors (cdr accessors)
270               testers (cdr testers)
271               defaulters (cdr defaulters))))))
272
273 (defun char-daikanwa-radical (char &optional radical ignore-sisters)
274   (or (and (encode-char char '=daikanwa@rev2 'defined-only)
275            (or (get-char-attribute char 'ideographic-radical@daikanwa)
276                (get-char-attribute char 'ideographic-radical)))
277       (char-ideographic-radical char radical ignore-sisters)))
278
279 (defun char-daikanwa-strokes (char &optional radical)
280   (unless radical
281     (setq radical ideographic-radical))
282   (let ((drc (char-representative-of-daikanwa char radical))
283         (r (char-ideographic-radical char radical)))
284     (if (and drc
285              (or (null r)
286                  (= (char-ideographic-radical drc radical) r)))
287         (setq char drc)))
288   (char-ideographic-strokes char radical '(daikanwa)))
289
290 ;;;###autoload
291 (defun char-daikanwa (char &optional radical checked depth)
292   (unless radical
293     (setq radical ideographic-radical))
294   (if (or (null radical)
295           (eq (or (get-char-attribute char 'ideographic-radical)
296                   (char-daikanwa-radical char radical t))
297               radical))
298       (let ((ret (or (encode-char char '=daikanwa@rev2 'defined-only)
299                      ;; (encode-char char '=daikanwa 'defined-only)
300                      (get-char-attribute char 'morohashi-daikanwa))))
301         (unless ret
302           (cond
303            ((setq ret (encode-char char '=daikanwa/+p 'defined-only))
304             (setq ret (list ret 1)))
305            ((setq ret (encode-char char '=daikanwa/+2p 'defined-only))
306             (setq ret (list ret 2)))
307            ((setq ret (encode-char char '=daikanwa/ho 'defined-only))
308             (setq ret (list 'ho ret)))))
309         (or (if ret
310                 (if depth
311                     (if (integerp ret)
312                         (list ret depth)
313                       (append ret (list depth)))
314                   ret))
315             (and (setq ret (get-char-attribute char '=>daikanwa))
316                  (if (numberp ret)
317                      (list ret -10)
318                    (append ret '(-10))))
319             (unless (memq char checked)
320               (unless depth
321                 (setq depth 0))
322               (catch 'tag
323                 (let ((rest
324                        (append (get-char-attribute char '->subsumptive)
325                                (get-char-attribute char '->denotational)))
326                       (i 0)
327                       sc lnum)
328                   (setq checked (cons char checked))
329                   (while rest
330                     (setq sc (car rest))
331                     (if (setq ret (char-daikanwa sc radical checked
332                                                  (1- depth)))
333                         (throw 'tag ret))
334                     (setq checked (cons sc checked)
335                           rest (cdr rest)
336                           i (1+ i)))
337                   (setq rest (get-char-attribute char '->identical))
338                   (while rest
339                     (setq sc (car rest))
340                     (when (setq ret (char-daikanwa sc radical checked depth))
341                       (throw 'tag
342                              (if (numberp ret)
343                                  (list ret 0)
344                                (append ret (list i)))))
345                     (setq checked (cons sc checked)
346                           rest (cdr rest)))
347                   (setq rest
348                         (append (get-char-attribute char '<-subsumptive)
349                                 (get-char-attribute char '<-denotational)))
350                   (while rest
351                     (setq sc (car rest))
352                     (when (setq ret (char-daikanwa sc radical checked depth))
353                       (throw 'tag
354                              (if (numberp ret)
355                                  (list ret 0 i)
356                                (if (>= (setq lnum (car (last ret))) 0)
357                                    (append ret (list i))
358                                  (nconc (butlast ret)
359                                         (list 0 (- lnum) i))))))
360                     (setq checked (cons sc checked)
361                           rest (cdr rest))))))))))
362
363 (defun char-ideographic-strokes-diff (char &optional radical)
364   (if (or (get-char-attribute char '<-subsumptive)
365           (get-char-attribute char '<-denotational))
366       (let (s ds)
367         (when (and (setq s (char-ideographic-strokes char radical))
368                    (setq ds (char-daikanwa-strokes char radical)))
369           (abs (- s ds))))
370     0))
371
372 ;;;###autoload
373 (defun ideograph-char< (a b &optional radical)
374   (let ((ideographic-radical (or radical
375                                  ideographic-radical)))
376     (char-attributes-poly<
377      a b
378      '(char-daikanwa-strokes char-daikanwa char-ucs
379                              char-ideographic-strokes-diff char-id)
380      '(< morohashi-daikanwa< < < <)
381      '(> > > > >))))
382
383 (defun insert-ideograph-radical-char-data (radical)
384   (let ((chars
385          (sort (copy-list (aref ideograph-radical-chars-vector radical))
386                (lambda (a b)
387                  (ideograph-char< a b radical))))
388         attributes ; ccss
389         )
390     (dolist (name (char-attribute-list))
391       (unless (memq name char-db-ignored-attributes)
392         ;; (if (find-charset name)
393         ;;     (push name ccss)
394         (push name attributes)
395         ;; )
396         ))
397     (setq attributes (sort attributes #'char-attribute-name<)
398           ;; ccss (sort ccss #'char-attribute-name<)
399           )
400     (aset ideograph-radical-chars-vector radical chars)
401     (dolist (char chars)
402       (when ;;(or
403           (not (some (lambda (atr)
404                        (get-char-attribute char atr))
405                      char-db-ignored-attributes))
406         ;; (some (lambda (ccs)
407         ;;         (encode-char char ccs 'defined-only))
408         ;;       ccss)
409         ;;)
410         (insert-char-data char nil attributes ;ccss
411                           )))))
412
413 (defun write-ideograph-radical-char-data (radical file)
414   (if (file-directory-p file)
415       (let ((name (char-feature (decode-char 'ucs (+ #x2EFF radical))
416                                 'name)))
417         (if (string-match "KANGXI RADICAL " name)
418             (setq name (capitalize (substring name (match-end 0)))))
419         (setq name (mapconcat (lambda (char)
420                                 (if (eq char ? )
421                                     "-"
422                                   (char-to-string char))) name ""))
423         (setq file
424               (expand-file-name
425                (format "Ideograph-R%03d-%s.el" radical name)
426                file))))
427   (with-temp-buffer
428     (insert (format ";; -*- coding: %s -*-\n"
429                     char-db-file-coding-system))
430     (insert-ideograph-radical-char-data radical)
431     (let ((coding-system-for-write char-db-file-coding-system))
432       (write-region (point-min)(point-max) file))))
433
434 (defun ideographic-structure= (char1 char2)
435   (if (char-ref-p char1)
436       (setq char1 (plist-get char1 :char)))
437   (if (char-ref-p char2)
438       (setq char2 (plist-get char2 :char)))
439   (let ((s1 (if (characterp char1)
440                 (get-char-attribute char1 'ideographic-structure)
441               (cdr (assq 'ideographic-structure char1))))
442         (s2 (if (characterp char2)
443                 (get-char-attribute char2 'ideographic-structure)
444               (cdr (assq 'ideographic-structure char2))))
445         e1 e2)
446     (if (or (null s1)(null s2))
447         (char-spec= char1 char2)
448       (catch 'tag
449         (while (and s1 s2)
450           (setq e1 (car s1)
451                 e2 (car s2))
452           (unless (ideographic-structure= e1 e2)
453             (throw 'tag nil))
454           (setq s1 (cdr s1)
455                 s2 (cdr s2)))
456         (and (null s1)(null s2))))))
457
458 ;;;###autoload
459 (defun ideographic-structure-find-char (structure)
460   (let (rest)
461     (map-char-attribute (lambda (char value)
462                           (setq rest structure)
463                           (catch 'tag
464                             (while (and rest value)
465                               (unless (ideographic-structure=
466                                        (car rest)(car value))
467                                 (throw 'tag nil))
468                               (setq rest (cdr rest)
469                                     value (cdr value)))
470                             (unless (or rest value)
471                               char)))
472                         'ideographic-structure)))
473
474
475 (provide 'ideograph-util)
476
477 ;;; ideograph-util.el ends here