/[emacs]/emacs/lisp/language/devan-util.el
ViewVC logotype

Diff of /emacs/lisp/language/devan-util.el

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.25 by pj, Mon Jul 16 12:22:59 2001 UTC revision 1.26 by rms, Sun Nov 25 02:40:11 2001 UTC
# Line 1  Line 1 
1  ;;; devan-util.el --- support for Devanagari Script Composition  ;;; devan-util.el --- Support for composing Devanagari characters
2    
3  ;; Copyright (C) 1996, 2001 Free Software Foundation, Inc.  ;; Copyright (C) 2001 Free Software Foundation, Inc.
4    
5  ;; Author: KAWABATA, Taichi <kawabata@is.s.u-tokyo.ac.jp>  ;; Maintainer:  KAWABATA, Taichi <batta@beige.ocn.ne.jp>
6    ;; Keywords: multilingual, Devanagari
 ;; Keywords: multilingual, Indian, Devanagari  
7    
8  ;; This file is part of GNU Emacs.  ;; This file is part of GNU Emacs.
9    
# Line 23  Line 22 
22  ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,  ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  ;; Boston, MA 02111-1307, USA.  ;; Boston, MA 02111-1307, USA.
24    
25  ;;; Commentary:  ;; Created: Feb. 17. 2001
   
 ;; History:  
 ;; 1996.10.18 written by KAWABATA, Taichi <kawabata@is.s.u-tokyo.ac.jp>  
 ;; 1997.3.24 fixed some bugs.  
26    
27  ;; Future work ::  ;;; Commentary:
 ;; Decompose the input characters and process them on the character basis.  
28    
29  ;; Devanagari script composition rules and related programs.  ;; This file provides character(Unicode) to glyph(CDAC) conversion and
30    ;; composition of Devanagari script characters.
31    
32  ;;; Code:  ;;; Code:
33    
 ;;;  
 ;;;   Steps toward composition of Devanagari Characters.  
 ;;;  
             
 ;;; Basic functions.  
   
34  ;;;###autoload  ;;;###autoload
 (defun indian-to-devanagari (char)  
   "Convert IS 13194 character CHAR to Devanagari basic characters.  
 If CHAR is not IS 13194, return CHAR as is."  
   (let ((charcodes (split-char char)))  
     (if (eq (car charcodes) 'indian-is13194)  
         (make-char 'indian-2-column ?\x21 (nth 1 charcodes))  
       char)))  
35    
36  ;;;###autoload  ;; Devanagari Composable Pattern
37  (defun devanagari-to-indian (char)  ;;    C .. Consonants
38    "Convert Devanagari basic character CHAR to IS 13194 characters.  ;;    V .. Vowel
39  If CHAR is not Devanagari basic character, return CHAR as is."  ;;    H .. Halant
40    (let ((charcodes (split-char char)))  ;;    M .. Matra
41      (if (and (eq (car charcodes) 'indian-2-column)  ;;    V .. Vowel
42               (= (nth 1 charcodes) ?\x21))  ;;    A .. Anuswar
43          (make-char 'indian-is13194 (nth 2 charcodes))  ;;    D .. Chandrabindu
44        char)))  ;;    (N .. Zerowidth Non Joiner)
45    ;;    (J .. Zerowidth Joiner.  )
46    ;; 1. vowel
47    ;;  V(A/D)?
48    ;; 2. syllable : maximum of 5 consecutive consonants.  (e.g. kartsnya)
49    ;;  ((CH)?(CH)?(CH)?CH)?C(MA?|D|H)?
50    
51    (defconst devanagari-consonant
52      "[$,15U(B-$,15y68(B-$,16?(B]")
53    
54    (defconst devanagari-composable-pattern
55      (concat
56       "\\([$,15E(B-$,15T6@6A(B][$,15A5B(B]?\\)\\|$,15C(B"
57       "\\|\\("
58       "\\(?:\\(?:[$,15U(B-$,15y68(B-$,16?(B]$,16-(B\\)?\\(?:[$,15U(B-$,15y68(B-$,16?(B]$,16-(B\\)?\\(?:[$,15U(B-$,15y68(B-$,16?(B]$,16-(B\\)?[$,15U(B-$,15y68(B-$,16?(B]$,16-(B\\)?"
59       "[$,15U(B-$,15y68(B-$,16?(B]\\(?:$,16-(B\\|[$,15~(B-$,16-6B6C(B]?[$,15B5A(B]?\\)?"
60       "\\)")
61      "Regexp matching a composable sequence of Devanagari characters.")
62    
63  ;;;###autoload  (defun devanagari-compose-region (from to)
 (defun indian-to-devanagari-region (from to)  
   "Convert IS 13194 characters in region to Devanagari basic characters.  
 When called from a program, expects two arguments,  
 positions (integers or markers) specifying the region."  
64    (interactive "r")    (interactive "r")
65    (save-excursion    (save-excursion
66      (goto-char from)      (save-restriction
67      (while (< (point) to)        (narrow-to-region from to)
68        (let ((char (following-char)))        (goto-char (point-min))
69          (if (eq (char-charset char) 'indian-is13194)        (while (re-search-forward devanagari-composable-pattern nil t)
70              (progn          (devanagari-compose-syllable-region (match-beginning 0)
71                (delete-char 1)                                              (match-end 0))))))
72                (insert (indian-to-devanagari char)))  (defun devanagari-compose-string (string)
73            (forward-char 1))))))    (with-temp-buffer
74        (insert (decompose-string string))
75  ;;;###autoload      (devanagari-compose-region (point-min) (point-max))
76  (defun devanagari-to-indian-region (from to)      (buffer-string)))
77    "Convert Devanagari basic characters in region to Indian characters.  
78  When called from a program, expects two arguments,  (defun range (from to)
79  positions (integers or markers) specifying the region."    "Make the list of the integers of range FROM to TO."
80    (interactive "r")    (let (result)
81    (save-excursion      (while (<= from to) (setq result (cons to result) to (1- to))) result))
82      (goto-char from)  
83      (while (< (point) to)  (defun regexp-of-hashtbl-keys (hashtbl)
84        (let ((char (following-char)))    "Returns the regular expression of hashtable keys."
85          (if (eq (char-charset char) 'indian-2-column)    (let ((max-specpdl-size 1000))
86              (progn      (regexp-opt
87                (delete-char 1)       (sort
88                (insert (devanagari-to-indian char)))        (let (dummy)
89            (forward-char 1))))))          (maphash (function (lambda (key val) (setq dummy (cons key dummy)))) hashtbl)
90            dummy)
91  ;;;###autoload        (function (lambda (x y) (> (length x) (length y))))))))
92  (defun indian-to-devanagari-string (string)  
93    "Convert Indian characters in STRING to Devanagari Basic characters."  (defun devanagari-composition-function (from to pattern &optional string)
94    (let* ((len (length string))    "Compose Devanagari characters in REGION, or STRING if specified.
95           (i 0)  Assume that the REGION or STRING must fully match the composable
96           (vec (make-vector len 0)))  PATTERN regexp."
97      (while (< i len)    (if string (devanagari-compose-syllable-string string)
98        (aset vec i (indian-to-devanagari (aref string i)))      (devanagari-compose-syllable-region from to))
99        (setq i (1+ i)))    (- to from))
100      (concat vec)))  
101    ;; Register a function to compose Devanagari characters.
102  ;; Phase 0 - Determine whether the characters can be composed.  (mapc
103  ;;   (function (lambda (ucs)
104  ;;;     (aset composition-function-table (decode-char 'ucs ucs)
105  ;;; Regular expressions to split characters for composition.           (list (cons devanagari-composable-pattern
106  ;;;                       'devanagari-composition-function)))))
107  ;;   (nconc '(#x0903) (range #x0905 #x0939) (range #x0958 #x0961)))
108  ;; Indian script word contains one or more syllables.  
109  ;; In BNF, it can be expressed as follows:  ;; Notes on conversion steps.
110  ;;  
111  ;; Word ::= {Syllable} [Cons-Syllable]  ;; 1. chars to glyphs
112  ;; Syllable ::= Cons-Vowel-Syllable | Vowel-Syllable  ;;
113  ;; Vowel-Syllable ::= V[D]  ;; Rules will not be applied to the halant appeared at the end of the
114  ;; Cons-Vowel-Syllable ::= [Cons-Syllable] Full-Cons [M] [D]  ;; text.  Also, the preceding/following "r" will be treated as special case.
115  ;; Cons-Syllable ::= [Pure-Cons] [Pure-Cons] [Pure-Cons] Pure-Cons  
116  ;; Pure-Cons ::= Full-Cons H  ;; 2. glyphs reordering.
117  ;; Full-Cons ::= C [N]  ;;
118  ;;  ;; The glyphs are split by halant, and each glyph groups are
119  ;; {} repeat, [] optional  ;; re-ordered in the following order.
120  ;;  ;;
121  ;; C - Consonant ($(5!3!4!5!6!7!8!9!:!;!<!=!>!?!@!A!B!C!D!E(B  ;; Note that `consonant-glyph' mentioned here does not contain the
122  ;;                $(5!F!G!H!I!J!K!L!M!N!O!P!Q!R!S!T!U!V!W!X(B)  ;; vertical bar (right modifier) attached at the right of the
123  ;; N - Nukta ($(5!i(B)  ;; consonant.
 ;; H - Halant($(5!h(B) or Virama  
 ;; V - Vowel ($(5!$!%!&!'!(!)!*!+!,!-!.!/!0!1!2#&#'#*(B)  
 ;;     ("$(5#&#'#*(B" can be obtained by IS13194 vowels with nukta.)  
 ;; D - Vowel Modifiers, i.e. Anuswar, Chandrabindu  ($(5!!!"(B)  
 ;;     (Visaraga ($(5!#(B) is excluded.)  
 ;; M - Matra ($(5!Z![!\!]!^!_!`!a!b!c!d!e!f!g#K#L#M(B)  
 ;;     ("$(5#K#L#M(B" can be obtained by IS13194 matras with nukta.)  
 ;;  
 ;; In Emacs, one syllable of Indian language is considered to be one  
 ;; composite glyph.  If we expand the above expression for  
 ;; cons-vowel-syllable, it would be:  
 ;;  
 ;; [[C [N] H] [C [N] H] [C [N] H] C [N] H] C [N] [M] [D]  
 ;;  
 ;; Therefore, in worst case, the one syllable may contain  
 ;; following characters.  
 ;;  
 ;; C N H C N H C N H C N H C N M D  
 ;;  
 ;; The example is a sanskrit word "kArtsnya", where five consecutive  
 ;; consonants appear.  
 ;;  
 ;; On the other hand, consonant-syllable, which appears at the end of  
 ;; the word, would have the following expression:  
 ;;  
 ;; [C [N] H] [C [N] H] [C [N] H] C [N] H  
 ;;  
 ;; This is acceptable BEFORE proper consonant-syllable is input.  The  
 ;; string which doesn't match with the above expression is invalid and  
 ;; thus must be fixed.  
 ;;  
 ;; Note:  
 ;; Third case can be considered, which is an acceptable syllable and can  
 ;; not add any code more.  
 ;;  
 ;; [[C [N] H] [C [N] H] [C [N] H] C [N] H] C [N] [M] D  
 ;;  
 ;; However, to make editing possible even in this condition, we will  
 ;; not consider about this case.  
 ;;  
 ;; Note:  
 ;; Currently, it seems that the only following consonants would have  
 ;; Nukta sign attatched.  
 ;; ($(5!3!4!5!:!?!@!I(B)  
 ;; Therefore, [$(5!3(B-$(5!X(B]$(5!i(B? can be re-written as  
 ;; \\([$(5!3!4!5!:!?!@!I(B]$(5!i(B\\)\\|[$(5!3(B-$(5!X(B]  
   
 (defconst devanagari-full-cons  
   "\\(\\([$(5!3!4!5!:!?!@!I(B]$(5!i(B\\)\\|[$(5!3(B-$(5!X$.$E"%(B]\\)"  
   "Devanagari full consonant")  
   
 (defconst devanagari-pure-cons  
   (concat "\\(" devanagari-full-cons "$(5!h(B\\)")  
   "Devanagari pure consonant")  
   
 (defconst devanagari-matra  
   "\\(\\([$(5!_![!\(B]$(5!i(B\\)\\|[$(5!Z(B-$(5!g#K#L#M(B]\\)"  
   "Devanagari Matra Signs.  '$(5#K#L#M(B' can also be created from the combination  
 of '$(5!_![!\(B' and nukta sign.")  
   
 (defconst devanagari-vowel  
   "\\(\\([$(5!*!&!'(B]$(5!i(B\\)\\|[$(5!$(B-$(5!2#&#'#*(B]\\)"  
   "Devanagari Vowels.  '$(5#&#'#*(B' can also be created from the combination  
 of '$(5!*!&!'(B' and nukta sign.")  
     
 (defconst devanagari-vowel-syllable  
   (concat devanagari-vowel "[$(5!!!"(B]?")  
   "Devanagari vowel syllable.")  
   
 (defconst devanagari-cons-syllable  
   (concat devanagari-pure-cons "?" devanagari-pure-cons "?"  
           devanagari-pure-cons "?" devanagari-pure-cons "$")  
   "Devanagari consonant syllable")  
   
 (defconst devanagari-cons-vowel-syllable  
   (concat "\\("  
           devanagari-pure-cons "?" devanagari-pure-cons "?"  
           devanagari-pure-cons "?" devanagari-pure-cons "\\)?"  
           devanagari-full-cons devanagari-matra "?[$(5!!!"(B]?")  
   "Devanagari consonant vowel syllable.")  
   
 ;;  
 ;; Also, digits and virams should be processed other than syllables.  
 ;;  
 ;; In IS 13194, Avagrah is obtained by Nukta after Viram, and  
 ;; OM is obtained by Nukta after Chandrabindu  
 ;;  
   
 (defconst devanagari-digit-viram-visarga  
  "[$(5!q(B-$(5!z!j!#(B]")  
   
 (defconst devanagari-other-sign  
   "\\([$(5!!!j(B]$(5!i(B\\)\\|\\([$(5#!#J(B]\\)")  
   
 (defconst devanagari-composite-glyph-unit  
   (concat "\\(" devanagari-cons-syllable  
           "\\)\\|\\(" devanagari-vowel-syllable  
           "\\)\\|\\(" devanagari-cons-vowel-syllable  
           "\\)\\|\\(" devanagari-other-sign  
           "\\)\\|\\(" devanagari-digit-viram-visarga "\\)")  
   "Regexp matching to Devanagari string to be composed form one glyph.")  
   
 ;;(put-charset-property charset-devanagari-1-column  
 ;;                    'char-to-glyph 'devanagari-compose-string)  
 ;;(put-charset-property charset-devanagari-2-column  
 ;;                    'char-to-glyph 'devanagari-compose-string)  
   
 ;; Sample  
 ;;  
 ;;(string-match devanagari-cons-vowel-syllable-examine "$(5!X![(B") => 0  
 ;;(string-match devanagari-cons-vowel-syllable-examine "$(5!F!h!D!\(B") => 0  
 ;;(string-match devanagari-cons-vowel-syllable-examine "$(5!X![!F!h!D!\(B") => 0  
   
 ;;  
 ;; Steps toward the composition  
 ;;  Converting Character Codes to Composite Glyph.  
 ;;  
 ;; Example : $(5!X![(B/$(5!F!h!D!\(B  
124  ;;  ;;
125  ;; First, convert Characters to appropriate glyphs.  ;; If the glyph-group contains right modifier,
126  ;;  ;;  (1) consonant-glyphs/vowels, with nukta sign
127  ;; => $(5!X![(B/$(5"F!D!\(B  ;;  (2) spacing
128  ;;  ;;  (3) right modifier (may be matra)
129  ;; Then, determine the base glyph, apply-orders and apply-rules.  ;;  (4) top matra
130  ;;  ;;  (5) preceding "r"
131  ;; => $(5!X(B (ml.mr) $(5![(B / $(5!D(B (ml.mr) $(5"F(B (mr ml) $(5!\(B  ;;  (6) anuswar
132  ;;  ;;  (7) following "r"
133  ;; Finally, convert 2-column glyphs to 1-column glyph  ;;  (8) bottom matra or halant.
 ;; if such a glyph exist.  
 ;;  
 ;; => $(6!X(B (ml.mr) $(6![(B / $(6!D(B (ml.mr) $(6"F(B (mr ml) $(6!\(B  
 ;;  
 ;; Compose the glyph.  
 ;;  
 ;; => 4$(6!Xt%![0!X![1(B/4$(6!Dt%"Fv#!\0!D"F!\1(B  
 ;; => 4$(6!Xt%![0!X![14!Dt%"Fv#!\0!D"F!\1(B  
 ;;  
   
 ;;  
 ;; Phase 1: Converting Character Code to Glyph Code.  
134  ;;  ;;
135  ;;  ;; Otherwise,
136  ;; IMPORTANT:    ;;  (1) consonant-glyph/vowels, with nukta sign
137  ;;        There may be many rules that you many want to suppress.  ;;  (3) left matra
138  ;;        In that case, please comment out that rule.  ;;  (4) top matra
139  ;;  ;;  (5) preceding "r"
140  ;;        RULES WILL BE EVALUATED FROM FIRST TO LAST.  ;;  (6) anuswar
141  ;;        PUT MORE SPECIFIC RULES FIRST.  ;;  (7) following "r"
142  ;;  ;;  (8) bottom matra or halant.
143  ;; TO DO:  ;;  (2) spacing
144  ;;        Prepare multiple specific list of rules for each languages  
145  ;;        that adopt Devanagari script.  ;; 3. glyph to glyph
146  ;;  ;;
147    ;; For better display, some glyph display would be tuned.
148  (defconst devanagari-char-to-glyph-rules  
149    '(  ;; 4. Composition.
150    ;;
151      ;; `r' at the top of syllable and followed by other consonants.  ;; left modifiers will be attached at the left.
152      ;; ("[^$(5!h(B]\\($(5!O!h(B\\)[$(5!3(B-$(5!X(B]" "$(5"p(B")  ;; others will be attached right.
153      ("^\\($(5!O!h(B\\)[$(5!3(B-$(5!X(B]" "$(5"p(B")  
154    ;; Problem::
155      ;; Ligature Rules  ;;  Can we generalize this methods to other Indian scripts?
156      ("\\($(5!3!h!B!h!O!h!M(B\\)" "$(5$!(B" sanskrit)  
157      ("\\($(5!3!h!B!h!T(B\\)" "$(5$"(B" sanskrit)  (defvar dev-char-glyph
158      ("\\($(5!3!h!B!h!M(B\\)" "$(5$#(B" sanskrit)    '(("$,15E(B" . "$,4 K(B")
159      ("\\($(5!3!h!F!h!M(B\\)" "$(5$$(B")      ("$,15F(B" . "$,4 K")(B")
160      ("\\($(5!3!h!O!h!M(B\\)" "$(5$%(B")      ("$,15~(B" . "$,4")(B")
161      ("\\($(5!3!h!O(B\\)" "$(5"#(B")                  ;                     Post "r"      ("$,15G(B" . "$,4 \(B")
162      ("\\($(5!3!h!T!h!M(B\\)" "$(5$&(B" sanskrit)      ("$,15(B" . "$,4"*(B")
163      ("\\($(5!3!h(B\\)$(5!3!h(B[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"3(B")    ; Special Half Form      ("$,155A(B" . "$,4"*(B\$,4"&(B")
164      ("\\($(5!3!h!3(B\\)" "$(5$'(B")      ("$,15H(B" . "$,4 \"'(B")
165      ("\\($(5!3!h(B\\)$(5!B!h!O(B" "$(5"3(B")              ; Special Rules for "k-tr"      ("$,15H5A(B" . "$,4 \"'"&(B")
166      ("\\($(5!3!h!B(B\\)" "$(5$((B")      ("$,16 (B" . "$,4"2(B")
167      ("\\($(5!3!h!F(B\\)" "$(5$)(B")      ("$,16 5A(B" . "$,4"2"&(B")
168      ("\\($(5!3!h!L(B\\)" "$(5$*(B")      ("$,15I(B" . "$,4 ](B")
169      ("\\($(5!3!h!M(B\\)" "$(5$+(B")      ("$,16!(B" . "$,4"6(B")
170      ("\\($(5!3!h!Q(B\\)" "$(5$,(B")      ("$,15J(B" . "$,4 ^"P(B")
171      ("\\($(5!3!h!T(B\\)" "$(5$-(B")      ("$,16"(B" . "$,4":(B")
172      ("\\($(5!3!h!V!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"l(B")    ;         Half Form      ("$,15K(B" . "$,4 `"Q(B")
173      ("\\($(5$.!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"l(B")        ;         Half Form      ("$,16#(B" . "$,4">(B")
174      ("\\($(5!3!h!V(B\\)" "$(5$.(B")      ;;("$,15L(B" . nil) ; not implemented.
175      ("\\($(5!3!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"3(B")        ;         Half Form      ("$,16$(B" . "$,4"?(B")
176      ("\\($(5!3!i!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"s(B")      ; Nukta   Half Form      ("$,15M(B" . "$,4 b"L(B")
177      ("\\($(5!3!i(B\\)" "$(5#3(B")                    ; Nukta      ("$,15M5A(B" . "$,4 b"$(B")
178      ("\\($(5!4!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"4(B")        ;         Half Form      ("$,15M5B(B" . "$,4 b"$(B")
179      ("\\($(5!4!i!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"t(B")      ; Nukta   Half Form      ("$,16%(B" . "\$,4"L(B")
180      ("\\($(5!4!i(B\\)" "$(5#4(B")                    ; Nukta      ("$,15N(B" . "$,4 b"@(B")
181      ("\\($(5!5!h!O!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"`(B")    ;         Half Form      ("$,15N5A(B" . "$,4 b"@"&(B")
182      ("\\($(5!5!h!O(B\\)" "$(5"$(B")                  ;                     Post "r"      ("$,16&(B" . "\$,4"@(B")
183      ("\\($(5!5!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"5(B")        ;         Half Form      ("$,16&5A(B" . "\$,4"@(B\$,4"&(B")
184      ("\\($(5!5!i!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"u(B")      ; Nukta   Half Form      ("$,15O(B" . "$,4 b(B")
185      ("\\($(5!5!i(B\\)" "$(5#5(B")                    ; Nukta      ("$,16'(B" . "\$,4"D(B")
186      ("\\($(5!6!h!F!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"a(B")    ;         Half Form      ("$,16'5A(B" . "\$,4"D(B\$,4"&(B")
187      ("\\($(5!6!h!F(B\\)" "$(5$/(B")      ("$,15P(B" . "$,4 b"D(B")
188      ; Slot      ("$,15P5A(B" . "$,4 b"D"&(B")
189      ("\\($(5!6!h!O(B\\)" "$(5!6"q(B")                ;                     Post "r"      ("$,16((B" . "\$,4"H(B")
190      ("\\($(5!6!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"6(B")        ;         Half Form      ("$,16(5A(B" . "\$,4"H(B\$,4"&(B")
191      ("\\($(5!7!h!3!h!B!h!M(B\\)" "$(5$0(B" sanskrit)      ("$,15Q(B" . "$,4 K")"L(B") ;; special rule for reodering.
192      ("\\($(5!7!h!3!h!V!h!T(B\\)" "$(5$1(B" sanskrit)      ("$,15Q5A(B" . "$,4 K")"$(B")
193      ("\\($(5!7!h!3!h!B(B\\)" "$(5$2(B" sanskrit)      ("$,15Q5B(B" . "$,4 K")"$(B")
194      ("\\($(5!7!h!3!h!V(B\\)" "$(5$3(B" sanskrit)      ("$,16)(B" . "\$,4")"L(B")
195      ("\\($(5!7!h!3!h!O(B\\)" "$(5$9"q(B")            ; Special Rule. May be precomposed font needed.      ("$,16)5A(B" . "\$,4")"$(B")
196      ("\\($(5!7!h!6!h!O(B\\)" "$(5$4(B" sanskrit)      ("$,16)5B(B" . "\$,4")"$(B")
197      ("\\($(5!7!h!3!h!M(B\\)" "$(5$5(B" sanskrit)      ("$,15R(B" . "$,4 K")"@(B")
198      ("\\($(5!7!h!4!h!M(B\\)" "$(5$6(B" sanskrit)      ("$,15R5A(B" . "$,4 K")"@"&(B")
199      ("\\($(5!7!h!5!h!M(B\\)" "$(5$7(B" sanskrit)      ("$,16*(B" . "\$,4")"@(B")
200      ("\\($(5!7!h!6!h!M(B\\)" "$(5$8(B" sanskrit)      ("$,16*5A(B" . "\$,4")"@"&(B")
201      ("\\($(5!7!h!3(B\\)" "$(5$9(B")      ("$,15S(B" . "$,4 K")"D(B")
202      ("\\($(5!7!h!4(B\\)" "$(5$:(B")      ("$,15S5A(B" . "$,4 K")"D"&(B")
203      ("\\($(5!7!h!5!h!O(B\\)" "$(5$;"q(B")            ; Special Rule. May be precomposed font needed.      ("$,16+(B" . "\$,4")"D(B")
204      ("\\($(5!7!h!5(B\\)" "$(5$;(B")      ("$,16+5A(B" . "\$,4")"D"&(B")
205      ("\\($(5!7!h!6(B\\)" "$(5$<(B")      ("$,15T(B" . "$,4 K")"H(B")
206      ("\\($(5!7!h!7(B\\)" "$(5$=(B")      ("$,15T5A(B" . "$,4 K")"H"&(B")
207      ("\\($(5!7!h!F(B\\)" "$(5$>(B")      ("$,16,(B" . "\$,4")"H(B")
208      ("\\($(5!7!h!L(B\\)" "$(5$?(B")      ("$,16,5A(B" . "\$,4")"H"&(B")
209      ("\\($(5!7!h!M(B\\)" "$(5$@(B")      ("$,16@(B" . "$,4 a"Q(B")
210      ("\\($(5!8!h(B\\)[$(5!8!<(B]$(5!h(B" "$(5"8(B")            ;         Half Form      ;;("$,16B(B" . nil)
211      ("\\($(5!8!h!8(B\\)" "$(5$A(B")      ;;("$,16A(B" . nil)
212      ("\\($(5!8!h!<(B\\)" "$(5$B(B")      ;;("$,16C(B" . nil)
213      ("\\($(5!8!h!O!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"8"q(B")  ;         Half Form   Post "r"  
214      ("\\($(5!8!h!O(B\\)" "$(5!8"q(B")                ;                     Post "r"      ;; GRUTTALS
215      ("\\($(5!8!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"8(B")        ;         Half Form      ("$,15U(B" . "$,4 e"R(B")
216      ("\\($(5!9!h!M(B\\)" "$(5$C(B")      ("$,15U6-(B" . "$,4 c(B")
217      ("\\($(5!:!h!O(B\\)" "$(5$D(B")      ("$,15U6-5p(B" . "$,4 g"R(B")
218      ("\\($(5!:!h!<!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"m(B")    ;         Half Form      ("$,15U6-5d(B" . "$,4 h"R(B")
219      ("\\($(5!:!h!<(B\\)" "$(5$E(B")      ("$,15U6-5w(B" . "$,4 i")(B")
220      ("\\($(5!:!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5":(B")        ;         Half Form      ("$,15U6-5w6-(B" . "$,4 i(B")
221      ("\\($(5!:!i!h!O(B\\)" "$(5"!(B")                ; Nukta               Post "r"  
222      ("\\($(5!:!i!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"z(B")      ; Nukta   Half Form      ("$,15V(B" . "$,4 j")(B")
223      ("\\($(5!:!i(B\\)" "$(5#:(B")                    ; Nukta      ("$,15V6-(B" . "$,4 j(B")
224      ("\\($(5!;!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5";(B")        ;         Half Form      ("$,15V6-5p(B" . "$,4 l")(B")
225      ("\\($(5!<!h(B\\)$(5!8!h(B[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"<(B")    ; Special Half Form      ("$,15V6-5p6-(B" . "$,4 l(B")
226      ("\\($(5!<!h!8(B\\)" "$(5$F(B")  
227      ("\\($(5!<!h(B\\)$(5!:!h(B[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"<(B")    ; Special Half Form      ("$,15W(B" . "$,4 m")(B")
228      ("\\($(5!<!h!:(B\\)" "$(5$G(B")      ("$,15W6-(B" . "$,4 m(B")
229      ("\\($(5!<!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"<(B")        ;         Half Form      ("$,15W6-5p(B" . "$,4 o")(B")
230      ("\\($(5!=!h!3(B\\)" "$(5$H(B")      ("$,15W6-5p6-(B" . "$,4 o(B")
231      ("\\($(5!=!h!=(B\\)" "$(5$I(B")  
232      ("\\($(5!=!h!>(B\\)" "$(5$J(B")      ("$,15X(B" . "$,4 p")(B")
233      ("\\($(5!=!h!M(B\\)" "$(5$K(B")      ("$,15X6-(B" . "$,4 p(B")
234      ("\\($(5!>!h!M(B\\)" "$(5$L(B")      ("$,15X6-5p(B" . "$,4 q")(B")
235      ("\\($(5!?!h!5!h!M(B\\)" "$(5$M(B" sanskrit)      ("$,15X6-5p6-(B" . "$,4 q(B")
236      ("\\($(5!?!h!6!h!O(B\\)" "$(5$N(B" sanskrit)  
237      ("\\($(5!?!h!O!h!M(B\\)" "$(5$O(B")      ("$,15Y(B" . "$,4 r"S(B")
238      ("\\($(5!?!h!5(B\\)" "$(5$P(B")      ;; PALATALS  
239      ("\\($(5!?!h!6(B\\)" "$(5$Q(B")      ("$,15Z(B" . "$,4 s")(B")
240      ("\\($(5!?!h!?(B\\)" "$(5$R(B")      ("$,15Z6-(B" . "$,4 s(B")
241      ("\\($(5!?!h!L(B\\)" "$(5$S(B")      ("$,15Z6-5p(B" . "$,4 t")(B")
242      ("\\($(5!?!h!M(B\\)" "$(5$T(B")      ("$,15Z6-5p6-(B" . "$,4 t(B")
243      ("\\($(5!?!i(B\\)" "$(5#?(B")                    ; Nukta  
244      ("\\($(5!@!h!M(B\\)" "$(5$`(B")      ("$,15[(B" . "$,4 u"T(B")
245      ("\\($(5!@!i(B\\)" "$(5#@(B")                    ; Nukta  
246      ("\\($(5!A!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"A(B")        ;         Half Form      ("$,15\(B" . "$,4 v")(B")
247      ("\\($(5!B!h(B\\)$(5!B!h!O(B" "$(5"B(B")              ; Special Rule for "t-tr"      ("$,15\6-(B" . "$,4 v(B")
248      ("\\($(5!B!h!B!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"c(B")    ;         Half Form      ("$,15\6-5p(B" . "$,4 x")(B")
249      ("\\($(5!B!h!B(B\\)" "$(5$a(B")      ("$,15\6-5p6-(B" . "$,4 x(B")
250      ("\\($(5!B!h!F(B\\)" "$(5$b(B")      ("$,15\6-5^(B" . "$,4 y")(B")
251      ("\\($(5!B!h!O!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"d(B")    ;         Half Form   Post "r"      ("$,15\6-5^6-(B" . "$,4 y(B")
252      ("\\($(5!B!h!O(B\\)" "$(5"%(B")                  ;                     Post "r"  
253      ("\\($(5!B!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"B(B")        ;         Half Form      ("$,15](B" . "$,4 z")(B")
254      ("\\($(5!C!h!O(B\\)" "$(5!C"q(B")                ;                     Post "r"      ("$,15]6-(B" . "$,4 z(B")
255      ("\\($(5!C!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"C(B")        ;         Half Form      ("$,15]6-5p(B" . "$,4 {")(B")
256      ("\\($(5!D!h!D!h!M(B\\)" "$(5$c(B")      ("$,15]6-5p6-(B" . "$,4 {(B")
257      ("\\($(5!D!h!E!h!M(B\\)" "$(5$d(B")  
258      ("\\($(5!D!h!K!h!M(B\\)" "$(5$e(B")      ("$,15^(B" . "$,4 |")(B")
259      ("\\($(5!D!h!K!h!O(B\\)" "$(5$r"r(B")            ; Special Case for "dbhr" ; ***      ("$,15^6-(B" . "$,4 |(B")
260      ("\\($(5!D!h!O!h!M(B\\)" "$(5$f(B")      ;; CEREBRALS
261      ("\\($(5!D!h!T!h!M(B\\)" "$(5$g(B")      ("$,15_(B" . "$,4 }"U(B")
262      ("\\($(5!D!h!5!h!O(B\\)" "$(5$h(B")      ("$,15_6-5_(B" . "$,4 ~"U(B")
263      ("\\($(5!D!h!6!h!O(B\\)" "$(5$i(B")      ("$,15_6-5`(B" . "$,4 "U(B")
264      ("\\($(5!D!h!D!h!T(B\\)" "$(5$j(B")  
265      ("\\($(5!D!h!E!h!T(B\\)" "$(5$k(B")      ("$,15`(B" . "$,4! "V(B")
266      ("\\($(5!D!h(B\\)$(5!E!h(B[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5!D!h(B")  ; Special Half Form (for ddhra)      ("$,15`6-5`(B" . "$,4!!"V(B")
267      ("\\($(5!D!h!5(B\\)" "$(5$l(B")  
268      ("\\($(5!D!h!6(B\\)" "$(5$m(B")      ("$,15a(B" . "$,4!""W(B")
269      ("\\($(5!D!h!D(B\\)" "$(5$n(B")      ("$,15a6-5a(B" . "$,4!$"W(B")
270      ("\\($(5!D!h!E(B\\)" "$(5$o(B")      ("$,15a6-5b(B" . "$,4!%"W(B")
271      ("\\($(5!D!h!F(B\\)" "$(5$p(B")  
272      ("\\($(5!D!h(B\\)$(5!J!h(B" "$(5!D!h(B")              ; Suppressing "db-"      ("$,15b(B" . "$,4!&"X(B")
273      ("\\($(5!D!h!J(B\\)" "$(5$q(B")  
274      ("\\($(5!D!h!K(B\\)" "$(5$r(B")      ("$,15c(B" . "$,4!(")(B")
275      ("\\($(5!D!h!L(B\\)" "$(5$s(B")      ("$,15c6-(B" . "$,4!((B")
276      ("\\($(5!D!h!M(B\\)" "$(5$t(B")      ;; DENTALS  
277      ("\\($(5!D!h!T(B\\)" "$(5$u(B")      ("$,15d(B" . "$,4!)")(B")
278      ("\\($(5!E!h!F!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"e(B")    ;         Half Form      ("$,15d6-(B" . "$,4!)(B")
279      ("\\($(5!E!h!F(B\\)" "$(5$v(B")      ("$,15d6-5p(B" . "$,4!*")(B")
280      ("\\($(5!E!h!O!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"f(B")    ;         Half Form     Post "r"      ("$,15d6-5p6-(B" . "$,4!*(B")
281      ("\\($(5!E!h!O(B\\)" "$(5!E"q(B")                ;                       Post "r"      ("$,15d6-5d(B" . "$,4!+")(B")
282      ("\\($(5!E!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"E(B")        ;         Half Form      ("$,15d6-5d6-(B" . "$,4!+(B")
283      ("\\($(5!F!h!F!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"k(B")    ;         Half Form  
284      ("\\($(5!F!h!F(B\\)" "$(5$w(B")      ("$,15e(B" . "$,4!,")(B")
285      ("\\($(5!F!h!O(B\\)" "$(5!F"q(B")      ("$,15e6-(B" . "$,4!,(B")
286      ("\\($(5!F!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"F(B")        ;         Half Form      ("$,15e6-5p(B" . "$,4!-")(B")
287      ("\\($(5!G!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"G(B")        ; Nukta   Half Form      ("$,15e6-5p6-(B" . "$,4!-(B")
288      ("\\($(5!H!h(B\\)$(5!B!h!O(B" "$(5"H(B")              ; Special Rule for "p-tr"  
289      ("\\($(5!H!h!B!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"g(B")    ;         Half Form      ("$,15f(B" . "$,4!."Y(B")
290      ("\\($(5!H!h!B(B\\)" "$(5$x(B")      ("$,15f6#(B" . "$,4!/"Y(B")
291      ("\\($(5!H!h!F(B\\)" "$(5$y(B")      ("$,15f6-5p(B" . "$,4!0"Y(B")
292      ("\\($(5!H!h!Q(B\\)" "$(5$z(B")      ("$,15f6-5f(B" . "$,4!1"Y(B")
293      ("\\($(5!H!h!O(B\\)" "$(5"&(B")                  ;                     Post "r"      ("$,15f6-5g(B" . "$,4!2"Y(B")
294      ("\\($(5!H!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"H(B")        ;         Half Form      ("$,15f6-5n(B" . "$,4!3(B")
295      ("\\($(5!I!h!O(B\\)" "$(5"'(B")                  ;                     Post "r"      ("$,15f6-5o(B" . "$,4!4(B")
296      ("\\($(5!I!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"I(B")        ;         Half Form      ("$,15f6-5u(B" . "$,4!5"Y(B")
297      ("\\($(5!I!i!h!O(B\\)" "$(5""(B")                ; Nukta               Post "r"  
298      ("\\($(5!I!i!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"y(B")      ; Nukta   Half Form      ("$,15g(B" . "$,4!6")(B")
299      ("\\($(5!I!i(B\\)" "$(5#I(B")                    ; Nukta      ("$,15g6-(B" . "$,4!6(B")
300      ("\\($(5!J!h(B\\)$(5!F!h(B[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"J(B")    ; Special Half Form      ("$,15g6-5p(B" . "$,4!7")(B")
301      ("\\($(5!J!h!F(B\\)" "$(5${(B")      ("$,15g6-5p6-(B" . "$,4!7(B")
302      ("\\($(5!J!h(B\\)$(5!J!h(B[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"J(B")    ; Special Half Form  
303      ("\\($(5!J!h!J(B\\)" "$(5$|(B")      ("$,15h(B" . "$,4!8")(B")
304      ("\\($(5!J!h(B\\)$(5!T!h(B[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"J(B")    ; Special Half Form      ("$,15h6-(B" . "$,4!8(B")
305      ("\\($(5!J!h!T(B\\)" "$(5$}(B")      ("$,15h6-5p(B" . "$,4!9")(B")
306      ("\\($(5!J!h!O(B\\)" "$(5!J"q(B")                ;                     Post "r"      ("$,15h6-5p6-(B" . "$,4!9")(B")
307      ("\\($(5!J!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"J(B")        ;         Half Form      ("$,15h6-5h(B" . "$,4!:")(B")
308      ("\\($(5!K!h!F(B\\)" "$(5$~(B")      ("$,15h6-5h6-(B" . "$,4!:(B")
309      ("\\($(5!K!h!O(B\\)" "$(5!K"q(B")                ;                     Post "r"  
310      ("\\($(5!K!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"K(B")        ;         Half Form      ("$,15i(B" . "$,4!8"#")(B")
311      ("\\($(5!L!h!F(B\\)" "$(5#P(B")      ;; LABIALS  
312      ("\\($(5!L!h!Q(B\\)" "$(5#Q(B")      ("$,15j(B" . "$,4!;")(B")
313      ("\\($(5!L!h!O(B\\)" "$(5!L"q(B")                ;                     Post "r"      ("$,15j6-(B" . "$,4!;(B")
314      ("\\($(5!L!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"L(B")        ;         Half Form      ("$,15j6-5p(B" . "$,4!<")(B")
315      ("\\($(5!M!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"M(B")        ;         Half Form      ("$,15j6-5p6-(B" . "$,4!<(B")
316      ("\\($(5!N!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"N(B")        ;         Half Form  
317      ;; special form for "ru".      ("$,15k(B" . "$,4!a"[(B")
318      ("\\($(5!O!](B\\)" "$(5",(B")      ("$,15k6-(B" . "$,4!=(B")
319      ("\\($(5!O!^(B\\)" "$(5"-(B")      ("$,15k6-5p(B" . "$,4!c"[(B")
320      ("\\($(5!P!](B\\)" "$(5".(B")  
321      ("\\($(5!P!^(B\\)" "$(5"/(B")      ("$,15l(B" . "$,4!d")(B")
322      ;;      ("$,15l6-(B" . "$,4!d(B")
323      ("\\($(5!Q!h!Q(B\\)" "$(5#`(B" sanskrit)      ("$,15l6-5p(B" . "$,4!e")(B")
324      ("\\($(5!Q!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"Q(B")        ;         Half Form      ("$,15l6-5p6-(B" . "$,4!e(B")
325      ("\\($(5!R!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"R(B")        ;         Half Form  
326      ("\\($(5!S!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"S(B")        ;         Half Form      ("$,15m(B" . "$,4!f")(B")
327      ("\\($(5!T!h!F(B\\)" "$(5#a(B")      ("$,15m6-(B" . "$,4!f(B")
328      ("\\($(5!T!h!T(B\\)" "$(5#b(B")      ("$,15m6-5p(B" . "$,4!g")(B")
329      ("\\($(5!T!h!O(B\\)" "$(5!T"q(B")                ;                     Post "r"      ("$,15m6-5p6-(B" . "$,4!g(B")
330      ("\\($(5!T!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"T(B")        ;         Half Form  
331      ("\\($(5!U!h!8!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"h(B")    ;         Half Form      ("$,15n(B" . "$,4!h")(B")
332      ("\\($(5!U!h!8(B\\)" "$(5#c(B")      ("$,15n6-(B" . "$,4!h(B")
333      ("\\($(5!U!h!F(B\\)" "$(5#d(B")      ("$,15n6-5p(B" . "$,4!i")(B")
334      ("\\($(5!U!h!J(B\\)" "$(5#e(B")      ("$,15n6-5p6-(B" . "$,4!i(B")
335      ("\\($(5!U!h!Q(B\\)" "$(5#f(B")      ;; SEMIVOWELS
336      ("\\($(5!U!h(B\\)$(5!T!h!O(B" "$(5"U(B")              ; Special Half Form      ("$,15o(B" . "$,4!j")(B")
337      ("\\($(5!U!h!T!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"j(B")    ;         Half Form      ("$,15o6-(B" . "$,4!j(B")
338  ;   ("\\($(5!U!h!T(B\\)" "$(5#g(B")      ("$,15o6-5p(B" . "$,4!k")(B")
339      ("\\($(5!U!h!O!h!T(B\\)" "$(5#g(B")      ("$,15o6-5p6-(B" . "$,4!k(B")
340      ("\\($(5!U!h!O!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"i(B")    ;         Half Form      ("$,16-5o(B" . "$,4!l(B") ;; when every ohter lig. fails.
341      ("\\($(5!U!h!O(B\\)" "$(5")(B")             ;                     Post "r"  
342      ("\\($(5!U!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"U(B")        ;         Half Form      ("$,15p(B" . "$,4!n"W(B")
343      ("\\($(5!V!h!=!h!O!h!M(B\\)" "$(5#h(B")      ;; ("$,15p6-(B" . "\$,4"'(B") ;; special case.  only the topmost pos.
344      ("\\($(5!V!h!=!h!M(B\\)" "$(5#i(B")      ("$,15q(B" . "$,4!n"#"W(B")
345      ("\\($(5!V!h!=!h!T(B\\)" "$(5#j(B")      ("$,15q6-(B" . "$,4!m(B") ;; IS 13194 speical rule.
346      ("\\($(5!V!h!=(B\\)" "$(5#k(B")      ("$,15p6!(B" . "$,4!o"[(B")
347      ("\\($(5!V!h!>(B\\)" "$(5#l(B")      ("$,15p6"(B" . "$,4!p"\(B")
348      ("\\($(5!V!h!O(B\\)" "$(5!V"q(B")                ;                     Post "r"  
349      ("\\($(5!V!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"V(B")        ;         Half Form      ("$,15r(B" . "$,4!q")(B")
350      ("\\($(5!W!h!F!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"W"F(B")  ; Special Half Form      ("$,15r6-(B" . "$,4!q(B")
351      ("\\($(5!W!h!F(B\\)" "$(5#m(B")      ("$,15s(B" . "$,4!s(B")
352      ("\\($(5!W!h!O(B\\)" "$(5#n(B")      ("$,15s6-(B" . "$,4!r(B")
353      ("\\($(5!W!h(B\\)[$(5!3(B-$(5!N!P(B-$(5!X(B]" "$(5"W(B")        ;         Half Form      ("$,15t(B" . "$,4!s"#(B")
354      ("\\($(5!X!h!A(B\\)" "$(5#p(B")      ("$,15t6-(B" . "$,4!r"#(B")
355      ("\\($(5!X!h!F(B\\)" "$(5#q(B")  
356      ("\\($(5!X!h!L(B\\)" "$(5#r(B")      ("$,15u(B" . "$,4!t")(B")
357      ("\\($(5!X!h!M(B\\)" "$(5#s(B")      ("$,15u6-(B" . "$,4!t(B")
358      ("\\($(5!X!h!O(B\\)" "$(5#t(B")      ("$,15u6-5p(B" . "$,4!u")(B")
359      ("\\($(5!X!h!Q(B\\)" "$(5#u(B")      ("$,15u6-5p6-(B" . "$,4!u(B")
360      ("\\($(5!X!h!T(B\\)" "$(5#v(B")      ;; SIBILANTS
361      ;; Special Ligature Rules      ("$,15v(B" . "$,4!v")(B")
362      ("\\($(5!X!_(B\\)" "$(5#R(B")      ("$,15v6-(B" . "$,4!v(B")
363        ("$,15v6-5u(B" . "$,4!w")(B")
364      ;; For consonants other than listed above, glyph-composition will      ("$,15v6-5u6-(B" . "$,4!w(B")
365      ;; be applied.  If the consonant which is preceding "$(5!O(B" does not      ("$,15v6-5p(B" . "$,4!x")(B")
366      ;; have the vertical line (such as "$(5!?(B"), "$(5"r(B" is put beneath the      ("$,15v6-5p6-(B" . "$,4!x(B")
367      ;; consonant.  
368      ;;      ("$,15w(B" . "$,4!y")(B")
369      ("[$(5!7!9!=!>!?!@!D!O!P!R!S!X(B]\\($(5!h!O(B\\)" "$(5"r(B")      ("$,15w6-(B" . "$,4!y(B")
370      ("[$(5!6!8!C!E!F!H!J!K!L!M!T!V(B]\\($(5!h!O(B\\)" "$(5"q(B")      ("$,15x(B" . "$,4!z")(B")
371      ("$(5!?!i(B\\($(5!h!O(B\\)" "$(5"r(B")      ("$,15x6-(B" . "$,4!z(B")
372      ("$(5!@!i(B\\($(5!h!O(B\\)" "$(5"r(B")      ("$,15x6-5p(B" . "$,4!{")(B")
373        ("$,15x6-5p6-(B" . "$,4!{(B")
374      ;; Nukta with Non-Consonants  
375      ("\\($(5!!!i(B\\)" "$(5#!(B")      ("$,15y(B" . "$,4!}(B")
376      ("\\($(5!&!i(B\\)" "$(5#&(B")      ("$,15y6-(B" . "$,4!|(B")
377      ("\\($(5!'!i(B\\)" "$(5#'(B")      ("$,15y6#(B" . "$,4!~(B")
378      ("\\($(5!*!i(B\\)" "$(5#*(B")      ("$,15y6-5p(B" . "$,4!(B")
379      ("\\($(5![!i(B\\)" "$(5#L(B")      ("$,15y6-5n(B" . "$,4" (B")
380      ("\\($(5!\!i(B\\)" "$(5#M(B")      ("$,15y6-5o(B" . "$,4"!(B")
381      ("\\($(5!_!i(B\\)" "$(5#K(B")      ;; NUKTAS    
382      ("\\($(5!j!i(B\\)" "$(5#J(B")      ("$,168(B" . "$,4 f"R"S(B")
383        ("$,1686-(B" . "$,4 d(B")
384      ;; Special rule for "r + some vowels"      ("$,169(B" . "$,4 k")(B")
385      ("\\($(5!O!_!i(B\\)" "$(5#*"p(B")      ("$,1696-(B" . "$,4 k(B")
386      ("\\($(5!O![!i(B\\)" "$(5#&"p(B")      ("$,16:(B" . "$,4 n")(B")
387      ("\\($(5!O!\!i(B\\)" "$(5#'"p(B")      ("$,16:6-(B" . "$,4 n(B")
388      ("\\($(5!O!_(B\\)" "$(5!*"p(B")      ("$,16;(B" . "$,4 w")(B")
389      ;; If everything fails, "y" will connect to the front consonant.      ("$,16;6-(B" . "$,4 w(B")
390      ("\\($(5!h!M(B\\)" "$(5"](B")      ("$,16<(B" . "$,4!#"W(B")
391        ("$,16=(B" . "$,4!'"X(B")
392        ("$,16>(B" . "$,4!b"[(B")
393        ("$,16>6-(B" . "$,4!>(B")
394        ("$,16?(B" . "$,4!j"#")(B")
395        ;; misc modifiers.
396        ("$,15A(B" . "\$,4"$(B")
397        ("$,15B(B" . "\$,4"&(B")
398        ("$,15C(B" . "$,4 F(B")
399        ("$,15|(B" . "$,4"#(B")
400        ("$,15}(B" . "$,4 E(B")
401        ("$,16-(B" . "$,4""(B")
402        ("$,16-5p(B" . "$,4"%(B") ;; following "r"
403        ;; ("$,160(B" . "$,4 D(B")
404        ;; ("$,16D(B" . "$,4 J(B")
405        ;; ("$,16F(B" . "")
406        ;; ("$,16G(B" . "")
407        ;; ("$,16H(B" . "")
408        ;; ("$,16I(B" . "")
409        ;; ("$,16J(B" . "")
410        ;; ("$,16K(B" . "")
411        ;; ("$,16L(B" . "")
412        ;; ("$,16M(B" . "")
413        ;; ("$,16N(B" . "")
414        ;; ("$,16O(B" . "")
415      )      )
416    "Alist of regexps of Devanagari character sequences vs composed characters.")    "Devanagari characters to glyphs conversion table.  
417    Default value contains only the basic rules.  You may add your own
418  (let ((rules devanagari-char-to-glyph-rules))  preferred rule from the sanskrit fonts."  )
419    (while rules  
420      (let ((rule (car rules))  (defvar dev-char-glyph-hash
421            (chars) (char) (glyphs) (glyph))    (let* ((hash (makehash 'equal)))
422        (setq rules (cdr rules))      (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
423        (string-match "\\\\(\\(.+\\)\\\\)" (car rule))            dev-char-glyph)
424        (setq chars (substring (car rule) (match-beginning 1) (match-end 1)))      hash))
425        (setq char (string-to-char chars))  
426        (setq glyphs (cdr rule))  (defvar dev-char-glyph-regexp
427        (setq glyph (string-to-char (car glyphs)))    (regexp-of-hashtbl-keys dev-char-glyph-hash))
428        (put-char-code-property  
429         char 'char-to-glyph  ;; glyph-to-glyph conversion table.
430         ;; We don't "cons" it since priority is top to down.  ;; it is supposed that glyphs are ordered in
431         (append (get-char-code-property char 'char-to-glyph) (list rule)))  ;;   [consonant/nukta] - [matra/halant] - [preceding-r] - [anuswar].
432    
433        (if (and (< ?(5z(B glyph) ; Glyphs only.  (defvar dev-glyph-glyph
434                 (null (get-char-code-property glyph 'glyph-to-char)))    '(("\$,4"'(B\$,4"&(B" . "\$,4"((B")
435                 ; One glyph may corresponds to multiple characters,      ("\$,4"'(B\$,4"$(B" . "\$,4"((B")
436                 ; e.g., surrounding vowel in Tamil, etc.      ("$,4"*(B\$,4"&(B" . "$,4"+(B")
437                 ; but for Devanagari, we put this restriction      ("$,4"*(B\$,4"'(B" . "$,4",(B")
438                 ; to make sure the fact that one glyph corresponds to one char.      ("$,4"*(B\$,4"'(B\$,4"&(B" . "$,4"-(B")
439            (put-char-code-property      ("$,4"2(B\$,4"&(B" . "$,4"3(B")
440             glyph 'glyph-to-char      ("$,4"2(B\$,4"'(B" . "$,4"4(B")
441             (cons (list (car glyphs) chars)      ("$,4"2(B\$,4"'(B\$,4"&(B" . "$,4"5(B")
442                   (get-char-code-property glyph 'glyph-to-char)      ("$,4"#(B\$,4"6(B" . "$,4"7(B")
443             ))))))      ("$,4"%(B\$,4"6(B" . "$,4"8(B")
444        ;;("$,4"6(B" . "$,4"9(B")
445  ;;      ("$,4"#(B\$,4":(B" . "$,4";(B")
446  ;; Function used in both characters-to-glyphs conversion and      ("$,4"%(B\$,4":(B" . "$,4"<(B")
447  ;; glyphs-to-characters conversion.      ;;("$,4":(B" . "$,4"=(B")
448  ;;      ("\$,4"@(B\$,4"&(B" . "\$,4"A(B")
449        ("\$,4"@(B\$,4"'(B" . "\$,4"B(B")
450  (defun max-match-len (regexp)      ("\$,4"@(B\$,4"'(B\$,4"&(B" . "\$,4"C(B")
451    "Return the maximum length of text that can match the pattern REGEXP.      ("\$,4"D(B\$,4"&(B" . "\$,4"E(B")
452  Only [...] pattern of regexp is recognized."      ("\$,4"D(B\$,4"'(B" . "\$,4"F(B")
453    (let ((len 0)      ("\$,4"D(B\$,4"'(B\$,4"&(B" . "\$,4"G(B")
454          (index 0))      ("\$,4"H(B\$,4"&(B" . "\$,4"I(B")
455      (while (string-match "\\[\\([^\]]\\)+\\]" regexp index)      ("\$,4"H(B\$,4"'(B" . "\$,4"J(B")
456        (setq len (+ len (- (match-beginning 0) index) 1)      ("\$,4"H(B\$,4"'(B\$,4"&(B" . "\$,4"K(B")
457              index (match-end 0)))      ("\$,4"L(B\$,4"&(B" . "\$,4"M(B")
458      len))      ("\$,4"L(B\$,4"'(B" . "\$,4"N(B")
459        ("\$,4"L(B\$,4"'(B\$,4"&(B" . "\$,4"O(B")
 ;; Return t iff at least one member appears in both LIST1 and LIST2.  
 (defun intersecting-p (list1 list2)  
   (let ((found nil))  
     (while (and list1 (not found))  
       (if (memq (car list1) list2)  
           (setq found t)  
         (setq list1 (cdr list1))))  
     found))  
   
 (defun string-conversion-by-rule (source symbol &rest specs)  
   "Convert string SOURCE by rules stored in SYMBOL property of each character.  
 The remaining arguments forms a list SPECS that restricts applicable rules.  
   
 The rules has the form ((REGEXP STR RULE-SPEC ...) ...).  
 Each character sequence in STRING that matches REGEXP is  
 replaced by STR.  
   
 If SPECS is nil, only rules with no RULE-SPECs is applied.  Otherwise  
 rules with no RULE-SPECS and rules that have at least one member of  
 SPECS in RULE-SPECs is applied.  
   
 Rules are tested in the order of the list, thus more specific rules  
 should be placed in front of less specific rules.  
   
 If rule is given in the forms of regexp '...\\(...\\)...', a character  
 sequence that matches the pattern inside of the parenthesis is the  
 subject of the match.  Otherwise, the entire expression is the subject  
 of the match."  
   (let ((pos 0)  
         (dst-str ""))  
     (while (< pos (length source))  
       (let ((found nil)  
             (rules (get-char-code-property  
                     (string-to-char  
                      (substring source pos)) symbol)))  
         (while rules  
           (let* ((rule (car rules))  
                  (regexp (car rule))  
                  (replace-str (car (cdr rule)))  
                  (rule-specs (cdr (cdr rule)))  
                  search-pos)  
             (if (not (or (null rule-specs)  
                          (intersecting-p specs rule-specs)))  
                 (setq rules (cdr rules))  
               (if (null (string-match "\\\\(.+\\\\)" regexp))  
                   (progn  
                     (setq regexp (concat "\\(" regexp "\\)"))  
                     (setq search-pos pos))  
                 (setq search-pos (- pos (max-match-len  
                                          (substring regexp  
                                                     (string-match "^[^\\\\]*" regexp)  
                                                     (match-end 0))))))  
               (if (< search-pos 0) (setq search-pos 0))  
               (if (string-match regexp source search-pos)  
                   (if (= (match-beginning 1) pos)  
                       (progn  
                         (setq dst-str (concat dst-str replace-str))  
                         (setq rules nil) ; Get out of the loop.  
                         (setq found t)  
                         ;; proceed `pos' for replaced characters.  
                         (setq pos (match-end 1)))  
                     (setq rules (cdr rules)))  
                 (setq rules (cdr rules))))))  
         ;; proceed to next position  
         (if (not found)  
             (setq dst-str (concat dst-str (substring source pos (1+ pos)))  
                   pos (1+ pos)))))  
     dst-str))  
   
   
 ;;  
 ;; Convert Character Code to Glyph Code  
 ;;  
   
 ;;;###autoload  
 (defun char-to-glyph-devanagari (string &rest langs)  
   "Convert Devanagari characters in STRING to Devanagari glyphs.    
 Ligatures and special rules are processed."  
   (apply  
    'string-conversion-by-rule  
    (append (list string 'char-to-glyph) langs)))  
   
 ;; Example:  
 ;;(char-to-glyph-devanagari "$(5!X![!F!h!D!\(B") => "$(5!X!["F!D!\(B"  
 ;;(char-to-glyph-devanagari "$(5!O!Z!V!h!=!h!O![!M(B") => ???  
   
 ;;  
 ;; Phase 2: Compose Glyphs to form One Glyph.  
 ;;  
   
 ;; Each list consists of glyph, application-priority and application-direction.  
 ;;  
 ;; Glyphs will be ordered from low priority number to high priority number.  
 ;; If application-priority is omitted, it is assumed to be 0.  
 ;; If application-direction is omitted, it is asumbed to be '(mr . ml).  
   
 (defconst devanagari-composition-rules  
   '((?$(5!!(B 0 (tr . br))  
     (?$(5!"(B 0 (mr . mr))  
     (?$(5!#(B 0)  
     (?$(5!$(B 0)  
     (?$(5!%(B 0)  
     (?$(5!&(B 0)  
     (?$(5!'(B 0)  
     (?$(5!((B 0)  
     (?$(5!)(B 0)  
     (?$(5!*(B 0)  
     (?$(5!+(B 0)  
     (?$(5!,(B 0)  
     (?$(5!-(B 0)  
     (?$(5!.(B 0)  
     (?$(5!/(B 0)  
     (?$(5!0(B 0)  
     (?$(5!1(B 0)  
     (?$(5!2(B 0)  
     (?$(5!3(B 0)  
     (?$(5!4(B 0)  
     (?$(5!5(B 0)  
     (?$(5!6(B 0)  
     (?$(5!7(B 0)  
     (?$(5!8(B 0)  
     (?$(5!9(B 0)  
     (?$(5!:(B 0)  
     (?$(5!;(B 0)  
     (?$(5!<(B 0)  
     (?$(5!=(B 0)  
     (?$(5!>(B 0)  
     (?$(5!?(B 0)  
     (?$(5!@(B 0)  
     (?$(5!A(B 0)  
     (?$(5!B(B 0)  
     (?$(5!C(B 0)  
     (?$(5!D(B 0)  
     (?$(5!E(B 0)  
     (?$(5!F(B 0)  
     (?$(5!G(B 0)  
     (?$(5!H(B 0)  
     (?$(5!I(B 0)  
     (?$(5!J(B 0)  
     (?$(5!K(B 0)  
     (?$(5!L(B 0)  
     (?$(5!M(B 0)  
     (?$(5!N(B 0)  
     (?$(5!O(B 0)  
     (?$(5!P(B 0)  
     (?$(5!Q(B 0)  
     (?$(5!R(B 0)  
     (?$(5!S(B 0)  
     (?$(5!T(B 0)  
     (?$(5!U(B 0)  
     (?$(5!V(B 0)  
     (?$(5!W(B 0)  
     (?$(5!X(B 0)  
     (?$(5!Y(B 0)  
     (?$(5!Z(B 0)  
     (?$(5![(B 0 (ml . mr))  
     (?$(5!\(B 0)  
     (?$(5!](B 0 (br . tr))  
     (?$(5!^(B 0 (br . tr))  
     (?$(5!_(B 0 (br . tr))  
     (?$(5!`(B 0 (mr . mr))  ; (tc . bc)  
     (?$(5!a(B 0 (mr . mr))  
     (?$(5!b(B 0 (mr . mr))  
     (?$(5!c(B 0 (mr . mr))  
     (?$(5!d(B 0)  
     (?$(5!e(B 0)  
     (?$(5!f(B 0)  
     (?$(5!g(B 0)  
     (?$(5!h(B 0 (br . tr))  
     (?$(5!i(B 0 (br . tr))  
     (?$(5!j(B 0)  
     (nil 0)  
     (nil 0)  
     (nil 0)  
     (nil 0)  
     (nil 0)  
     (nil 0)  
     (?$(5!q(B 0)  
     (?$(5!r(B 0)  
     (?$(5!s(B 0)  
     (?$(5!t(B 0)  
     (?$(5!u(B 0)  
     (?$(5!v(B 0)  
     (?$(5!w(B 0)  
     (?$(5!x(B 0)  
     (?$(5!y(B 0)  
     (?$(5!z(B 0)  
     (nil 0)  
     (nil 0)  
     (nil 0)  
     (nil 0)  
     (?$(5"!(B 0)  
     (?$(5""(B 0)  
     (?$(5"#(B 0)  
     (?$(5"$(B 0)  
     (?$(5"%(B 0)  
     (?$(5"&(B 0)  
     (?$(5"'(B 0)  
     (?$(5"((B 0)  
     (?$(5")(B 0)  
     (?$(5"*(B 0)  
     (?$(5"+(B 0)  
     (?$(5",(B 0)  
     (?$(5"-(B 0)  
     (?$(5".(B 0)  
     (?$(5"/(B 0)  
     (?$(5"0(B 0)  
     (?$(5"1(B 0)  
     (?$(5"2(B 0)  
     (?$(5"3(B 0)  
     (?$(5"4(B 0)  
     (?$(5"5(B 0)  
     (?$(5"6(B 0)  
     (?$(5"7(B 0)  
     (?$(5"8(B 0)  
     (?$(5"9(B 0)  
     (?$(5":(B 0)  
     (?$(5";(B 0)  
     (?$(5"<(B 0)  
     (?$(5"=(B 0)  
     (?$(5">(B 0)  
     (?$(5"?(B 0)  
     (?$(5"@(B 0)  
     (?$(5"A(B 0)  
     (?$(5"B(B 0)  
     (?$(5"C(B 0)  
     (?$(5"D(B 0)  
     (?$(5"E(B 0)  
     (?$(5"F(B 0)  
     (?$(5"G(B 0)  
     (?$(5"H(B 0)  
     (?$(5"I(B 0)  
     (?$(5"J(B 0)  
     (?$(5"K(B 0)  
     (?$(5"L(B 0)  
     (?$(5"M(B 0)  
     (?$(5"N(B 0)  
     (?$(5"O(B 0)  
     (?$(5"P(B 0)  
     (?$(5"Q(B 0)  
     (?$(5"R(B 0)  
     (?$(5"S(B 0)  
     (?$(5"T(B 0)  
     (?$(5"U(B 0)  
     (?$(5"V(B 0)  
     (?$(5"W(B 0)  
     (?$(5"X(B 0)  
     (?$(5"Y(B 0)  
     (?$(5"Z(B 0)  
     (?$(5"[(B 0)  
     (?$(5"\(B 0)  
     (?$(5"](B 0)  
     (?$(5"^(B 0)  
     (?$(5"_(B 0)  
     (?$(5"`(B 0)  
     (?$(5"a(B 0)  
     (?$(5"b(B 0)  
     (?$(5"c(B 0)  
     (?$(5"d(B 0)  
     (?$(5"e(B 0)  
     (?$(5"f(B 0)  
     (?$(5"g(B 0)  
     (?$(5"h(B 0)  
     (?$(5"i(B 0)  
     (?$(5"j(B 0)  
     (?$(5"k(B 0)  
     (?$(5"l(B 0)  
     (?$(5"m(B 0)  
     (?$(5"n(B 0)  
     (?$(5"o(B 0)  
     (?$(5"p(B 10 (mr . mr))  
     (?$(5"q(B 0 (br . br))  
     (?$(5"r(B 0 (br . tr))  
     (?$(5"s(B 0)  
     (?$(5"t(B 0)  
     (?$(5"u(B 0)  
     (?$(5"v(B 0)  
     (?$(5"w(B 0)  
     (?$(5"x(B 0)  
     (?$(5"y(B 0)  
     (?$(5"z(B 0)  
     (?$(5"{(B 0)  
     (?$(5"|(B 0)  
     (?$(5"}(B 0)  
     (?$(5"~(B 0)  
     (?$(5#!(B 0)  
     (?$(5#"(B 0)  
     (?$(5##(B 0)  
     (?$(5#$(B 0)  
     (?$(5#%(B 0)  
     (?$(5#&(B 0)  
     (?$(5#'(B 0)  
     (?$(5#((B 0)  
     (?$(5#)(B 0)  
     (?$(5#*(B 0)  
     (?$(5#+(B 0)  
     (?$(5#,(B 0)  
     (?$(5#-(B 0)  
     (?$(5#.(B 0)  
     (?$(5#/(B 0)  
     (?$(5#0(B 0)  
     (?$(5#1(B 0)  
     (?$(5#2(B 0)  
     (?$(5#3(B 0)  
     (?$(5#4(B 0)  
     (?$(5#5(B 0)  
     (?$(5#6(B 0)  
     (?$(5#7(B 0)  
     (?$(5#8(B 0)  
     (?$(5#9(B 0)  
     (?$(5#:(B 0)  
     (?$(5#;(B 0)  
     (?$(5#<(B 0)  
     (?$(5#=(B 0)  
     (?$(5#>(B 0)  
     (?$(5#?(B 0)  
     (?$(5#@(B 0)  
     (?$(5#A(B 0)  
     (?$(5#B(B 0)  
     (?$(5#C(B 0)  
     (?$(5#D(B 0)  
     (?$(5#E(B 0)  
     (?$(5#F(B 0)  
     (?$(5#G(B 0)  
     (?$(5#H(B 0)  
     (?$(5#I(B 0)  
     (?$(5#J(B 0)  
     (?$(5#K(B 0 (br . tr))  
     (?$(5#L(B 0 (br . tr))  
     (?$(5#M(B 0 (br . tr))  
     (?$(5#N(B 0)  
     (?$(5#O(B 0)  
     (?$(5#P(B 0)  
     (?$(5#Q(B 0)  
     (?$(5#R(B 0)  
     (?$(5#S(B 0)  
     (?$(5#T(B 0)  
     (?$(5#U(B 0)  
     (?$(5#V(B 0)  
     (?$(5#W(B 0)  
     (?$(5#X(B 0)  
     (?$(5#Y(B 0)  
     (?$(5#Z(B 0)  
     (?$(5#[(B 0)  
     (?$(5#\(B 0)  
     (?$(5#](B 0)  
     (?$(5#^(B 0)  
     (?$(5#_(B 0)  
     (?$(5#`(B 0)  
     (?$(5#a(B 0)  
     (?$(5#b(B 0)  
     (?$(5#c(B 0)  
     (?$(5#d(B 0)  
     (?$(5#e(B 0)  
     (?$(5#f(B 0)  
     (?$(5#g(B 0)  
     (?$(5#h(B 0)  
     (?$(5#i(B 0)  
     (?$(5#j(B 0)  
     (?$(5#k(B 0)  
     (?$(5#l(B 0)  
     (?$(5#m(B 0)  
     (?$(5#n(B 0)  
     (?$(5#o(B 0)  
     (?$(5#p(B 0)  
     (?$(5#q(B 0)  
     (?$(5#r(B 0)  
     (?$(5#s(B 0)  
     (?$(5#t(B 0)  
     (?$(5#u(B 0)  
     (?$(5#v(B 0)  
     (?$(5#w(B 0)  
     (?$(5#x(B 0)  
     (?$(5#y(B 0)  
     (?$(5#z(B 0)  
     (?$(5#{(B 0)  
     (?$(5#|(B 0)  
     (?$(5#}(B 0)  
     (?$(5#~(B 0)  
     (?$(5$!(B 0)  
     (?$(5$"(B 0)  
     (?$(5$#(B 0)  
     (?$(5$$(B 0)  
     (?$(5$%(B 0)  
     (?$(5$&(B 0)  
     (?$(5$'(B 0)  
     (?$(5$((B 0)  
     (?$(5$)(B 0)  
     (?$(5$*(B 0)  
     (?$(5$+(B 0)  
     (?$(5$,(B 0)  
     (?$(5$-(B 0)  
     (?$(5$.(B 0)  
     (?$(5$/(B 0)  
     (?$(5$0(B 0)  
     (?$(5$1(B 0)  
     (?$(5$2(B 0)  
     (?$(5$3(B 0)  
     (?$(5$4(B 0)  
     (?$(5$5(B 0)  
     (?$(5$6(B 0)  
     (?$(5$7(B 0)  
     (?$(5$8(B 0)  
     (?$(5$9(B 0)  
     (?$(5$:(B 0)  
     (?$(5$;(B 0)  
     (?$(5$<(B 0)  
     (?$(5$=(B 0)  
     (?$(5$>(B 0)  
     (?$(5$?(B 0)  
     (?$(5$@(B 0)  
     (?$(5$A(B 0)  
     (?$(5$B(B 0)  
     (?$(5$C(B 0)  
     (?$(5$D(B 0)  
     (?$(5$E(B 0)  
     (?$(5$F(B 0)  
     (?$(5$G(B 0)  
     (?$(5$H(B 0)  
     (?$(5$I(B 0)  
     (?$(5$J(B 0)  
     (?$(5$K(B 0)  
     (?$(5$L(B 0)  
     (?$(5$M(B 0)  
     (?$(5$N(B 0)  
     (?$(5$O(B 0)  
     (?$(5$P(B 0)  
     (?$(5$Q(B 0)  
     (?$(5$R(B 0)  
     (?$(5$S(B 0)  
     (?$(5$T(B 0)  
     (?$(5$U(B 0)  
     (?$(5$V(B 0)  
     (?$(5$W(B 0)  
     (?$(5$X(B 0)  
     (?$(5$Y(B 0)  
     (?$(5$Z(B 0)  
     (?$(5$[(B 0)  
     (?$(5$\(B 0)  
     (?$(5$](B 0)  
     (?$(5$^(B 0)  
     (?$(5$_(B 0)  
     (?$(5$`(B 0)  
     (?$(5$a(B 0)  
     (?$(5$b(B 0)  
     (?$(5$c(B 0)  
     (?$(5$d(B 0)  
     (?$(5$e(B 0)  
     (?$(5$f(B 0)  
     (?$(5$g(B 0)  
     (?$(5$h(B 0)  
     (?$(5$i(B 0)  
     (?$(5$j(B 0)  
     (?$(5$k(B 0)  
     (?$(5$l(B 0)  
     (?$(5$m(B 0)  
     (?$(5$n(B 0)  
     (?$(5$o(B 0)  
     (?$(5$p(B 0)  
     (?$(5$q(B 0)  
     (?$(5$r(B 0)  
     (?$(5$s(B 0)  
     (?$(5$t(B 0)  
     (?$(5$u(B 0)  
     (?$(5$v(B 0)  
     (?$(5$w(B 0)  
     (?$(5$x(B 0)  
     (?$(5$y(B 0)  
     (?$(5$z(B 0)  
     (?$(5${(B 0)  
     (?$(5$|(B 0)  
     (?$(5$}(B 0)  
     (?$(5$~(B 0)  
460      ))      ))
461    (defvar dev-glyph-glyph-hash
462      (let* ((hash (makehash 'equal)))
463        (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
464              dev-glyph-glyph)
465        hash))
466    (defvar dev-glyph-glyph-regexp
467      (regexp-of-hashtbl-keys dev-glyph-glyph-hash))
468    
469    
470    ;; yet another glyph-to-glyph conversions.
471    (defvar dev-glyph-glyph-2
472      '(("$,4"*(B" . "$,4".(B")
473        ("$,4"+(B" . "$,4"/(B")
474        ("$,4",(B" . "$,4"0(B")
475        ("$,4"-(B" . "$,4"1(B")))
476    (defvar dev-glyph-glyph-2-hash
477      (let* ((hash (makehash 'equal)))
478        (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
479              dev-glyph-glyph-2)
480        hash))
481    (defvar dev-glyph-glyph-2-regexp
482      (regexp-of-hashtbl-keys dev-glyph-glyph-2-hash))
483    
484    
485    (defun dev-charseq (from &optional to)
486      (if (null to) (setq to from))
487      (mapcar (function (lambda (x) (indian-glyph-char x 'devanagari)))
488              (range from to)))
489    
490    (defvar dev-glyph-cvn
491      (append
492       (dev-charseq #x2b)
493       (dev-charseq #x3c #xc1)
494       (dev-charseq #xc3))
495      "Devanagari Consonants/Vowels/Nukta Glyphs")
496    
497    (defvar dev-glyph-space
498      (dev-charseq #xf0 #xfe)
499      "Devanagari Spacing Glyphs")
500    
501    (defvar dev-glyph-right-modifier
502      (append
503       (dev-charseq #xc9)
504       (dev-charseq #xd2 #xd5))
505      "Devanagari Modifiers attached at the right side.")
506    
507    (defvar dev-glyph-right-modifier-regexp
508      (concat "[" dev-glyph-right-modifier "]"))
509    
510    (defvar dev-glyph-left-matra
511      (dev-charseq #xca #xd1)
512      "Devanagari Matras attached at the left side.")
513    
514    (defvar dev-glyph-top-matra
515      (dev-charseq #xe0 #xef)
516      "Devanagari Matras attached at the top side.")
517    
518    (defvar dev-glyph-bottom-modifier
519      (append
520       (dev-charseq #xd6 #xdf)
521       (dev-charseq #xc2))
522      "Devanagari Modifiers attached at the bottom.")
523    
524    (defvar dev-glyph-order
525      `((,dev-glyph-cvn . 1)
526        (,dev-glyph-space . 2)
527        (,dev-glyph-right-modifier . 3)
528        (,dev-glyph-left-matra . 3) ;; processed by reference point.
529        (,dev-glyph-top-matra . 4)
530        (,(dev-charseq #xc7 #xc8) . 5)
531        (,(dev-charseq #xc6) . 6)
532        (,(dev-charseq #xc5) . 7)
533        (,dev-glyph-bottom-modifier . 8)))
534    
535    (mapc
536     (function (lambda (x)
537       (mapc
538         (function (lambda (y)
539           (put-char-code-property y 'composition-order (cdr x))))
540         (car x))))
541      dev-glyph-order)
542    
543    (mapc
544      (function (lambda (x)
545        (put-char-code-property x 'reference-point '(3 . 5))))
546     dev-glyph-left-matra)
547    
548    (defun devanagari-compose-syllable-string (string)
549      (with-temp-buffer
550        (insert (decompose-string string))
551        (devanagari-compose-syllable-region (point-min) (point-max))
552        (buffer-string)))
553    
554    (defun devanagari-compose-syllable-region (from to)
555      "Compose devanagari syllable in region FROM to TO."
556      (let ((glyph-str nil) (cons-num 0) glyph-str-list
557            (last-halant nil) (preceding-r nil) (last-modifier nil)
558            (last-char (char-before to)) match-str
559            glyph-block split-pos)
560        (save-excursion
561          (save-restriction
562              ;;; *** char-to-glyph conversion ***
563            ;; Special rule 1. -- Last halant must be preserved.
564            (if (eq last-char ?$,16-(B)
565                (progn
566                  (setq last-halant t)
567                  (narrow-to-region from (1- to)))
568              (narrow-to-region from to)
569              ;; note if the last char is modifier.
570              (if (or (eq last-char ?$,15A(B) (eq last-char ?$,15B(B))
571                  (setq last-modifier t)))
572            (goto-char (point-min))
573            ;; Special rule 2. -- preceding "r halant" must be modifier.
574            (when (looking-at "$,15p6-(B.")
575              (setq preceding-r t)
576              (goto-char (+ 2 (point))))
577            ;; translate the rest characters into glyphs
578            (while (re-search-forward dev-char-glyph-regexp nil t)
579              (setq match-str (match-string 0))
580              (setq glyph-str
581                    (concat glyph-str
582                            (gethash match-str dev-char-glyph-hash)))
583              ;; count the number of consonant-glyhs.
584              (if (string-match devanagari-consonant match-str)
585                  (setq cons-num (1+ cons-num))))
586            ;; preceding-r must be attached before the anuswar if exists.
587            (if preceding-r
588                (if last-modifier
589                    (setq glyph-str (concat (substring glyph-str 0 -1)
590                                            "$,4"'(B" (substring glyph-str -1)))
591                  (setq glyph-str (concat glyph-str "$,4"'(B"))))
592            (if last-halant (setq glyph-str (concat glyph-str "$,4""(B")))
593              ;;; *** glyph-to-glyph conversion ***
594            (when (string-match dev-glyph-glyph-regexp glyph-str)
595              (setq glyph-str
596                    (replace-match (gethash (match-string 0 glyph-str)
597                                            dev-glyph-glyph-hash)
598                                   nil t glyph-str))
599              (if (and (> cons-num 1)
600                       (string-match dev-glyph-glyph-2-regexp glyph-str))
601                  (setq glyph-str
602                        (replace-match (gethash (match-string 0 glyph-str)
603                                                dev-glyph-glyph-2-hash)
604                                       nil t glyph-str))))
605              ;;; *** glyph reordering ***
606            (while (setq split-pos (string-match "$,4""(B\\|.$" glyph-str))
607              (setq glyph-block (substring glyph-str 0 (1+ split-pos)))
608              (setq glyph-str (substring glyph-str (1+ split-pos)))
609              (setq
610               glyph-block
611               (if (string-match dev-glyph-right-modifier-regexp glyph-block)
612                   (sort (string-to-list glyph-block)
613                         (function (lambda (x y)
614                            (< (get-char-code-property x 'composition-order)
615                               (get-char-code-property y 'composition-order)))))
616                 (sort (string-to-list glyph-block)
617                       (function (lambda (x y)
618                          (let ((xo (get-char-code-property x 'composition-order))
619                                (yo (get-char-code-property y 'composition-order)))
620                            (if (= xo 2) nil (if (= yo 2) t (< xo yo)))))))))
621              (setq glyph-str-list (nconc glyph-str-list glyph-block)))
622              ;; concatenate and attach reference-points.
623            (setq glyph-str
624                  (cdr
625                   (apply
626                    'nconc
627                    (mapcar
628                     (function (lambda (x)
629                       (list
630                        (or (get-char-code-property x 'reference-point)
631                        '(5 . 3) ;; default reference point.
632                         )
633                        x)))
634                     glyph-str-list))))))
635          (compose-region from to glyph-str)))
636    
 ;; Determine composition priority and rule of the array of Glyphs.  
 ;; Sort the glyphs with their priority.  
   
 (defun devanagari-reorder-glyphs-for-composition (string start end)  
   (let ((pos start)  
         (ordered-glyphs nil))  
     (while (< pos end)  
       (let ((glyph (aref string pos)))  
         (setq pos (1+ pos))  
         (setq ordered-glyphs  
               (append ordered-glyphs  
                       (list (assq glyph devanagari-composition-rules))))))  
     (sort ordered-glyphs '(lambda (x y) (< (car (cdr x)) (car (cdr y)))))))  
   
 ! ;;(devanagari-compose-to-one-glyph "$(5"5!X![(B") => "4$(6!Xv#"5t%![0!X"5![1(B"  
   
 (defun devanagari-compose-to-one-glyph (devanagari-string)  
   (let* ((o-glyph-list (devanagari-reorder-glyphs-for-composition  
                         devanagari-string 0 (length devanagari-string)))  
          ;; List of glyphs to be composed.  
          (cmp-glyph-list (list (car (car o-glyph-list))))  
          (o-glyph-list (cdr o-glyph-list)))  
     (while o-glyph-list  
       (let* ((o-glyph (car o-glyph-list))  
              (glyph (if (< 2 (length o-glyph))  
                         ;; default composition  
                         (list (car (cdr (cdr o-glyph))) (car o-glyph))  
                       ;; composition with a specified rule  
                       (list '(mr . ml) (car o-glyph)))))  
         (setq o-glyph-list (cdr o-glyph-list))  
         (setq cmp-glyph-list (append cmp-glyph-list glyph))))  
     ;; Before applying compose-chars, convert glyphs to  
     ;; 1-column width if possible.  
     (setq cmp-glyph-list (devanagari-wide-to-narrow cmp-glyph-list))  
     (if (= (length cmp-glyph-list) 1) (char-to-string (car cmp-glyph-list))  
       (apply 'compose-chars cmp-glyph-list))))  
   
 (defun devanagari-composition-component (string &optional start end)  
   (or start (setq start 0))  
   (or end (setq end (length string)))  
   (let* ((o-glyph-list (devanagari-reorder-glyphs-for-composition  
                         string start end))  
          ;; List of glyphs to be composed.  
          (cmp-glyph-list (list (car (car o-glyph-list)))))  
     (setq o-glyph-list (cdr o-glyph-list))  
     (while o-glyph-list  
       (let* ((o-glyph (car o-glyph-list))  
              (glyph (if (< 2 (length o-glyph))  
                         ;; default composition  
                         (list (car (cdr (cdr o-glyph))) (car o-glyph))  
                       ;; composition with a specified rule  
                       (list '(mr . ml) (car o-glyph)))))  
         (setq o-glyph-list (cdr o-glyph-list))  
         (setq cmp-glyph-list (append cmp-glyph-list glyph))))  
     ;; Convert glyphs to 1-column width if possible.  
     (devanagari-wide-to-narrow cmp-glyph-list)))  
   
 ;; Utility function for Phase 2.5  
   
 ;; Check whether GLYPH is a Devanagari vertical modifier or not.  
 ;; If it is a vertical modifier, whether it should be 1-column shape or not  
 ;; depends on previous non-vertical modifier.  
 (defun devanagari-vertical-modifier-p (glyph)  
   (string-match (char-to-string glyph)  
                 "[$(5!"!]!^!_!`!a!b!c!h!i"p"q"r#K#L#M(B]"))  
   
 (defun devanagari-non-vertical-modifier-p (glyph)  
   (string-match (char-to-string glyph)  
 ;               "[$(5!Z![!\!d!e!f!g(B]"))  
                 "[$(5![(B]"))  
   
 (defun devanagari-wide-to-narrow-char (char)  
   "Convert Devanagari character CHAR to the corresponding narrow character.  
 If there's no corresponding narrow character, return CHAR as is."  
   (let ((narrow (cdr (assq char devanagari-1-column-char))))  
     (or narrow char)))  
   
 ;;  
 ;;    Phase 2.5  Convert appropriate character to 1-column shape.  
 ;;  
 ;; This is temporary and should be removed out when Emacs supports  
 ;; variable width characters.  
 ;;  
 ;; This will convert the composing glyphs (2 column glyphs)  
 ;; to narrow (1 column) glyphs if they exist.  
 ;;  
 ;; devanagari-wide-to-narrow-old converts glyphs simply.  
 ;; devanagari-wide-to-narrow takes care of upper/lower apply-glyphs  
 ;;   with 2 column base-glyph.  
 ;;  
 ;; Execution Examples  
 ;;(devanagari-wide-to-narrow '(?$(5!3(B (ml . ml) ?$(5!a(B))  
 ;;(devanagari-wide-to-narrow '(?$(5!F(B (ml . ml) ?$(5!a(B))  
   
 (defun devanagari-wide-to-narrow (src-list)  
   (devanagari-wide-to-narrow-iter src-list t))  
   
 (defun devanagari-wide-to-narrow-iter (src-list 2-col-glyph)  
   (let ((glyph (car src-list)))  
     (cond ((null src-list) '())  
           ; not glyph code  
           ((not (numberp glyph))  
            (cons glyph  
                  (devanagari-wide-to-narrow-iter (cdr src-list) 2-col-glyph)))  
           ; glyphs to be processed regardless of the value of "2-col-glyph"  
           ((devanagari-non-vertical-modifier-p glyph)  
            (cons (devanagari-wide-to-narrow-char glyph)  
                  (devanagari-wide-to-narrow-iter (cdr src-list) 2-col-glyph)))  
           ; glyphs which are depends on the value of "2-col-glyph"  
           ((devanagari-vertical-modifier-p glyph)  
            (if 2-col-glyph  
                (cons glyph  
                      (devanagari-wide-to-narrow-iter (cdr src-list) t))  
                (cons (devanagari-wide-to-narrow-char glyph)  
                      (devanagari-wide-to-narrow-iter (cdr src-list)  
                                                      2-col-glyph))))  
           ; normal glyph  
           (t  
            (if (cdr (assq glyph devanagari-1-column-char))  
                (cons (devanagari-wide-to-narrow-char glyph)  
                      (devanagari-wide-to-narrow-iter (cdr src-list) nil))  
                (cons glyph  
                      (devanagari-wide-to-narrow-iter (cdr src-list) t)))))))  
   
   
 ;;  
 ;; Summary  
 ;;  
   
 ;;  
 ;; Decomposition of composite sequence.  
 ;;  
   
 ;;;###autoload  
 (defun devanagari-decompose-string (str)  
   "Decompose Devanagari string STR"  
   (decompose-string (copy-sequence str)))  
   
 ;;;###autoload  
 (defun devanagari-decompose-region (from to)  
   (interactive "r")  
   (decompose-region from to))  
   
 ;;;  
 ;;; Composition  
 ;;;  
   
 ;;;###autoload  
 (defun devanagari-compose-string (str &rest langs)  
   (setq str (copy-sequence str))  
   (let ((idx 0)  
         rest match-b match-e)  
     (while (string-match devanagari-composite-glyph-unit str idx)  
       (let* ((match-b (match-beginning 0))  
              (match-e (match-end 0))  
              (cmps (devanagari-composition-component  
                     (apply  
                      'char-to-glyph-devanagari  
                      (cons (substring str match-b match-e) langs)))))  
         (compose-string str match-b match-e cmps)  
         (setq idx match-e))))  
   str)  
   
 ;;;###autoload  
 (defun devanagari-compose-region (from to &rest langs)  
   (interactive "r")  
   (save-excursion  
     (save-restriction  
       (narrow-to-region from to)  
       (goto-char (point-min))  
       (while (re-search-forward devanagari-composite-glyph-unit nil t)  
         (let* ((match-b (match-beginning 0)) (match-e (match-end 0))  
                (cmps (devanagari-composition-component  
                       (apply  
                        'char-to-glyph-devanagari  
                        (cons (buffer-substring match-b match-e) langs)))))  
           (compose-region match-b match-e cmps))))))  
   
 ;; For pre-write and post-read conversion  
   
 ;;;###autoload  
 (defun devanagari-compose-from-is13194-region (from to)  
   "Compose IS 13194 characters in the region to Devanagari characters."  
   (interactive "r")  
   (save-excursion  
     (save-restriction  
       (narrow-to-region from to)  
       (indian-to-devanagari-region (point-min) (point-max))  
       (devanagari-compose-region (point-min) (point-max))  
       (- (point-max) (point-min)))))  
   
 ;;;###autoload  
 (defun in-is13194-devanagari-post-read-conversion (len)  
   (let ((pos (point)))  
     (devanagari-compose-from-is13194-region pos (+ pos len))))  
   
 ;;;###autoload  
 (defun devanagari-decompose-to-is13194-region (from to)  
   "Decompose Devanagari characters in the region to IS 13194 characters."  
   (interactive "r")  
   (save-excursion  
     (save-restriction  
       (narrow-to-region from to)  
       (devanagari-decompose-region (point-min) (point-max))  
       (devanagari-to-indian-region (point-min) (point-max)))))  
   
 ;;;###autoload  
 (defun in-is13194-devanagari-pre-write-conversion (from to)  
   (let ((old-buf (current-buffer)))  
     (set-buffer (generate-new-buffer " *temp*"))  
     (if (stringp from)  
         (insert from)  
       (insert-buffer-substring old-buf from to))  
     (devanagari-decompose-to-is13194-region (point-min) (point-max))  
     ;; Should return nil as annotations.  
     nil))  
   
 ;; For input/output of ITRANS  
   
 ;;;###autoload  
 (defun devanagari-encode-itrans-region (from to)  
   (interactive "r")  
   (save-restriction  
     (narrow-to-region from to)  
     (devanagari-decompose-to-is13194-region (point-min) (point-max))  
     (indian-encode-itrans-region (point-min) (point-max))))  
   
 ;;;###autoload  
 (defun devanagari-decode-itrans-region (from to)  
   (interactive "r")  
   (save-restriction  
     (narrow-to-region from to)  
     (indian-decode-itrans-region (point-min) (point-max))  
     (devanagari-compose-from-is13194-region (point-min) (point-max))))  
   
 ;;  
637  (provide 'devan-util)  (provide 'devan-util)
   
 ;; Local Variables:  
 ;; coding: iso-2022-7bit  
 ;; End:  
   
 ;;; devan-util.el ends here  

Legend:
Removed from v.1.25  
changed lines
  Added in v.1.26

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26