]> git.eshelyaron.com Git - emacs.git/commitdiff
New file.
authorKenichi Handa <handa@m17n.org>
Sat, 8 Nov 2003 01:40:48 +0000 (01:40 +0000)
committerKenichi Handa <handa@m17n.org>
Sat, 8 Nov 2003 01:40:48 +0000 (01:40 +0000)
lisp/language/kannada.el [new file with mode: 0644]
lisp/language/knd-util.el [new file with mode: 0644]

diff --git a/lisp/language/kannada.el b/lisp/language/kannada.el
new file mode 100644 (file)
index 0000000..06f7719
--- /dev/null
@@ -0,0 +1,46 @@
+;;; kannada.el --- Support for Kannada -*- coding: iso-2022-7bit; no-byte-compile: t -*-
+
+;; Copyright (C) 2003 Free Software Foundation, Inc.
+
+;; Maintainer:  CHOWKSEY, Kailash C. <klchxbec@m-net.arbornet.org>
+;; Keywords: multilingual, Indian, Kannada
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This file defines language-info of Kannada script.
+
+;;; Code:
+
+(set-language-info-alist
+ "Kannada" '((charset mule-unicode-0100-24ff indian-is13194
+                         indian-2-column indian-glyph ;; comment out later
+                         )
+               (coding-system mule-utf-8)
+               (coding-priority mule-utf-8)
+               (input-method . "kannada-itrans")
+               (features knd-util)
+               (documentation . "\
+Kannada language and script is supported in this language
+environment.")) 
+ '("Indian"))
+
+(provide 'kannada)
+
+;;; kannada.el ends here
diff --git a/lisp/language/knd-util.el b/lisp/language/knd-util.el
new file mode 100644 (file)
index 0000000..e0aa219
--- /dev/null
@@ -0,0 +1,540 @@
+;;; knd-util.el --- Support for composing Kannada characters
+
+;; Copyright (C) 2003 Free Software Foundation, Inc.
+
+;; Maintainer:  Maintainer:  CHOWKSEY, Kailash C. <klchxbec@m-net.arbornet.org>
+;; Keywords: multilingual, Kannada
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;; Created: Jul. 14. 2003
+
+;;; Commentary:
+
+;; This file provides character(Unicode) to glyph(CDAC) conversion and
+;; composition of Kannada script characters.
+
+;;; Code:
+
+;;;###autoload
+
+;; Kannada Composable Pattern
+;;    C .. Consonants
+;;    V .. Vowel
+;;    H .. Virama
+;;    M .. Matra
+;;    V .. Vowel
+;;    (N .. Zerowidth Non Joiner)
+;;    (J .. Zerowidth Joiner.  )
+;; 1. vowel
+;;  V(A)?
+;; 2. syllable : maximum of 5 consecutive consonants.  (e.g. kartsnya)
+;;  ((CH)?(CH)?(CH)?CH)?C(H|M?)?
+
+(defconst kannada-consonant
+  "[\e$,1>u\e(B-\e$,1?9\e(B]")
+
+(defconst kannada-consonant-needs-twirl
+  "[\e$,1>u>w\e(B-\e$,1>{>}\e(B-\e$,1>~? \e(B-\e$,1?"?$\e(B-\e$,1?+?-?0?3\e(B-\e$,1?9\e(B]\\(\e$,1?M\e(B[\e$,1>u\e(B-\e$,1?9\e(B]\\)*[\e$,1?A?B?C?D>b\e(B]?$")
+
+(defconst kannada-composable-pattern
+  (concat
+   "\\([\e$,1>b\e(B-\e$,1>t?`>l\e(B]\\)\\|[\e$,1>c\e(B]"
+   "\\|\\("
+   "\\(?:\\(?:[\e$,1>u\e(B-\e$,1?9\e(B]\e$,1?M\e(B\\)?\\(?:[\e$,1>u\e(B-\e$,1?9\e(B]\e$,1?M\e(B\\)?\\(?:[\e$,1>u\e(B-\e$,1?9\e(B]\e$,1?M\e(B\\)?[\e$,1>u\e(B-\e$,1?9\e(B]\e$,1?M\e(B\\)?"
+   "[\e$,1>u\e(B-\e$,1?9\e(B]\\(?:\e$,1?M\e(B\\|[\e$,1?>\e(B-\e$,1?M?U?C\e(B]?\\)?"
+   "\\)")
+  "Regexp matching a composable sequence of Kannada characters.")
+
+(defun kannada-compose-region (from to)
+  (interactive "r")
+  (save-excursion
+    (save-restriction
+      (narrow-to-region from to)
+      (goto-char (point-min))
+      (while (re-search-forward kannada-composable-pattern nil t)
+        (kannada-compose-syllable-region (match-beginning 0)
+                                            (match-end 0))))))
+(defun kannada-compose-string (string)
+  (with-temp-buffer
+    (insert (decompose-string string))
+    (kannada-compose-region (point-min) (point-max))
+    (buffer-string)))
+
+(defun kannada-post-read-conversion (len)
+  (save-excursion
+    (save-restriction
+      (let ((buffer-modified-p (buffer-modified-p)))
+       (narrow-to-region (point) (+ (point) len))
+       (kannada-compose-region (point-min) (point-max))
+       (set-buffer-modified-p buffer-modified-p)
+       (- (point-max) (point-min))))))
+
+(defun kannada-range (from to)
+  "Make the list of the integers of range FROM to TO."
+  (let (result)
+    (while (<= from to) (setq result (cons to result) to (1- to))) result))
+
+(defun kannada-regexp-of-hashtbl-keys (hashtbl)
+  "Return a regular expression that matches all keys in hashtable HASHTBL."
+  (let ((max-specpdl-size 1000))
+    (regexp-opt
+     (sort
+      (let (dummy)
+       (maphash (function (lambda (key val) (setq dummy (cons key dummy)))) hashtbl)
+       dummy)
+      (function (lambda (x y) (> (length x) (length y))))))))
+
+(defun kannada-regexp-of-hashtbl-vals (hashtbl)
+  "Return a regular expression that matches all values in hashtable HASHTBL."
+  (let ((max-specpdl-size 1000))
+    (regexp-opt
+     (sort
+      (let (dummy)
+       (maphash (function (lambda (key val) (setq dummy (cons val dummy)))) hashtbl)
+       dummy)
+      (function (lambda (x y) (> (length x) (length y))))))))
+
+(defun kannada-composition-function (from to pattern &optional string)
+  "Compose Kannada characters in REGION, or STRING if specified.
+Assume that the REGION or STRING must fully match the composable
+PATTERN regexp."
+  (if string (kannada-compose-syllable-string string)
+    (kannada-compose-syllable-region from to))
+  (- to from))
+
+;; Register a function to compose Kannada characters.
+(mapc
+ (function (lambda (ucs)
+   (aset composition-function-table (decode-char 'ucs ucs)
+        (list (cons kannada-composable-pattern
+                     'kannada-composition-function)))))
+ (kannada-range #x0c80 #x0cff))
+
+;; Notes on conversion steps.
+
+;; 1. chars to glyphs
+;;
+;; Rules will not be applied to the virama appeared at the end of the
+;; text.  Also, the preceding/following "r" will be treated as special case.
+
+;; 2. glyphs reordering.
+;;
+;; The glyphs are split by virama, and each glyph groups are
+;; re-ordered in the following order.
+;;
+;; Note that `consonant-glyph' mentioned here does not contain the
+;; vertical bar (right modifier) attached at the right of the
+;; consonant.
+;;
+;; If the glyph-group contains right modifier,
+;;  (1) consonant-glyphs/vowels
+;;  (2) spacing
+;;  (3) right modifier (may be matra)
+;;  (4) top matra
+;;  (5) preceding "r"
+;;  (7) following "r"
+;;  (8) bottom matra or virama.
+;;
+;; Otherwise,
+;;  (1) consonant-glyph/vowels, with nukta sign
+;;  (3) left matra
+;;  (4) top matra
+;;  (5) preceding "r"
+;;  (7) following "r"
+;;  (8) bottom matra or virama.
+;;  (2) spacing
+
+;; 3. glyph to glyph
+;;
+;; For better display, some glyph display would be tuned.
+
+;; 4. Composition.
+;;
+;; left modifiers will be attached at the left.
+;; others will be attached right.
+
+;; Problem::
+;;  Can we generalize this methods to other Indian scripts?
+
+(defvar knd-char-glyph
+  '(("\e$,1>e\e(B" . "\e$,43@\e(B")
+    ("\e$,1>f\e(B" . "\e$,43A\e(B")
+    ("\e$,1?>\e(B" . "\e$,44{\e(B")
+    ("\e$,1>g\e(B" . "\e$,43B\e(B")
+    ("\e$,1??\e(B" . nil)
+    ("\e$,1>h\e(B" . "\e$,43C\e(B")
+    ("\e$,1?@\e(B" . nil)
+    ("\e$,1>i\e(B" . "\e$,43D\e(B")
+    ("\e$,1?A\e(B" . "\\e$,44\7f\e(B")
+    ("\e$,1>j\e(B" . "\e$,43E\e(B")
+    ("\e$,1?B\e(B" . "\\e$,45 \e(B")
+    ("\e$,1>k\e(B" . "\e$,43F4\7f\e(B")
+    ("\e$,1?C\e(B" . "\\e$,45$\e(B")
+    ("\e$,1?`\e(B" . "\e$,43F5 \e(B")
+    ("\e$,1?D\e(B" . "\\e$,45%\e(B")
+    ;;("\e$,1>l\e(B" . nil) ; not implemented.
+    ;;("\e$,1?a\e(B" . nil)
+    ("\e$,1>n\e(B" . "\e$,43G\e(B")
+    ("\e$,1>o\e(B" . "\e$,43H\e(B")
+    ("\e$,1>p\e(B" . "\e$,43I\e(B")
+    ("\e$,1?F\e(B" . "\\e$,45&\e(B")
+    ("\e$,1?G\e(B" . "\\e$,45&4~\e(B")
+    ("\e$,1?H\e(B" . "\\e$,45&5'\e(B")
+    ("\e$,1>r\e(B" . "\e$,43J\e(B")
+    ("\e$,1?J\e(B" . "\e$,45&5 \e(B")
+    ("\e$,1>s\e(B" . "\e$,43K\e(B")
+    ("\e$,1?K\e(B" . "\\e$,45&5 4~\e(B")
+    ("\e$,1>t\e(B" . "\e$,43L\e(B")
+    ("\e$,1?L\e(B" . "\\e$,45(\e(B")
+    ("\e$,1>b\e(B" . "\e$,43M\e(B")
+    ("\e$,1>c\e(B" . "\e$,43N\e(B")
+    ("\e$,1>u?M\e(B" . "\e$,43O5)\e(B") ("\e$,1>u\e(B" . "\e$,43O\e(B") ("\e$,1>u??\e(B" . "\e$,43P\e(B") ("\e$,1>u?@\e(B" . "\e$,43P4~\e(B")
+    ("\e$,1>v?M\e(B" . "\e$,43S5)\e(B") ("\e$,1>v\e(B" .  "\e$,43S\e(B") ("\e$,1>v??\e(B" . "\e$,43T\e(B") ("\e$,1>v?@\e(B" . "\e$,43T4~\e(B") ("\e$,1>v?F\e(B" . "\e$,43S5&\e(B") ("\e$,1>v?G\e(B" . "\e$,43S5&4~\e(B") ("\e$,1>v?H\e(B" . "\e$,43S5&5'\e(B") ("\e$,1>v?J\e(B" .  "\e$,43S5&5&5 \e(B") ("\e$,1>v?K\e(B" . "\e$,43S5&5&5 4~\e(B") ("\e$,1>v?L\e(B" . "\e$,43S5(\e(B")
+    ("\e$,1>w?M\e(B" . "\e$,43V5)\e(B") ("\e$,1>w\e(B" . "\e$,43V\e(B") ("\e$,1>w??\e(B" . "\e$,43W\e(B") ("\e$,1>w?@\e(B" . "\e$,43W4~\e(B")
+    ("\e$,1>x?M\e(B" . "\e$,43Y5)\e(B") ("\e$,1>x\e(B" . "\e$,43Y\e(B") ("\e$,1>x??\e(B" . "\e$,43Z\e(B") ("\e$,1>x?@\e(B" . "\e$,43Z4~\e(B")
+    ("\e$,1>y?M\e(B" . "\e$,43\5)\e(B") ("\e$,1>y\e(B" . "\e$,43\\e(B")
+    ("\e$,1>z?M\e(B" . "\e$,43^5)\e(B") ("\e$,1>z\e(B" . "\e$,43^\e(B") ("\e$,1>z??\e(B" . "\e$,43_\e(B") ("\e$,1>z?@\e(B" . "\e$,43_4~\e(B")
+    ("\e$,1>{?M\e(B" . "\e$,43a5)\e(B") ("\e$,1>{\e(B" . "\e$,43a\e(B") ("\e$,1>{??\e(B" . "\e$,43b\e(B") ("\e$,1>{?@\e(B" . "\e$,43b4~\e(B")
+    ("\e$,1>|?M\e(B" . "\e$,43d5)\e(B") ("\e$,1>|\e(B" . "\e$,43d\e(B") ("\e$,1>|??\e(B" . "\e$,43f\e(B") ("\e$,1>|?@\e(B" . "\e$,43f4~\e(B") ("\e$,1>|?F\e(B" . "\e$,43e5&\e(B") ("\e$,1>|?G\e(B" . "\e$,43e5&4~\e(B") ("\e$,1>|?H\e(B" . "\e$,43e5&5'\e(B") ("\e$,1>|?J\e(B" .  "\e$,43e5&5&5 \e(B") ("\e$,1>|?K\e(B" . "\e$,43e5&5&5 4~\e(B") ("\e$,1>|?L\e(B" . "\e$,43e5(\e(B")
+    ("\e$,1>}?M\e(B" . "\e$,44a4z3h4\7f5)\e(B") ("\e$,1>}\e(B" . "\e$,44a4z3h4\7f\e(B") ("\e$,1>}??\e(B" . "\e$,44b3h4\7f\e(B") ("\e$,1>}?@\e(B" . "\e$,44b3h4\7f4~\e(B") ("\e$,1>}?B\e(B". "\e$,44a4z3h5 \e(B") ("\e$,1>}?J\e(B". "\e$,44a5&3h5 \e(B") ("\e$,1>}?K\e(B". "\e$,44a5&3h5 4~\e(B")
+    ("\e$,1>~?M\e(B" . "\e$,43j5)\e(B") ("\e$,1>~\e(B" . "\e$,43j\e(B")
+    ("\e$,1>\7f?M\e(B" . "\e$,43m5)\e(B") ("\e$,1>\7f\e(B" . "\e$,43l\e(B") ("\e$,1?#?>\e(B" . "\e$,43m4{\e(B") ("\e$,1>\7f??\e(B" . "\e$,43n\e(B") ("\e$,1>\7f?@\e(B" . "\e$,43n4~\e(B") ("\e$,1>\7f?F\e(B" . "\e$,43m5&\e(B") ("\e$,1>\7f?G\e(B" . "\e$,43m5&4~\e(B") ("\e$,1>\7f?H\e(B" . "\e$,43m5&5'\e(B") ("\e$,1>\7f?J\e(B" .  "\e$,43m5&5&5 \e(B") ("\e$,1>\7f?K\e(B" . "\e$,43m5&5&5 4~\e(B") ("\e$,1>\7f?L\e(B" . "\e$,43m5(\e(B")
+    ("\e$,1? ?M\e(B" . "\e$,43p5)\e(B") ("\e$,1? \e(B" . "\e$,43p\e(B") ("\e$,1? ??\e(B" . "\e$,43q\e(B") ("\e$,1? ?@\e(B" . "\e$,43q4~\e(B")
+    ("\e$,1?!?M\e(B" . "\e$,43s5)\e(B") ("\e$,1?!\e(B" . "\e$,43s\e(B") ("\e$,1?!??\e(B" . "\e$,43t\e(B") ("\e$,1?!?@\e(B" . "\e$,43t4~\e(B")
+    ("\e$,1?"?M\e(B" . "\e$,43v5)\e(B") ("\e$,1?"\e(B" . "\e$,43v\e(B") ("\e$,1?"??\e(B" . "\e$,43w\e(B") ("\e$,1?"?@\e(B" . "\e$,43w4~\e(B")
+    ("\e$,1?#?M\e(B" . "\e$,43z5)\e(B") ("\e$,1?#\e(B" . "\e$,43y\e(B") ("\e$,1?#?>\e(B" . "\e$,43z4{\e(B") ("\e$,1?#??\e(B" . "\e$,43{\e(B") ("\e$,1?#?@\e(B" . "\e$,43{4~\e(B") ("\e$,1?#?F\e(B" . "\e$,43z5&\e(B") ("\e$,1?#?G\e(B" . "\e$,43z5&4~\e(B") ("\e$,1?#?H\e(B" . "\e$,43z5&5'\e(B") ("\e$,1?#?J\e(B" .  "\e$,43z5&5&5 \e(B") ("\e$,1?#?K\e(B" . "\e$,43z5&5&5 4~\e(B") ("\e$,1?#?L\e(B" . "\e$,43z5(\e(B")
+    ("\e$,1?$?M\e(B" . "\e$,43}5)\e(B") ("\e$,1?$\e(B" . "\e$,43}\e(B") ("\e$,1?$??\e(B" . "\e$,43~\e(B") ("\e$,1?$?@\e(B" . "\e$,43~4~\e(B")
+    ("\e$,1?%?M\e(B" . "\e$,44B5)\e(B") ("\e$,1?%\e(B" . "\e$,44B\e(B") ("\e$,1?%??\e(B" . "\e$,44C\e(B") ("\e$,1?%?@\e(B" . "\e$,44C4~\e(B")
+    ("\e$,1?&?M\e(B" . "\e$,44E5)\e(B") ("\e$,1?&\e(B" . "\e$,44E\e(B") ("\e$,1?&??\e(B" . "\e$,44F\e(B") ("\e$,1?&?@\e(B" . "\e$,44F4~\e(B")
+    ("\e$,1?'?M\e(B" . "\e$,44H5)\e(B") ("\e$,1?'\e(B" . "\e$,44H\e(B") ("\e$,1?'??\e(B" . "\e$,44I\e(B") ("\e$,1?'?@\e(B" . "\e$,44I4~\e(B")
+    ("\e$,1?(?M\e(B" . "\e$,44K5)\e(B") ("\e$,1?(\e(B" . "\e$,44K\e(B") ("\e$,1?(??\e(B" . "\e$,44L\e(B") ("\e$,1?(?@\e(B" . "\e$,44L4~\e(B")
+    ("\e$,1?*?M\e(B" . "\e$,44N5)\e(B") ("\e$,1?*\e(B" . "\e$,44N\e(B") ("\e$,1?*??\e(B" . "\e$,44O\e(B") ("\e$,1?*?@\e(B" . "\e$,44O4~\e(B") ("\e$,1?*?A\e(B" . "\e$,44N5"\e(B") ("\e$,1?*?B\e(B" . "\e$,44N5#\e(B") ("\e$,1?*?J\e(B" . "\e$,44N5&5#\e(B") ("\e$,1?*?K\e(B" . "\e$,44N5&5#4~\e(B")
+    ("\e$,1?+?M\e(B" . "\e$,44Q5)\e(B") ("\e$,1?+\e(B" . "\e$,44Q\e(B") ("\e$,1?+??\e(B" . "\e$,44R\e(B") ("\e$,1?+?@\e(B" . "\e$,44R4~\e(B") ("\e$,1?+?A\e(B" . "\e$,44Q5"\e(B") ("\e$,1?+?B\e(B" . "\e$,44Q5#\e(B") ("\e$,1?+?J\e(B" . "\e$,44Q5&5#\e(B") ("\e$,1?+?K\e(B" . "\e$,44Q5&5#4~\e(B")
+    ("\e$,1?,?M\e(B" . "\e$,44W5)\e(B") ("\e$,1?,\e(B" . "\e$,44V\e(B") ("\e$,1?,?>\e(B". "\e$,44W4{\e(B") ("\e$,1?,??\e(B" . "\e$,44X\e(B") ("\e$,1?,?@\e(B" . "\e$,44X4~\e(B") ("\e$,1?,?F\e(B" . "\e$,44W5&\e(B") ("\e$,1?,?G\e(B" . "\e$,44W5&4~\e(B") ("\e$,1?,?H\e(B" . "\e$,44W5&5'\e(B") ("\e$,1?,?J\e(B" .  "\e$,44W5&5&5 \e(B") ("\e$,1?,?K\e(B" . "\e$,44W5&5&5 4~\e(B") ("\e$,1?,?L\e(B" . "\e$,44W5(\e(B")
+    ("\e$,1?-?M\e(B" . "\e$,44Z5)\e(B") ("\e$,1?-\e(B" . "\e$,44Z\e(B") ("\e$,1?-??\e(B" . "\e$,44[\e(B") ("\e$,1?-?@\e(B" . "\e$,44[4~\e(B")
+    ("\e$,1?.?M\e(B" . "\e$,44h5!5)\e(B") ("\e$,1?.\e(B" . "\e$,44h4z4\7f\e(B") ("\e$,1?.?>\e(B" . "\e$,44h4z5!4{\e(B") ("\e$,1?.??\e(B" . "\e$,44i4\7f\e(B") ("\e$,1?.?@\e(B" . "\e$,44i4\7f4~\e(B") ("\e$,1?.?J\e(B". "\e$,44h5&5 \e(B") ("\e$,1?.?K\e(B". "\e$,44h5&5 4~\e(B")
+    ("\e$,1?/?M\e(B" . "\e$,44^4z5!5)\e(B") ("\e$,1?/\e(B" . "\e$,44^4z4\7f\e(B") ("\e$,1?/?>\e(B" . "\e$,44^4z5!4{\e(B")("\e$,1?/??\e(B" . "\e$,44_4\7f\e(B") ("\e$,1?/?@\e(B" . "\e$,44_4\7f4~\e(B") ("\e$,1?/?J\e(B" . "\e$,44^5&5 \e(B") ("\e$,1?/?K\e(B" . "\e$,44^5&5 4~\e(B")
+    ("\e$,1?0?M\e(B" . "\e$,44a5)\e(B") ("\e$,1?0\e(B" . "\e$,44a\e(B") ("\e$,1?0??\e(B" . "\e$,44b\e(B") ("\e$,1?0?@\e(B" . "\e$,44b4~\e(B")
+    ("\e$,1?0?M\e(B" . "\e$,44a5)\e(B") ("\e$,1?0\e(B" . "\e$,44a\e(B") ("\e$,1?0??\e(B" . "\e$,44b\e(B") ("\e$,1?0?@\e(B" . "\e$,44b4~\e(B")
+    ("\e$,1?2?M\e(B" . "\e$,44e5)\e(B") ("\e$,1?2\e(B" . "\e$,44d\e(B") ("\e$,1?2?>\e(B" . "\e$,44e4{\e(B") ("\e$,1?2??\e(B" . "\e$,44f\e(B") ("\e$,1?2?@\e(B" . "\e$,44f4~\e(B") ("\e$,1?2?F\e(B" . "\e$,44e5&\e(B") ("\e$,1?2?G\e(B" . "\e$,44e5&4~\e(B") ("\e$,1?2?H\e(B" . "\e$,44e5&5'\e(B") ("\e$,1?2?J\e(B" .  "\e$,44e5&5&5 \e(B") ("\e$,1?2?K\e(B" . "\e$,44e5&5&5 4~\e(B") ("\e$,1?2?L\e(B" . "\e$,44e5(\e(B")
+    ("\e$,1?5?M\e(B" . "\e$,44h5)\e(B") ("\e$,1?5\e(B" . "\e$,44h\e(B") ("\e$,1?5??\e(B" . "\e$,44i\e(B") ("\e$,1?5?@\e(B" . "\e$,44i4~\e(B") ("\e$,1?5?A\e(B" . "\e$,44h5"\e(B") ("\e$,1?5?B\e(B" . "\e$,44h5#\e(B") ("\e$,1?5?J\e(B" . "\e$,44h5&5#\e(B") ("\e$,1?5?K\e(B" . "\e$,44h5&5#4~\e(B")
+    ("\e$,1?6?M\e(B" . "\e$,44k5)\e(B") ("\e$,1?6\e(B" . "\e$,44k\e(B") ("\e$,1?6??\e(B" . "\e$,44l\e(B") ("\e$,1?6?@\e(B" . "\e$,44l4~\e(B")
+    ("\e$,1?7?M\e(B" . "\e$,44n5)\e(B") ("\e$,1?7\e(B" . "\e$,44n\e(B") ("\e$,1?7??\e(B" . "\e$,44o\e(B") ("\e$,1?7?@\e(B" . "\e$,44o4~\e(B")
+    ("\e$,1?8?M\e(B" . "\e$,44q5)\e(B") ("\e$,1?8\e(B" . "\e$,44q\e(B") ("\e$,1?8??\e(B" . "\e$,44r\e(B") ("\e$,1?8?@\e(B" . "\e$,44r4~\e(B")
+    ("\e$,1?9?M\e(B" . "\e$,44t5)\e(B") ("\e$,1?9\e(B" . "\e$,44t\e(B") ("\e$,1?9??\e(B" . "\e$,44u\e(B") ("\e$,1?9?@\e(B" . "\e$,44u4~\e(B")
+    ("\e$,1?3?M\e(B" . "\e$,44w5)\e(B") ("\e$,1?3\e(B" . "\e$,44w\e(B") ("\e$,1?3??\e(B" . "\e$,44x\e(B") ("\e$,1?3?@\e(B" . "\e$,44x4~\e(B"))
+"Kannada characters to glyphs conversion table.
+Default value contains only the basic rules.")
+
+(defvar knd-char-glyph-hash
+  (let* ((hash (make-hash-table :test 'equal)))
+    (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
+         knd-char-glyph)
+    hash))
+
+(defvar knd-char-glyph-regexp
+  (kannada-regexp-of-hashtbl-keys knd-char-glyph-hash))
+
+(defvar knd-conjunct-glyph
+  '(("\e$,1>u\e(B" . "\e$,43Q\e(B") ("\e$,1>v\e(B" . "\e$,43U\e(B") ("\e$,1>w\e(B" . "\e$,43X\e(B") ("\e$,1>x\e(B" . "\e$,43[\e(B") ("\e$,1>y\e(B" . "\e$,43]\e(B")
+    ("\e$,1>z\e(B" . "\e$,43`\e(B") ("\e$,1>{\e(B" . "\e$,43c\e(B") ("\e$,1>|\e(B" . "\e$,43g\e(B") ("\e$,1>}\e(B" . "\e$,43i\e(B") ("\e$,1>~\e(B" . "\e$,43k\e(B")
+    ("\e$,1>\7f\e(B" . "\e$,43o\e(B") ("\e$,1? \e(B" . "\e$,43r\e(B") ("\e$,1?!\e(B" . "\e$,43u\e(B") ("\e$,1?"\e(B" . "\e$,43x\e(B") ("\e$,1?#\e(B" . "\e$,43|\e(B")
+    ("\e$,1?$\e(B" . "\e$,44A\e(B") ("\e$,1?%\e(B" . "\e$,44D\e(B") ("\e$,1?&\e(B" . "\e$,44G\e(B") ("\e$,1?'\e(B" . "\e$,44J\e(B") ("\e$,1?(\e(B" . "\e$,44M\e(B")
+    ("\e$,1?*\e(B" . "\e$,44P\e(B") ("\e$,1?+\e(B" . "\e$,44U\e(B") ("\e$,1?,\e(B" . "\e$,44Y\e(B") ("\e$,1?-\e(B" . "\e$,44\\e(B") ("\e$,1?.\e(B" . "\e$,44]\e(B")
+    ("\e$,1?/\e(B" . "\e$,44`\e(B") ("\e$,1?0\e(B" . "\e$,44c\e(B") ("\e$,1?2\e(B" . "\e$,44g\e(B") ("\e$,1?3\e(B" . "\e$,44y\e(B") ("\e$,1?5\e(B" . "\e$,44j\e(B")
+    ("\e$,1?6\e(B" . "\e$,44m\e(B") ("\e$,1?7\e(B" . "\e$,44p\e(B") ("\e$,1?8\e(B" . "\e$,44s\e(B") ("\e$,1?9\e(B" . "\e$,44v\e(B"))
+"Kannada characters to conjunct glyphs conversion table.")
+
+(defvar knd-conjunct-glyph-hash
+  (let* ((hash (make-hash-table :test 'equal)))
+    (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
+         knd-conjunct-glyph)
+    hash))
+    
+(defvar knd-conjunct-glyph-regexp
+  (kannada-regexp-of-hashtbl-vals knd-conjunct-glyph-hash))
+
+(mapc
+  (function (lambda (x)
+    (put-char-code-property (aref (cdr x) 0) 'reference-point '(5 . 3))))
+  knd-conjunct-glyph)
+
+;; glyph-to-glyph conversion table.
+;; it is supposed that glyphs are ordered in
+;;   [consonant/nukta] - [matra/virama] - [preceding-r] - [anuswar].
+
+(defvar knd-glyph-glyph
+  '(("\e$,45$4A\e(B" . "\e$,45*\e(B")
+    ("\e$,45'4A\e(B" . "\e$,45+\e(B")
+    ("\e$,44A3g\e(B" . "\e$,45,\e(B")
+    ("\e$,45$3Q\e(B" . "\e$,45-\e(B")))
+
+(defvar knd-glyph-glyph-hash
+  (let* ((hash (make-hash-table :test 'equal)))
+    (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
+         knd-glyph-glyph)
+    hash))
+(defvar knd-glyph-glyph-regexp
+  (kannada-regexp-of-hashtbl-keys knd-glyph-glyph-hash))
+
+(defun knd-charseq (from &optional to)
+  (if (null to) (setq to from))
+  (mapcar (function (lambda (x) (indian-glyph-char x 'kannada)))
+          (kannada-range from to)))
+
+(defvar knd-glyph-cv
+  (append
+   (knd-charseq #x40 #x50)
+   (knd-charseq #x52 #x54)
+   (knd-charseq #x56 #x57)
+   (knd-charseq #x59 #x5a)
+   (knd-charseq #x5c)
+   (knd-charseq #x5e #x5f)
+   (knd-charseq #x61 #x62)
+   (knd-charseq #x64 #x66)
+   (knd-charseq #x6a)
+   (knd-charseq #x6c #x6e)
+   (knd-charseq #x70 #x71)
+   (knd-charseq #x73 #x74)
+   (knd-charseq #x76 #x77)
+   (knd-charseq #x79 #x7b)
+   (knd-charseq #x7d #x7e)
+   (knd-charseq #xa2 #xa3)
+   (knd-charseq #xa5 #xa6)
+   (knd-charseq #xa8 #xa9)
+   (knd-charseq #xab #xac)
+   (knd-charseq #xae #xaf)
+   (knd-charseq #xb1 #xb2)
+   (knd-charseq #xb6 #xb8)
+   (knd-charseq #xb6 #xb8)
+   (knd-charseq #xba #xbb)
+   (knd-charseq #xbe #xbf)
+   (knd-charseq #xc1 #xc2)
+   (knd-charseq #xc4 #xc6)
+   (knd-charseq #xc8 #xc9)
+   (knd-charseq #xcb #xcc)
+   (knd-charseq #xce #xcf)
+   (knd-charseq #xd1 #xd2)
+   (knd-charseq #xd4 #xd5)
+   (knd-charseq #xd7 #xd8)
+   (knd-charseq #xc3))
+  "Kannada Consonants/Vowels/Nukta Glyphs")
+
+(defvar knd-glyph-space
+  (knd-charseq #xb3 #xb4)
+  "Kannada Spacing Glyphs")
+
+(defvar knd-glyph-right-modifier
+  (append
+   (knd-charseq #xdb #xdd)
+   (knd-charseq #xdf)
+   (knd-charseq #xe0 #xe3)
+   (knd-charseq #xe9))
+  "Kannada Modifiers attached at the right side.")
+
+(defvar knd-glyph-right-modifier-regexp
+  (concat "[" knd-glyph-right-modifier "]"))
+
+(defvar knd-glyph-jha-tail
+   (knd-charseq #x68)
+  "Kannada tail for jha.")
+
+(defvar knd-glyph-top-matra
+  (append
+   (knd-charseq #xda)
+   (knd-charseq #xdd)
+   (knd-charseq #xe6)
+   (knd-charseq #xe8))
+  "Kannada Matras attached at the top side.")
+
+(defvar knd-glyph-bottom-matra
+  (append
+   (knd-charseq #xe4 #xe5)
+   (knd-charseq #xe7))
+  "Kannada Matras attached at the bottom.")
+
+(defvar knd-glyph-end-marks
+  (append
+   (knd-charseq #x25)
+   (knd-charseq #x4d #x4e)
+   (knd-charseq #xde))
+  "Kannada end marks: arkavattu, virama, au and diirghaa.")
+
+(defvar knd-glyph-bottom-modifier
+  (append
+   (knd-charseq #x51)
+   (knd-charseq #x55)
+   (knd-charseq #x58)
+   (knd-charseq #x5b)
+   (knd-charseq #x5d)
+   (knd-charseq #x60)
+   (knd-charseq #x63)
+   (knd-charseq #x67)
+   (knd-charseq #x69)
+   (knd-charseq #x6b)
+   (knd-charseq #x6f)
+   (knd-charseq #x72)
+   (knd-charseq #x75)
+   (knd-charseq #x78)
+   (knd-charseq #x7c)
+   (knd-charseq #xa1)
+   (knd-charseq #xa4)
+   (knd-charseq #xa7)
+   (knd-charseq #xaa)
+   (knd-charseq #xad)
+   (knd-charseq #xb0)
+   (knd-charseq #xb5)
+   (knd-charseq #xb9)
+   (knd-charseq #xbc #xbd)
+   (knd-charseq #xc0)
+   (knd-charseq #xc3)
+   (knd-charseq #xc7)
+   (knd-charseq #xca)
+   (knd-charseq #xcd)
+   (knd-charseq #xd0)
+   (knd-charseq #xd3)
+   (knd-charseq #xd6)
+   (knd-charseq #xd9)
+   (knd-charseq #xea #xef))
+  "Kannada Modifiers attached at the bottom.")
+
+(defvar knd-glyph-order
+  `((,knd-glyph-cv . 1)
+    (,knd-glyph-top-matra . 2)
+    (,knd-glyph-jha-tail . 3)
+    (,knd-glyph-right-modifier . 4)
+    (,knd-glyph-space . 5)
+    (,knd-glyph-bottom-modifier . 5)
+    (,knd-glyph-bottom-matra . 6)
+    (,knd-glyph-end-marks . 7)
+    ))
+
+(mapc
+ (function (lambda (x)
+   (mapc
+     (function (lambda (y)
+       (put-char-code-property y 'composition-order (cdr x))))
+     (car x))))
+  knd-glyph-order)
+
+(defun kannada-compose-syllable-string (string)
+  (with-temp-buffer
+    (insert (decompose-string string))
+    (kannada-compose-syllable-region (point-min) (point-max))
+    (buffer-string)))
+
+;; kch
+(defun kannada-compose-syllable-region (from to)
+  "Compose kannada syllable in region FROM to TO."
+  (let ((glyph-str nil) (cons-num 0) (glyph-str-list nil)
+        (last-virama nil) (preceding-r nil) (last-modifier nil)
+        (last-char (char-before to)) match-str pos
+        glyph-block split-pos (conj nil) (rest nil))
+    (save-excursion
+      (save-restriction
+          ;;; *** char-to-glyph conversion ***
+        ;; Special rule 1. -- Last virama must be preserved.
+        (if (eq last-char ?\e$,1?M\e(B)
+            (progn
+              (setq last-virama t)
+              (narrow-to-region from (1- to)))
+          (narrow-to-region from to))
+        (goto-char (point-min))
+        ;; Special rule 2. -- preceding "r virama" must be modifier.
+        (when (looking-at "\e$,1?0?M\e(B.")
+          (setq preceding-r t)
+          (goto-char (+ 2 (point))))
+       ;; remove conjunct consonants
+        (while (re-search-forward knd-char-glyph-regexp nil t)
+          (setq match-str (match-string 0))
+         (if (and (string-match kannada-consonant match-str)
+                  (> cons-num 0))
+             (progn
+               (setq conj (concat conj (gethash (match-string 0 match-str)
+                                                knd-conjunct-glyph-hash)))
+               (setq match-str (replace-match "" t nil match-str))
+               (if (string-match "\e$,1?M\e(B" rest)
+                   (setq rest (replace-match "" t nil rest)))))
+         (setq rest (concat rest match-str))
+         ;; count the number of consonant-glyhs.
+         (if (string-match kannada-consonant match-str)
+             (setq cons-num (1+ cons-num))))
+        ;; translate the rest characters into glyphs
+       (setq pos 0)
+        (while (string-match knd-char-glyph-regexp rest pos)
+          (setq match-str (match-string 0 rest))
+         (setq pos (match-end 0))
+         (setq glyph-str
+               (concat glyph-str (gethash match-str knd-char-glyph-hash))))
+
+       (if conj (setq glyph-str (concat glyph-str conj)))
+        (if last-virama (setq glyph-str (concat glyph-str "\e$,45)\e(B"))
+         (goto-char (point-min))
+         (if (re-search-forward kannada-consonant-needs-twirl nil t)
+             (progn
+               (setq match-str (match-string 0))
+               (setq glyph-str (concat glyph-str "\e$,44z\e(B")))))
+        ;; preceding-r must be attached
+        (if preceding-r
+              (setq glyph-str (concat glyph-str "\e$,43%\e(B")))
+          ;;; *** glyph-to-glyph conversion ***
+        (when (string-match knd-glyph-glyph-regexp glyph-str)
+          (setq glyph-str
+                (replace-match (gethash (match-string 0 glyph-str)
+                                        knd-glyph-glyph-hash)
+                               nil t glyph-str)))
+          ;;; *** glyph reordering ***
+        (while (setq split-pos (string-match "\e$,45)\e(B\\|.$" glyph-str))
+          (setq glyph-block (substring glyph-str 0 (1+ split-pos)))
+          (setq glyph-str (substring glyph-str (1+ split-pos)))
+          (setq
+           glyph-block
+               (sort (string-to-list glyph-block)
+                     (function (lambda (x y)
+                        (< (get-char-code-property x 'composition-order)
+                           (get-char-code-property y 'composition-order))))))
+          (setq glyph-str-list (nconc glyph-str-list glyph-block)))
+         ;;; *** insert space glyphs for kerning ***
+       (if (> cons-num 0)
+           (let ((curr glyph-str-list) (prev nil) (last-bott nil) bott co)
+             (while curr
+               (setq co (get-char-code-property 
+                               (car curr) 'composition-order)
+                     bott (or (eq co 5) (eq co 6)))
+               (if (and bott last-bott)
+                   (setcdr prev (cons ?\e$,44T\e(B curr)))
+               (setq last-bott bott prev curr curr (cdr curr)))))
+          ;; concatenate and attach reference-points.
+        (setq glyph-str
+              (cdr
+               (apply
+                'nconc
+                (mapcar
+                 (function (lambda (x)
+                   (list
+                    (or (get-char-code-property x 'reference-point)
+                    '(5 . 3) ;; default reference point.
+                     )
+                    x)))
+                 glyph-str-list))))))
+      (compose-region from to glyph-str)))
+
+(provide 'knd-util)
+
+;;; knd-util.el ends here