diff lisp/language/devan-util.el @ 17052:d0d7b244b1d0

Initial revision
author Karl Heuer <kwzh@gnu.org>
date Thu, 20 Feb 1997 07:02:49 +0000
parents
children 70194012fb3a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/language/devan-util.el	Thu Feb 20 07:02:49 1997 +0000
@@ -0,0 +1,1160 @@
+;;; devan-util.el --- Support for Devanagari Script Composition
+
+;; Copyright (C) 1996 Free Software Foundation, Inc.
+
+;; Author: KAWABATA, Taichi <kawabata@is.s.u-tokyo.ac.jp>
+
+;; Keywords: multilingual, Indian, Devanagari
+
+;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; History:
+;; 1996.10.18 written by KAWABATA, Taichi <kawabata@is.s.u-tokyo.ac.jp>
+
+;; Devanagari script composition rules and related programs.
+
+;;; Code:
+
+;;;
+;;;   Steps toward composition of Devanagari Characters.
+;;;
+
+;;; Basic functions.
+
+;;;###autoload
+(defun indian-to-devanagari (ch)
+  "Convert IS 13194 characters to Devanagari basic characters."
+  (let ((charcodes (split-char ch)))
+    (if (eq (car charcodes) 'indian-is13194)
+	(make-char 'indian-2-column ?\x21 (nth 1 charcodes))
+      ch)))
+
+;;;###autoload
+(defun devanagari-to-indian (ch)
+  "Convert Devanagari basic characters to IS 13194 characters."
+  (let* ((charcodes (split-char ch))
+	 (charset (car charcodes))
+	 (code-h  (car (cdr charcodes))))
+    (if (and (eq (car charcodes) 'indian-2-column)
+	     (= (nth 1 charcodes) ?\x21))
+	(make-char 'indian-is13194 (nth 2 charcodes))
+      ch)))
+
+;;;###autoload
+(defun indian-to-devanagari-region (from to)
+  "Convert IS 13194 characters in region to Devanagari basic characters."
+  (interactive "r")
+  (save-restriction 
+    (narrow-to-region from to)
+    (goto-char (point-min))
+    (while (re-search-forward "\\cd" nil t)
+      (let* ((devanagari-char (indian-to-devanagari (preceding-char))))
+	(delete-char -1)
+	(insert devanagari-char)))))
+
+;;;###autoload
+(defun devanagari-to-indian-region (from to)
+  "Convert Devanagari basic characters in region to Indian characters."
+  (interactive "r")
+  (save-restriction
+    (narrow-to-region from to)
+    (goto-char (point-min))
+    (while (re-search-forward "\\cD" nil t) ; Devanagari Character Code.
+      (let* ((indian-char (devanagari-to-indian (preceding-char))))
+	(delete-char -1)
+	(insert indian-char)))))
+
+;;;###autoload
+(defun indian-to-devanagari-string (str)
+  "Convert Indian String to Devanagari Basic Character String."
+  (let ((pos 0) (dst "") (src str) char)
+    (while (not (equal src ""))
+      (setq char (string-to-char src))
+      (setq src (substring src (char-bytes char)))
+      (setq dst (concat dst (char-to-string (indian-to-devanagari char)))))
+    dst))
+
+;; Phase 0 - Determine whether the characters can be composed.
+;;
+;;;
+;;; Regular expressions to split characters for composition.
+;;;
+;;
+;; Indian script word contains one or more syllables.
+;; In BNF, it can be expressed as follows:
+;;
+;; Word ::= {Syllable} [Cons-Syllable]
+;; Syllable ::= Cons-Vowel-Syllable | Vowel-Syllable
+;; Vowel-Syllable ::= V[D]
+;; Cons-Vowel-Syllable ::= [Cons-Syllable] Full-Cons [M] [D]
+;; Cons-Syllable ::= [Pure-Cons] [Pure-Cons] Pure-Cons
+;; Pure-Cons ::= Full-Cons H
+;; Full-Cons ::= C [N]
+;;
+;; {} repeat, [] optional
+;;
+;; C - Consonant ($(5!3!4!5!6!7!8!9!:!;!<!=!>!?!@!A!B!C!D!E(B
+;;                $(5!F!G!H!I!J!K!L!M!N!O!P!Q!R!S!T!U!V!W!X(B)
+;; N - Nukta ($(5!i(B)
+;; H - Halant($(5!h(B)
+;; V - Vowel ($(5!$!%!&!'!(!)!*!+!,!-!.!/!0!1!2(B)
+;; D - Vowel Modifiers, i.e. Anuswar, Chandrabindu, Visarg  ($(5!!!"(B)
+;; M - Matra ($(5!Z![!\!]!^!_!`!a!b!c!d!e!f!g(B)
+;;
+;; In Emacs, one syllable of Indian language is considered to be one 
+;; composite glyph.  If we expand the above expression, it would be:
+;;
+;; [[C [N] H] [C [N] H] C [N] H] C [N] [M] [D] | V [D]
+;; 
+;; Therefore, in worst case, the consonant syllabe will consist of
+;; following characters.
+;;
+;; C N H C N H C N H C N M D
+;;
+;; On the other hand, incomplete consonant syllable before inputting
+;; base consonant must satisfy the following condition:
+;;
+;; [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 acceptable syllable and can
+;; not add any code more.
+;;
+;; [[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.
+
+(defconst devanagari-cons-syllable-examine
+  "\\(\\([$(5!3(B-$(5!X(B]$(5!i(B?$(5!h(B\\)?\\([$(5!3(B-$(5!X(B]$(5!i(B?$(5!h(B\\)?[$(5!3(B-$(5!X(B]$(5!i(B?$(5!h(B\\)?[$(5!3(B-$(5!X(B]$(5!i(B?[$(5!Z(B-$(5!g(B]?[$(5!!!"(B]?"
+  "Regexp matching to one Devanagari consonant syllable.")
+
+(defconst devanagari-cons-syllable-incomplete-examine
+  "\\([$(5!3(B-$(5!X(B]$(5!i(B?$(5!h(B\\)?\\([$(5!3(B-$(5!X(B]$(5!i(B?$(5!h(B\\)?[$(5!3(B-$(5!X(B]$(5!i(B?$(5!h(B$"
+  "Regexp matching to one Devanagari incomplete consonant syllable.")
+
+(defconst devanagari-vowel-syllable-examine
+  "[$(5!$(B-$(5!2(B][$(5!!!"!#(B]?"
+  "Regexp matching to one Devanagari 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-examine 
+  "[$(5!q(B-$(5!z!j(B]")
+(defconst devanagari-other-sign-examine
+  "[$(5!!!j(B]$(5!i(B")
+
+(defconst devanagari-composite-glyph-unit-examine
+  (concat "\\(" devanagari-cons-syllable-incomplete-examine 
+	  "\\)\\|\\(" devanagari-vowel-syllable-examine 
+	  "\\)\\|\\(" devanagari-digit-viram-examine
+	  "\\)\\|\\(" devanagari-cons-syllable-examine
+	  "\\)\\|\\(" devanagari-other-sign-examine"\\)")
+  "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-syllable-examine "$(5!X![(B") => 0
+;;(string-match devanagari-cons-syllable-examine "$(5!F!h!D!\(B") => 0
+;;(string-match devanagari-cons-syllable-examine "$(5!X![!F!h!D!\(B") => 0
+
+;;
+;; Steps toward the composition
+;;  Converting Character Code to Composite Glyph.
+;;
+;; Example : $(5!X![(B/$(5!F!h!D!\(B
+;; 
+;; First, convert Characters to appropriate glyphs.
+;;
+;; => $(5!X![(B/$(5"F!D!\(B
+;;
+;; Then, determine the base glyph, apply-orders and apply-rules.
+;;
+;; => $(5!X(B (ml.mr) $(5![(B / $(5!D(B (ml.mr) $(5"F(B (mr ml) $(5!\(B
+;;
+;; Finally, convert 2-column glyphs to 1-column glyph
+;; if such a glyph exist.
+;;
+;; => $(6![(B (ml.mr) $(6!X(B / $(6!D(B (ml.mr) $(6"F(B (mr ml) $(6!\(B
+;;
+;; Compose the glyph.
+;;
+;; => 2$(6!X@![1(B/2$(6!D@"FP!\1(B
+;; => 2$(6!X@![12!D@"FP!\1(B
+;;
+
+;;
+;; Phase 1: Converting Character Code to Glyph Code.
+;; 
+;;
+;; IMPORTANT:  
+;;        There may be many rules which you many want to be suppressed.
+;;        In that case, please comment out that rule.
+;;
+;;        RULES WILL BE EVALUATED FROM FIRST TO LAST.
+;;        PUT MORE SPECIFIC RULES FIRST.
+;;
+;; TO DO: 
+;;        Prepare multiple specific list of rules for each languages
+;;        which adopts Devanagari script.
+;;
+
+
+(defconst devanagari-char-to-glyph-rules
+  '(
+    ;; special form for "ru".
+    ("\\($(5!O!](B\\)" . "$(5",(B")
+    ("\\($(5!O!^(B\\)" . "$(5"-(B")
+    ("\\($(5!P!](B\\)" . "$(5".(B")
+    ("\\($(5!P!^(B\\)" . "$(5"/(B")
+
+    ;; `r' at the top of syllable and followed by other consonants.
+    ;; ("[^$(5!h(B]\\($(5!O!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"p(B")
+    ("^\\($(5!O!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"p(B")
+
+    ;; If "r" is preceded by the vowel-suppressed consonant
+    ;; (especially those with vertical line), it will be written as
+    ;; slanted line below the preceding consonant character.  Some of
+    ;; them are pre-composed as one glyph.
+
+    ("\\($(5!:!i!h!O(B\\)" . "$(5"!(B")
+    ("\\($(5!I!i!h!O(B\\)" . "$(5""(B")
+    ("\\($(5!3!h!O(B\\)" . "$(5"#(B")
+    ("\\($(5!:!h!O(B\\)" . "$(5"$(B")
+    ("\\($(5!B!h!O(B\\)" . "$(5"%(B")
+    ("\\($(5!H!h!O(B\\)" . "$(5"&(B")
+    ("\\($(5!I!h!O(B\\)" . "$(5"'(B")
+    ("\\($(5!U!h!O(B\\)" . "$(5"((B")
+    ("\\($(5!W!h!O(B\\)" . "$(5")(B")
+
+    ;; Ligature Rules 
+    ("\\($(5!3!h!B!h!O!h!M(B\\)" . "$(5$!(B")
+    ("\\($(5!3!h!B!h!T(B\\)" . "$(5$"(B")
+    ("\\($(5!3!h!B!h!M(B\\)" . "$(5$#(B")
+    ("\\($(5!3!h!F!h!M(B\\)" . "$(5$$(B")
+    ("\\($(5!3!h!O!h!M(B\\)" . "$(5$%(B")
+    ("\\($(5!3!h!T!h!M(B\\)" . "$(5$&(B")
+    ("\\($(5!3!h!3(B\\)" . "$(5$'(B")
+    ("\\($(5!3!h!B(B\\)" . "$(5$((B")
+    ("\\($(5!3!h!F(B\\)" . "$(5$)(B")
+    ("\\($(5!3!h!L(B\\)" . "$(5$*(B")
+    ("\\($(5!3!h!M(B\\)" . "$(5$+(B")
+    ("\\($(5!3!h!Q(B\\)" . "$(5$,(B")
+    ("\\($(5!3!h!T(B\\)" . "$(5$-(B")
+    ("\\($(5!3!h!V(B\\)" . "$(5$.(B")
+    ("\\($(5!6!h!F(B\\)" . "$(5$/(B")
+    ("\\($(5!7!h!3!h!B!h!M(B\\)" . "$(5$0(B")
+    ("\\($(5!7!h!3!h!V!h!T(B\\)" . "$(5$1(B")
+    ("\\($(5!7!h!3!h!B(B\\)" . "$(5$2(B")
+    ("\\($(5!7!h!3!h!V(B\\)" . "$(5$3(B")
+    ("\\($(5!7!h!6!h!O(B\\)" . "$(5$4(B")
+    ("\\($(5!7!h!3!h!M(B\\)" . "$(5$5(B")
+    ("\\($(5!7!h!4!h!M(B\\)" . "$(5$6(B")
+    ("\\($(5!7!h!5!h!M(B\\)" . "$(5$7(B")
+    ("\\($(5!7!h!6!h!M(B\\)" . "$(5$8(B")
+    ("\\($(5!7!h!3(B\\)" . "$(5$9(B")
+    ("\\($(5!7!h!4(B\\)" . "$(5$:(B")
+    ("\\($(5!7!h!5(B\\)" . "$(5$;(B")
+    ("\\($(5!7!h!6(B\\)" . "$(5$<(B")
+    ("\\($(5!7!h!7(B\\)" . "$(5$=(B")
+    ("\\($(5!7!h!F(B\\)" . "$(5$>(B")
+    ("\\($(5!7!h!L(B\\)" . "$(5$?(B")
+    ("\\($(5!7!h!M(B\\)" . "$(5$@(B")
+    ("\\($(5!8!h!8(B\\)" . "$(5$A(B")
+    ("\\($(5!8!h!<(B\\)" . "$(5$B(B")
+    ("\\($(5!9!h!M(B\\)" . "$(5$C(B")
+    ("\\($(5!:!h!O(B\\)" . "$(5$D(B")
+    ("\\($(5!:!h!h(B\\)" . "$(5$E(B")
+    ("\\($(5!<!h!8(B\\)" . "$(5$F(B")
+    ("\\($(5!<!h!:(B\\)" . "$(5$G(B")
+    ("\\($(5!=!h!3(B\\)" . "$(5$H(B")
+    ("\\($(5!=!h!=(B\\)" . "$(5$I(B")
+    ("\\($(5!=!h!>(B\\)" . "$(5$J(B")
+    ("\\($(5!=!h!M(B\\)" . "$(5$K(B")
+    ("\\($(5!>!h!M(B\\)" . "$(5$L(B")
+    ("\\($(5!?!h!5!h!M(B\\)" . "$(5$M(B")
+    ("\\($(5!?!h!6!h!O(B\\)" . "$(5$N(B")
+    ("\\($(5!?!h!O!h!M(B\\)" . "$(5$O(B")
+    ("\\($(5!?!h!5(B\\)" . "$(5$P(B")
+    ("\\($(5!?!h!6(B\\)" . "$(5$Q(B")
+    ("\\($(5!?!h!?(B\\)" . "$(5$R(B")
+    ("\\($(5!?!h!L(B\\)" . "$(5$S(B")
+    ("\\($(5!?!h!M(B\\)" . "$(5$T(B")
+    ("\\($(5!@!h!M(B\\)" . "$(5$`(B")
+    ("\\($(5!B!h!B(B\\)" . "$(5$a(B")
+    ("\\($(5!B!h!F(B\\)" . "$(5$b(B")
+    ("\\($(5!D!h!D!h!M(B\\)" . "$(5$c(B")
+    ("\\($(5!D!h!E!h!M(B\\)" . "$(5$d(B")
+    ("\\($(5!D!h!K!h!M(B\\)" . "$(5$e(B")
+    ("\\($(5!D!h!O!h!M(B\\)" . "$(5$f(B")
+    ("\\($(5!D!h!T!h!M(B\\)" . "$(5$g(B")
+    ("\\($(5!D!h!5!h!O(B\\)" . "$(5$h(B")
+    ("\\($(5!D!h!6!h!O(B\\)" . "$(5$i(B")
+    ("\\($(5!D!h!D!h!T(B\\)" . "$(5$j(B")
+    ("\\($(5!D!h!E!h!T(B\\)" . "$(5$k(B")
+    ("\\($(5!D!h!5(B\\)" . "$(5$l(B")
+    ("\\($(5!D!h!6(B\\)" . "$(5$m(B")
+    ("\\($(5!D!h!D(B\\)" . "$(5$n(B")
+    ("\\($(5!D!h!E(B\\)" . "$(5$o(B")
+    ("\\($(5!D!h!F(B\\)" . "$(5$p(B")
+    ("\\($(5!D!h!J(B\\)" . "$(5$q(B")
+    ("\\($(5!D!h!K(B\\)" . "$(5$r(B")
+    ("\\($(5!D!h!L(B\\)" . "$(5$s(B")
+    ("\\($(5!D!h!M(B\\)" . "$(5$t(B")
+    ("\\($(5!D!h!T(B\\)" . "$(5$u(B")
+    ("\\($(5!E!h!F(B\\)" . "$(5$v(B")
+    ("\\($(5!F!h!F(B\\)" . "$(5$w(B")
+    ("\\($(5!H!h!B(B\\)" . "$(5$x(B")
+    ("\\($(5!H!h!F(B\\)" . "$(5$y(B")
+    ("\\($(5!H!h!Q(B\\)" . "$(5$z(B")
+    ("\\($(5!J!h!F(B\\)" . "$(5${(B")
+    ("\\($(5!J!h!J(B\\)" . "$(5$|(B")
+    ("\\($(5!J!h!T(B\\)" . "$(5$}(B")
+    ("\\($(5!K!h!F(B\\)" . "$(5$~(B")
+    ("\\($(5!L!h!F(B\\)" . "$(5#P(B")
+    ("\\($(5!L!h!Q(B\\)" . "$(5#Q(B")
+    ("\\($(5!Q!h!Q(B\\)" . "$(5#`(B")
+    ("\\($(5!T!h!F(B\\)" . "$(5#a(B")
+    ("\\($(5!T!h!T(B\\)" . "$(5#b(B")
+    ("\\($(5!U!h!8(B\\)" . "$(5#c(B")
+    ("\\($(5!U!h!F(B\\)" . "$(5#d(B")
+    ("\\($(5!U!h!J(B\\)" . "$(5#e(B")
+    ("\\($(5!U!h!Q(B\\)" . "$(5#f(B")
+    ("\\($(5!U!h!T(B\\)" . "$(5#g(B")
+    ("\\($(5!V!h!=!h!O!h!M(B\\)" . "$(5#h(B")
+    ("\\($(5!V!h!=!h!M(B\\)" . "$(5#i(B")
+    ("\\($(5!V!h!=!h!T(B\\)" . "$(5#j(B")
+    ("\\($(5!V!h!=(B\\)" . "$(5#k(B")
+    ("\\($(5!V!h!>(B\\)" . "$(5#l(B")
+    ("\\($(5!W!h!F(B\\)" . "$(5#m(B")
+    ("\\($(5!W!h!O(B\\)" . "$(5#n(B")
+    ("\\($(5!X!h!A(B\\)" . "$(5#p(B")
+    ("\\($(5!X!h!F(B\\)" . "$(5#q(B")
+    ("\\($(5!X!h!L(B\\)" . "$(5#r(B")
+    ("\\($(5!X!h!M(B\\)" . "$(5#s(B")
+    ("\\($(5!X!h!O(B\\)" . "$(5#t(B")
+    ("\\($(5!X!h!Q(B\\)" . "$(5#u(B")
+    ("\\($(5!X!h!T(B\\)" . "$(5#v(B")
+    ;; Special Ligature Rules 
+    ("\\($(5!X!_(B\\)" . "$(5#R(B")
+
+    ;; Half form with ligature.  Special "r" case is included.  "r"
+    ;; connection which is not listed here has not been examined yet.
+    ;; I don't know what to do with them.
+    ;;
+    ;; special forms 
+    ("\\($(5!3!h!V!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"l(B")
+    ("\\($(5!:!h!<!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"m(B")
+    ;; ordinary forms 
+    ("\\($(5!5!h!O!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"`(B")
+    ("\\($(5!6!h!F!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"a(B")
+    ;; ("\\($(5!<!h!8!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"c(B") ; Mistake, must check later.
+    ("\\($(5!B!h!B!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"c(B")
+    ("\\($(5!B!h!O!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"d(B")
+    ("\\($(5!E!h!F!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"e(B")
+    ("\\($(5!E!h!O!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"f(B")
+    ("\\($(5!H!h!B!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"g(B")
+    ("\\($(5!U!h!8!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"h(B")
+    ("\\($(5!U!h!O!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"i(B")
+    ("\\($(5!U!h!T!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"j(B")
+    ;; ("\\($(5!U!h!T!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"k(B") ; must check later.
+    ;; Conjunction form associated with Nukta sign.
+    ("\\($(5!3!i!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"s(B")
+    ("\\($(5!4!i!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"t(B")
+    ("\\($(5!5!i!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"u(B")
+    ("\\($(5!:!i!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"z(B")
+    ("\\($(5!I!i!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"y(B")
+
+    ;; For consonants other than listed above, glyph-composition will
+    ;; be applied.  If the consonant which is preceding "$(5!O(B" does not
+    ;; have the vertical line (such as "$(5!?(B"), "$(5"r(B" is put beneath the
+    ;; consonant.
+    ;;
+    ;; ("cons-not-yet-listed-up\\($(5!h!O(B\\)" . "$(5"q(B")
+    ("[$(5!7!9!=!>!?!@!D!O!P!R!S!X(B]\\($(5!h!O(B\\)" . "$(5"r(B")
+    ("$(5!?!i(B\\($(5!h!O(B\\)" . "$(5"r(B")
+    ("$(5!@!i(B\\($(5!h!O(B\\)" . "$(5"r(B")
+
+    ;; Nukta 
+    ("\\($(5!!!i(B\\)" . "$(5#!(B")
+    ("\\($(5!&!i(B\\)" . "$(5#&(B")
+    ("\\($(5!'!i(B\\)" . "$(5#'(B")
+    ("\\($(5!*!i(B\\)" . "$(5#*(B")
+    ("\\($(5!3!i(B\\)" . "$(5#3(B")
+    ("\\($(5!4!i(B\\)" . "$(5#4(B")
+    ("\\($(5!5!i(B\\)" . "$(5#5(B")
+    ("\\($(5!:!i(B\\)" . "$(5#:(B")
+    ("\\($(5!?!i(B\\)" . "$(5#?(B")
+    ("\\($(5!@!i(B\\)" . "$(5#@(B")
+    ("\\($(5!I!i(B\\)" . "$(5#I(B")
+    ("\\($(5!j!i(B\\)" . "$(5#J(B")
+
+    ;; Half forms.
+    ("\\($(5!3!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"3(B")
+    ("\\($(5!4!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"4(B")
+    ("\\($(5!5!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"5(B")
+    ("\\($(5!6!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"6(B")
+    ("\\($(5!8!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"8(B")
+    ("\\($(5!:!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5":(B")
+    ("\\($(5!;!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5";(B")
+    ("\\($(5!<!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"<(B")
+    ("\\($(5!A!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"A(B")
+    ("\\($(5!B!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"B(B")
+    ("\\($(5!C!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"C(B")
+    ("\\($(5!E!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"E(B")
+    ("\\($(5!F!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"F(B")
+    ("\\($(5!G!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"G(B")
+    ("\\($(5!H!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"H(B")
+    ("\\($(5!I!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"I(B")
+    ("\\($(5!J!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"J(B")
+    ("\\($(5!K!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"K(B")
+    ("\\($(5!L!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"L(B")
+    ("\\($(5!M!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"M(B")
+    ("\\($(5!N!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"N(B")
+    ("\\($(5!Q!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"Q(B")
+    ("\\($(5!R!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"R(B")
+    ("\\($(5!S!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"S(B")
+    ("\\($(5!T!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"T(B")
+    ("\\($(5!U!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"U(B")
+    ("\\($(5!V!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"V(B")
+    ("\\($(5!W!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"W(B")
+    )
+  "Alist of regexps of Devanagari character sequences vs composed characters.")
+
+;; Example:
+;;("\\($(5!F!h(B\\)[$(5!3(B-$(5!X(B]" . "$(5"F(B")
+;;(string-match "\\($(5!F!h(B\\)[$(5!3(B-$(5!X(B]" "$(5!X![!F!h!D!\(B") => 8
+;;(match-end 1) => 16
+
+;;
+;; Defining character properties : char-to-glyph, glyph-to-char
+;;
+;; *  If char-to-glyph is non-nil, it would be one of the following forms.
+;;
+;;  (("character-regexp" . "glyphs")
+;;   .....) or
+;;  (("character-regexp" . ?glyph)
+;;   .....) or
+;;  ("characters-regexp" . "glyphs")
+;;  or
+;;  ?glyph
+;;
+;; *  If glyph-to-char is non-nil, it would be one of the following forms.
+;;
+;;  (("glyph-regexp" . "characters")  ;; This is the only case in Devanagari
+;;   ....) or
+;;  (("glyph-regexp" . ?character)
+;;   ....) or
+;;  ("glyph-regexp" . "characters")
+;;    or
+;;  "characters"
+;;    or
+;;  ?character  
+;;
+
+(let ((rules devanagari-char-to-glyph-rules))
+  (while rules
+    (let ((rule (car rules)) 
+	  (chars) (char) (glyph))
+      (setq rules (cdr rules))
+      (string-match "\\\\(\\(.+\\)\\\\)" (car rule))
+      (setq chars (substring (car rule) (match-beginning 1) (match-end 1)))
+      (setq char (string-to-char chars))
+      (setq glyph (string-to-char (cdr rule))) ; assume one glyph in devan.
+      (put-char-code-property 
+         char 'char-to-glyph 
+	 (append (get-char-code-property char 'char-to-glyph) (list rule)))
+      (put-char-code-property glyph 'glyph-to-char chars))))
+
+;;
+;; Convert Character Code to Glyph Code
+;;
+
+;;;###autoload
+(defun char-to-glyph-devanagari (src-str)
+  "Convert Devanagari characters in the string to Devanagari glyphs.  
+Ligatures and special rules are processed."
+  (let ((pos 0) 
+	(dst-str ""))
+    (while (< pos (length src-str))
+      (let ((found nil)
+	    (rules (get-char-code-property 
+		    (string-to-char 
+		     ;; caution. other forms not supported for now.
+		     (substring src-str pos)) 'char-to-glyph)))
+	(while rules
+	  (let* ((rule (car rules))
+		 (regexp (car rule)))
+	    (if (string-match regexp src-str)
+		(if (= (match-beginning 1) pos)
+		    (progn
+		      (setq dst-str (concat dst-str (cdr rule)))
+		      (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)
+	    (let ((nextchar (string-to-char (substring src-str pos))))
+	      (setq pos (+ pos 
+			   (char-bytes (string-to-char (substring src-str pos)))))
+	      (setq dst-str (concat dst-str (char-to-string nextchar)))))))
+    dst-str))
+
+;; 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 consist 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 60 (tr . br))
+    (?$(5!"(B 60 (tr . br))
+    (?$(5!#(B 60)
+    (?$(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 40)
+    (?$(5![(B 40 (ml . mr))
+    (?$(5!\(B 40)
+    (?$(5!](B 40 (bc . tc))
+    (?$(5!^(B 40 (bc . tc))
+    (?$(5!_(B 40 (bc . tc))
+    (?$(5!`(B 40 (tc . bc))
+    (?$(5!a(B 40 (tc . bc))
+    (?$(5!b(B 40 (tc . bc))
+    (?$(5!c(B 40 (tc . bc))
+    (?$(5!d(B 40)
+    (?$(5!e(B 40)
+    (?$(5!f(B 40)
+    (?$(5!g(B 40)
+    (?$(5!h(B 0 (br . tr))			; Halant's special treatment.
+    (?$(5!i(B 0 (br . tr))			; Nukta's special treatment.
+    (?$(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 20 (tr . br))
+    (?$(5"q(B 20 (br . tr))
+    (?$(5"r(B 20 (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)
+    (?$(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)
+    (?$(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)
+    ))
+
+;; Determine composition priority and rule of the array of Glyphs.
+;; Sort the glyphs with their priority.
+
+;; Example:
+;;(devanagari-reorder-glyph-for-composition '[?$(5"5(B ?$(5!X(B ?$(5![(B])
+;;	=> ((446680 0) (446773 0) (446683 50 (ml . mr)))
+
+(defun devanagari-reorder-glyph-for-composition (glyph-alist)
+  (let* ((pos 0)
+	 (ordered-glyphs '()))
+    (while (< pos (length glyph-alist))
+      (let* ((glyph (aref glyph-alist 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") => "2$(6!XP"5@![1(B"
+
+(defun devanagari-compose-to-one-glyph (devanagari-string)
+  (let* ((o-glyph-list (devanagari-reorder-glyph-for-composition
+			(string-to-vector 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))))
+
+
+;;
+;;    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 '(446680 446773 (ml . mr) 446683))
+;;(devanagari-wide-to-narrow '(?$(5!6(B (ml . ml) 446773 (tc . mr) 446683))
+
+(defun devanagari-wide-to-narrow (src-list)
+  (if (null src-list) '()
+    (cons 
+     (if (and (numberp (car src-list))
+	      (cdr (assq (car src-list) devanagari-1-column-char)))
+	 (cdr (assq (car src-list) devanagari-1-column-char))
+       (car src-list))
+     (devanagari-wide-to-narrow (cdr src-list)))))
+
+;; Make this function obsolete temporary Because now Emacs supports
+;; attaching 1 column character at the center 2 column char.  However,
+;; there are still problems attempting to attach Halant or Nukta sign
+;; at the non-vowel consonant.  This problem can not be solved until
+;; Emacs supports attaching the glyph at `temporary-preserved metric'.
+
+(defun devanagari-wide-to-narrow-old (src-list)
+  (if (null src-list) (progn (error "devanagari-wide-to-narrow error") nil)
+    (let* ((base-glyph (cdr (assq (car src-list) devanagari-1-column-char)))
+	   (wide-base-glyph nil)
+	   (apply-glyph-list (cdr src-list)))
+      (if (null base-glyph)
+	  (progn 
+	    (setq wide-base-glyph t)
+	    (setq base-glyph (car src-list))))
+      (cons base-glyph
+	    (devanagari-wide-to-narrow-iter apply-glyph-list wide-base-glyph))
+      )))
+
+;; Convert apply-glyph-list from 2-column to 1-column.
+;;   wide-base-glyph is t when base-glyph is 2-column.
+;;   When apply-glyph is put at the top or bottom of 2-column base-glyph,
+;;   they must be 2-column glyph, too.  Otherwise, they will be 
+;;   converted to 1-column glyph if possible.
+
+(defun devanagari-wide-to-narrow-iter (apply-glyph-list wide-base-glyph)
+  (if (< (length apply-glyph-list) 2) '()
+    (let* ((apply-dir    (car apply-glyph-list))
+	   (apply-glyph  (car (cdr apply-glyph-list)))
+	   (apply-rest   (cdr (cdr apply-glyph-list)))
+	   (put-t-or-b   (member (car apply-dir) '(tl tc tr bl bc br)))
+	   (narrow-glyph (cdr (assq apply-glyph devanagari-1-column-char))))
+      (append 
+       (list apply-dir
+	     (if (or (and wide-base-glyph put-t-or-b)
+		     (null narrow-glyph))
+		 apply-glyph narrow-glyph))
+       (devanagari-wide-to-narrow-iter apply-rest wide-base-glyph)))))
+
+;;
+;; Summary
+;; 
+
+;;;###autoload
+(defun devanagari-compose-string (str)
+  (let ((len (length str))
+	(src str) (dst "") rest match-b match-e)
+    (while (string-match devanagari-composite-glyph-unit-examine src)
+      (setq match-b (match-beginning 0) match-e (match-end 0))
+      (setq dst 
+	    (concat dst 
+		    (substring src 0 match-b)
+		    (devanagari-compose-to-one-glyph 
+		     (char-to-glyph-devanagari
+		      (substring src match-b match-e)))))
+      (setq src (substring src match-e)))
+    (setq dst (concat dst src))
+    dst))
+
+;;;###autoload
+(defun devanagari-compose-region (from to)
+  (interactive "r")
+  (save-restriction
+    (narrow-to-region from to)
+    (goto-char (point-min))
+    (while (re-search-forward devanagari-composite-glyph-unit-examine nil t)
+      (let* ((match-b (match-beginning 0)) (match-e (match-end 0))
+	     (cmps (devanagari-compose-to-one-glyph
+		    (char-to-glyph-devanagari
+		     (buffer-substring match-b match-e)))))
+	(delete-region match-b match-e)
+	(insert cmps)))))
+
+;;
+;; Decomposition of composite font.
+;;
+
+(defun devanagari-normalize-narrow-glyph (charlist)
+  (let ((wide-char (car (rassoc (car charlist) devanagari-1-column-char))))
+    (if (null charlist) nil
+      (cons (if (null wide-char) (car charlist) wide-char)
+	    (devanagari-normalize-narrow-glyph (cdr charlist))))))
+
+(defvar devanagari-decomposition-rules
+  '(
+    (?$(5"p(B -20)
+    )
+  )
+
+(defun devanagari-reorder-glyph-for-decomposition (glyphlist)
+  "This function re-orders glyph list."
+  (sort glyphlist 
+	'(lambda (x y) 
+	   (let ((xx (assoc x devanagari-decomposition-rules))
+		 (yy (assoc y devanagari-decomposition-rules)))
+	     (if (null xx) (setq xx 0))
+	     (if (null yy) (setq yy 0))
+	     (< xx yy)))))
+
+(defun devanagari-decompose-char (char)
+  "This function decomposes one Devanagari composite character to 
+   basic Devanagari character."
+  (let ((glyphlist (decompose-composite-char char)))
+    (if (not (listp glyphlist)) 
+	(setq glyphlist (list glyphlist)))
+    (setq glyphlist (devanagari-normalize-narrow-glyph glyphlist))
+    (mapconcat '(lambda (x) (let ((char (get-char-code-property 
+					 x 'glyph-to-char)))
+			   (if (null char) (char-to-string x) char)))
+	       (devanagari-reorder-glyph-for-decomposition glyphlist)
+	       "")))
+
+;;;###autoload
+(defun devanagari-decompose-string (str)
+  "This function Decomposes Devanagari glyph string to 
+basic Devanagari character string."
+  (let ((src str) (dst ""))
+    (while (not (equal src ""))
+      (let* ((char (string-to-char src))
+	     (clen (char-bytes char)))
+	(setq src (substring src clen))
+	(setq dst (concat dst
+			  (devanagari-decompose-char char)))))
+    dst))
+
+;;;###autoload
+(defun devanagari-decompose-region (from to)
+  (interactive "r")
+  (save-restriction
+    (narrow-to-region from to)
+    (goto-char (point-min))
+    (while (re-search-forward "." nil t)
+      (let* ((match-b (match-beginning 0)) (match-e (match-end 0))
+	     (decmps (devanagari-decompose-string (buffer-substring match-b match-e))))
+	(delete-char -1)
+	(insert decmps)))))
+
+
+
+;; 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-restriction
+    (narrow-to-region from to)
+    (indian-to-devanagari-region (point-min) (point-max))
+    (devanagari-compose-region (point-min) (point-max))))
+
+;;;###autoload
+(defun devanagari-decompose-to-is13194-region (from to)
+  "Decompose Devanagari characters in the region to IS 13194 characters."
+  (interactive "r")
+  (save-restriction
+    (narrow-to-region from to)
+    (devanagari-decompose-region (point-min) (point-max))
+    (devanagari-to-indian-region (point-min) (point-max))))
+
+;;
+(provide 'language/devan-util)
+
+;;; Local Variables:
+;;; generated-autoload-file: "../loaddefs.el"
+;;; End:
+;;; devan-util.el ends here