Merge from emacs--rel--22
[bpt/emacs.git] / lisp / language / ethio-util.el
dissimilarity index 84%
index ad86d8d..857df13 100644 (file)
-;; ethio-util.el -- utilities for Ethiopic
-
-;; Copyright (C) 1995 Free Software Foundation, Inc.
-;; Copyright (C) 1995 Electrotechnical Laboratory, JAPAN.
-
-;; Keywords: mule, multilingual, Chinese
-
-;; 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.
-
-;;; Code:
-
-;;
-;; ETHIOPIC UTILITY FUNCTIONS
-;;
-
-;; To automatically convert Ethiopic text to SERA format when sending mail,
-;;   (add-hook 'mail-send-hook 'fidel-to-sera-mail)
-;;
-;; To automatically convert SERA format to Ethiopic when receiving mail,
-;;   (add-hook 'rmail-show-message-hook 'sera-to-fidel-mail)
-;;
-;; To automatically convert Ethiopic text to SERA format when posting news,
-;;   (add-hook 'news-inews-hook 'fidel-to-sera-mail)
-;;
-;; If the filename ends in ".sera", editing will be done in fidel
-;; while file I/O will be done in sera.
-
-;;
-;; SERA to FIDEL
-;;
-   
-(defconst sera-to-fidel-table
-  [
-   nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
-   nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
-;;; SP  !   "   #   $   %   &   '    (   )   *   +    ,     -    .     /
-   nil nil nil nil nil nil nil ("") nil nil nil nil ("\e$(2$Q\e(B") nil ("\e$(2$P\e(B") nil
-;;; 0   1   2   3   4   5   6   7   8   9    :      ;     <   =   >   ?   @
-   nil nil nil nil nil nil nil nil nil nil ("\e$(2$S\e(B") ("\e$(2$R\e(B") nil nil nil nil nil
-;;; A
-   ("\e$(2"V\e(B" (?2 "\e$(2#b\e(B"))
-;;; B
-   ("\e$(2!F\e(B" (?e "\e$(2!A\e(B") (?u "\e$(2!B\e(B") (?i "\e$(2!C\e(B") (?a "\e$(2!D\e(B") (?E "\e$(2!E\e(B") (?o "\e$(2!G\e(B") (?| "\e$(2!F\e(B")
-         (?W "\e$(2!H\e(B" (?a "\e$(2!H\e(B")
-                 (?e "\e$(2!F#L\e(B") (?u "\e$(2!F#M\e(B") (?i "\e$(2!F#N\e(B") (?E "\e$(2!F#P\e(B") (?' "\e$(2!F#M\e(B")))
-;;; C
-   ("\e$(2"8\e(B" (?e "\e$(2"3\e(B") (?u "\e$(2"4\e(B") (?i "\e$(2"5\e(B") (?a "\e$(2"6\e(B") (?E "\e$(2"7\e(B") (?o "\e$(2"9\e(B") (?| "\e$(2"8\e(B")
-         (?W "\e$(2":\e(B" (?a "\e$(2":\e(B")
-                 (?e "\e$(2"8#L\e(B") (?u "\e$(2"8#M\e(B") (?i "\e$(2"8#N\e(B") (?E "\e$(2"8#P\e(B") (?' "\e$(2"8#M\e(B")))
-;;; D
-   ("\e$(2$0\e(B" (?e "\e$(2$+\e(B") (?u "\e$(2$,\e(B") (?i "\e$(2$-\e(B") (?a "\e$(2$.\e(B") (?E "\e$(2$/\e(B") (?o "\e$(2$1\e(B") (?| "\e$(2$0\e(B"))
-;;; E
-   ("\e$(2"W\e(B" (?2 "\e$(2#c\e(B"))
-;;; F
-   ("\e$(2"@\e(B" (?e "\e$(2";\e(B") (?u "\e$(2"<\e(B") (?i "\e$(2"=\e(B") (?a "\e$(2">\e(B") (?E "\e$(2"?\e(B") (?o "\e$(2"A\e(B") (?| "\e$(2"@\e(B")
-         (?W "\e$(2"B\e(B" (?a "\e$(2"B\e(B")
-                 (?e "\e$(2"@#L\e(B") (?u "\e$(2"@#M\e(B") (?i "\e$(2"@#N\e(B") (?E "\e$(2"@#P\e(B") (?' "\e$(2"@#M\e(B")))
-;;; G
-   ("\e$(2$>\e(B" (?e "\e$(2$9\e(B") (?u "\e$(2$:\e(B") (?i "\e$(2$;\e(B") (?a "\e$(2$<\e(B") (?E "\e$(2$=\e(B") (?o "\e$(2$?\e(B") (?| "\e$(2$>\e(B"))
-;;; H
-   ("\e$(2$"\e(B" (?e "\e$(2#{\e(B") (?u "\e$(2#|\e(B") (?i "\e$(2#}\e(B") (?a "\e$(2#~\e(B") (?E "\e$(2$!\e(B") (?o "\e$(2$#\e(B") (?| "\e$(2$"\e(B"))
-;;; I
-   ("\e$(2"X\e(B" (?2 "\e$(2#d\e(B"))
-;;; J
-   ("\e$(2$7\e(B" (?e "\e$(2$2\e(B") (?u "\e$(2$3\e(B") (?i "\e$(2$4\e(B") (?a "\e$(2$5\e(B") (?E "\e$(2$6\e(B") (?o "\e$(2$8\e(B") (?| "\e$(2$7\e(B"))
-;;; K
-   ("\e$(2"x\e(B" (?e "\e$(2"s\e(B") (?u "\e$(2"t\e(B") (?i "\e$(2"u\e(B") (?a "\e$(2"v\e(B") (?E "\e$(2"w\e(B") (?o "\e$(2"y\e(B") (?| "\e$(2"x\e(B")
-         (?W "\e$(2"{\e(B" (?e "\e$(2"z\e(B") (?u "\e$(2"{\e(B") (?i "\e$(2"|\e(B") (?a "\e$(2"}\e(B") (?E "\e$(2"~\e(B")))
-;;; L
-   ("\e$(2!&\e(B" (?e "\e$(2!!\e(B") (?u "\e$(2!"\e(B") (?i "\e$(2!#\e(B") (?a "\e$(2!$\e(B") (?E "\e$(2!%\e(B") (?o "\e$(2!'\e(B") (?| "\e$(2!&\e(B")
-         (?W "\e$(2!(\e(B" (?a "\e$(2!(\e(B")
-                  (?e "\e$(2!&#L\e(B") (?u "\e$(2!&#M\e(B") (?i "\e$(2!&#N\e(B") (?E "\e$(2!&#P\e(B") (?' "\e$(2!&#M\e(B")))
-;;; M
-   ("\e$(2!.\e(B" (?e "\e$(2!)\e(B") (?u "\e$(2!*\e(B") (?i "\e$(2!+\e(B") (?a "\e$(2!,\e(B") (?E "\e$(2!-\e(B") (?o "\e$(2!/\e(B") (?| "\e$(2!.\e(B")
-         (?W "\e$(2!0\e(B" (?a "\e$(2!0\e(B")
-                 (?e "\e$(2!.#L\e(B") (?u "\e$(2!.#M\e(B") (?i "\e$(2!.#N\e(B") (?E "\e$(2!.#P\e(B") (?' "\e$(2!.#M\e(B")))
-;;; N
-   ("\e$(2!n\e(B" (?e "\e$(2!i\e(B") (?u "\e$(2!j\e(B") (?i "\e$(2!k\e(B") (?a "\e$(2!l\e(B") (?E "\e$(2!m\e(B") (?o "\e$(2!o\e(B") (?| "\e$(2!n\e(B")
-         (?W "\e$(2!p\e(B" (?a "\e$(2!p\e(B")
-                 (?e "\e$(2!n#L\e(B") (?u "\e$(2!n#M\e(B") (?i "\e$(2!n#N\e(B") (?E "\e$(2!n#P\e(B") (?' "\e$(2!n#M\e(B")))
-;;; O
-   ("\e$(2"Y\e(B" (?2 "\e$(2#e\e(B"))
-;;; P
-   ("\e$(2$E\e(B" (?e "\e$(2$@\e(B") (?u "\e$(2$A\e(B") (?i "\e$(2$B\e(B") (?a "\e$(2$C\e(B") (?E "\e$(2$D\e(B") (?o "\e$(2$F\e(B") (?| "\e$(2$E\e(B"))
-;;; Q
-   ("\e$(2#2\e(B" (?e "\e$(2#-\e(B") (?u "\e$(2#.\e(B") (?i "\e$(2#/\e(B") (?a "\e$(2#0\e(B") (?E "\e$(2#1\e(B") (?o "\e$(2#3\e(B") (?| "\e$(2#2\e(B")
-         (?W "\e$(2#5\e(B" (?e "\e$(2#4\e(B") (?u "\e$(2#5\e(B") (?i "\e$(2#6\e(B") (?a "\e$(2#7\e(B") (?E "\e$(2#8\e(B")))
-;;; R
-   ("\e$(2!6\e(B" (?e "\e$(2!1\e(B") (?u "\e$(2!2\e(B") (?i "\e$(2!3\e(B") (?a "\e$(2!4\e(B") (?E "\e$(2!5\e(B") (?o "\e$(2!7\e(B") (?| "\e$(2!6\e(B")
-         (?W "\e$(2!8\e(B" (?a "\e$(2!8\e(B")
-                 (?e "\e$(2!6#L\e(B") (?u "\e$(2!6#M\e(B") (?i "\e$(2!6#N\e(B") (?E "\e$(2!6#P\e(B") (?' "\e$(2!6#M\e(B")))
-;;; S
-   ("\e$(2"P\e(B" (?e "\e$(2"K\e(B") (?u "\e$(2"L\e(B") (?i "\e$(2"M\e(B") (?a "\e$(2"N\e(B") (?E "\e$(2"O\e(B") (?o "\e$(2"Q\e(B") (?| "\e$(2"P\e(B")
-         (?W "\e$(2"R\e(B" (?a "\e$(2"R\e(B")
-                  (?e "\e$(2"P#L\e(B") (?u "\e$(2"P#M\e(B") (?i "\e$(2"P#N\e(B") (?E "\e$(2"P#P\e(B") (?' "\e$(2"P#M\e(B"))
-        (?2 "\e$(2#]\e(B" (?| "\e$(2#]\e(B")
-            (?e "\e$(2#X\e(B") (?u "\e$(2#Y\e(B") (?i "\e$(2#Z\e(B") (?a "\e$(2#[\e(B") (?E "\e$(2#\\e(B") (?o "\e$(2#^\e(B")
-            (?W "\e$(2"R\e(B"
-                (?a "\e$(2"R\e(B")
-                (?e "\e$(2#]#L\e(B") (?u "\e$(2#]#M\e(B") (?i "\e$(2#]#N\e(B") (?E "\e$(2#]#P\e(B") (?' "\e$(2#]#M\e(B"))))
-               
-;;; T
-   ("\e$(2"0\e(B" (?e "\e$(2"+\e(B") (?u "\e$(2",\e(B") (?i "\e$(2"-\e(B") (?a "\e$(2".\e(B") (?E "\e$(2"/\e(B") (?o "\e$(2"1\e(B") (?| "\e$(2"0\e(B")
-         (?W "\e$(2"2\e(B" (?a "\e$(2"2\e(B")
-                 (?e "\e$(2"0#L\e(B") (?u "\e$(2"0#M\e(B") (?i "\e$(2"0#N\e(B") (?E "\e$(2"0#P\e(B") (?' "\e$(2"0#M\e(B")))
-;;; U
-   ("\e$(2"T\e(B" (?2 "\e$(2#`\e(B"))
-;;; V
-   ("\e$(2!N\e(B" (?e "\e$(2!I\e(B") (?u "\e$(2!J\e(B") (?i "\e$(2!K\e(B") (?a "\e$(2!L\e(B") (?E "\e$(2!M\e(B") (?o "\e$(2!O\e(B") (?| "\e$(2!N\e(B")
-         (?W "\e$(2!P\e(B" (?a "\e$(2!P\e(B")
-                 (?e "\e$(2!N#L\e(B") (?u "\e$(2!N#M\e(B") (?i "\e$(2!N#N\e(B") (?E "\e$(2!N#P\e(B") (?' "\e$(2!N#M\e(B")))
-;;; W
-   ("\e$(2#M\e(B" (?e "\e$(2#L\e(B") (?u "\e$(2#M\e(B") (?i "\e$(2#N\e(B") (?a "\e$(2#O\e(B") (?E "\e$(2#P\e(B"))
-;;; X
-   ("\e$(2#y\e(B" (?e "\e$(2#t\e(B") (?u "\e$(2#u\e(B") (?i "\e$(2#v\e(B") (?a "\e$(2#w\e(B") (?E "\e$(2#x\e(B") (?o "\e$(2#z\e(B") (?| "\e$(2#y\e(B"))
-;;; Y
-   ("\e$(2$)\e(B" (?e "\e$(2$$\e(B") (?u "\e$(2$%\e(B") (?i "\e$(2$&\e(B") (?a "\e$(2$'\e(B") (?E "\e$(2$(\e(B") (?o "\e$(2$*\e(B") (?| "\e$(2$)\e(B"))
-;;; Z
-   ("\e$(2!~\e(B" (?e "\e$(2!y\e(B") (?u "\e$(2!z\e(B") (?i "\e$(2!{\e(B") (?a "\e$(2!|\e(B") (?E "\e$(2!}\e(B") (?o "\e$(2"!\e(B") (?| "\e$(2!~\e(B")
-         (?W "\e$(2""\e(B" (?a "\e$(2""\e(B")
-                 (?e "\e$(2!~#L\e(B") (?u "\e$(2!~#M\e(B") (?i "\e$(2!~#N\e(B") (?E "\e$(2!~#P\e(B") (?' "\e$(2!~#M\e(B")))
-;;; [   \   ]   ^   _
-   nil nil nil nil nil
-;;; `
-   ("`"
-    (?e "\e$(2#_\e(B") (?u "\e$(2#`\e(B") (?U "\e$(2#`\e(B") (?i "\e$(2#a\e(B") (?a "\e$(2#b\e(B") (?A "\e$(2#b\e(B")
-    (?E "\e$(2#c\e(B") (?I "\e$(2#d\e(B") (?o "\e$(2#e\e(B") (?O "\e$(2#e\e(B")
-    (?s "\e$(2#V\e(B"
-       (?e "\e$(2#Q\e(B") (?u "\e$(2#R\e(B") (?i "\e$(2#S\e(B") (?a "\e$(2#T\e(B") (?E "\e$(2#U\e(B") (?o "\e$(2#W\e(B") (?| "\e$(2#V\e(B")
-       (?W "\e$(2"J\e(B" (?a "\e$(2"J\e(B")
-                (?e "\e$(2#V#L\e(B") (?u "\e$(2#V#M\e(B") (?i "\e$(2#V#N\e(B") (?E "\e$(2#V#P\e(B") (?' "\e$(2#V#M\e(B")))
-    (?S "\e$(2#]\e(B"
-       (?e "\e$(2#X\e(B") (?u "\e$(2#Y\e(B") (?i "\e$(2#Z\e(B") (?a "\e$(2#[\e(B") (?E "\e$(2#\\e(B") (?o "\e$(2#^\e(B") (?| "\e$(2#]\e(B")
-       (?W "\e$(2"R\e(B" (?a "\e$(2"R\e(B")
-                (?e "\e$(2#]#L\e(B") (?u "\e$(2#]#M\e(B") (?i "\e$(2#]#N\e(B") (?E "\e$(2#]#P\e(B") (?' "\e$(2#]#M\e(B")))
-    (?h "\e$(2#k\e(B"
-       (?e "\e$(2#f\e(B") (?u "\e$(2#g\e(B") (?i "\e$(2#h\e(B") (?a "\e$(2#i\e(B") (?E "\e$(2#j\e(B") (?o "\e$(2#l\e(B") (?| "\e$(2#k\e(B")
-        (?W "\e$(2"c\e(B" (?e "\e$(2"b\e(B") (?u "\e$(2"c\e(B") (?i "\e$(2"d\e(B") (?a "\e$(2"e\e(B") (?E "\e$(2"f\e(B")))
-    (?k "\e$(2#r\e(B"
-        (?e "\e$(2#m\e(B") (?u "\e$(2#n\e(B") (?i "\e$(2#o\e(B") (?a "\e$(2#p\e(B") (?E "\e$(2#q\e(B") (?o "\e$(2#s\e(B") (?| "\e$(2#r\e(B")))
-;;; a
-   ("\e$(2"S\e(B" (?2 "\e$(2#b\e(B"))
-
-;;; b
-   ("\e$(2!F\e(B" (?e "\e$(2!A\e(B") (?u "\e$(2!B\e(B") (?i "\e$(2!C\e(B") (?a "\e$(2!D\e(B") (?E "\e$(2!E\e(B") (?o "\e$(2!G\e(B") (?| "\e$(2!F\e(B")
-         (?W "\e$(2!H\e(B" (?a "\e$(2!H\e(B")
-                 (?e "\e$(2!F#L\e(B") (?u "\e$(2!F#M\e(B") (?i "\e$(2!F#N\e(B") (?E "\e$(2!F#P\e(B") (?' "\e$(2!F#M\e(B")))
-;;; c
-   ("\e$(2!^\e(B" (?e "\e$(2!Y\e(B") (?u "\e$(2!Z\e(B") (?i "\e$(2![\e(B") (?a "\e$(2!\\e(B") (?E "\e$(2!]\e(B") (?o "\e$(2!_\e(B") (?| "\e$(2!^\e(B")
-         (?W "\e$(2!`\e(B" (?a "\e$(2!`\e(B")
-                 (?e "\e$(2!^#L\e(B") (?u "\e$(2!^#M\e(B") (?i "\e$(2!^#N\e(B") (?E "\e$(2!^#P\e(B") (?' "\e$(2!^#M\e(B")))
-;;; d
-   ("\e$(2"(\e(B" (?e "\e$(2"#\e(B") (?u "\e$(2"$\e(B") (?i "\e$(2"%\e(B") (?a "\e$(2"&\e(B") (?E "\e$(2"'\e(B") (?o "\e$(2")\e(B") (?| "\e$(2"(\e(B")
-         (?W "\e$(2"*\e(B" (?a "\e$(2"*\e(B")
-                 (?e "\e$(2"(#L\e(B") (?u "\e$(2"(#M\e(B") (?i "\e$(2"(#N\e(B") (?E "\e$(2"(#P\e(B") (?' "\e$(2"(#M\e(B")))
-;;; e
-   ("\e$(2"S\e(B" (?2 "\e$(2#_\e(B") (?3 "\e$(2"Z\e(B"))
-;;; f
-   ("\e$(2"@\e(B" (?e "\e$(2";\e(B") (?u "\e$(2"<\e(B") (?i "\e$(2"=\e(B") (?a "\e$(2">\e(B") (?E "\e$(2"?\e(B") (?o "\e$(2"A\e(B") (?| "\e$(2"@\e(B")
-         (?W "\e$(2"B\e(B" (?a "\e$(2"B\e(B")
-                 (?e "\e$(2"@#L\e(B") (?u "\e$(2"@#M\e(B") (?i "\e$(2"@#N\e(B") (?E "\e$(2"@#P\e(B") (?' "\e$(2"@#M\e(B")))
-;;; g
-   ("\e$(2#>\e(B" (?e "\e$(2#9\e(B") (?u "\e$(2#:\e(B") (?i "\e$(2#;\e(B") (?a "\e$(2#<\e(B") (?E "\e$(2#=\e(B") (?o "\e$(2#?\e(B") (?| "\e$(2#>\e(B")
-         (?W "\e$(2#A\e(B" (?e "\e$(2#@\e(B") (?u "\e$(2#A\e(B") (?i "\e$(2#B\e(B") (?a "\e$(2#C\e(B") (?E "\e$(2#D\e(B")))
-;;; h
-   ("\e$(2"`\e(B" (?e "\e$(2"[\e(B") (?u "\e$(2"\\e(B") (?i "\e$(2"]\e(B") (?a "\e$(2"^\e(B") (?E "\e$(2"_\e(B") (?o "\e$(2"a\e(B") (?| "\e$(2"`\e(B")
-         (?W "\e$(2"c\e(B" (?e "\e$(2"b\e(B") (?u "\e$(2"c\e(B") (?i "\e$(2"d\e(B") (?a "\e$(2"e\e(B") (?E "\e$(2"f\e(B"))
-        (?2 "\e$(2#k\e(B" (?e "\e$(2#f\e(B") (?u "\e$(2#g\e(B") (?i "\e$(2#h\e(B") (?a "\e$(2#i\e(B") (?E "\e$(2#j\e(B") (?o "\e$(2#l\e(B")
-                 (?| "\e$(2#k\e(B")
-                 (?W "\e$(2"c\e(B" (?e "\e$(2"b\e(B") (?u "\e$(2"c\e(B") (?i "\e$(2"d\e(B") (?a "\e$(2"e\e(B") (?E "\e$(2"f\e(B"))))
-;;; i
-   ("\e$(2"U\e(B" (?2 "\e$(2#a\e(B"))
-;;; j
-   ("\e$(2$7\e(B" (?e "\e$(2$2\e(B") (?u "\e$(2$3\e(B") (?i "\e$(2$4\e(B") (?a "\e$(2$5\e(B") (?E "\e$(2$6\e(B") (?o "\e$(2$8\e(B") (?| "\e$(2$7\e(B"))
-;;; k
-   ("\e$(2"l\e(B" (?e "\e$(2"g\e(B") (?u "\e$(2"h\e(B") (?i "\e$(2"i\e(B") (?a "\e$(2"j\e(B") (?E "\e$(2"k\e(B") (?o "\e$(2"m\e(B") (?| "\e$(2"l\e(B")
-         (?W "\e$(2"o\e(B" (?e "\e$(2"n\e(B") (?u "\e$(2"o\e(B") (?i "\e$(2"p\e(B") (?a "\e$(2"q\e(B") (?E "\e$(2"r\e(B"))
-        (?2 "\e$(2#r\e(B" (?e "\e$(2#m\e(B") (?u "\e$(2#n\e(B") (?i "\e$(2#o\e(B") (?a "\e$(2#p\e(B") (?E "\e$(2#q\e(B") (?o "\e$(2#s\e(B")
-                 (?| "\e$(2#r\e(B")))
-;;; l
-   ("\e$(2!&\e(B" (?e "\e$(2!!\e(B") (?u "\e$(2!"\e(B") (?i "\e$(2!#\e(B") (?a "\e$(2!$\e(B") (?E "\e$(2!%\e(B") (?o "\e$(2!'\e(B") (?| "\e$(2!&\e(B")
-         (?W "\e$(2!(\e(B" (?a "\e$(2!(\e(B")
-                  (?e "\e$(2!&#L\e(B") (?u "\e$(2!&#M\e(B") (?i "\e$(2!&#N\e(B") (?E "\e$(2!&#P\e(B") (?' "\e$(2!&#M\e(B")))
-;;; m
-   ("\e$(2!.\e(B" (?e "\e$(2!)\e(B") (?u "\e$(2!*\e(B") (?i "\e$(2!+\e(B") (?a "\e$(2!,\e(B") (?E "\e$(2!-\e(B") (?o "\e$(2!/\e(B") (?| "\e$(2!.\e(B")
-         (?W "\e$(2!0\e(B" (?a "\e$(2!0\e(B")
-                 (?e "\e$(2!.#L\e(B") (?u "\e$(2!.#M\e(B") (?i "\e$(2!.#N\e(B") (?E "\e$(2!.#P\e(B") (?' "\e$(2!.#M\e(B")))
-;;; n
-   ("\e$(2!f\e(B" (?e "\e$(2!a\e(B") (?u "\e$(2!b\e(B") (?i "\e$(2!c\e(B") (?a "\e$(2!d\e(B") (?E "\e$(2!e\e(B") (?o "\e$(2!g\e(B") (?| "\e$(2!f\e(B")
-         (?W "\e$(2!h\e(B" (?a "\e$(2!h\e(B")
-                 (?e "\e$(2!f#L\e(B") (?u "\e$(2!f#M\e(B") (?i "\e$(2!f#N\e(B") (?E "\e$(2!f#P\e(B") (?' "\e$(2!f#M\e(B")))
-;;; o
-   ("\e$(2"Y\e(B" (?2 "\e$(2#e\e(B"))
-;;; p
-   ("\e$(2$L\e(B" (?e "\e$(2$G\e(B") (?u "\e$(2$H\e(B") (?i "\e$(2$I\e(B") (?a "\e$(2$J\e(B") (?E "\e$(2$K\e(B") (?o "\e$(2$M\e(B") (?| "\e$(2$L\e(B"))
-;;; q
-   ("\e$(2#&\e(B" (?e "\e$(2#!\e(B") (?u "\e$(2#"\e(B") (?i "\e$(2##\e(B") (?a "\e$(2#$\e(B") (?E "\e$(2#%\e(B") (?o "\e$(2#'\e(B") (?| "\e$(2#&\e(B")
-         (?W "\e$(2#)\e(B" (?e "\e$(2#(\e(B") (?u "\e$(2#)\e(B") (?i "\e$(2#*\e(B") (?a "\e$(2#+\e(B") (?E "\e$(2#,\e(B")))
-;;; r
-   ("\e$(2!6\e(B" (?e "\e$(2!1\e(B") (?u "\e$(2!2\e(B") (?i "\e$(2!3\e(B") (?a "\e$(2!4\e(B") (?E "\e$(2!5\e(B") (?o "\e$(2!7\e(B") (?| "\e$(2!6\e(B")
-         (?W "\e$(2!8\e(B" (?a "\e$(2!8\e(B")
-                 (?e "\e$(2!6#L\e(B") (?u "\e$(2!6#M\e(B") (?i "\e$(2!6#N\e(B") (?E "\e$(2!6#P\e(B") (?' "\e$(2!6#M\e(B")))
-;;; s
-   ("\e$(2"H\e(B" (?e "\e$(2"C\e(B") (?u "\e$(2"D\e(B") (?i "\e$(2"E\e(B") (?a "\e$(2"F\e(B") (?E "\e$(2"G\e(B") (?o "\e$(2"I\e(B") (?| "\e$(2"H\e(B")
-         (?W "\e$(2"J\e(B" (?a "\e$(2"J\e(B")
-                 (?e "\e$(2"H#L\e(B") (?u "\e$(2"H#M\e(B") (?i "\e$(2"H#N\e(B") (?E "\e$(2"H#P\e(B") (?' "\e$(2"H#M\e(B"))
-        (?2 "\e$(2#V\e(B" (?e "\e$(2#Q\e(B") (?u "\e$(2#R\e(B") (?i "\e$(2#S\e(B") (?a "\e$(2#T\e(B") (?E "\e$(2#U\e(B") (?o "\e$(2#W\e(B")
-                 (?| "\e$(2#V\e(B")
-                 (?W "\e$(2"J\e(B" (?a "\e$(2"J\e(B")
-                          (?e "\e$(2#V#L\e(B") (?u "\e$(2#V#M\e(B") (?i "\e$(2#V#N\e(B") (?E "\e$(2#V#P\e(B")
-                          (?' "\e$(2#V#M\e(B"))))
-;;; t
-   ("\e$(2!V\e(B" (?e "\e$(2!Q\e(B") (?u "\e$(2!R\e(B") (?i "\e$(2!S\e(B") (?a "\e$(2!T\e(B") (?E "\e$(2!U\e(B") (?o "\e$(2!W\e(B") (?| "\e$(2!V\e(B")
-         (?W "\e$(2!X\e(B" (?a "\e$(2!X\e(B")
-                 (?e "\e$(2!V#L\e(B") (?u "\e$(2!V#M\e(B") (?i "\e$(2!V#N\e(B") (?E "\e$(2!V#P\e(B") (?' "\e$(2!V#M\e(B")))
-;;; u
-   ("\e$(2"T\e(B" (?2 "\e$(2#`\e(B"))
-;;; v
-   ("\e$(2!N\e(B" (?e "\e$(2!I\e(B") (?u "\e$(2!J\e(B") (?i "\e$(2!K\e(B") (?a "\e$(2!L\e(B") (?E "\e$(2!M\e(B") (?o "\e$(2!O\e(B") (?| "\e$(2!N\e(B")
-         (?W "\e$(2!P\e(B" (?a "\e$(2!P\e(B")
-                 (?e "\e$(2!N#L\e(B") (?u "\e$(2!N#M\e(B") (?i "\e$(2!N#N\e(B") (?E "\e$(2!N#P\e(B") (?' "\e$(2!N#M\e(B")))
-;;; w
-   ("\e$(2#J\e(B" (?e "\e$(2#E\e(B") (?u "\e$(2#F\e(B") (?i "\e$(2#G\e(B") (?a "\e$(2#H\e(B") (?E "\e$(2#I\e(B") (?o "\e$(2#K\e(B") (?| "\e$(2#J\e(B")
-         (?W "\e$(2#M\e(B" (?e "\e$(2#L\e(B") (?u "\e$(2#M\e(B") (?i "\e$(2#N\e(B") (?a "\e$(2#O\e(B") (?E "\e$(2#P\e(B")))
-;;; x
-   ("\e$(2!>\e(B" (?e "\e$(2!9\e(B") (?u "\e$(2!:\e(B") (?i "\e$(2!;\e(B") (?a "\e$(2!<\e(B") (?E "\e$(2!=\e(B") (?o "\e$(2!?\e(B") (?| "\e$(2!>\e(B")
-         (?W "\e$(2!@\e(B" (?a "\e$(2!@\e(B")
-                 (?e "\e$(2!>#L\e(B") (?u "\e$(2!>#M\e(B") (?i "\e$(2!>#N\e(B") (?E "\e$(2!>#P\e(B") (?' "\e$(2!>#M\e(B")))
-;;; y
-   ("\e$(2$)\e(B" (?e "\e$(2$$\e(B") (?u "\e$(2$%\e(B") (?i "\e$(2$&\e(B") (?a "\e$(2$'\e(B") (?E "\e$(2$(\e(B") (?o "\e$(2$*\e(B") (?| "\e$(2$)\e(B"))
-;;; z
-   ("\e$(2!v\e(B" (?e "\e$(2!q\e(B") (?u "\e$(2!r\e(B") (?i "\e$(2!s\e(B") (?a "\e$(2!t\e(B") (?E "\e$(2!u\e(B") (?o "\e$(2!w\e(B") (?| "\e$(2!v\e(B")
-         (?W "\e$(2!x\e(B" (?a "\e$(2!x\e(B")
-                 (?e "\e$(2!v#L\e(B") (?u "\e$(2!v#M\e(B") (?i "\e$(2!v#N\e(B") (?E "\e$(2!v#P\e(B") (?' "\e$(2!v#M\e(B")))
-   ])
-
-;;;###autoload
-(defun sera-to-fidel-region (beg end &optional ascii-mode force)
-  "Translates the characters in region from SERA to FIDEL.
-
-If the 1st optional parameter ASCII-MODE is non-NIL, assumes that the
-region begins in ASCII script.
-
-If the 2nd optional parametr FORCE is non-NIL, translates even if the
-buffer is read-only."
-
-  (interactive "r\nP")
-  (save-excursion
-    (save-restriction
-      (narrow-to-region beg end)
-      (sera-to-fidel-buffer ascii-mode force))))
-
-;;;###autoload
-(defun sera-to-fidel-buffer (&optional ascii-mode force)
-  "Translates the current buffer from SERA to FIDEL.
-
-If the 1st optional parameter ASCII-MODE is non-NIL, assumes that the
-current buffer begins in ASCII script.
-
-If the 2nd optional panametr FORCE is non-NIL, translates even if the
-buffer is read-only."
-
-  (interactive "P")
-  (if (and buffer-read-only
-          (not force)
-          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
-      (error ""))
-  (let (start pre fol hard table table2 (buffer-read-only nil))
-    (goto-char (point-min))
-    (while (not (eobp))
-      (setq start (point))
-      (forward-char 1)
-      (setq pre (preceding-char)
-           fol (following-char))
-
-      (if ascii-mode
-         (cond
-
-          ;; ascii mode, pre != \ 
-          ((/= pre ?\\ ))
-
-          ;; ascii mode, pre = \, fol = !
-          ((= fol ?!)
-           (backward-delete-char 1)
-           (delete-char 1)
-           (setq ascii-mode nil
-                 hard (not hard)))
-
-          ;; hard ascii mode, pre = \, fol != !
-          (hard)
-
-          ;; soft ascii mode, pre = \, fol = {\ _ * < > 0..9 ~}
-          ((or (backward-delete-char 1) ; always nil
-               (eobp)
-               (sera-to-fidel-backslash)))
-
-          ;; soft ascii mode, pre = \, fol = SPC
-          ((= fol 32)
-           (delete-char 1)
-           (setq ascii-mode nil))
-
-          ;; soft ascii mode, pre = \, fol = .
-          ((= fol ?.)
-           (delete-char 1)
-           (insert ?\e$(2$P\e(B))
-
-          ;; soft ascii mode, pre = \, fol = ,
-          ((= fol ?,)
-           (delete-char 1)
-           (insert ?\e$(2$Q\e(B))
-
-          ;; soft ascii mode, pre = \, fol = ;
-          ((= fol ?\;)
-           (delete-char 1)
-           (insert ?\e$(2$R\e(B))
-
-          ;; soft ascii mode, pre = \, fol = :
-          ((= fol ?:)
-           (delete-char 1)
-           (insert ?\e$(2$S\e(B))
-
-          ;; soft ascii mode, pre = \, fol = others
-          (t
-           (setq ascii-mode nil)))
-
-       (cond
-
-        ;; very special: skip "<" to ">" (or "&" to ";") if in w3-mode
-        ((and (boundp 'sera-being-called-by-w3)
-              sera-being-called-by-w3
-              (or (= pre ?<) (= pre ?&)))
-         (search-forward (if (= pre ?<) ">" ";")
-                         nil 0))
-
-        ;; ethio mode, pre != sera
-        ((or (< pre ?') (> pre ?z)))
-
-        ;; ethio mode, pre != \ 
-        ((/= pre ?\\ )
-         (setq table (aref sera-to-fidel-table pre))
-         (while (setq table2 (cdr (assoc (following-char) table)))
-           (setq table table2)
-           (forward-char 1))
-         (if (car table)
-             (progn
-               (delete-region start (point))
-               (insert (car table)))))
-
-        ;; ethio mode, pre = \, fol = !
-        ((= fol ?!)
-         (backward-delete-char 1)
-         (delete-char 1)
-         (setq ascii-mode t
-               hard (not hard)))
-
-        ;; hard ethio mode, pre = \, fol != !
-        (hard)
-
-        ;; soft ethio mode, pre = \, fol = {\ _ * < > 0..9 ~}
-        ((or (backward-delete-char 1)  ; always nil
-             (eobp)
-             (sera-to-fidel-backslash)))
-
-        ;; soft ethio mode, pre = \, fol = SPC
-        ((= fol 32)
-         (delete-char 1)
-         (setq ascii-mode t))
-
-        ;; soft ethio mode, pre = \, fol = {. , ; : | ' `}
-        ((memq fol '(?. ?, ?\; ?: ?| ?' ?`))
-         (forward-char 1))
-
-        ;; soft ethio mode, pre = \, fol = others
-        (t
-         (setq ascii-mode t))))))
-  (goto-char (point-min)))
-
-(defun sera-to-fidel-backslash ()
-  "Handle SERA backslash escapes common to ethio- and ascii-mode.
-Returns t if something has been processed."
-  (let ((ch (following-char))
-       (converted t))
-    (if (and (>= ch ?1) (<= ch ?9))
-       (ethio-convert-digit)
-      (delete-char 1)
-      (cond
-       ((= ch ?\\ )
-       (insert ?\\ ))
-       ((= ch ?_)
-       (insert ?\e$(2$O\e(B))
-       ((= ch ?*)
-       (insert ?\e$(2$T\e(B))
-       ((= ch ?<)
-       (insert ?\e$(2$U\e(B))
-       ((= ch ?>)
-       (insert ?\e$(2$V\e(B))
-       ((= ch ?~)
-       (setq ch (following-char))
-       (delete-char 1)
-       (cond
-        ((= ch ?e)
-         (insert "\e$(2$k\e(B"))
-        ((= ch ?E)
-         (insert "\e$(2$l\e(B"))
-        ((= ch ?a)
-         (insert "\e$(2$m\e(B"))
-        ((= ch ?A)
-         (insert "\e$(2$n\e(B"))))
-       (t
-       (insert ch)
-       (backward-char 1)
-       (setq converted nil))))
-    converted))
-
-(defun ethio-convert-digit ()
-  "Convert Arabic digits to Ethiopic digits."
-  (let (ch z)
-    (while (and (>= (setq ch (following-char)) ?1)
-               (<= ch ?9))
-      (delete-char 1)
-
-      ;; count up following zeros
-      (setq z 0)
-      (while (= (following-char) ?0)
-       (delete-char 1)
-       (setq z (1+ z)))
-
-      (cond
-
-       ;; first digit is 10, 20, ..., or 90
-       ((= (mod z 2) 1)
-       ;; (- ch 40) means ?1 -> 9, ?2 -> 10, etc.
-       (insert (aref [?\e$(2$`\e(B ?\e$(2$a\e(B ?\e$(2$b\e(B ?\e$(2$c\e(B ?\e$(2$d\e(B ?\e$(2$e\e(B ?\e$(2$f\e(B ?\e$(2$g\e(B ?\e$(2$h\e(B] (- ch ?1)))
-       (setq z (1- z)))
-
-       ;; first digit is 2, 3, ..., or 9
-       ((/= ch ?1)
-       (insert (aref [?\e$(2$X\e(B ?\e$(2$Y\e(B ?\e$(2$Z\e(B ?\e$(2$[\e(B ?\e$(2$\\e(B ?\e$(2$]\e(B ?\e$(2$^\e(B ?\e$(2$_\e(B] (- ch ?2))))
-
-       ;; single 1
-       ((= z 0)
-       (insert "\e$(2$W\e(B")))
-
-      ;; 100
-      (if (= (mod z 4) 2)
-         (insert"\e$(2$i\e(B"))
-
-      ;; 10000
-      (insert-char ?\e$(2$j\e(B (/ z 4)))))
-
-;;;###autoload
-(defun sera-to-fidel-mail (&optional arg)
-  "Does SERA to FIDEL conversion for reading/writing mail and news.
-
-If the buffer contains the markers \"<sera>\" and \"</sera>\",
-converts the segment between the two markers in Ethio start mode and
-the subject field in ASCII start mode.
-
-If invoked interactively and there is no marker, converts both the
-whole body and the subject field in Ethio start mode.
-
-For backward compatibility, \"<ethiopic>\" and \"<>\" can be used instead of
-\"<sera>\" and \"</sera>\"."
-
-  (interactive "p")
-  (let* ((buffer-read-only nil) border)
-
-    (save-excursion
-      (goto-char (point-min))
-      (setq border
-           (search-forward
-            (if (eq major-mode 'rmail-mode)
-                "\n\n"
-              (concat "\n" mail-header-separator "\n"))))
-
-      (cond
-
-       ;; with markers
-       ((re-search-forward "^<sera>\n" nil t)
-       (goto-char (match-beginning 0))
-       (while (re-search-forward "^<sera>\n" nil t)
-         (replace-match "" nil t)
-         (sera-to-fidel-region
-          (point)
-          (progn
-            (if (re-search-forward "^</sera>\n" nil 0)
-                (replace-match "" nil t))
-            (point))))
-
-       (goto-char (point-min))
-       (if (re-search-forward "^Subject: " border t)
-           (sera-to-fidel-region
-            (point)
-            (progn (end-of-line) (point))
-            'ascii-start)))
-
-       ;; backward compatibility
-       ((re-search-forward "^<ethiopic>\n" nil t)
-       (goto-char (match-beginning 0))
-       (while (re-search-forward "^<ethiopic>\n" nil t)
-         (replace-match "" nil t)
-         (sera-to-fidel-region
-          (setq border (point))
-          (progn
-            (if (re-search-forward "^<>\n" nil 0)
-                (replace-match "" nil t))
-            (point))))
-
-       (goto-char (point-min))
-       (if (re-search-forward "^Subject: " border t)
-           (sera-to-fidel-region
-            (point)
-            (progn (end-of-line) (point))
-            'ascii-start)))
-
-       ;; interactive & no markers
-       (arg
-       (sera-to-fidel-region border (point-max))
-       (goto-char (point-min))
-       (if (re-search-forward "^Subject: " border t)
-           (sera-to-fidel-region
-            (point)
-            (progn (end-of-line) (point))))))
-
-      ;; adjust the rmail marker
-      (if (eq major-mode 'rmail-mode)
-         (set-marker
-          (aref rmail-message-vector (1+ rmail-current-message))
-          (point-max))))))
-
-;;;###autoload
-(defun sera-to-fidel-marker ()
-  "If the buffer contains the markers \"<sera>\" and \"</sera>\",
-converts the segment between the two markers from SERA to Fidel
-in Ethio start mode.  The markers will not be removed."
-
-  (interactive)
-  (if (and buffer-read-only
-          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
-      (error ""))
-  (save-excursion
-    (goto-char (point-min))
-    (while (re-search-forward "<sera>" nil t)
-      (sera-to-fidel-region
-       (point)
-       (if (re-search-forward "</sera>" nil t)
-          (match-beginning 0)
-        (point-max))
-       nil
-       'force))))
-
-;;
-;; FIDEL to SERA
-;;
-
-(defconst fidel-to-sera-map
-  ["le" "lu" "li" "la" "lE" "l" "lo" "lWa"
-   "me" "mu" "mi" "ma" "mE" "m" "mo" "mWa"
-   "re" "ru" "ri" "ra" "rE" "r" "ro" "rWa"
-   "xe" "xu" "xi" "xa" "xE" "x" "xo" "xWa"
-   "be" "bu" "bi" "ba" "bE" "b" "bo" "bWa"
-   "ve" "vu" "vi" "va" "vE" "v" "vo" "vWa"
-   "te" "tu" "ti" "ta" "tE" "t" "to" "tWa"
-   "ce" "cu" "ci" "ca" "cE" "c" "co" "cWa"
-   "ne" "nu" "ni" "na" "nE" "n" "no" "nWa"
-   "Ne" "Nu" "Ni" "Na" "NE" "N" "No" "NWa"
-   "ze" "zu" "zi" "za" "zE" "z" "zo" "zWa"
-   "Ze" "Zu" "Zi" "Za" "ZE" "Z" "Zo" "ZWa"
-   "de" "du" "di" "da" "dE" "d" "do" "dWa"
-   "Te" "Tu" "Ti" "Ta" "TE" "T" "To" "TWa"
-   "Ce" "Cu" "Ci" "Ca" "CE" "C" "Co" "CWa"
-   "fe" "fu" "fi" "fa" "fE" "f" "fo" "fWa"
-   "se" "su" "si" "sa" "sE" "s" "so" "sWa"
-   "Se" "Su" "Si" "Sa" "SE" "S" "So" "SWa"
-   "a"  "u"  "i"  "A"  "E"  "I" "o"  "e3"
-   "he" "hu" "hi" "ha" "hE" "h" "ho" "hWe" "hWu" "hWi" "hWa" "hWE"
-   "ke" "ku" "ki" "ka" "kE" "k" "ko" "kWe" "kWu" "kWi" "kWa" "kWE"
-   "Ke" "Ku" "Ki" "Ka" "KE" "K" "Ko" "KWe" "KWu" "KWi" "KWa" "KWE"
-   "qe" "qu" "qi" "qa" "qE" "q" "qo" "qWe" "qWu" "qWi" "qWa" "qWE"
-   "Qe" "Qu" "Qi" "Qa" "QE" "Q" "Qo" "QWe" "QWu" "QWi" "QWa" "QWE"
-   "ge" "gu" "gi" "ga" "gE" "g" "go" "gWe" "gWu" "gWi" "gWa" "gWE"
-   "we" "wu" "wi" "wa" "wE" "w" "wo" "wWe" "wWu" "wWi" "wWa" "wWE"
-   "`se" "`su" "`si" "`sa" "`sE" "`s" "`so"
-   "`Se" "`Su" "`Si" "`Sa" "`SE" "`S" "`So"
-   "`e"  "`u"  "`i"  "`a"  "`E"  "`I" "`o"
-   "`he" "`hu" "`hi" "`ha" "`hE" "`h" "`ho"
-   "`ke" "`ku" "`ki" "`ka" "`kE" "`k" "`ko"
-   "Xe" "Xu" "Xi" "Xa" "XE" "X" "Xo"
-   "He" "Hu" "Hi" "Ha" "HE" "H" "Ho"
-   "ye" "yu" "yi" "ya" "yE" "y" "yo"
-   "De" "Du" "Di" "Da" "DE" "D" "Do"
-   "je" "ju" "ji" "ja" "jE" "j" "jo"
-   "Ge" "Gu" "Gi" "Ga" "GE" "G" "Go"
-   "Pe" "Pu" "Pi" "Pa" "PE" "P" "Po"
-   "pe" "pu" "pi" "pa" "pE" "p" "po"
-   " " "\\_" "." "," ";" ":" "\\*" "\\<" "\\>"
-   "1" "2" "3" "4" "5" "6" "7" "8" "9"
-   "10" "20" "30" "40" "50" "60" "70" "80" "90"
-   "100" "10000"
-   "\\~e" "\\~E" "\\~a" "\\~A"])
-
-(defvar ethio-use-tigrigna-style nil
-  "*If non-NIL, use \"e\" instead of \"a\" for the first lone vowel
-translation in sera-to-fidel and fidel-to-sera conversions.")
-
-(defvar ethio-quote-vowel-always nil
-  "*If non-NIL, lone vowels are always transcribed by \"an apostrophe
-+ the vowel\" except at word initial.  Otherwise, they are quoted by
-an apostrophe only if the preceding Ethiopic character is a lone
-consonant.")
-
-(defvar ethio-W-sixth-always nil
-  "*If non-NIL, the Wu-form of a 12-form consonant is transcribed by
-\"W'\" instead of \"Wu\".")
-
-(defvar ethio-numeric-reduction 0
-  "*Degree of reduction in transcribing Ethiopic digits by Arabic
-digits.  For example, \e$(2$`$_$i$g$]\e(B ({10}{9}{100}{80}{7}) will be
-transcribed by:
-    \10\9\100\80\7     if ETHIO-NUMERIC-REDUCTION is 0,
-    \109100807                                    is 1,
-    \10900807                                     is 2.")
-
-;;;###autoload
-(defun fidel-to-sera-region (begin end &optional ascii-mode force)
-  "Replaces all the FIDEL characters in the region to sera format.
-
-If the 1st optional parameter ASCII-MODE is non-NIL, converts the
-region so that it begins in ASCII script.
-
-If the 2nd optional parameter FORCE is non-NIL, converts even if the
-buffer is read-only."
-
-  (interactive "r\nP")
-  (save-excursion
-    (save-restriction
-      (narrow-to-region begin end)
-      (fidel-to-sera-buffer ascii-mode force))))
-
-;;;###autoload
-(defun fidel-to-sera-buffer (&optional ascii-mode force)
-  "Replace all the FIDEL characters in the current buffer to sera format.
-
-If the 1st optional parameter ASCII-MODE is non-NIL,
-convert the current buffer so that it begins in ASCII script.
-
-If the 2nd optional parameter FORCE is non-NIL, converts even if the
-buffer is read-only.
-
-See also the description of the variables ethio-use-tigrigna-style,
-ethio-quote-vowel-on-demand and ethio-numeric-reduction."
-
-  (interactive "P")
-  (if (and buffer-read-only
-          (not force)
-          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
-      (error ""))
-
-  ;; user's preference in transcription
-  (aset fidel-to-sera-map 144 (if ethio-use-tigrigna-style "e" "a"))
-  (let ((i 160)
-       (x (if ethio-W-sixth-always
-              '("hW'" "kW'" "KW'" "qW'" "QW'" "gW'" "wW'")
-            '("hWu" "kWu" "KWu" "qWu" "QWu" "gWu" "wWu"))))
-    (while x
-      (aset fidel-to-sera-map i (car x))
-      (setq i (+ i 12)
-           x (cdr x))))
-
-  ;; main conversion routine
-  (let ((lonec nil) ; if lonec = t, previous char was a lone consonant.
-       (fidel nil) ; if fidel = t, previous char was a fidel.
-       (digit nil) ; if digit = t, previous char was an Ethiopic digit.
-       (buffer-read-only nil)
-       ch)
-    (goto-char (point-min))
-    (while (not (eobp))
-      (setq ch (following-char))
-
-      ;; ethiopic charactes
-      (if (eq (char-charset ch) 'ethiopic)
-         (progn
-           (setq ch (char-to-ethiocode ch))
-           (delete-char 1)
-
-           (cond
-
-            ;; fidels
-            ((<= ch 326)
-             (if ascii-mode
-                 (insert "\\ "))
-             (if (and (memq ch '(144 145 146 147 148 150 151)) ; (auiAEoe3)
-                      (or lonec
-                          (and ethio-quote-vowel-always
-                               fidel)))
-                 (insert "'"))
-             (insert (aref fidel-to-sera-map ch))
-             (setq ascii-mode nil
-                   lonec (ethio-lone-consonant-p ch)
-                   fidel t
-                   digit nil))
-
-            ;; punctuations and symbols
-            ((or (< ch 336) (> ch 355))
-             (if (and ascii-mode
-                      (memq ch '(329 330 331 332))) ; (.,;:)
-                 (insert "\\"))
-             (insert (aref fidel-to-sera-map ch))
-             (setq lonec nil
-                   fidel nil
-                   digit nil))
-
-            ;; now CH must be an ethiopic digit
-
-            ;; reduction = 0 or leading digit
-            ((or (= ethio-numeric-reduction 0)
-                 (not digit))
-             (insert "\\" (aref fidel-to-sera-map ch))
-             (setq lonec nil
-                   fidel nil
-                   digit t))
-
-            ;; reduction = 2 and following 10s, 100s, 10000s 
-            ((and (= ethio-numeric-reduction 2)
-                  (memq ch '(345 354 355)))
-             (insert (substring (aref fidel-to-sera-map ch) 1))
-             (setq lonec nil
-                   fidel nil
-                   digit t))
-
-            ;; ordinary following digits
-            (t
-             (insert (aref fidel-to-sera-map ch))
-             (setq lonec nil
-                   fidel nil
-                   digit t))))
-
-       ;; non-ethiopic characters
-       (cond
-
-        ;; backslash is always quoted
-        ((= ch ?\\ )
-         (insert "\\"))
-
-        ;; nothing to do if in ascii-mode
-        (ascii-mode)
-
-        ;; ethio-mode -> ascii-mode
-        ((or (and (>= ch ?a) (<= ch ?z))
-             (and (>= ch ?A) (<= ch ?Z))
-             (memq ch '(?| ?' ?`)))
-         (insert "\\ ")
-         (setq ascii-mode t))
-
-        ;; ascii punctuations in ethio-mode
-        ((memq ch '(?. ?, ?\; ?:))
-         (insert "\\")))
-
-       (forward-char 1)
-       (setq lonec nil
-             fidel nil
-             digit nil)))
-
-    ;; a few modifications for readability
-    (goto-char (point-min))
-    (while (re-search-forward "\\([]!\"#$%&()*+/<=>?@[^_-]+\\)\\\\ " nil t)
-      (replace-match "\\\\ \\1"))
-
-    (goto-char (point-min))
-    (while (re-search-forward "\n\\([ \t]*\\)\\\\ " nil t)
-      (replace-match "\\\\\n\\1")))
-
-  (goto-char (point-min)))
-
-(defun ethio-lone-consonant-p (code)
-  "If the ethiocode CODE is an Ethiopic lone consonant, return t."
-  (cond
-   ((< code 144)
-    (= (mod code 8) 5))
-   ((< code 153)
-    nil)
-   ((< code 236)
-    (= (mod code 12) 1))
-   ((< code 327)
-    (= (mod code 7) 3))))
-
-;;;###autoload
-(defun fidel-to-sera-mail ()
-  "Does FIDEL to SERA conversion for reading/writing mail and news.
-
-If the buffer contains at least one Ethiopic character,
- 1) inserts the string \"<sera>\" right after the header-body separator,
- 2) inserts \"</sera>\" at the end of the buffer,
- 3) converts the body into SERA in Ethiopic start mode, and
- 4) converts the subject field in ASCII start mode."
-
-  (interactive)
-  (save-excursion
-    (goto-char (point-min))
-    (if (re-search-forward "\\cE" nil t)
-       (let ((buffer-read-only nil) border)
-
-         (goto-char (point-min))
-         (setq border
-               (search-forward
-                (if (eq major-mode 'rmail-mode)
-                    "\n\n"
-                  (concat "\n" mail-header-separator "\n"))))
-         (insert "<sera>\n")
-
-         (fidel-to-sera-region (point) (point-max))
-
-         (goto-char (point-max))
-         (if (/= (preceding-char) ?\n)
-             (insert "\n"))
-         (insert "</sera>\n")
-
-         (goto-char (point-min))
-         (if (re-search-forward "^Subject: " border t)
-             (fidel-to-sera-region
-              (point)
-              (progn (end-of-line) (point))
-              'ascii-start))
-
-         ;; adjust the rmail marker
-         (if (eq major-mode 'rmail-mode)
-             (set-marker
-              (aref rmail-message-vector (1+ rmail-current-message))
-              (point-max))))
-
-      (message "No Ethiopic characters in this buffer."))))
-
-;;;###autoload
-(defun fidel-to-sera-marker ()
-  "If the buffer contains the markers \"<sera>\" and \"</sera>\",
-converts the segment between the two markers from Fidel to SERA
-in Ethio start mode.  The markers will not be removed."
-
-  (interactive)
-  (if (and buffer-read-only
-          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
-      (error ""))
-  (save-excursion
-    (goto-char (point-min))
-    (while (re-search-forward "^<sera>\n" nil t)
-      (fidel-to-sera-region
-       (point)
-       (if (re-search-forward "^</sera>\n" nil t)
-          (match-beginning 0)
-        (point-max))
-       nil
-       'force))))
-
-;;
-;; file I/O hooks
-;;
-
-(if (not (assoc "\\.sera$" auto-mode-alist))
-    (setq auto-mode-alist
-         (cons '("\\.sera$" . sera-to-fidel-find-file) auto-mode-alist)))
-(add-hook 'write-file-hooks 'fidel-to-sera-write-file)
-(add-hook 'after-save-hook 'sera-to-fidel-after-save)
-
-;;;###autoload
-(defun sera-to-fidel-find-file ()
-  "Intended to be called when a file whose name ends in \".sera\" is read in."
-  (sera-to-fidel-buffer nil 'force)
-  (set-buffer-modified-p nil)
-  nil)
-
-;;;###autoload
-(defun fidel-to-sera-write-file ()
-  "Intended to be used as write-file-hooks for the files
-whose name ends in \".sera\"."
-  (if (string-match "\\.sera$" (buffer-file-name))
-      (save-excursion
-       (fidel-to-sera-buffer nil 'force)
-       (set-buffer-modified-p nil)))
-  nil)
-
-;;;###autoload
-(defun sera-to-fidel-after-save ()
-  "Intended to be used as after-save-hook for the files
-whose name ends in \".sera\"."
-  (if (string-match "\\.sera$" (buffer-file-name))
-      (save-excursion
-       (sera-to-fidel-buffer nil 'force)
-       (set-buffer-modified-p nil)))
-  nil)
-
-;;
-;; vowel modification
-;;
-
-;;;###autoload
-(defun ethio-modify-vowel ()
-  "Modify the vowel of the FIDEL that is under the cursor."
-  (interactive)
-  (let ((ch (following-char)) newch base vowel)
-    (if (eq (char-charset ch) 'ethiopic)
-       (setq ch (char-to-ethiocode ch))
-      (error "Not a valid character."))
-    (if (or (and (>= ch 144) (<= ch 151)) ; lone vowels
-           (and (>= ch 250) (<= ch 256)) ; secondary lone vowels
-           (>= ch 327))                  ; not FIDEL
-       (error "Not a valid character."))
-    (message "Modify vowel to: ")
-    (if (null (setq vowel (memq (read-char) '(?e ?u ?i ?a ?E ?' ?o))))
-       (error "Not a valid vowel.")
-      ;; ?e -> 0, ?u -> 1, ?i -> 2, ?a -> 3, ?E -> 4, ?' -> 5, ?o -> 6
-      (setq vowel (- 7 (length vowel))))
-
-    (cond
-
-     ;; 8-form consonant
-     ((<= ch 143)
-      (setq base (* (/ ch 8) 8))
-      (cond
-       ((< (mod ch 8) 7)               ; e-form <= ch <= o-form
-       (setq newch (+ base vowel)))
-       ((= vowel 3)                    ; 3 = a
-       (setq newch (+ base 7)))        ; (+ base 7) = Wa-form
-       ((= vowel 5)                    ; 5 = '
-       (setq newch
-             (cons (+ base 5)          ; (+ base 5) = lone consonant
-                   232)))              ; 232 = Wu
-       (t
-       (setq newch
-             (cons (+ base 5)          ; (+ base 5) = lone consonant
-                   (+ 231 vowel))))))  ; 231 = We
-
-     ;; 12-form consonant
-     ((<= ch 235)
-      (setq ch (- ch 152)              ; 152 = 12-form consonant offset
-           base (* (/ ch 12) 12))
-      (cond
-       ((< (mod ch 12) 7)              ; e-form <= ch <= o-form
-       (setq newch (+ base vowel 152)))
-       ((< vowel 5)                    ; We-form <= ch <= WE-form
-       (setq newch (+ base vowel 159))) ; 159 = 152 (offset) + 7 (We-form)
-       ((= vowel 5)                    ; 5 = ' (= u in this case)
-       (setq newch (+ base 160)))      ; 160 = 152 (offset) + 8 (Wu-form)
-       (t
-       (error "Not a valid vowel."))))
-
-     ;; 7-form consonant
-     (t                                        ; 236 = 7-form consonant offset
-      (setq newch (+ (* (/ (- ch 236) 7) 7) vowel 236))))
-
-    (delete-char 1)
-
-    (cond
-     ((consp newch)
-      (insert (ethiocode-to-char (car newch))
-             (ethiocode-to-char (cdr newch)))
-      (backward-char 2))
-     (t
-      (insert (ethiocode-to-char newch))
-      (backward-char 1)))))
-
-(defun ethiocode-to-char (code)
-  (make-char 'ethiopic (/ code 94) (mod code 94)))
-
-(defun char-to-ethiocode (ch)
-  (and (eq (char-charset ch) 'ethiopic)
-       (let ((char-components (split-char ch)))
-        (+ (* (- (nth char-components 1) 161) 94)
-           (- (nth char-components 2) 161)))))
-
-;;
-;; space replacement
-;;
-
-;;;###autoload
-(defun ethio-replace-space (ch begin end)
-  "In the specified region, replace spaces between two Ethiopic characters."
-  (interactive "*cReplace spaces to: 1 (sg col), 2 (dbl col), 3 (Ethiopic)\nr")
-  (if (not (memq ch '(?1 ?2 ?3)))
-      (error ""))
-  (save-excursion
-    (save-restriction
-      (narrow-to-region begin end)
-      (goto-char (point-min))
-
-      (cond
-
-       ((= ch ?1)
-
-       ;; A double column space or an Ethiopic word separator is always
-       ;; converted to an ASCII space.
-       (while (re-search-forward "[\e$(2$N$O\e(B]" nil t)
-         (replace-match " " nil nil)))
-
-       ((= ch ?2)
-
-       ;; An Ethiopic word separator is always converted to
-       ;; a double column space.
-       (while (search-forward "\e$(2$O\e(B" nil t)
-         (replace-match "\e$(2$N\e(B"))
-
-       (goto-char (point-min))
-
-       ;; ASCII spaces are converted only if they are placed
-       ;; between two Ethiopic characters.
-       (while (re-search-forward "\\(\\cE\\)\\( \\)\\( *\\cE\\)" nil t)
-
-         ;; Converting the first ASCII space
-         (replace-match "\\1\e$(2$N\e(B\\3")
-
-         ;; A double column space is \cE, so going back to the just
-         ;; converted double column space makes it possible to find
-         ;; the following ASCII spaces.
-         (goto-char (match-beginning 2))))
-
-       ((= ch ?3)
-
-       ;; If more than one consecutive space (either ASCII or double
-       ;; width) is found between two Ethiopic characters, the first
-       ;; space will be converted to an Ethiopic word separator.
-       (let (pred succ)
-         (while (re-search-forward "[ \e$(2$N\e(B]\\([ \e$(2$N\e(B]*\\)" nil t)
-           (and (setq pred (char-before (match-beginning 0)))
-                (eq (char-charset pred) 'ethiopic)
-                (setq succ (char-after (match-end 0)))
-                (eq (char-charset succ) 'ethiopic)
-                (replace-match "\e$(2$O\e(B\\1" nil nil)))))))))
-
-;;
-;; special characters
-;;
-
-;;;###autoload
-(defun ethio-input-special-character (arg)
-  "Allow the user to input special characters."
-  (interactive "*cInput number: 1.\e$(2$k\e(B  2.\e$(2$l\e(B  3.\e$(2$m\e(B  4.\e$(2$n\e(B")
-  (cond
-   ((= arg ?1)
-    (insert ?\e$(2$k\e(B))
-   ((= arg ?2)
-    (insert ?\e$(2$l\e(B))
-   ((= arg ?3)
-    (insert ?\e$(2$m\e(B))
-   ((= arg ?4)
-    (insert ?\e$(2$n\e(B))
-   (t
-    (error ""))))
-
-;;
-(provide 'language/ethio-util)
-
-;;; Local Variables:
-;;; generated-autoload-file: "../loaddefs.el"
-;;; End:
-;;; ethio-util.el ends here
+;;; ethio-util.el --- utilities for Ethiopic -*- coding: iso-2022-7bit; -*-
+
+;; Copyright (C) 1997, 1998, 2002, 2003, 2004, 2005, 2006, 2007
+;;   Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+;;   National Institute of Advanced Industrial Science and Technology (AIST)
+;;   Registration Number H14PRO021
+
+;; Keywords: mule, multilingual, Ethiopic
+
+;; 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., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;; Author: TAKAHASHI Naoto <ntakahas@m17n.org>
+
+;;; Commentary:
+
+;;; Code:
+
+(defvar rmail-current-message)
+(defvar rmail-message-vector)
+
+;; Information for exiting Ethiopic environment.
+(defvar exit-ethiopic-environment-data nil)
+
+;;;###autoload
+(defun setup-ethiopic-environment-internal ()
+  (let ((key-bindings '((" " . ethio-insert-space)
+                       ([?\S- ] . ethio-insert-ethio-space)
+                       ([?\C-'] . ethio-gemination)
+
+                       ;; these old bindings conflict
+                       ;; with Emacs' binding policy
+
+                       ;; ([f2] . ethio-toggle-space)
+                       ;; ([S-f2] . ethio-replace-space) ; as requested
+                       ;; ([f3] . ethio-toggle-punctuation)
+                       ;; ([f4] . ethio-sera-to-fidel-buffer)
+                       ;; ([S-f4] . ethio-sera-to-fidel-region)
+                       ;; ([C-f4] . ethio-sera-to-fidel-mail-or-marker)
+                       ;; ([f5] . ethio-fidel-to-sera-buffer)
+                       ;; ([S-f5] . ethio-fidel-to-sera-region)
+                       ;; ([C-f5] . ethio-fidel-to-sera-mail-or-marker)
+                       ;; ([f6] . ethio-modify-vowel)
+                       ;; ([f7] . ethio-replace-space)
+                       ;; ([f8] . ethio-input-special-character)
+
+                       ;; this is the rewritten bindings
+
+                       ([f3] . ethio-fidel-to-sera-buffer)
+                       ([S-f3] . ethio-fidel-to-sera-region)
+                       ([C-f3] . ethio-fidel-to-sera-mail-or-marker)
+                       ([f4] . ethio-sera-to-fidel-buffer)
+                       ([S-f4] . ethio-sera-to-fidel-region)
+                       ([C-f4] . ethio-sera-to-fidel-mail-or-marker)
+                       ([S-f5] . ethio-toggle-punctuation)
+                       ([S-f6] . ethio-modify-vowel)
+                       ([S-f7] . ethio-replace-space)
+                       ([S-f8] . ethio-input-special-character)
+                       ([C-f9] . ethio-toggle-space)
+                       ([S-f9] . ethio-replace-space) ; as requested
+                       ))
+       kb)
+    (while key-bindings
+      (setq kb (car (car key-bindings)))
+      (setq exit-ethiopic-environment-data
+           (cons (cons kb (global-key-binding kb))
+                 exit-ethiopic-environment-data))
+      (global-set-key kb (cdr (car key-bindings)))
+      (setq key-bindings (cdr key-bindings))))
+
+  (add-hook 'quail-activate-hook 'ethio-select-a-translation)
+  (add-hook 'find-file-hook 'ethio-find-file)
+  (add-hook 'write-file-functions 'ethio-write-file)
+  (add-hook 'after-save-hook 'ethio-find-file))
+
+(defun exit-ethiopic-environment ()
+  "Exit Ethiopic language environment."
+  (while exit-ethiopic-environment-data
+    (global-set-key (car (car exit-ethiopic-environment-data))
+                   (cdr (car exit-ethiopic-environment-data)))
+    (setq exit-ethiopic-environment-data
+         (cdr exit-ethiopic-environment-data)))
+
+  (remove-hook 'quail-activate-hook 'ethio-select-a-translation)
+  (remove-hook 'find-file-hook 'ethio-find-file)
+  (remove-hook 'write-file-functions 'ethio-write-file)
+  (remove-hook 'after-save-hook 'ethio-find-file))
+
+;;
+;; ETHIOPIC UTILITY FUNCTIONS
+;;
+
+;; If the filename ends in ".sera", editing is done in fidel
+;; but file I/O is done in SERA.
+;;
+;; If the filename ends in ".java", editing is done in fidel
+;; but file I/O is done in the \uXXXX style, where XXXX is
+;; the Unicode codepoint for the Ethiopic character.
+;;
+;; If the filename ends in ".tex", editing is done in fidel
+;; but file I/O is done in EthioTeX format.
+;;
+;; To automatically convert Ethiopic text to SERA format when sending mail,
+;;   (add-hook 'mail-send-hook 'ethio-fidel-to-sera-mail)
+;;
+;; To automatically convert SERA format to Ethiopic when receiving mail,
+;;   (add-hook 'rmail-show-message-hook 'ethio-sera-to-fidel-mail)
+;;
+;; To automatically convert Ethiopic text to SERA format when posting news,
+;;   (add-hook 'news-inews-hook 'ethio-fidel-to-sera-mail)
+
+;;
+;; users' preference
+;;
+
+(defvar ethio-primary-language 'tigrigna
+  "*Symbol that defines the primary language in SERA --> FIDEL conversion.
+The value should be one of: `tigrigna', `amharic' or `english'.")
+
+(defvar ethio-secondary-language 'english
+  "*Symbol that defines the secondary language in SERA --> FIDEL conversion.
+The value should be one of: `tigrigna', `amharic' or `english'.")
+
+(defvar ethio-use-colon-for-colon nil
+  "*Non-nil means associate ASCII colon with Ethiopic colon.
+If nil, associate ASCII colon with Ethiopic word separator, i.e., two
+vertically stacked dots.  All SERA <--> FIDEL converters refer this
+variable.")
+
+(defvar ethio-use-three-dot-question nil
+  "*Non-nil means associate ASCII question mark with Ethiopic old style question mark (three vertically stacked dots).
+If nil, associate ASCII question mark with Ethiopic stylized question
+mark.  All SERA <--> FIDEL converters refer this variable.")
+
+(defvar ethio-quote-vowel-always nil
+  "*Non-nil means always put an apostrophe before an isolated vowel (except at word initial) in FIDEL --> SERA conversion.
+If nil, put an apostrophe only between a sixth-form consonant and an
+isolated vowel.")
+
+(defvar ethio-W-sixth-always nil
+  "*Non-nil means convert the Wu-form of a 12-form consonant to \"W'\" instead of \"Wu\" in FIDEL --> SERA conversion.")
+
+(defvar ethio-numeric-reduction 0
+  "*Degree of reduction in converting Ethiopic digits into Arabic digits.
+Should be 0, 1 or 2.
+For example, ({10}{9}{100}{80}{7}) is converted into:
+    `10`9`100`80`7  if `ethio-numeric-reduction' is 0,
+    `109100807     if `ethio-numeric-reduction' is 1,
+    `10900807      if `ethio-numeric-reduction' is 2.")
+
+(defvar ethio-implicit-period-conversion t
+  "*Non-nil means replacing the Ethiopic dot at the end of an Ethiopic sentence
+with an Ethiopic full stop.")
+
+(defvar ethio-java-save-lowercase nil
+  "*Non-nil means save Ethiopic characters in lowercase hex numbers to Java files.
+If nil, use uppercases.")
+
+;;
+;; SERA to FIDEL
+;;
+
+(defconst ethio-sera-to-fidel-table
+  [
+   nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
+   nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
+;;; SP
+   (" "
+    (?: (if ethio-use-colon-for-colon " \e$(3$l\e(B" "\e$(3$h\e(B")
+       (32 (if ethio-use-colon-for-colon " \e$(3$l\e(B " "\e$(3$h\e(B"))
+       (?- " \e$(3$m\e(B")
+       (?: " \e$(3$i\e(B")
+       (?| (if ethio-use-colon-for-colon " \e$(3$l\e(B|" " \e$(3$h\e(B|")
+           (?: " \e$(3$o\e(B"))))
+
+;;; !   "   #   $   %   &    '
+   nil nil nil nil nil nil ("" (?' "\e$(3%s\e(B"))
+;;; (   )   *   +    ,      -               .
+   nil nil nil nil ("\e$(3$j\e(B") ("-" (?: "\e$(3$l\e(B")) ("\e$(3%u\e(B")
+;;;  /   0   1   2   3   4   5   6   7   8   9
+    nil nil nil nil nil nil nil nil nil nil nil
+;;; :
+   ((if ethio-use-colon-for-colon "\e$(3$l\e(B" "\e$(3$h\e(B")
+    (32 (if ethio-use-colon-for-colon "\e$(3$l\e(B " "\e$(3$h\e(B"))
+    (?- "\e$(3$m\e(B")
+    (?: "\e$(3$i\e(B")
+    (?| (if ethio-use-colon-for-colon "\e$(3$l\e(B|" "\e$(3$h\e(B|")
+       (?: "\e$(3$o\e(B")))
+;;;  ;      <              =    >
+   ("\e$(3$k\e(B") ("<" (?< "\e$(3%v\e(B")) nil (">" (?> "\e$(3%w\e(B"))
+;;; ?
+   ((if ethio-use-three-dot-question "\e$(3$n\e(B" "\e$(3%x\e(B"))
+;;; @
+    nil
+;;; A
+   ("\e$(3"f\e(B" (?2 "\e$(3#8\e(B"))
+;;; B
+   ("\e$(3"(\e(B" (?e "\e$(3"#\e(B") (?u "\e$(3"$\e(B") (?i "\e$(3"%\e(B") (?a "\e$(3"&\e(B") (?E "\e$(3"'\e(B") (?o "\e$(3")\e(B")
+         (?W "\e$(3%b\e(B" (?e "\e$(3%2\e(B") (?u "\e$(3%b\e(B") (?i "\e$(3%B\e(B") (?a "\e$(3"*\e(B") (?E "\e$(3%R\e(B")))
+;;; C
+   ("\e$(3$4\e(B" (?e "\e$(3$/\e(B") (?u "\e$(3$0\e(B") (?i "\e$(3$1\e(B") (?a "\e$(3$2\e(B") (?E "\e$(3$3\e(B") (?o "\e$(3$5\e(B")
+         (?W "\e$(3$6\e(B" (?a "\e$(3$6\e(B")
+                  (?e "\e$(3$4%n\e(B") (?u "\e$(3$4%r\e(B") (?i "\e$(3$4%o\e(B") (?E "\e$(3$4%q\e(B")))
+;;; D
+   ("\e$(3#b\e(B" (?e "\e$(3#]\e(B") (?u "\e$(3#^\e(B") (?i "\e$(3#_\e(B") (?a "\e$(3#`\e(B") (?E "\e$(3#a\e(B") (?o "\e$(3#c\e(B")
+         (?W "\e$(3#d\e(B" (?a "\e$(3#d\e(B")
+                  (?e "\e$(3#b%n\e(B") (?u "\e$(3#b%r\e(B") (?i "\e$(3#b%o\e(B") (?E "\e$(3#b%q\e(B")))
+;;; E
+   ("\e$(3"g\e(B" (?2 "\e$(3#9\e(B"))
+;;; F
+   ("\e$(3$T\e(B" (?e "\e$(3$O\e(B") (?u "\e$(3$P\e(B") (?i "\e$(3$Q\e(B") (?a "\e$(3$R\e(B") (?E "\e$(3$S\e(B") (?o "\e$(3$U\e(B")
+         (?W "\e$(3%d\e(B" (?e "\e$(3%4\e(B") (?u "\e$(3%d\e(B") (?i "\e$(3%D\e(B") (?a "\e$(3$V\e(B") (?E "\e$(3%T\e(B"))
+        (?Y "\e$(3$a\e(B" (?a "\e$(3$a\e(B")))
+;;; G
+   ("\e$(3$$\e(B" (?e "\e$(3#}\e(B") (?u "\e$(3#~\e(B") (?i "\e$(3$!\e(B") (?a "\e$(3$"\e(B") (?E "\e$(3$#\e(B") (?o "\e$(3$%\e(B")
+         (?W "\e$(3%c\e(B" (?e "\e$(3%3\e(B") (?u "\e$(3%c\e(B") (?i "\e$(3%C\e(B") (?a "\e$(3$&\e(B") (?E "\e$(3%S\e(B")))
+;;; H
+   ("\e$(3!6\e(B" (?e "\e$(3!1\e(B") (?u "\e$(3!2\e(B") (?i "\e$(3!3\e(B") (?a "\e$(3!4\e(B") (?E "\e$(3!5\e(B") (?o "\e$(3!7\e(B")
+         (?W "\e$(3!8\e(B" (?a "\e$(3!8\e(B")
+                  (?e "\e$(3!6%n\e(B") (?u "\e$(3!6%r\e(B") (?i "\e$(3!6%o\e(B") (?E "\e$(3!6%q\e(B")))
+;;; I
+   ("\e$(3"h\e(B" (?2 "\e$(3#:\e(B"))
+;;; J
+   ("\e$(3#j\e(B" (?e "\e$(3#e\e(B") (?u "\e$(3#f\e(B") (?i "\e$(3#g\e(B") (?a "\e$(3#h\e(B") (?E "\e$(3#i\e(B") (?o "\e$(3#k\e(B")
+         (?W "\e$(3#l\e(B" (?a "\e$(3#l\e(B")
+                 (?e "\e$(3#j%n\e(B") (?u "\e$(3#j%r\e(B") (?i "\e$(3#j%o\e(B") (?E "\e$(3#j%q\e(B")))
+;;; K
+   ("\e$(3#"\e(B" (?e "\e$(3"{\e(B") (?u "\e$(3"|\e(B") (?i "\e$(3"}\e(B") (?a "\e$(3"~\e(B") (?E "\e$(3#!\e(B") (?o "\e$(3##\e(B")
+         (?W "\e$(3#*\e(B" (?e "\e$(3#%\e(B") (?u "\e$(3#*\e(B") (?i "\e$(3#'\e(B") (?a "\e$(3#(\e(B") (?E "\e$(3#)\e(B")))
+;;; L
+   ("\e$(3!.\e(B" (?e "\e$(3!)\e(B") (?u "\e$(3!*\e(B") (?i "\e$(3!+\e(B") (?a "\e$(3!,\e(B") (?E "\e$(3!-\e(B") (?o "\e$(3!/\e(B")
+         (?W "\e$(3!0\e(B" (?a "\e$(3!0\e(B")
+                  (?e "\e$(3!.%n\e(B") (?u "\e$(3!.%r\e(B") (?i "\e$(3!.%o\e(B") (?E "\e$(3!.%q\e(B")))
+;;; M
+   ("\e$(3!>\e(B" (?e "\e$(3!9\e(B") (?u "\e$(3!:\e(B") (?i "\e$(3!;\e(B") (?a "\e$(3!<\e(B") (?E "\e$(3!=\e(B") (?o "\e$(3!?\e(B")
+         (?W "\e$(3%a\e(B" (?e "\e$(3%1\e(B") (?u "\e$(3%a\e(B") (?i "\e$(3%A\e(B") (?a "\e$(3!@\e(B") (?E "\e$(3%Q\e(B"))
+        (?Y "\e$(3$_\e(B" (?a "\e$(3$_\e(B")))
+;;; N
+   ("\e$(3"`\e(B" (?e "\e$(3"[\e(B") (?u "\e$(3"\\e(B") (?i "\e$(3"]\e(B") (?a "\e$(3"^\e(B") (?E "\e$(3"_\e(B") (?o "\e$(3"a\e(B")
+         (?W "\e$(3"b\e(B" (?a "\e$(3"b\e(B")
+                  (?e "\e$(3"`%n\e(B") (?u "\e$(3"`%r\e(B") (?i "\e$(3"`%o\e(B") (?E "\e$(3"`%q\e(B")))
+;;; O
+   ("\e$(3"i\e(B" (?2 "\e$(3#;\e(B"))
+;;; P
+   ("\e$(3$<\e(B" (?e "\e$(3$7\e(B") (?u "\e$(3$8\e(B") (?i "\e$(3$9\e(B") (?a "\e$(3$:\e(B") (?E "\e$(3$;\e(B") (?o "\e$(3$=\e(B")
+         (?W "\e$(3$>\e(B" (?a "\e$(3$>\e(B")
+                  (?e "\e$(3$<%n\e(B") (?u "\e$(3$<%r\e(B") (?i "\e$(3$<%o\e(B") (?E "\e$(3$<%q\e(B")))
+;;; Q
+   ("\e$(3!v\e(B" (?e "\e$(3!q\e(B") (?u "\e$(3!r\e(B") (?i "\e$(3!s\e(B") (?a "\e$(3!t\e(B") (?E "\e$(3!u\e(B") (?o "\e$(3!w\e(B")
+         (?W "\e$(3!~\e(B" (?e "\e$(3!y\e(B") (?u "\e$(3!~\e(B") (?i "\e$(3!{\e(B") (?a "\e$(3!|\e(B") (?E "\e$(3!}\e(B")))
+;;; R
+   ("\e$(3!N\e(B" (?e "\e$(3!I\e(B") (?u "\e$(3!J\e(B") (?i "\e$(3!K\e(B") (?a "\e$(3!L\e(B") (?E "\e$(3!M\e(B") (?o "\e$(3!O\e(B")
+         (?W "\e$(3!P\e(B" (?a "\e$(3!P\e(B")
+                 (?e "\e$(3!N%n\e(B") (?u "\e$(3!N%r\e(B") (?i "\e$(3!N%o\e(B") (?E "\e$(3!N%q\e(B"))
+         (?Y "\e$(3$`\e(B" (?a "\e$(3$`\e(B")))
+;;; S
+   ("\e$(3$D\e(B" (?e "\e$(3$?\e(B") (?u "\e$(3$@\e(B") (?i "\e$(3$A\e(B") (?a "\e$(3$B\e(B") (?E "\e$(3$C\e(B") (?o "\e$(3$E\e(B")
+         (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
+                  (?e "\e$(3$D%n\e(B") (?u "\e$(3$D%r\e(B") (?i "\e$(3$D%o\e(B") (?E "\e$(3$D%q\e(B"))
+        (?2 "\e$(3$L\e(B"
+            (?e "\e$(3$G\e(B") (?u "\e$(3$H\e(B") (?i "\e$(3$I\e(B") (?a "\e$(3$J\e(B") (?E "\e$(3$K\e(B") (?o "\e$(3$M\e(B")
+            (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
+                (?e "\e$(3$L%n\e(B") (?u "\e$(3$L%r\e(B") (?i "\e$(3$L%o\e(B") (?E "\e$(3$L%q\e(B"))))
+;;; T
+   ("\e$(3$,\e(B" (?e "\e$(3$'\e(B") (?u "\e$(3$(\e(B") (?i "\e$(3$)\e(B") (?a "\e$(3$*\e(B") (?E "\e$(3$+\e(B") (?o "\e$(3$-\e(B")
+         (?W "\e$(3$.\e(B" (?a "\e$(3$.\e(B")
+                 (?e "\e$(3$,%n\e(B") (?u "\e$(3$,%r\e(B") (?i "\e$(3$,%o\e(B") (?E "\e$(3$,%q\e(B")))
+;;; U
+   ("\e$(3"d\e(B" (?2 "\e$(3#6\e(B"))
+;;; V
+   ("\e$(3"0\e(B" (?e "\e$(3"+\e(B") (?u "\e$(3",\e(B") (?i "\e$(3"-\e(B") (?a "\e$(3".\e(B") (?E "\e$(3"/\e(B") (?o "\e$(3"1\e(B")
+         (?W "\e$(3"2\e(B" (?a "\e$(3"2\e(B")
+                 (?e "\e$(3"0%n\e(B") (?u "\e$(3"0%r\e(B") (?i "\e$(3"0%o\e(B") (?E "\e$(3"0%q\e(B")))
+;;; W
+   ("\e$(3%r\e(B" (?e "\e$(3%n\e(B") (?u "\e$(3%r\e(B") (?i "\e$(3%o\e(B") (?a "\e$(3%p\e(B") (?E "\e$(3%q\e(B"))
+;;; X
+   ("\e$(3%N\e(B" (?e "\e$(3%I\e(B") (?u "\e$(3%J\e(B") (?i "\e$(3%K\e(B") (?a "\e$(3%L\e(B") (?E "\e$(3%M\e(B") (?o "\e$(3%O\e(B"))
+;;; Y
+   ("\e$(3#R\e(B" (?e "\e$(3#M\e(B") (?u "\e$(3#N\e(B") (?i "\e$(3#O\e(B") (?a "\e$(3#P\e(B") (?E "\e$(3#Q\e(B") (?o "\e$(3#S\e(B")
+         (?W "\e$(3#T\e(B" (?a "\e$(3#T\e(B")
+                 (?e "\e$(3#R%n\e(B") (?u "\e$(3#R%r\e(B") (?i "\e$(3#R%o\e(B") (?E "\e$(3#R%q\e(B")))
+;;; Z
+   ("\e$(3#J\e(B" (?e "\e$(3#E\e(B") (?u "\e$(3#F\e(B") (?i "\e$(3#G\e(B") (?a "\e$(3#H\e(B") (?E "\e$(3#I\e(B") (?o "\e$(3#K\e(B")
+         (?W "\e$(3#L\e(B" (?a "\e$(3#L\e(B")
+                 (?e "\e$(3#J%n\e(B") (?u "\e$(3#J%r\e(B") (?i "\e$(3#J%o\e(B") (?E "\e$(3#J%q\e(B")))
+;;; [   \   ]   ^   _
+   nil nil nil nil nil
+;;; `
+   (""
+    (?: "\e$(3$h\e(B")
+    (?? (if ethio-use-three-dot-question "\e$(3%x\e(B" "\e$(3$n\e(B"))
+    (?! "\e$(3%t\e(B")
+    (?e "\e$(3#5\e(B") (?u "\e$(3#6\e(B") (?U "\e$(3#6\e(B") (?i "\e$(3#7\e(B") (?a "\e$(3#8\e(B") (?A "\e$(3#8\e(B")
+        (?E "\e$(3#9\e(B") (?I "\e$(3#:\e(B") (?o "\e$(3#;\e(B") (?O "\e$(3#;\e(B")
+    (?g "\e$(3%^\e(B"
+        (?e "\e$(3%Y\e(B") (?u "\e$(3%Z\e(B") (?i "\e$(3%[\e(B") (?a "\e$(3%\\e(B") (?E "\e$(3%]\e(B") (?o "\e$(3%_\e(B"))
+    (?h "\e$(3"H\e(B"
+        (?e "\e$(3"C\e(B") (?u "\e$(3"D\e(B") (?i "\e$(3"E\e(B") (?a "\e$(3"F\e(B") (?E "\e$(3"G\e(B") (?o "\e$(3"I\e(B")
+                 (?W "\e$(3"P\e(B" (?e "\e$(3"K\e(B") (?u "\e$(3"P\e(B") (?i "\e$(3"M\e(B") (?a "\e$(3"N\e(B") (?E "\e$(3"O\e(B")))
+    (?k "\e$(3%>\e(B"
+        (?e "\e$(3%9\e(B") (?u "\e$(3%:\e(B") (?i "\e$(3%;\e(B") (?a "\e$(3%<\e(B") (?E "\e$(3%=\e(B") (?o "\e$(3%?\e(B"))
+    (?s "\e$(3!F\e(B"
+        (?e "\e$(3!A\e(B") (?u "\e$(3!B\e(B") (?i "\e$(3!C\e(B") (?a "\e$(3!D\e(B") (?E "\e$(3!E\e(B") (?o "\e$(3!G\e(B")
+       (?W "\e$(3!H\e(B" (?a "\e$(3!H\e(B")
+                  (?e "\e$(3!F%n\e(B") (?u "\e$(3!F%r\e(B") (?i "\e$(3!F%o\e(B") (?E "\e$(3!F%q\e(B")))
+    (?S "\e$(3$L\e(B"
+       (?e "\e$(3$G\e(B") (?u "\e$(3$H\e(B") (?i "\e$(3$I\e(B") (?a "\e$(3$J\e(B") (?E "\e$(3$K\e(B") (?o "\e$(3$M\e(B")
+       (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
+                (?e "\e$(3$L%n\e(B") (?u "\e$(3$L%r\e(B") (?i "\e$(3$L%o\e(B") (?E "\e$(3$L%q\e(B")))
+    (?q "\e$(3%.\e(B" (?e "\e$(3%)\e(B") (?u "\e$(3%*\e(B") (?i "\e$(3%+\e(B") (?a "\e$(3%,\e(B") (?E "\e$(3%-\e(B") (?o "\e$(3%/\e(B")))
+;;; a
+   ("\e$(3"f\e(B" (?2 "\e$(3#8\e(B"))
+;;; b
+   ("\e$(3"(\e(B" (?e "\e$(3"#\e(B") (?u "\e$(3"$\e(B") (?i "\e$(3"%\e(B") (?a "\e$(3"&\e(B") (?E "\e$(3"'\e(B") (?o "\e$(3")\e(B")
+         (?W "\e$(3%b\e(B" (?e "\e$(3%2\e(B") (?u "\e$(3%b\e(B") (?i "\e$(3%B\e(B") (?a "\e$(3"*\e(B") (?E "\e$(3%R\e(B")))
+;;; c
+   ("\e$(3"@\e(B" (?e "\e$(3";\e(B") (?u "\e$(3"<\e(B") (?i "\e$(3"=\e(B") (?a "\e$(3">\e(B") (?E "\e$(3"?\e(B") (?o "\e$(3"A\e(B")
+         (?W "\e$(3"B\e(B" (?a "\e$(3"B\e(B")
+                 (?e "\e$(3"@%n\e(B") (?u "\e$(3"@%r\e(B") (?i "\e$(3"@%o\e(B") (?E "\e$(3"@%q\e(B")))
+;;; d
+   ("\e$(3#Z\e(B" (?e "\e$(3#U\e(B") (?u "\e$(3#V\e(B") (?i "\e$(3#W\e(B") (?a "\e$(3#X\e(B") (?E "\e$(3#Y\e(B") (?o "\e$(3#[\e(B")
+         (?W "\e$(3#\\e(B" (?a "\e$(3#\\e(B")
+                 (?e "\e$(3#Z%o\e(B") (?u "\e$(3#Z%r\e(B") (?i "\e$(3#Z%p\e(B") (?E "\e$(3#Z%q\e(B")))
+;;; e
+   ("\e$(3"c\e(B" (?2 "\e$(3#5\e(B") (?a "\e$(3"j\e(B"))
+;;; f
+   ("\e$(3$T\e(B" (?e "\e$(3$O\e(B") (?u "\e$(3$P\e(B") (?i "\e$(3$Q\e(B") (?a "\e$(3$R\e(B") (?E "\e$(3$S\e(B") (?o "\e$(3$U\e(B")
+         (?W "\e$(3%d\e(B" (?e "\e$(3%4\e(B") (?u "\e$(3%d\e(B") (?i "\e$(3%D\e(B") (?a "\e$(3$V\e(B") (?E "\e$(3%T\e(B"))
+        (?Y "\e$(3$a\e(B" (?a "\e$(3$a\e(B")))
+;;; g
+   ("\e$(3#r\e(B" (?e "\e$(3#m\e(B") (?u "\e$(3#n\e(B") (?i "\e$(3#o\e(B") (?a "\e$(3#p\e(B") (?E "\e$(3#q\e(B") (?o "\e$(3#s\e(B")
+         (?W "\e$(3#z\e(B" (?e "\e$(3#u\e(B") (?u "\e$(3#z\e(B") (?i "\e$(3#w\e(B") (?a "\e$(3#x\e(B") (?E "\e$(3#y\e(B"))
+         (?2 "\e$(3%^\e(B" (?e "\e$(3%Y\e(B") (?u "\e$(3%Z\e(B") (?i "\e$(3%[\e(B") (?a "\e$(3%\\e(B") (?E "\e$(3%]\e(B") (?o "\e$(3%_\e(B")))
+;;; h
+   ("\e$(3!&\e(B" (?e "\e$(3!!\e(B") (?u "\e$(3!"\e(B") (?i "\e$(3!#\e(B") (?a "\e$(3!$\e(B") (?E "\e$(3!%\e(B") (?o "\e$(3!'\e(B")
+         (?W "\e$(3"P\e(B" (?e "\e$(3"K\e(B") (?u "\e$(3"P\e(B") (?i "\e$(3"M\e(B") (?a "\e$(3"N\e(B") (?E "\e$(3"O\e(B"))
+        (?2 "\e$(3"H\e(B" (?e "\e$(3"C\e(B") (?u "\e$(3"D\e(B") (?i "\e$(3"E\e(B") (?a "\e$(3"F\e(B") (?E "\e$(3"G\e(B") (?o "\e$(3"I\e(B")
+                 (?W "\e$(3"P\e(B" (?e "\e$(3"K\e(B") (?u "\e$(3"P\e(B") (?i "\e$(3"M\e(B") (?a "\e$(3"N\e(B") (?E "\e$(3"O\e(B"))))
+;;; i
+   ("\e$(3"e\e(B" (?2 "\e$(3#7\e(B"))
+;;; j
+   ("\e$(3#j\e(B" (?e "\e$(3#e\e(B") (?u "\e$(3#f\e(B") (?i "\e$(3#g\e(B") (?a "\e$(3#h\e(B") (?E "\e$(3#i\e(B") (?o "\e$(3#k\e(B")
+         (?W "\e$(3#l\e(B" (?a "\e$(3#l\e(B")
+                 (?e "\e$(3#j%n\e(B") (?u "\e$(3#j%r\e(B") (?i "\e$(3#j%o\e(B") (?E "\e$(3#j%q\e(B")))
+;;; k
+   ("\e$(3"p\e(B" (?e "\e$(3"k\e(B") (?u "\e$(3"l\e(B") (?i "\e$(3"m\e(B") (?a "\e$(3"n\e(B") (?E "\e$(3"o\e(B") (?o "\e$(3"q\e(B")
+         (?W "\e$(3"x\e(B" (?e "\e$(3"s\e(B") (?u "\e$(3"x\e(B") (?i "\e$(3"u\e(B") (?a "\e$(3"v\e(B") (?E "\e$(3"w\e(B"))
+        (?2 "\e$(3%>\e(B" (?e "\e$(3%9\e(B") (?u "\e$(3%:\e(B") (?i "\e$(3%;\e(B") (?a "\e$(3%<\e(B") (?E "\e$(3%=\e(B") (?o "\e$(3%?\e(B")))
+;;; l
+   ("\e$(3!.\e(B" (?e "\e$(3!)\e(B") (?u "\e$(3!*\e(B") (?i "\e$(3!+\e(B") (?a "\e$(3!,\e(B") (?E "\e$(3!-\e(B") (?o "\e$(3!/\e(B")
+         (?W "\e$(3!0\e(B" (?a "\e$(3!0\e(B")
+                  (?e "\e$(3!.%n\e(B") (?u "\e$(3!.%r\e(B") (?i "\e$(3!.%o\e(B") (?E "\e$(3!.%q\e(B")))
+;;; m
+   ("\e$(3!>\e(B" (?e "\e$(3!9\e(B") (?u "\e$(3!:\e(B") (?i "\e$(3!;\e(B") (?a "\e$(3!<\e(B") (?E "\e$(3!=\e(B") (?o "\e$(3!?\e(B")
+         (?W "\e$(3%a\e(B" (?e "\e$(3%1\e(B") (?u "\e$(3%a\e(B") (?i "\e$(3%A\e(B") (?a "\e$(3!@\e(B") (?E "\e$(3%Q\e(B"))
+        (?Y "\e$(3$_\e(B" (?a "\e$(3$_\e(B")))
+;;; n
+   ("\e$(3"X\e(B" (?e "\e$(3"S\e(B") (?u "\e$(3"T\e(B") (?i "\e$(3"U\e(B") (?a "\e$(3"V\e(B") (?E "\e$(3"W\e(B") (?o "\e$(3"Y\e(B")
+         (?W "\e$(3"Z\e(B" (?a "\e$(3"Z\e(B")
+                 (?e "\e$(3"X%n\e(B") (?u "\e$(3"X%r\e(B") (?i "\e$(3"X%o\e(B") (?E "\e$(3"X%q\e(B")))
+;;; o
+   ("\e$(3"i\e(B" (?2 "\e$(3#;\e(B"))
+;;; p
+   ("\e$(3$\\e(B" (?e "\e$(3$W\e(B") (?u "\e$(3$X\e(B") (?i "\e$(3$Y\e(B") (?a "\e$(3$Z\e(B") (?E "\e$(3$[\e(B") (?o "\e$(3$]\e(B")
+         (?W "\e$(3%e\e(B" (?e "\e$(3%5\e(B") (?u "\e$(3%e\e(B") (?i "\e$(3%E\e(B") (?a "\e$(3$^\e(B") (?E "\e$(3%U\e(B")))
+;;; q
+   ("\e$(3!f\e(B" (?e "\e$(3!a\e(B") (?u "\e$(3!b\e(B") (?i "\e$(3!c\e(B") (?a "\e$(3!d\e(B") (?E "\e$(3!e\e(B") (?o "\e$(3!g\e(B")
+         (?W "\e$(3!n\e(B" (?e "\e$(3!i\e(B") (?u "\e$(3!n\e(B") (?i "\e$(3!k\e(B") (?a "\e$(3!l\e(B") (?E "\e$(3!m\e(B"))
+         (?2 "\e$(3%.\e(B" (?e "\e$(3%)\e(B") (?u "\e$(3%*\e(B") (?i "\e$(3%+\e(B") (?a "\e$(3%,\e(B") (?E "\e$(3%-\e(B") (?o "\e$(3%/\e(B")))
+;;; r
+   ("\e$(3!N\e(B" (?e "\e$(3!I\e(B") (?u "\e$(3!J\e(B") (?i "\e$(3!K\e(B") (?a "\e$(3!L\e(B") (?E "\e$(3!M\e(B") (?o "\e$(3!O\e(B")
+         (?W "\e$(3!P\e(B" (?a "\e$(3!P\e(B")
+                 (?e "\e$(3!N%n\e(B") (?u "\e$(3!N%r\e(B") (?i "\e$(3!N%o\e(B") (?E "\e$(3!N%q\e(B"))
+         (?Y "\e$(3$`\e(B" (?a "\e$(3$`\e(B")))
+;;; s
+   ("\e$(3!V\e(B" (?e "\e$(3!Q\e(B") (?u "\e$(3!R\e(B") (?i "\e$(3!S\e(B") (?a "\e$(3!T\e(B") (?E "\e$(3!U\e(B") (?o "\e$(3!W\e(B")
+         (?W "\e$(3!X\e(B" (?a "\e$(3!X\e(B")
+                 (?e "\e$(3!V%n\e(B") (?u "\e$(3!V%r\e(B") (?i "\e$(3!V%o\e(B") (?E "\e$(3!V%q\e(B"))
+        (?2 "\e$(3!F\e(B" (?e "\e$(3!A\e(B") (?u "\e$(3!B\e(B") (?i "\e$(3!C\e(B") (?a "\e$(3!D\e(B") (?E "\e$(3!E\e(B") (?o "\e$(3!G\e(B")
+                 (?W "\e$(3!H\e(B" (?a "\e$(3!H\e(B")
+                          (?e "\e$(3!F%n\e(B") (?u "\e$(3!F%r\e(B") (?i "\e$(3!F%o\e(B") (?E "\e$(3!F%q\e(B"))))
+;;; t
+   ("\e$(3"8\e(B" (?e "\e$(3"3\e(B") (?u "\e$(3"4\e(B") (?i "\e$(3"5\e(B") (?a "\e$(3"6\e(B") (?E "\e$(3"7\e(B") (?o "\e$(3"9\e(B")
+         (?W "\e$(3":\e(B" (?a "\e$(3":\e(B")
+                 (?e "\e$(3"8%n\e(B") (?u "\e$(3"8%r\e(B") (?i "\e$(3"8%o\e(B") (?E "\e$(3"8%q\e(B")))
+;;; u
+   ("\e$(3"d\e(B" (?2 "\e$(3#6\e(B"))
+;;; v
+   ("\e$(3"0\e(B" (?e "\e$(3"+\e(B") (?u "\e$(3",\e(B") (?i "\e$(3"-\e(B") (?a "\e$(3".\e(B") (?E "\e$(3"/\e(B") (?o "\e$(3"1\e(B")
+         (?W "\e$(3"2\e(B" (?a "\e$(3"2\e(B")
+                 (?e "\e$(3"0%n\e(B") (?u "\e$(3"0%r\e(B") (?i "\e$(3"0%o\e(B") (?E "\e$(3"0%q\e(B")))
+;;; w
+   ("\e$(3#2\e(B" (?e "\e$(3#-\e(B") (?u "\e$(3#.\e(B") (?i "\e$(3#/\e(B") (?a "\e$(3#0\e(B") (?E "\e$(3#1\e(B") (?o "\e$(3#3\e(B")
+         (?W "\e$(3%p\e(B" (?e "\e$(3%n\e(B") (?u "\e$(3%r\e(B") (?i "\e$(3%o\e(B") (?a "\e$(3%p\e(B") (?E "\e$(3%q\e(B")))
+;;; x
+   ("\e$(3!^\e(B" (?e "\e$(3!Y\e(B") (?u "\e$(3!Z\e(B") (?i "\e$(3![\e(B") (?a "\e$(3!\\e(B") (?E "\e$(3!]\e(B") (?o "\e$(3!_\e(B")
+         (?W "\e$(3!`\e(B" (?a "\e$(3!`\e(B")
+                 (?e "\e$(3!^%n\e(B") (?u "\e$(3!^%r\e(B") (?i "\e$(3!^%o\e(B") (?E "\e$(3!^%q\e(B")))
+;;; y
+   ("\e$(3#R\e(B" (?e "\e$(3#M\e(B") (?u "\e$(3#N\e(B") (?i "\e$(3#O\e(B") (?a "\e$(3#P\e(B") (?E "\e$(3#Q\e(B") (?o "\e$(3#S\e(B")
+         (?W "\e$(3#T\e(B" (?a "\e$(3#T\e(B")
+                 (?e "\e$(3#R%n\e(B") (?u "\e$(3#R%r\e(B") (?i "\e$(3#R%o\e(B") (?E "\e$(3#R%q\e(B")))
+;;; z
+   ("\e$(3#B\e(B" (?e "\e$(3#=\e(B") (?u "\e$(3#>\e(B") (?i "\e$(3#?\e(B") (?a "\e$(3#@\e(B") (?E "\e$(3#A\e(B") (?o "\e$(3#C\e(B")
+         (?W "\e$(3#D\e(B" (?a "\e$(3#D\e(B")
+                 (?e "\e$(3#B%n\e(B") (?u "\e$(3#B%r\e(B") (?i "\e$(3#B%o\e(B") (?E "\e$(3#B%q\e(B")))
+;;; {   |   }   ~  DEL
+   nil nil nil nil nil
+   ])
+
+;; To avoid byte-compiler warnings.  It should never be set globally.
+(defvar ethio-sera-being-called-by-w3)
+;; This variable will be bound by some third-party package.
+(defvar sera-being-called-by-w3)
+
+;;;###autoload
+(defun ethio-sera-to-fidel-region (beg end &optional secondary force)
+  "Convert the characters in region from SERA to FIDEL.
+The variable `ethio-primary-language' specifies the primary language
+and `ethio-secondary-language' specifies the secondary.
+
+If the 3rd parameter SECONDARY is given and non-nil, assume the region
+begins with the secondary language; otherwise with the primary
+language.
+
+If the 4th parameter FORCE is given and non-nil, perform conversion
+even if the buffer is read-only.
+
+See also the descriptions of the variables
+`ethio-use-colon-for-colon' and
+`ethio-use-three-dot-question'."
+
+  (interactive "r\nP")
+  (save-restriction
+    (narrow-to-region beg end)
+    (ethio-sera-to-fidel-buffer secondary force)))
+
+;;;###autoload
+(defun ethio-sera-to-fidel-buffer (&optional secondary force)
+  "Convert the current buffer from SERA to FIDEL.
+
+The variable `ethio-primary-language' specifies the primary
+language and `ethio-secondary-language' specifies the secondary.
+
+If the 1st optional parameter SECONDARY is non-nil, assume the buffer
+begins with the secondary language; otherwise with the primary
+language.
+
+If the 2nd optional parametr FORCE is non-nil, perform conversion even if the
+buffer is read-only.
+
+See also the descriptions of the variables
+`ethio-use-colon-for-colon' and
+`ethio-use-three-dot-question'."
+
+  (interactive "P")
+
+  (if (and buffer-read-only
+          (not force)
+          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
+      (error ""))
+
+  (let ((ethio-primary-language ethio-primary-language)
+       (ethio-secondary-language ethio-secondary-language)
+       (ethio-use-colon-for-colon ethio-use-colon-for-colon)
+       (ethio-use-three-dot-question ethio-use-three-dot-question)
+       ;; The above four variables may be changed temporary
+       ;; by tilde escapes during conversion.  So we bind them to other
+       ;; variables but of the same names.
+       (buffer-read-only nil)
+       (case-fold-search nil)
+       current-language
+       next-language)
+
+    (setq current-language
+         (if secondary
+             ethio-secondary-language
+           ethio-primary-language))
+
+    (goto-char (point-min))
+
+    (while (not (eobp))
+      (setq next-language
+           (cond
+            ((eq current-language 'english)
+             (ethio-sera-to-fidel-english))
+            ((eq current-language 'amharic)
+             (ethio-sera-to-fidel-ethio 'amharic))
+            ((eq current-language 'tigrigna)
+             (ethio-sera-to-fidel-ethio 'tigrigna))
+            (t                         ; we don't know what to do
+             (ethio-sera-to-fidel-english))))
+
+      (setq current-language
+           (cond
+
+            ;; when language tag is explicitly specified
+            ((not (eq next-language 'toggle))
+             next-language)
+
+            ;; found a toggle in a primary language section
+            ((eq current-language ethio-primary-language)
+             ethio-secondary-language)
+
+            ;; found a toggle in a secondary, third, fourth, ...
+            ;; language section
+            (t
+             ethio-primary-language))))
+
+    ;; If ethio-implicit-period-conversion is non-nil, the
+    ;; Ethiopic dot "\e$(3%u\e(B" at the end of an Ethiopic sentence is
+    ;; replaced with the Ethiopic full stop "\e$(3$i\e(B".
+    (if ethio-implicit-period-conversion
+       (progn
+         (goto-char (point-min))
+         (while (re-search-forward "\\([\e$(3!!\e(B-\e$(3$a%)\e(B-\e$(3%e%n\e(B-\e$(3%r%s\e(B]\\)\e$(3%u\e(B\\([ \t]\\)"
+                                   nil t)
+           (replace-match "\\1\e$(3$i\e(B\\2"))
+         (goto-char (point-min))
+         (while (re-search-forward "\\([\e$(3!!\e(B-\e$(3$a%)\e(B-\e$(3%e%n\e(B-\e$(3%r%s\e(B]\\)\e$(3%u\e(B$" nil t)
+           (replace-match "\\1\e$(3$i\e(B"))))
+
+    ;; gemination
+    (goto-char (point-min))
+    (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
+      (compose-region
+       (save-excursion (backward-char 2) (point))
+       (point)))
+    ))
+
+(defun ethio-sera-to-fidel-english nil
+  "Handle English section in SERA to FIDEL conversion.
+Conversion stops when a language switch is found.  Then delete that
+switch and return the name of the new language as a symbol."
+  (let ((new-language nil))
+
+    (while (and (not (eobp)) (null new-language))
+      (cond
+
+       ;; if no more "\", nothing to do.
+       ((not (search-forward "\\" nil 0)))
+
+       ;; hereafter point is put after a "\".
+       ;; first delete that "\", then check the following chars
+
+       ;; "\\" :  leave the second "\"
+       ((progn
+         (delete-backward-char 1)
+         (= (following-char) ?\\ ))
+       (forward-char 1))
+
+       ;; "\ " :  delete the following " "
+       ((= (following-char) 32)
+       (delete-char 1)
+       (setq new-language 'toggle))
+
+       ;; a language flag
+       ((setq new-language (ethio-process-language-flag)))
+
+       ;; just a "\" :  not special sequence.
+       (t
+       (setq new-language 'toggle))))
+
+    new-language))
+
+(defun ethio-sera-to-fidel-ethio (lang)
+  "Handle Ethiopic section in SERA to FIDEL conversion.
+Conversion stops when a language switch is found.  Then delete that
+switch and return the name of the new language as a symbol.
+
+The parameter LANG (symbol, either `amharic' or `tigrigna') affects
+the conversion of \"a\"."
+
+  (let ((new-language nil)
+       (verbatim nil)
+       start table table2 ch)
+
+    (setcar (aref ethio-sera-to-fidel-table ?a)
+           (if (eq lang 'tigrigna) "\e$(3"f\e(B" "\e$(3"c\e(B"))
+
+    (while (and (not (eobp)) (null new-language))
+      (setq ch (following-char))
+      (cond
+
+       ;; skip from "<" to ">" (or from "&" to ";") if in w3-mode
+       ((and (or (= ch ?<) (= ch ?&))
+            (or (and (boundp 'ethio-sera-being-called-by-w3)
+                     ethio-sera-being-called-by-w3)
+                (and (boundp 'sera-being-called-by-w3)
+                     sera-being-called-by-w3)))
+       (search-forward (if (= ch ?<) ">" ";")
+                       nil 0))
+
+       ;; leave non-ASCII characters as they are
+       ((>= ch 128)
+       (forward-char 1))
+
+       ;; ethiopic digits
+       ((looking-at "`[1-9][0-9]*")
+       (delete-char 1)
+       (ethio-convert-digit))
+
+       ;; if not seeing a "\", do sera to fidel conversion
+       ((/= ch ?\\ )
+       (setq start (point))
+       (forward-char 1)
+       (setq table (aref ethio-sera-to-fidel-table ch))
+       (while (setq table2 (cdr (assoc (following-char) table)))
+         (setq table table2)
+         (forward-char 1))
+       (if (setq ch (car table))
+           (progn
+             (delete-region start (point))
+             (if (stringp ch)
+                 (insert ch)
+               (insert (eval ch))))))
+
+       ;; if control reaches here, we must be looking at a "\"
+
+       ;; verbatim mode
+       (verbatim
+       (if (looking-at "\\\\~! ?")
+
+           ;; "\~!" or "\~! ".  switch to non-verbatim mode
+           (progn
+             (replace-match "")
+             (setq verbatim nil))
+
+         ;; "\" but not "\~!" nor "\~! ".  skip the current "\".
+         (forward-char 1)))
+
+       ;; hereafter, non-verbatim mode and looking at a "\"
+       ;; first delete that "\", then check the following chars.
+
+       ;; "\ " : delete the following " "
+       ((progn
+         (delete-char 1)
+         (setq ch (following-char))
+         (= ch 32))
+       (delete-char 1)
+       (setq new-language 'toggle))
+
+       ;; "\~!" or "\~! " : switch to verbatim mode
+       ((looking-at "~! ?")
+       (replace-match "")
+       (setq verbatim t))
+
+       ;; a language flag
+       ((setq new-language (ethio-process-language-flag)))
+
+       ;; "\~" but not "\~!" nor a language flag
+       ((= ch ?~)
+       (delete-char 1)
+       (ethio-tilde-escape))
+
+       ;; ASCII punctuation escape.  skip
+       ((looking-at "\\(,\\|\\.\\|;\\|:\\|'\\|`\\|\?\\|\\\\\\)+")
+       (goto-char (match-end 0)))
+
+       ;; "\", but not special sequence
+       (t
+       (setq new-language 'toggle))))
+
+    new-language))
+
+(defun ethio-process-language-flag nil
+  "Process a language flag of the form \"~lang\" or \"~lang1~lang2\".
+
+If looking at \"~lang1~lang2\", set `ethio-primary-language' and
+`ethio-une-secondary-language' based on \"lang1\" and \"lang2\".
+Then delete the language flag \"~lang1~lang2\" from the buffer.
+Return value is the new primary language.
+
+If looking at \"~lang\", delete that language flag \"~lang\" from the
+buffer and return that language.  In this case
+`ethio-primary-language' and `ethio-uni-secondary-language'
+are left unchanged.
+
+If an unsupported language flag is found, just return nil without
+changing anything."
+
+  (let (lang1 lang2)
+    (cond
+
+     ;; ~lang1~lang2
+     ((and (looking-at
+           "~\\([a-z][a-z][a-z]?\\)~\\([a-z][a-z][a-z]?\\)[ \t\n\\]")
+          (setq lang1
+                (ethio-flag-to-language
+                 (buffer-substring (match-beginning 1) (match-end 1))))
+          (setq lang2
+                (ethio-flag-to-language
+                 (buffer-substring (match-beginning 2) (match-end 2)))))
+      (setq ethio-primary-language lang1
+           ethio-secondary-language lang2)
+      (delete-region (point) (match-end 2))
+      (if (= (following-char) 32)
+         (delete-char 1))
+      ethio-primary-language)
+
+     ;; ~lang
+     ((and (looking-at "~\\([a-z][a-z][a-z]?\\)[ \t\n\\]")
+          (setq lang1
+                (ethio-flag-to-language
+                 (buffer-substring (match-beginning 1) (match-end 1)))))
+      (delete-region (point) (match-end 1))
+      (if (= (following-char) 32)
+         (delete-char 1))
+      lang1)
+
+     ;; otherwise
+     (t
+      nil))))
+
+(defun ethio-tilde-escape nil
+  "Handle a SERA tilde escape in Ethiopic section and delete it.
+Delete the escape even it is not recognized."
+
+  (let ((p (point)) command)
+    (skip-chars-forward "^ \t\n\\\\")
+    (setq command (buffer-substring p (point)))
+    (delete-region p (point))
+    (if (= (following-char) 32)
+       (delete-char 1))
+
+    (cond
+
+     ;; \~-:
+     ((string= command "-:")
+      (setq ethio-use-colon-for-colon t))
+
+     ;; \~`:
+     ((string= command "`:")
+      (setq ethio-use-colon-for-colon nil))
+
+     ;; \~?
+     ((string= command "?")
+      (setq ethio-use-three-dot-question nil))
+
+     ;; \~`|
+     ((string= command "`|")
+      (setq ethio-use-three-dot-question t))
+
+     ;; \~e
+     ((string= command "e")
+      (insert "\e$(3%j\e(B"))
+
+     ;; \~E
+     ((string= command "E")
+      (insert "\e$(3%k\e(B"))
+
+     ;; \~a
+     ((string= command "a")
+      (insert "\e$(3%l\e(B"))
+
+     ;; \~A
+     ((string= command "A")
+      (insert "\e$(3%m\e(B"))
+
+     ;; \~X
+     ((string= command "X")
+      (insert "\e$(3%i\e(B"))
+
+     ;; unsupported tilde escape
+     (t
+      nil))))
+
+(defun ethio-flag-to-language (flag)
+  (cond
+   ((or (string= flag "en") (string= flag "eng")) 'english)
+   ((or (string= flag "ti") (string= flag "tir")) 'tigrigna)
+   ((or (string= flag "am") (string= flag "amh")) 'amharic)
+   (t nil)))
+
+(defun ethio-convert-digit nil
+  "Convert Arabic digits to Ethiopic digits."
+  (let (ch z)
+    (while (and (>= (setq ch (following-char)) ?1)
+               (<= ch ?9))
+      (delete-char 1)
+
+      ;; count up following zeros
+      (setq z 0)
+      (while (= (following-char) ?0)
+       (delete-char 1)
+       (setq z (1+ z)))
+
+      (cond
+
+       ;; first digit is 10, 20, ..., or 90
+       ((= (mod z 2) 1)
+       (insert (aref [?\e$(3$y\e(B ?\e$(3$z\e(B ?\e$(3${\e(B ?\e$(3$|\e(B ?\e$(3$}\e(B ?\e$(3$~\e(B ?\e$(3%!\e(B ?\e$(3%"\e(B ?\e$(3%#\e(B] (- ch ?1)))
+       (setq z (1- z)))
+
+       ;; first digit is 2, 3, ..., or 9
+       ((/= ch ?1)
+       (insert (aref [?\e$(3$q\e(B ?\e$(3$r\e(B ?\e$(3$s\e(B ?\e$(3$t\e(B ?\e$(3$u\e(B ?\e$(3$v\e(B ?\e$(3$w\e(B ?\e$(3$x\e(B] (- ch ?2))))
+
+       ;; single 1
+       ((= z 0)
+       (insert "\e$(3$p\e(B")))
+
+      ;; 100
+      (if (= (mod z 4) 2)
+         (insert "\e$(3%$\e(B"))
+
+      ;; 10000
+      (insert-char ?\e$(3%%\e(B (/ z 4)))))
+
+;;;###autoload
+(defun ethio-sera-to-fidel-mail-or-marker (&optional arg)
+  "Execute `ethio-sera-to-fidel-mail' or `ethio-sera-to-fidel-marker' depending on the current major mode.
+If in rmail-mode or in mail-mode, execute the former; otherwise latter."
+
+  (interactive "P")
+  (if (or (eq major-mode 'rmail-mode)
+         (eq major-mode 'mail-mode))
+      (ethio-sera-to-fidel-mail (prefix-numeric-value arg))
+    (ethio-sera-to-fidel-marker arg)))
+
+;;;###autoload
+(defun ethio-sera-to-fidel-mail (&optional arg)
+  "Convert SERA to FIDEL to read/write mail and news.
+
+If the buffer contains the markers \"<sera>\" and \"</sera>\",
+convert the segments between them into FIDEL.
+
+If invoked interactively and there is no marker, convert the subject field
+and the body into FIDEL using `ethio-sera-to-fidel-region'."
+
+  (interactive "p")
+  (let ((buffer-read-only nil)
+       border)
+    (save-excursion
+
+      ;; follow RFC822 rules instead of looking for a fixed separator
+      (rfc822-goto-eoh)
+      (forward-line 1)
+      (setq border (point))
+
+      ;; note that the point is placed at the border
+      (if (or (re-search-forward "^<sera>$" nil t)
+             (progn
+               (goto-char (point-min))
+               (re-search-forward "^Subject: <sera>" border t)))
+
+         ;; there are markers
+         (progn
+           ;; we start with the body so that the border will not change
+           ;; use "^<sera>\n" instead of "^<sera>$" not to leave a blank line
+           (goto-char border)
+           (while (re-search-forward "^<sera>\n" nil t)
+             (replace-match "")
+             (ethio-sera-to-fidel-region
+              (point)
+              (progn
+                (if (re-search-forward "^</sera>\n" nil 0)
+                    (replace-match ""))
+                (point))))
+           ;; now process the subject
+           (goto-char (point-min))
+           (if (re-search-forward "^Subject: <sera>" border t)
+               (ethio-sera-to-fidel-region
+                (progn (delete-backward-char 6) (point))
+                (progn
+                  (if (re-search-forward "</sera>$" (line-end-position) 0)
+                      (replace-match ""))
+                  (point)))))
+
+       ;; in case there are no marks but invoked interactively
+       (if arg
+           (progn
+             (ethio-sera-to-fidel-region border (point-max))
+             (goto-char (point-min))
+             (if (re-search-forward "^Subject: " border t)
+                 (ethio-sera-to-fidel-region (point) (line-end-position))))))
+
+      ;; adjust the rmail marker
+      (if (eq major-mode 'rmail-mode)
+         (set-marker
+          (aref rmail-message-vector (1+ rmail-current-message))
+          (point-max))))))
+
+;;;###autoload
+(defun ethio-sera-to-fidel-marker (&optional force)
+  "Convert the regions surrounded by \"<sera>\" and \"</sera>\" from SERA to FIDEL.
+Assume that each region begins with `ethio-primary-language'.
+The markers \"<sera>\" and \"</sera>\" themselves are not deleted."
+  (interactive "P")
+  (if (and buffer-read-only
+          (not force)
+          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
+      (error ""))
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward "<sera>" nil t)
+      (ethio-sera-to-fidel-region
+       (point)
+       (if (re-search-forward "</sera>" nil t)
+          (match-beginning 0)
+        (point-max))
+       nil
+       'force))))
+
+;;
+;; FIDEL to SERA
+;;
+
+(defconst ethio-fidel-to-sera-map
+ [ "he"  "hu"  "hi"  "ha"  "hE"  "h"  "ho"    ""       ;;   0 - 7
+   "le"  "lu"  "li"  "la"  "lE"  "l"  "lo"  "lWa"      ;;   8
+   "He"  "Hu"  "Hi"  "Ha"  "HE"  "H"  "Ho"  "HWa"      ;;  16
+   "me"  "mu"  "mi"  "ma"  "mE"  "m"  "mo"  "mWa"      ;;  24
+  "`se" "`su" "`si" "`sa" "`sE" "`s" "`so" "`sWa"      ;;  32
+   "re"  "ru"  "ri"  "ra"  "rE"  "r"  "ro"  "rWa"      ;;  40
+   "se"  "su"  "si"  "sa"  "sE"  "s"  "so"  "sWa"      ;;  48
+   "xe"  "xu"  "xi"  "xa"  "xE"  "x"  "xo"  "xWa"      ;;  56
+   "qe"  "qu"  "qi"  "qa"  "qE"  "q"  "qo"    ""       ;;  64
+  "qWe"   ""  "qWi" "qWa" "qWE"  "qW'" ""     ""       ;;  72
+   "Qe"  "Qu"  "Qi"  "Qa"  "QE"  "Q"  "Qo"    ""       ;;  80
+  "QWe"   ""  "QWi" "QWa" "QWE"  "QW'" ""     ""       ;;  88
+   "be"  "bu"  "bi"  "ba"  "bE"  "b"  "bo"  "bWa"      ;;  96
+   "ve"  "vu"  "vi"  "va"  "vE"  "v"  "vo"  "vWa"      ;; 104
+   "te"  "tu"  "ti"  "ta"  "tE"  "t"  "to"  "tWa"      ;; 112
+   "ce"  "cu"  "ci"  "ca"  "cE"  "c"  "co"  "cWa"      ;; 120
+  "`he" "`hu" "`hi" "`ha" "`hE" "`h" "`ho"    ""       ;; 128
+  "hWe"   ""  "hWi" "hWa"  "hWE" "hW'" ""     ""       ;; 136
+   "ne"  "nu"  "ni"  "na"  "nE"  "n"  "no"  "nWa"      ;; 144
+   "Ne"  "Nu"  "Ni"  "Na"  "NE"  "N"  "No"  "NWa"      ;; 152
+    "e"   "u"   "i"   "A"   "E"  "I"   "o"   "ea"      ;; 160
+   "ke"  "ku"  "ki"  "ka"  "kE"  "k"  "ko"    ""       ;; 168
+  "kWe"   ""  "kWi" "kWa" "kWE"  "kW'" ""     ""       ;; 176
+   "Ke"  "Ku"  "Ki"  "Ka"  "KE"  "K"  "Ko"    ""       ;; 184
+  "KWe"   ""  "KWi" "KWa" "KWE"  "KW'" ""     ""       ;; 192
+   "we"  "wu"  "wi"  "wa"  "wE"  "w"  "wo"    ""       ;; 200
+   "`e"  "`u"  "`i"  "`a"  "`E" "`I"  "`o"    ""       ;; 208
+   "ze"  "zu"  "zi"  "za"  "zE"  "z"  "zo"  "zWa"      ;; 216
+   "Ze"  "Zu"  "Zi"  "Za"  "ZE"  "Z"  "Zo"  "ZWa"      ;; 224
+   "ye"  "yu"  "yi"  "ya"  "yE"  "y"  "yo"  "yWa"      ;; 232
+   "de"  "du"  "di"  "da"  "dE"  "d"  "do"  "dWa"      ;; 240
+   "De"  "Du"  "Di"  "Da"  "DE"  "D"  "Do"  "DWa"      ;; 248
+   "je"  "ju"  "ji"  "ja"  "jE"  "j"  "jo"  "jWa"      ;; 256
+   "ge"  "gu"  "gi"  "ga"  "gE"  "g"  "go"    ""       ;; 264
+  "gWe"   ""  "gWi" "gWa" "gWE" "gW'"  ""     ""       ;; 272
+   "Ge"  "Gu"  "Gi"  "Ga"  "GE"  "G"  "Go"  "GWa"      ;; 280
+   "Te"  "Tu"  "Ti"  "Ta"  "TE"  "T"  "To"  "TWa"      ;; 288
+   "Ce"  "Cu"  "Ci"  "Ca"  "CE"  "C"  "Co"  "CWa"      ;; 296
+   "Pe"  "Pu"  "Pi"  "Pa"  "PE"  "P"  "Po"  "PWa"      ;; 304
+   "Se"  "Su"  "Si"  "Sa"  "SE"  "S"  "So"  "SWa"      ;; 312
+  "`Se" "`Su" "`Si" "`Sa" "`SE" "`S" "`So"    ""       ;; 320
+   "fe"  "fu"  "fi"  "fa"  "fE"  "f"  "fo"  "fWa"      ;; 328
+   "pe"  "pu"  "pi"  "pa"  "pE"  "p"  "po"  "pWa"      ;; 336
+  "mYa" "rYa" "fYa"   ""    ""   ""    ""     ""       ;; 344
+   " "  " : "  "::"  ","   ";"  "-:"  ":-"   "`?"      ;; 352
+  ":|:"  "1"   "2"   "3"   "4"   "5"   "6"   "7"       ;; 360
+   "8"   "9"   "10"  "20"  "30"  "40" "50"   "60"      ;; 368
+   "70"  "80"  "90" "100" "10000" ""   ""     ""       ;; 376
+  "`qe" "`qu" "`qi" "`qa" "`qE" "`q" "`qo"    ""       ;; 384
+  "mWe" "bWe" "GWe" "fWe" "pWe"  ""    ""     ""       ;; 392
+  "`ke" "`ku" "`ki" "`ka" "`kE" "`k" "`ko"    ""       ;; 400
+  "mWi" "bWi" "GWi" "fWi" "pWi"  ""    ""     ""       ;; 408
+   "Xe"  "Xu"  "Xi"  "Xa"  "XE"  "X"  "Xo"    ""       ;; 416
+  "mWE" "bWE" "GWE" "fWE" "pWE"  ""    ""     ""       ;; 424
+  "`ge" "`gu" "`gi" "`ga" "`gE" "`g" "`go"    ""       ;; 432
+  "mW'" "bW'" "GW'" "fW'" "pW'"  ""    ""     ""       ;; 440
+  "\\~X " "\\~e " "\\~E " "\\~a " "\\~A " "wWe" "wWi" "wWa" ;; 448
+  "wWE" "wW'"  "''"  "`!"  "."  "<<"  ">>"   "?" ])    ;; 456
+
+(defun ethio-prefer-amharic-p nil
+  (or (eq ethio-primary-language 'amharic)
+      (and (not (eq ethio-primary-language 'tigrigna))
+          (eq ethio-secondary-language 'amharic))))
+
+(defun ethio-language-to-flag (lang)
+  (cond
+   ((eq lang 'english) "eng")
+   ((eq lang 'tigrigna) "tir")
+   ((eq lang 'amharic) "amh")
+   (t "")))
+
+;;;###autoload
+(defun ethio-fidel-to-sera-region (begin end &optional secondary force)
+  "Replace all the FIDEL characters in the region to the SERA format.
+The variable `ethio-primary-language' specifies the primary
+language and `ethio-secondary-language' specifies the secondary.
+
+If the 3dr parameter SECONDARY is given and non-nil, try to convert
+the region so that it begins in the secondary language; otherwise with
+the primary language.
+
+If the 4th parameter FORCE is given and non-nil, convert even if the
+buffer is read-only.
+
+See also the descriptions of the variables
+`ethio-use-colon-for-colon', `ethio-use-three-dot-question',
+`ethio-quote-vowel-always' and `ethio-numeric-reduction'."
+
+  (interactive "r\nP")
+  (save-restriction
+    (narrow-to-region begin end)
+    (ethio-fidel-to-sera-buffer secondary force)))
+
+;;;###autoload
+(defun ethio-fidel-to-sera-buffer (&optional secondary force)
+  "Replace all the FIDEL characters in the current buffer to the SERA format.
+The variable `ethio-primary-language' specifies the primary
+language and `ethio-secondary-language' specifies the secondary.
+
+If the 1st optional parameter SECONDARY is non-nil, try to convert the
+region so that it begins in the secondary language; otherwise with the
+primary language.
+
+If the 2nd optional parameter FORCE is non-nil, convert even if the
+buffer is read-only.
+
+See also the descriptions of the variables
+`ethio-use-colon-for-colon', `ethio-use-three-dot-question',
+`ethio-quote-vowel-always' and `ethio-numeric-reduction'."
+
+  (interactive "P")
+  (if (and buffer-read-only
+          (not force)
+          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
+      (error ""))
+
+  (let ((buffer-read-only nil)
+       (case-fold-search nil)
+       (lonec nil) ;; t means previous char was a lone consonant
+       (fidel nil) ;; t means previous char was a FIDEL
+       (digit nil) ;; t means previous char was an Ethiopic digit
+       (flag (if (ethio-prefer-amharic-p) "\\~amh " "\\~tir "))
+       mode ch)
+
+    ;; user's preference in transcription
+    (if ethio-use-colon-for-colon
+       (progn
+         (aset ethio-fidel-to-sera-map 353 "`:")
+         (aset ethio-fidel-to-sera-map 357 ":"))
+      (aset ethio-fidel-to-sera-map 353 " : ")
+      (aset ethio-fidel-to-sera-map 357 "-:"))
+
+    (if ethio-use-three-dot-question
+       (progn
+         (aset ethio-fidel-to-sera-map 359 "?")
+         (aset ethio-fidel-to-sera-map 463 "`?"))
+      (aset ethio-fidel-to-sera-map 359 "`?")
+      (aset ethio-fidel-to-sera-map 463 "?"))
+
+    (mapcar
+     '(lambda (x)
+       (aset (aref ethio-fidel-to-sera-map x)
+             2
+             (if ethio-W-sixth-always ?' ?u)))
+     '(77 93 141 181 197 277 440 441 442 443 444 457))
+
+    (if (ethio-prefer-amharic-p)
+       (aset ethio-fidel-to-sera-map 160 "a")
+      (aset ethio-fidel-to-sera-map 160 "e"))
+    ;; end of user's preference
+
+    ;; first, decompose geminated characters
+    (decompose-region (point-min) (point-max))
+
+    ;; main conversion routine
+    (goto-char (point-min))
+    (while (not (eobp))
+      (setq ch (following-char))
+
+      (cond                            ; ethiopic, english, neutral
+
+       ;; ethiopic character.  must go to ethiopic mode, if not in it.
+       ((eq (char-charset ch) 'ethiopic)
+       (setq ch (ethio-char-to-ethiocode ch))
+       (delete-char 1)
+       (if (not (eq mode 'ethiopic))
+           (progn
+             (insert flag)
+             (setq mode 'ethiopic)))
+
+       (cond                           ; fidel, punc, digit
+
+        ;; fidels
+        ((or (<= ch 346)               ;  he - fYa
+             (and (>= ch 384) (<= ch 444)) ; `qe - pw
+             (and (>= ch 453) (<= ch 457))) ; wWe - wW
+         (if (and (memq ch '(160 161 162 163 164 166 167)) ; (e - ea)
+                  (or lonec
+                      (and ethio-quote-vowel-always
+                           fidel)))
+             (insert "'"))
+         (insert (aref ethio-fidel-to-sera-map ch))
+         (setq lonec (ethio-lone-consonant-p ch)
+               fidel t
+               digit nil))
+
+        ;; punctuations or icons
+        ((or (and (>= ch 353) (<= ch 360)) ;  : - :|:
+             (>= ch 458)               ;  '' -  ?
+             (and (>= ch 448) (<= ch 452))) ;  \~X \~e \~E \~a \~A
+         (insert (aref ethio-fidel-to-sera-map ch))
+         (setq lonec nil
+               fidel nil
+               digit nil))
+
+        ;; now CH must be an ethiopic digit
+
+        ;; reduction = 0 or not preceded by Ethiopic number(s)
+        ((or (= ethio-numeric-reduction 0)
+             (not digit))
+         (insert "`" (aref ethio-fidel-to-sera-map ch))
+         (setq lonec nil
+               fidel nil
+               digit t))
+
+        ;; reduction = 2 and following 10s, 100s, 10000s
+        ((and (= ethio-numeric-reduction 2)
+              (memq ch '(370 379 380)))
+         (insert (substring (aref ethio-fidel-to-sera-map ch) 1))
+         (setq lonec nil
+               fidel nil
+               digit t))
+
+        ;; ordinary following digits
+        (t
+         (insert (aref ethio-fidel-to-sera-map ch))
+         (setq lonec nil
+               fidel nil
+               digit t))))
+
+       ;; english character.  must go to english mode, if not in it.
+       ((or (and (>= ch ?a) (<= ch ?z))
+           (and (>= ch ?A) (<= ch ?Z)))
+       (if (not (eq mode 'english))
+           (insert "\\~eng "))
+       (forward-char 1)
+       (setq mode 'english
+             lonec nil
+             fidel nil
+             digit nil))
+
+       ;; ch can appear both in ethiopic section and in english section.
+       (t
+
+       ;; we must decide the mode, if not decided yet
+       (if (null mode)
+           (progn
+             (setq mode
+                   (if secondary
+                       ethio-secondary-language
+                     ethio-primary-language))
+             (if (eq mode 'english)
+                 (insert "\\~eng ")
+               (insert flag)
+               (setq mode 'ethiopic)))) ; tigrigna & amharic --> ethiopic
+
+       (cond                           ; \ , eng-mode , punc , w3 , other
+
+        ;; backslash is always quoted
+        ((= ch ?\\ )
+         (insert "\\")
+         (forward-char 1))
+
+        ;; nothing to do if in english mode
+        ((eq mode 'english)
+         (forward-char 1))
+
+        ;; now we must be in ethiopic mode and seeing a non-"\"
+
+        ;; ascii punctuations in ethiopic mode
+        ((looking-at "[,.;:'`?]+")
+         (insert "\\")
+         (goto-char (1+ (match-end 0)))) ; because we inserted one byte (\)
+
+        ;; skip from "<" to ">" (or from "&" to ";") if called from w3
+        ((and (or (= ch ?<) (= ch ?&))
+              (or (and (boundp 'ethio-sera-being-called-by-w3)
+                       ethio-sera-being-called-by-w3)
+                  (and (boundp 'sera-being-called-by-w3)
+                       sera-being-called-by-w3)))
+         (search-forward (if (= ch ?<) ">" ";")
+                         nil 0))
+
+        ;; neutral character.  no need to quote.  just skip it.
+        (t
+         (forward-char 1)))
+
+       (setq lonec nil
+             fidel nil
+             digit nil)))
+    ;; end of main conversion routine
+    )))
+
+(defun ethio-lone-consonant-p (ethiocode)
+  "If ETHIOCODE is an Ethiopic lone consonant, return t."
+  (or (and (< ethiocode 344) (= (% ethiocode 8) 5))
+
+      ;;                     `q  `k   X  `g  mW  bW  GW  fW  pW  wW
+      (memq ethiocode '(389 405 421 437 440 441 442 443 444 457))))
+
+;;;###autoload
+(defun ethio-fidel-to-sera-mail-or-marker (&optional arg)
+  "Execute `ethio-fidel-to-sera-mail' or `ethio-fidel-to-sera-marker' depending on the current major mode.
+If in rmail-mode or in mail-mode, execute the former; otherwise latter."
+
+  (interactive "P")
+  (if (or (eq major-mode 'rmail-mode)
+         (eq major-mode 'mail-mode))
+      (ethio-fidel-to-sera-mail)
+    (ethio-fidel-to-sera-marker arg)))
+
+;;;###autoload
+(defun ethio-fidel-to-sera-mail nil
+  "Convert FIDEL to SERA to read/write mail and news.
+
+If the body contains at least one Ethiopic character,
+ 1) insert the string \"<sera>\" at the beginning of the body,
+ 2) insert \"</sera>\" at the end of the body, and
+ 3) convert the body into SERA.
+
+The very same procedure applies to the subject field, too."
+
+  (interactive)
+  (let ((buffer-read-only nil)
+       border)
+    (save-excursion
+
+      ;; follow RFC822 rules instead of looking for a fixed separator
+      (rfc822-goto-eoh)
+      (forward-line 1)
+      (setq border (point))
+
+      ;; process body first not to change the border
+      ;; note that the point is already at the border
+      (if (re-search-forward "\\ce" nil t)
+         (progn
+           (ethio-fidel-to-sera-region border (point-max))
+           (goto-char border)
+           (insert "<sera>")
+           (goto-char (point-max))
+           (insert "</sera>")))
+
+      ;; process subject
+      (goto-char (point-min))
+      (if (re-search-forward "^Subject: " border t)
+         (let ((beg (point))
+               (end (line-end-position)))
+           (if (re-search-forward "\\ce" end t)
+               (progn
+                 (ethio-fidel-to-sera-region beg end)
+                 (goto-char beg)
+                 (insert "<sera>")
+                 (end-of-line)
+                 (insert "</sera>")))))
+
+      ;; adjust the rmail marker
+      (if (eq major-mode 'rmail-mode)
+         (set-marker
+          (aref rmail-message-vector (1+ rmail-current-message))
+          (point-max))))))
+
+;;;###autoload
+(defun ethio-fidel-to-sera-marker (&optional force)
+  "Convert the regions surrounded by \"<sera>\" and \"</sera>\" from FIDEL to SERA.
+The markers \"<sera>\" and \"</sera>\" themselves are not deleted."
+
+  (interactive "P")
+  (if (and buffer-read-only
+          (not force)
+          (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
+      (error ""))
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward "<sera>" nil t)
+      (ethio-fidel-to-sera-region
+       (point)
+       (if (re-search-forward "</sera>" nil t)
+          (match-beginning 0)
+        (point-max))
+       nil
+       'force))))
+
+;;
+;; vowel modification
+;;
+
+;;;###autoload
+(defun ethio-modify-vowel nil
+  "Modify the vowel of the FIDEL that is under the cursor."
+  (interactive)
+  (let ((ch (following-char))
+       (composite nil)                 ; geminated or not
+       newch base vowel modulo)
+
+    (cond
+     ;; in case of gemination
+     ((eq (char-charset ch) 'composition)
+      (setq ch (string-to-char (char-to-string ch))
+           composite t))
+     ;; neither gemination nor fidel
+     ((not (eq (char-charset ch) 'ethiopic))
+      (error "Not a valid character")))
+
+    ;; set frequently referred character features
+    (setq ch     (ethio-char-to-ethiocode ch)
+         base   (* (/ ch 8) 8)
+         modulo (% ch 8))
+
+    (if (or (and (>= ch 344) (<= ch 380)) ;; mYa - `10000
+           (and (>= ch 448) (<= ch 452)) ;; \~X - \~A
+           (>= ch 458))                  ;; private punctuations
+       (error "Not a valid character"))
+
+    (setq
+     newch
+     (cond
+
+      ;; first standalone vowels
+      ((= base 160)
+       (if (ethio-prefer-amharic-p)
+          (message "Modify vowel to: [auiAEIoW\"] ")
+        (message "Modify vowel to: [euiAEIoW\"] "))
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 160)
+       ((= vowel ?u) 161)
+       ((= vowel ?i) 162)
+       ((= vowel ?A) 163)
+       ((= vowel ?E) 164)
+       ((= vowel ?I) 165)
+       ((= vowel ?o) 166)
+       ((= vowel ?W) 167)
+       ((= vowel ?a) (if (ethio-prefer-amharic-p) 160 163))
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+
+      ;; second standalone vowels
+      ((= base 208)
+       (message "Modify vowel to: [euiaEIo\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 208)
+       ((= vowel ?u) 209)
+       ((= vowel ?i) 210)
+       ((= vowel ?a) 211)
+       ((= vowel ?E) 212)
+       ((= vowel ?I) 213)
+       ((= vowel ?o) 214)
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+
+      ;; 12-form consonants, *W* form
+      ((memq base '(72 88 136 176 192 272)) ; qW QW hW kW KW gW
+       (message "Modify vowel to: [euiaE'\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) base)
+       ((= vowel ?u) (+ base 5))
+       ((= vowel ?i) (+ base 2))
+       ((= vowel ?a) (+ base 3))
+       ((= vowel ?E) (+ base 4))
+       ((= vowel ?') (+ base 5))
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+
+      ;; extended 12-form consonants, mWa bWa GWa fWa pWa
+      ((= ch 31)                       ; mWa
+       (message "Modify vowel to: [euiaE'\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 392)
+       ((= vowel ?u) 440)
+       ((= vowel ?i) 408)
+       ((= vowel ?a) ch)
+       ((= vowel ?E) 424)
+       ((= vowel ?') 440)
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+      ((= ch 103)                      ; bWa
+       (message "Modify vowel to: [euiaE'\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 393)
+       ((= vowel ?u) 441)
+       ((= vowel ?i) 409)
+       ((= vowel ?a) ch)
+       ((= vowel ?E) 425)
+       ((= vowel ?') 441)
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+      ((= ch 287)                      ; GWa
+       (message "Modify vowel to: [euiaE'\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 394)
+       ((= vowel ?u) 442)
+       ((= vowel ?i) 410)
+       ((= vowel ?a) ch)
+       ((= vowel ?E) 426)
+       ((= vowel ?') 442)
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+      ((= ch 335)                      ; fWa
+       (message "Modify vowel to: [euiaE'\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 395)
+       ((= vowel ?u) 443)
+       ((= vowel ?i) 411)
+       ((= vowel ?a) ch)
+       ((= vowel ?E) 427)
+       ((= vowel ?') 443)
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+      ((= ch 343)                      ; pWa
+       (message "Modify vowel to: [euiaE'\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 396)
+       ((= vowel ?u) 444)
+       ((= vowel ?i) 412)
+       ((= vowel ?a) ch)
+       ((= vowel ?E) 428)
+       ((= vowel ?') 444)
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+
+      ;; extended 12-form consonatns, mW* bW* GW* fW* pW*
+      ((memq base '(392 408 424 440))  ; *We *Wi *WE *W
+       (message "Modify vowel to: [eiEau'\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) (+ 392 modulo))
+       ((= vowel ?i) (+ 408 modulo))
+       ((= vowel ?E) (+ 424 modulo))
+       ((= vowel ?a) (cond
+                      ((= modulo 0)  31) ; mWa
+                      ((= modulo 1) 103) ; bWa
+                      ((= modulo 2) 287) ; GWa
+                      ((= modulo 3) 335) ; fWa
+                      ((= modulo 4) 343) ; pWa
+                      (t nil)))        ; never reach here
+       ((= vowel ?') (+ 440 modulo))
+       ((= vowel ?u) (+ 440 modulo))
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+
+      ((and (>= ch 453) (<= ch 457))   ; wWe wWi wWa wWE wW
+       (message "Modify vowel to: [eiaE'u\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) 453)
+       ((= vowel ?i) 454)
+       ((= vowel ?a) 455)
+       ((= vowel ?E) 456)
+       ((= vowel ?') 457)
+       ((= vowel ?u) 457)
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+
+      ;; 7-form consonants, or
+      ;; first 7 of 8-form consonants
+      ((<= modulo 6)
+       (message "Modify vowel to: [euiaE'o\"] ")
+       (setq vowel (read-char))
+       (cond
+       ((= vowel ?e) base)
+       ((= vowel ?u) (+ base 1))
+       ((= vowel ?i) (+ base 2))
+       ((= vowel ?a) (+ base 3))
+       ((= vowel ?E) (+ base 4))
+       ((= vowel ?') (+ base 5))
+       ((= vowel ?o) (+ base 6))
+       ((= vowel ?\") (setq composite t) ch)
+       (t nil)))
+
+      ;; otherwise
+      (t
+       nil)))
+
+    (cond
+
+     ;; could not get new character
+     ((null newch)
+      (error "Invalid vowel"))
+
+     ;; vowel changed on a composite Fidel
+     (composite
+      (delete-char 1)
+      (insert
+       (compose-string
+       (concat (char-to-string (ethio-ethiocode-to-char newch))        "\e$(3%s\e(B"))))
+
+     ;; simple vowel modification
+     (t
+      (delete-char 1)
+      (insert (ethio-ethiocode-to-char newch))))))
+
+(defun ethio-ethiocode-to-char (ethiocode)
+  (make-char
+   'ethiopic
+   (+ (/ ethiocode 94) 33)
+   (+ (mod ethiocode 94) 33)))
+
+(defun ethio-char-to-ethiocode (ch)
+  (and (eq (char-charset ch) 'ethiopic)
+       (let ((char-components (split-char ch)))
+        (+ (* (- (nth 1 char-components) 33) 94)
+           (- (nth 2 char-components) 33)))))
+
+;;
+;; space replacement
+;;
+
+;;;###autoload
+(defun ethio-replace-space (ch begin end)
+  "Replace ASCII spaces with Ethiopic word separators in the region.
+
+In the specified region, replace word separators surrounded by two
+Ethiopic characters, depending on the first parameter CH, which should
+be 1, 2, or 3.
+
+If CH = 1, word separator will be replaced with an ASCII space.
+If CH = 2, with two ASCII spaces.
+If CH = 3, with the Ethiopic colon-like word separator.
+
+The second and third parameters BEGIN and END specify the region."
+
+  (interactive "*cReplace spaces to: 1 (sg col), 2 (dbl col), 3 (Ethiopic)\nr")
+  (if (not (memq ch '(?1 ?2 ?3)))
+      (error ""))
+  (save-excursion
+    (save-restriction
+      (narrow-to-region begin end)
+
+      (cond
+       ((= ch ?1)
+       ;; an Ethiopic word separator --> an ASCII space
+       (goto-char (point-min))
+       (while (search-forward "\e$(3$h\e(B" nil t)
+         (replace-match " " nil t))
+
+       ;; two ASCII spaces between Ethiopic characters --> an ASCII space
+       (goto-char (point-min))
+       (while (re-search-forward "\\(\\ce\\)  \\(\\ce\\)" nil t)
+         (replace-match "\\1 \\2")
+         (goto-char (match-beginning 2))))
+
+       ((= ch ?2)
+       ;; An Ethiopic word separator --> two ASCII spaces
+       (goto-char (point-min))
+       (while (search-forward "\e$(3$h\e(B" nil t)
+         (replace-match "  "))
+
+       ;; An ASCII space between Ethiopic characters --> two ASCII spaces
+       (goto-char (point-min))
+       (while (re-search-forward "\\(\\ce\\) \\(\\ce\\)" nil t)
+         (replace-match "\\1  \\2")
+         (goto-char (match-beginning 2))))
+
+       (t
+       ;; One or two ASCII spaces between Ethiopic characters
+       ;;   --> An Ethiopic word separator
+       (goto-char (point-min))
+       (while (re-search-forward "\\(\\ce\\)  ?\\(\\ce\\)" nil t)
+         (replace-match "\\1\e$(3$h\e(B\\2")
+         (goto-char (match-beginning 2)))
+
+       ;; Three or more ASCII spaces between Ethiopic characters
+       ;;   --> An Ethiopic word separator + (N - 2) ASCII spaces
+       (goto-char (point-min))
+       (while (re-search-forward "\\(\\ce\\)  \\( *\\ce\\)" nil t)
+         (replace-match "\\1\e$(3$h\e(B\\2")
+         (goto-char (match-beginning 2))))))))
+
+;;
+;; special icons
+;;
+
+;;;###autoload
+(defun ethio-input-special-character (arg)
+  "Allow the user to input special characters."
+  (interactive "*cInput number: 1.\e$(3%j\e(B  2.\e$(3%k\e(B  3.\e$(3%l\e(B  4.\e$(3%m\e(B  5.\e$(3%i\e(B")
+  (cond
+   ((= arg ?1)
+    (insert "\e$(3%j\e(B"))
+   ((= arg ?2)
+    (insert "\e$(3%k\e(B"))
+   ((= arg ?3)
+    (insert "\e$(3%l\e(B"))
+   ((= arg ?4)
+    (insert "\e$(3%m\e(B"))
+   ((= arg ?5)
+    (insert "\e$(3%i\e(B"))
+   (t
+    (error ""))))
+
+;;
+;; TeX support
+;;
+
+(defconst ethio-fidel-to-tex-map
+ [ "heG"  "huG"  "hiG"  "haG"  "hEG"   "hG"  "hoG"      ""     ;;   0 - 7
+   "leG"  "luG"  "liG"  "laG"  "lEG"   "lG"  "loG"  "lWaG"     ;;   8
+   "HeG"  "HuG"  "HiG"  "HaG"  "HEG"   "HG"  "HoG"  "HWaG"     ;;  16
+   "meG"  "muG"  "miG"  "maG"  "mEG"   "mG"  "moG"  "mWaG"     ;;  24
+  "sseG" "ssuG" "ssiG" "ssaG" "ssEG"  "ssG" "ssoG" "ssWaG"     ;;  32
+   "reG"  "ruG"  "riG"  "raG"  "rEG"   "rG"  "roG"  "rWaG"     ;;  40
+   "seG"  "suG"  "siG"  "saG"  "sEG"   "sG"  "soG"  "sWaG"     ;;  48
+   "xeG"  "xuG"  "xiG"  "xaG"  "xEG"   "xG"  "xoG"  "xWaG"     ;;  56
+   "qeG"  "quG"  "qiG"  "qaG"  "qEG"   "qG"  "qoG"      ""     ;;  64
+  "qWeG"     "" "qWiG" "qWaG" "qWEG"  "qWG"     ""      ""     ;;  72
+   "QeG"  "QuG"  "QiG"  "QaG"  "QEG"   "QG"  "QoG"      ""     ;;  80
+  "QWeG"     "" "QWiG" "QWaG" "QWEG"  "QWG"     ""      ""     ;;  88
+   "beG"  "buG"  "biG"  "baG"  "bEG"   "bG"  "boG"  "bWaG"     ;;  96
+   "veG"  "vuG"  "viG"  "vaG"  "vEG"   "vG"  "voG"  "vWaG"     ;; 104
+   "teG"  "tuG"  "tiG"  "taG"  "tEG"   "tG"  "toG"  "tWaG"     ;; 112
+   "ceG"  "cuG"  "ciG"  "caG"  "cEG"   "cG"  "coG"  "cWaG"     ;; 120
+  "hheG" "hhuG" "hhiG" "hhaG" "hhEG"  "hhG" "hhoG"      ""     ;; 128
+  "hWeG"     "" "hWiG" "hWaG" "hWEG"  "hWG"     ""      ""     ;; 136
+   "neG"  "nuG"  "niG"  "naG"  "nEG"   "nG"  "noG"  "nWaG"     ;; 144
+   "NeG"  "NuG"  "NiG"  "NaG"  "NEG"   "NG"  "NoG"  "NWaG"     ;; 152
+    "eG"   "uG"   "iG"   "AG"   "EG"   "IG"   "oG"   "eaG"     ;; 160
+   "keG"  "kuG"  "kiG"  "kaG"  "kEG"   "kG"  "koG"      ""     ;; 168
+  "kWeG"     "" "kWiG" "kWaG" "kWEG"  "kWG"     ""      ""     ;; 176
+   "KeG"  "KuG"  "KiG"  "KaG"  "KEG"   "KG"  "KoG"      ""     ;; 184
+  "KWeG"     "" "KWiG" "KWaG" "KWEG"  "KWG"     ""      ""     ;; 192
+   "weG"  "wuG"  "wiG"  "waG"  "wEG"   "wG"  "woG"      ""     ;; 200
+   "eeG"  "uuG"  "iiG"  "aaG"  "EEG"  "IIG"  "ooG"      ""     ;; 208
+   "zeG"  "zuG"  "ziG"  "zaG"  "zEG"   "zG"  "zoG"  "zWaG"     ;; 216
+   "ZeG"  "ZuG"  "ZiG"  "ZaG"  "ZEG"   "ZG"  "ZoG"  "ZWaG"     ;; 224
+   "yeG"  "yuG"  "yiG"  "yaG"  "yEG"   "yG"  "yoG"  "yWaG"     ;; 232
+   "deG"  "duG"  "diG"  "daG"  "dEG"   "dG" "doG"   "dWaG"     ;; 240
+   "DeG"  "DuG"  "DiG"  "DaG"  "DEG"   "DG"  "DoG"  "DWaG"     ;; 248
+   "jeG"  "juG"  "jiG"  "jaG"  "jEG"   "jG"  "joG"  "jWaG"     ;; 256
+   "geG"  "guG"  "giG"  "gaG"  "gEG"   "gG"  "goG"     ""      ;; 264
+  "gWeG"     "" "gWiG" "gWaG" "gWEG"  "gWG"     ""     ""      ;; 272
+   "GeG"  "GuG"  "GiG"  "GaG"  "GEG"   "GG"  "GoG"  "GWaG"     ;; 280
+   "TeG"  "TuG"  "TiG"  "TaG"  "TEG"   "TG"  "ToG"  "TWaG"     ;; 288
+   "CeG"  "CuG"  "CiG"  "CaG"  "CEG"   "CG"  "CoG"  "CWaG"     ;; 296
+   "PeG"  "PuG"  "PiG"  "PaG"  "PEG"   "PG"  "PoG"  "PWaG"     ;; 304
+   "SeG"  "SuG"  "SiG"  "SaG"  "SEG"   "SG"  "SoG"  "SWaG"     ;; 312
+  "SSeG" "SSuG" "SSiG" "SSaG" "SSEG"  "SSG" "SSoG"      ""     ;; 320
+   "feG"  "fuG"  "fiG"  "faG"  "fEG"   "fG"  "foG"  "fWaG"     ;; 328
+   "peG"  "puG"  "piG"  "paG"  "pEG"   "pG"  "poG"  "pWaG"     ;; 336
+  "mYaG" "rYaG" "fYaG"     ""     ""     ""     ""      ""     ;; 344
+      "" "spaceG" "periodG" "commaG"                           ;; 352
+  "semicolonG" "colonG" "precolonG" "oldqmarkG"                ;; 356
+  "pbreakG" "andG" "huletG" "sostG" "aratG" "amstG" "sadstG" "sabatG"  ;; 360
+  "smntG" "zeteNG" "asrG" "heyaG" "selasaG" "arbaG" "hemsaG" "slsaG"   ;; 368
+  "sebaG" "semanyaG" "zeTanaG" "metoG" "asrxiG" "" "" ""               ;; 376
+  "qqeG" "qquG" "qqiG" "qqaG" "qqEG" "qqG" "qqoG"    ""      ;; 384
+  "mWeG" "bWeG" "GWeG" "fWeG" "pWeG"    ""     ""    ""      ;; 392
+  "kkeG" "kkuG" "kkiG" "kkaG" "kkEG" "kkG" "kkoG"    ""      ;; 400
+  "mWiG" "bWiG" "GWiG" "fWiG" "pWiG"    ""     ""    ""      ;; 408
+   "XeG"  "XuG" "GXiG"  "XaG"  "XEG"  "XG"  "XoG"    ""      ;; 416
+  "mWEG" "bWEG" "GWEG" "fWEG" "pWEG"    ""     ""    ""      ;; 424
+  "ggeG" "gguG" "ggiG" "ggaG" "ggEG" "ggG" "ggoG"    ""      ;; 432
+   "mWG" "bWG"   "GWG"  "fWG"  "pWG"    ""     ""    ""      ;; 440
+  "ornamentG" "flandG" "iflandG" "africaG"                      ;; 448
+  "iafricaG" "wWeG" "wWiG" "wWaG"                            ;; 452
+  "wWEG"  "wWG" "" "slaqG" "dotG" "lquoteG" "rquoteG" "qmarkG" ])  ;; 456
+
+;;
+;; To make tex-to-fidel mapping.
+;; The following code makes
+;;     (get 'ethio-tex-command-he 'ethio-fidel-char)  ==>  ?\e$(3!!\e(B
+;; etc.
+;;
+
+(let ((i 0) str)
+  (while (< i (length ethio-fidel-to-tex-map))
+    (setq str (aref ethio-fidel-to-tex-map i))
+    (if (not (string= str ""))
+       (put
+        (intern (concat "ethio-tex-command-" (aref ethio-fidel-to-tex-map i)))
+        'ethio-fidel-char
+        (ethio-ethiocode-to-char i)))
+    (setq i (1+ i))))
+
+;;;###autoload
+(defun ethio-fidel-to-tex-buffer nil
+  "Convert each fidel characters in the current buffer into a fidel-tex command.
+Each command is always surrounded by braces."
+  (interactive)
+  (let ((buffer-read-only nil))
+
+    ;; Isolated gemination marks need special treatement
+    (goto-char (point-min))
+    (while (search-forward "\e$(3%s\e(B" nil t)
+      (replace-match "\\geminateG{}" t t))
+
+    ;; First, decompose geminations
+    ;; Here we assume that each composed character consists of
+    ;; one Ethiopic character and the Ethiopic gemination mark.
+    (decompose-region (point-min) (point-max))
+
+    ;; Special treatment for geminated characters
+    ;; The geminated character (la'') will be "\geminateG{\la}".
+    (goto-char (point-min))
+    (while (search-forward "\e$(3%s\e(B" nil t)
+      (delete-backward-char 1)
+      (backward-char 1)
+      (insert "\\geminateG")
+      (forward-char 1))
+
+    ;; Ethiopic characters to TeX macros
+    (goto-char (point-min))
+    (while (re-search-forward "\\ce" nil t)
+      (insert
+       "{\\"
+       (aref ethio-fidel-to-tex-map
+            (prog1 (ethio-char-to-ethiocode (preceding-char))
+              (backward-delete-char 1)))
+       "}"))
+    (goto-char (point-min))
+    (set-buffer-modified-p nil)))
+
+;;;###autoload
+(defun ethio-tex-to-fidel-buffer nil
+  "Convert fidel-tex commands in the current buffer into fidel chars."
+  (interactive)
+  (let ((buffer-read-only nil)
+       (p) (ch))
+
+    ;; Special treatment for gemination
+    ;; "\geminateG{\la}" or "\geminateG{{\la}}" will be "\la\e$(3%s\e(B"
+    ;; "\geminateG{}" remains unchanged.
+    (goto-char (point-min))
+    (while (re-search-forward "\\\\geminateG{\\(\\\\[a-zA-Z]+\\)}" nil t)
+      (replace-match "\\1\e$(3%s\e(B"))
+
+    ;; TeX macros to Ethiopic characters
+    (goto-char (point-min))
+    (while (search-forward "\\" nil t)
+      (setq p (point))
+      (skip-chars-forward "a-zA-Z")
+      (setq ch
+           (get (intern (concat "ethio-tex-command-"
+                                (buffer-substring p (point))))
+                'ethio-fidel-char))
+      (if ch
+         (progn
+           (delete-region (1- p) (point)) ; don't forget the preceding "\"
+           (if (and (= (preceding-char) ?{)
+                    (= (following-char) ?}))
+               (progn
+                 (backward-delete-char 1)
+                 (delete-char 1)))
+           (insert ch))))
+
+    ;; compose geminated characters
+    (goto-char (point-min))
+    (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
+      (compose-region
+       (save-excursion (backward-char 2) (point))
+       (point)))
+
+    ;; Now it's time to convert isolated gemination marks.
+    (goto-char (point-min))
+    (while (search-forward "\\geminateG{}" nil t)
+      (replace-match "\e$(3%s\e(B"))
+
+    (goto-char (point-min))
+    (set-buffer-modified-p nil)))
+
+;;
+;; Java support
+;;
+
+;;;###autoload
+(defun ethio-fidel-to-java-buffer nil
+  "Convert Ethiopic characters into the Java escape sequences.
+
+Each escape sequence is of the form \\uXXXX, where XXXX is the
+character's codepoint (in hex) in Unicode.
+
+If `ethio-java-save-lowercase' is non-nil, use [0-9a-f].
+Otherwise, [0-9A-F]."
+  (let ((ucode))
+
+    ;; first, decompose geminations
+    (decompose-region (point-min) (point-max))
+
+    (goto-char (point-min))
+    (while (re-search-forward "\\ce" nil t)
+      (setq ucode (+ ?\x1200 (ethio-char-to-ethiocode (preceding-char))))
+      (if (> ucode ?\x13bc)
+         (setq ucode (+ ucode 59952)))
+      (delete-backward-char 1)
+      (if ethio-java-save-lowercase
+         (insert (format "\\u%4x" ucode))
+       (insert (upcase (format "\\u%4x" ucode)))))))
+
+;;;###autoload
+(defun ethio-java-to-fidel-buffer nil
+  "Convert the Java escape sequences into corresponding Ethiopic characters."
+  (let ((ucode))
+    (goto-char (point-min))
+    (while (re-search-forward "\\\\u\\([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\\)" nil t)
+      (setq ucode
+           (read
+            (concat
+             "?\\x"
+             (buffer-substring (match-beginning 1) (match-end 1)))))
+      (cond
+       ((and (>= ucode ?\x1200) (<= ucode ?\x13bc))
+       (replace-match "")
+       (insert (ethio-ethiocode-to-char (- ucode ?\x1200))))
+       ((and (>= ucode ?\xfdf1) (<= ucode ?\xfdff))
+       (replace-match "")
+       (insert (ethio-ethiocode-to-char (- ucode 64560))))
+       (t
+       nil)))
+
+    ;; gemination
+    (goto-char (point-min))
+    (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
+      (compose-region
+       (save-excursion (backward-char 2) (point))
+       (point)))
+    ))
+
+;;
+;; file I/O hooks
+;;
+
+;;;###autoload
+(defun ethio-find-file nil
+  "Transcribe file content into Ethiopic depending on filename suffix."
+  (cond
+
+   ((string-match "\\.sera$" (buffer-file-name))
+    (save-excursion
+      (ethio-sera-to-fidel-buffer nil 'force)
+      (set-buffer-modified-p nil)))
+
+   ((string-match "\\.html$" (buffer-file-name))
+    (let ((ethio-sera-being-called-by-w3 t))
+      (save-excursion
+       (ethio-sera-to-fidel-marker 'force)
+       (goto-char (point-min))
+       (while (re-search-forward "&[lr]aquote;" nil t)
+         (if (= (char-after (1+ (match-beginning 0))) ?l)
+             (replace-match "\e$(3%v\e(B")
+           (replace-match "\e$(3%w\e(B")))
+       (set-buffer-modified-p nil))))
+
+   ((string-match "\\.tex$" (buffer-file-name))
+    (save-excursion
+      (ethio-tex-to-fidel-buffer)
+      (set-buffer-modified-p nil)))
+
+   ((string-match "\\.java$" (buffer-file-name))
+    (save-excursion
+      (ethio-java-to-fidel-buffer)
+      (set-buffer-modified-p nil)))
+
+   (t
+    nil)))
+
+;;;###autoload
+(defun ethio-write-file nil
+  "Transcribe Ethiopic characters in ASCII depending on the file extension."
+  (cond
+
+   ((string-match "\\.sera$" (buffer-file-name))
+    (save-excursion
+      (ethio-fidel-to-sera-buffer nil 'force)
+      (goto-char (point-min))
+      (ethio-record-user-preference)
+      (set-buffer-modified-p nil)))
+
+   ((string-match "\\.html$" (buffer-file-name))
+    (save-excursion
+      (let ((ethio-sera-being-called-by-w3 t)
+           (lq (aref ethio-fidel-to-sera-map 461))
+           (rq (aref ethio-fidel-to-sera-map 462)))
+       (aset ethio-fidel-to-sera-map 461 "&laquote;")
+       (aset ethio-fidel-to-sera-map 462 "&raquote;")
+       (ethio-fidel-to-sera-marker 'force)
+       (goto-char (point-min))
+       (if (search-forward "<sera>" nil t)
+           (ethio-record-user-preference))
+       (aset ethio-fidel-to-sera-map 461 lq)
+       (aset ethio-fidel-to-sera-map 462 rq)
+       (set-buffer-modified-p nil))))
+
+   ((string-match "\\.tex$" (buffer-file-name))
+    (save-excursion
+      (ethio-fidel-to-tex-buffer)
+      (set-buffer-modified-p nil)))
+
+   ((string-match "\\.java$" (buffer-file-name))
+    (save-excursion
+      (ethio-fidel-to-java-buffer)
+      (set-buffer-modified-p nil)))
+
+   (t
+    nil)))
+
+(defun ethio-record-user-preference nil
+  (if (looking-at "\\\\~\\(tir?\\|amh?\\) ")
+      (goto-char (match-end 0))
+    (insert (if (ethio-prefer-amharic-p) "\\~amh " "\\~tir ")))
+  (insert (if ethio-use-colon-for-colon "\\~-: " "\\~`: ")
+         (if ethio-use-three-dot-question "\\~`| " "\\~`? ")))
+
+;;
+;; Ethiopic word separator vs. ASCII space
+;;
+
+(defvar ethio-prefer-ascii-space t)
+(make-variable-buffer-local 'ethio-prefer-ascii-space)
+
+(defun ethio-toggle-space nil
+  "Toggle ASCII space and Ethiopic separator for keyboard input."
+  (interactive)
+  (setq ethio-prefer-ascii-space
+       (not ethio-prefer-ascii-space))
+  (if (equal current-input-method "ethiopic")
+      (setq current-input-method-title (quail-title)))
+  (force-mode-line-update))
+
+(defun ethio-insert-space (arg)
+  "Insert ASCII spaces or Ethiopic word separators depending on context.
+
+If the current word separator (indicated in mode-line) is the ASCII space,
+insert an ASCII space.  With ARG, insert that many ASCII spaces.
+
+If the current word separator is the colon-like Ethiopic word
+separator and the point is preceded by `an Ethiopic punctuation mark
+followed by zero or more ASCII spaces', then insert also an ASCII
+space.  With ARG, insert that many ASCII spaces.
+
+Otherwise, insert a colon-like Ethiopic word separator.  With ARG, insert that
+many Ethiopic word separators."
+
+  (interactive "*p")
+  (cond
+   (ethio-prefer-ascii-space
+    (insert-char 32 arg))
+   ((save-excursion
+      (skip-chars-backward " ")
+      (memq (preceding-char)
+           '(?\e$(3$h\e(B ?\e$(3$i\e(B ?\e$(3$j\e(B ?\e$(3$k\e(B ?\e$(3$l\e(B ?\e$(3$m\e(B ?\e$(3$n\e(B ?\e$(3$o\e(B ?\e$(3%t\e(B ?\e$(3%u\e(B ?\e$(3%v\e(B ?\e$(3%w\e(B ?\e$(3%x\e(B)))
+    (insert-char 32 arg))
+   (t
+    (insert-char ?\e$(3$h\e(B arg))))
+
+(defun ethio-insert-ethio-space (arg)
+  "Insert the Ethiopic word delimiter (the colon-like character).
+With ARG, insert that many delimiters."
+  (interactive "*p")
+  (insert-char ?\e$(3$h\e(B arg))
+
+;;
+;; Ethiopic punctuation vs. ASCII punctuation
+;;
+
+(defvar ethio-prefer-ascii-punctuation nil)
+(make-variable-buffer-local 'ethio-prefer-ascii-punctuation)
+
+(defun ethio-toggle-punctuation nil
+  "Toggle Ethiopic punctuations and ASCII punctuations for keyboard input."
+  (interactive)
+  (setq ethio-prefer-ascii-punctuation
+       (not ethio-prefer-ascii-punctuation))
+  (let* ((keys '("." ".." "..." "," ",," ";" ";;" ":" "::" ":::" "*" "**"))
+        (puncs
+         (if ethio-prefer-ascii-punctuation
+             '(?. [".."] ["..."] ?, [",,"] ?\; [";;"] ?: ["::"] [":::"] ?* ["**"])
+           '(?\e$(3$i\e(B ?\e$(3%u\e(B ?. ?\e$(3$j\e(B ?, ?\e$(3$k\e(B ?\; ?\e$(3$h\e(B ?\e$(3$i\e(B ?: ?* ?\e$(3$o\e(B))))
+    (while keys
+      (quail-defrule (car keys) (car puncs) "ethiopic")
+      (setq keys (cdr keys)
+           puncs (cdr puncs)))
+    (if (equal current-input-method "ethiopic")
+       (setq current-input-method-title (quail-title)))
+    (force-mode-line-update)))
+
+;;
+;; Gemination
+;;
+
+(defun ethio-gemination nil
+  "Compose the character before the point with the Ethiopic gemination mark.
+If the character is already composed, decompose it and remove the gemination
+mark."
+  (interactive "*")
+  (cond
+   ((eq (char-charset (preceding-char)) 'ethiopic)
+    (insert "\e$(3%s\e(B")
+    (compose-region
+     (save-excursion (backward-char 2) (point))
+     (point))
+    (forward-char 1))
+   ((eq (char-charset (preceding-char)) 'leading-code-composition)
+    (decompose-region
+     (save-excursion (backward-char 1) (point))
+     (point))
+    (delete-backward-char 1))
+   (t
+    (error ""))))
+
+;;
+(provide 'ethio-util)
+
+;;; arch-tag: c8feb3d6-39bf-4b0a-b6ef-26f03fbc8140
+;;; ethio-util.el ends here