Remove non-free old and crusty clearcase pkg
[packages] / mule-packages / mule-base / ethio-util.el
1 ;;; ethio-util.el --- utilities for Ethiopic
2
3 ;; Copyright (C) 1997 Electrotechnical Laboratory, JAPAN.
4 ;; Licensed to the Free Software Foundation.
5
6 ;; Keywords: mule, multilingual, Ethiopic
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;; Author: TAKAHASHI Naoto <ntakahas@etl.go.jp>
26
27 ;;; Code:
28
29 ;; Information for exiting Ethiopic environment.
30 (defvar exit-ethiopic-environment-data nil)
31
32 ;;;###autoload
33 (defun setup-ethiopic-environment ()
34   "Setup multilingual environment for Ethiopic."
35   (set-language-environment "Ethiopic"))
36
37 ;;;###autoload
38 (defun setup-ethiopic-environment-internal ()
39   (let ((key-bindings '((" " . ethio-insert-space)
40                         ([(shift space)] . ethio-insert-ethio-space)
41                         ([(control ?')] . ethio-gemination)
42                         ([f2] . ethio-toggle-space)
43                         ([(shift f2)] . ethio-replace-space) ; as requested
44                         ([f3] . ethio-toggle-punctuation)
45                         ([f4] . ethio-sera-to-fidel-buffer)
46                         ([(shift f4)] . ethio-sera-to-fidel-region)
47                         ([(control f4)] . ethio-sera-to-fidel-mail-or-marker)
48                         ([f5] . ethio-fidel-to-sera-buffer)
49                         ([(shift f5)] . ethio-fidel-to-sera-region)
50                         ([(control f5)] . ethio-fidel-to-sera-mail-or-marker)
51                         ([f6] . ethio-modify-vowel)
52                         ([f7] . ethio-replace-space)
53                         ([f8] . ethio-input-special-character)))
54         kb)
55     (while key-bindings
56       (setq kb (car (car key-bindings)))
57       (setq exit-ethiopic-environment-data
58             (cons (cons kb (global-key-binding kb))
59                   exit-ethiopic-environment-data))
60       (global-set-key kb (cdr (car key-bindings)))
61       (setq key-bindings (cdr key-bindings))))
62
63   (add-hook 'quail-mode-hook 'ethio-select-a-translation)
64   (add-hook 'find-file-hooks 'ethio-find-file)
65   (add-hook 'write-file-hooks 'ethio-write-file)
66   (add-hook 'after-save-hook 'ethio-find-file))
67
68 (defun exit-ethiopic-environment ()
69   "Exit Ethiopic language environment"
70   (while exit-ethiopic-environment-data
71     (global-set-key (car (car exit-ethiopic-environment-data))
72                     (cdr (car exit-ethiopic-environment-data)))
73     (setq exit-ethiopic-environment-data
74           (cdr exit-ethiopic-environment-data)))
75
76   (remove-hook 'quail-mode-hook 'ethio-select-a-translation)
77   (remove-hook 'find-file-hooks 'ethio-find-file)
78   (remove-hook 'write-file-hooks 'ethio-write-file)
79   (remove-hook 'after-save-hook 'ethio-find-file))
80
81 ;;
82 ;; ETHIOPIC UTILITY FUNCTIONS
83 ;;
84
85 ;; If the filename ends in ".sera", editing is done in fidel
86 ;; but file I/O is done in SERA.
87 ;;
88 ;; If the filename ends in ".java", editing is done in fidel
89 ;; but file I/O is done in the \uXXXX style, where XXXX is 
90 ;; the Unicode codepoint for the Ethiopic character.
91 ;;
92 ;; If the filename ends in ".tex", editing is done in fidel
93 ;; but file I/O is done in EthioTeX format.
94 ;;
95 ;; To automatically convert Ethiopic text to SERA format when sending mail,
96 ;;   (add-hook 'mail-send-hook 'ethio-fidel-to-sera-mail)
97 ;;
98 ;; To automatically convert SERA format to Ethiopic when receiving mail,
99 ;;   (add-hook 'rmail-show-message-hook 'ethio-sera-to-fidel-mail)
100 ;;
101 ;; To automatically convert Ethiopic text to SERA format when posting news,
102 ;;   (add-hook 'news-inews-hook 'ethio-fidel-to-sera-mail)
103
104 ;;
105 ;; users' preference
106 ;;
107
108 (defvar ethio-primary-language 'tigrigna
109   "*Symbol that defines the primary language in SERA --> FIDEL conversion.
110 The value should be one of: `tigrigna', `amharic' or `english'.")
111
112 (defvar ethio-secondary-language 'english
113   "*Symbol that defines the secondary language in SERA --> FIDEL conversion.
114 The value should be one of: `tigrigna', `amharic' or `english'.")
115
116 (defvar ethio-use-colon-for-colon nil
117   "*Non-nil means associate ASCII colon with Ethiopic colon.
118 If nil, associate ASCII colon with Ethiopic word separator, i.e., two
119 vertically stacked dots.  All SERA <--> FIDEL converters refer this
120 variable.")
121
122 (defvar ethio-use-three-dot-question nil
123   "*Non-nil means associate ASCII question mark with Ethiopic old style question mark (three vertically stacked dots).
124 If nil, associate ASCII question mark with Ethiopic stylised question
125 mark.  All SERA <--> FIDEL converters refer this variable.")
126
127 (defvar ethio-quote-vowel-always nil
128   "*Non-nil means always put an apostrophe before an isolated vowel (except at word initial) in FIDEL --> SERA conversion.
129 If nil, put an apostrophe only between a sixth-form consonant and an
130 isolated vowel.")
131
132 (defvar ethio-W-sixth-always nil
133   "*Non-nil means convert the Wu-form of a 12-form consonant to \"W'\" instead of \"Wu\" in FIDEL --> SERA conversion.")
134
135 (defvar ethio-numeric-reduction 0
136   "*Degree of reduction in converting Ethiopic digits into Arabic digits.
137 Should be 0, 1 or 2.
138 For example, ({10}{9}{100}{80}{7}) is converted into:
139     `10`9`100`80`7  if `ethio-numeric-reduction' is 0,
140     `109100807      if `ethio-numeric-reduction' is 1,
141     `10900807       if `ethio-numeric-reduction' is 2.")
142
143 (defvar ethio-implicit-period-conversion t
144   "*Non-nil means replacing the Ethiopic dot at the end of an Ethiopic sentence
145 with an Ethiopic full stop.")
146
147 (defvar ethio-java-save-lowercase nil
148   "*Non-nil means save Ethiopic characters in lowercase hex numbers to Java files.
149 If nil, use uppercases.")
150
151 ;;
152 ;; SERA to FIDEL
153 ;;
154  
155 (defconst ethio-sera-to-fidel-table
156   [
157    nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
158    nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
159 ;;; SP
160    (" "
161     (?: (if ethio-use-colon-for-colon " \e$(3$l\e(B" "\e$(3$h\e(B")
162         (32 (if ethio-use-colon-for-colon " \e$(3$l\e(B " "\e$(3$h\e(B"))
163         (?- " \e$(3$m\e(B")
164         (?: " \e$(3$i\e(B")
165         (?| (if ethio-use-colon-for-colon " \e$(3$l\e(B|" " \e$(3$h\e(B|")
166             (?: " \e$(3$o\e(B"))))
167
168 ;;; !   "   #   $   %   &    '
169    nil nil nil nil nil nil ("" (?' "\e$(3%s\e(B"))
170 ;;; (   )   *   +    ,      -               .
171    nil nil nil nil ("\e$(3$j\e(B") ("-" (?: "\e$(3$l\e(B")) ("\e$(3%u\e(B")
172 ;;;  /   0   1   2   3   4   5   6   7   8   9
173     nil nil nil nil nil nil nil nil nil nil nil
174 ;;; :
175    ((if ethio-use-colon-for-colon "\e$(3$l\e(B" "\e$(3$h\e(B")
176     (32 (if ethio-use-colon-for-colon "\e$(3$l\e(B " "\e$(3$h\e(B"))
177     (?- "\e$(3$m\e(B")
178     (?: "\e$(3$i\e(B")
179     (?| (if ethio-use-colon-for-colon "\e$(3$l\e(B|" "\e$(3$h\e(B|")
180         (?: "\e$(3$o\e(B")))
181 ;;;  ;      <              =    >
182    ("\e$(3$k\e(B") ("<" (?< "\e$(3%v\e(B")) nil (">" (?> "\e$(3%w\e(B"))
183 ;;; ?
184    ((if ethio-use-three-dot-question "\e$(3$n\e(B" "\e$(3%x\e(B"))
185 ;;; @
186     nil
187 ;;; A
188    ("\e$(3"f\e(B" (?2 "\e$(3#8\e(B"))
189 ;;; B
190    ("\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")
191          (?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")))
192 ;;; C
193    ("\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")
194          (?W "\e$(3$6\e(B" (?a "\e$(3$6\e(B")
195                   (?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")))
196 ;;; D
197    ("\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")
198          (?W "\e$(3#d\e(B" (?a "\e$(3#d\e(B")
199                   (?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")))
200 ;;; E
201    ("\e$(3"g\e(B" (?2 "\e$(3#9\e(B"))
202 ;;; F
203    ("\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")
204          (?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"))
205          (?Y "\e$(3$a\e(B" (?a "\e$(3$a\e(B")))
206 ;;; G
207    ("\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")
208          (?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")))
209 ;;; H
210    ("\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")
211          (?W "\e$(3!8\e(B" (?a "\e$(3!8\e(B")
212                   (?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")))
213 ;;; I
214    ("\e$(3"h\e(B" (?2 "\e$(3#:\e(B"))
215 ;;; J
216    ("\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") 
217          (?W "\e$(3#l\e(B" (?a "\e$(3#l\e(B")
218                   (?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")))
219 ;;; K
220    ("\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")
221          (?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")))
222 ;;; L
223    ("\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")
224          (?W "\e$(3!0\e(B" (?a "\e$(3!0\e(B")
225                   (?e "\e$(3!.%n\e(B") (?u "\e$(3!.%r\e(B") (?i "\e$(3!.%o\e(B") (?E "\e$(3!.%q\e(B")))
226 ;;; M
227    ("\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")
228          (?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"))
229          (?Y "\e$(3$_\e(B" (?a "\e$(3$_\e(B")))
230 ;;; N
231    ("\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")
232          (?W "\e$(3"b\e(B" (?a "\e$(3"b\e(B")
233                   (?e "\e$(3"`%n\e(B") (?u "\e$(3"`%r\e(B") (?i "\e$(3"`%o\e(B") (?E "\e$(3"`%q\e(B")))
234 ;;; O
235    ("\e$(3"i\e(B" (?2 "\e$(3#;\e(B"))
236 ;;; P
237    ("\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")
238          (?W "\e$(3$>\e(B" (?a "\e$(3$>\e(B")
239                   (?e "\e$(3$<%n\e(B") (?u "\e$(3$<%r\e(B") (?i "\e$(3$<%o\e(B") (?E "\e$(3$<%q\e(B")))
240 ;;; Q
241    ("\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")
242          (?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")))
243 ;;; R
244    ("\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")
245          (?W "\e$(3!P\e(B" (?a "\e$(3!P\e(B")
246                   (?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"))
247          (?Y "\e$(3$`\e(B" (?a "\e$(3$`\e(B")))
248 ;;; S
249    ("\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")
250          (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
251                   (?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"))
252          (?2 "\e$(3$L\e(B"
253              (?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")
254              (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
255                  (?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"))))
256 ;;; T
257    ("\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")
258          (?W "\e$(3$.\e(B" (?a "\e$(3$.\e(B")
259                   (?e "\e$(3$,%n\e(B") (?u "\e$(3$,%r\e(B") (?i "\e$(3$,%o\e(B") (?E "\e$(3$,%q\e(B")))
260 ;;; U
261    ("\e$(3"d\e(B" (?2 "\e$(3#6\e(B"))
262 ;;; V
263    ("\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")
264          (?W "\e$(3"2\e(B" (?a "\e$(3"2\e(B")
265                   (?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")))
266 ;;; W
267    ("\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"))
268 ;;; X
269    ("\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"))
270 ;;; Y
271    ("\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")
272          (?W "\e$(3#T\e(B" (?a "\e$(3#T\e(B")
273                   (?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")))
274 ;;; Z
275    ("\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")
276          (?W "\e$(3#L\e(B" (?a "\e$(3#L\e(B")
277                   (?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")))
278 ;;; [   \   ]   ^   _
279    nil nil nil nil nil
280 ;;; `
281    (""
282     (?: "\e$(3$h\e(B")
283     (?? (if ethio-use-three-dot-question "\e$(3%x\e(B" "\e$(3$n\e(B"))
284     (?! "\e$(3%t\e(B")
285     (?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")
286         (?E "\e$(3#9\e(B") (?I "\e$(3#:\e(B") (?o "\e$(3#;\e(B") (?O "\e$(3#;\e(B")
287     (?g "\e$(3%^\e(B" 
288         (?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"))
289     (?h "\e$(3"H\e(B"
290         (?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")
291                   (?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")))
292     (?k "\e$(3%>\e(B" 
293         (?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"))
294     (?s "\e$(3!F\e(B" 
295         (?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")
296         (?W "\e$(3!H\e(B" (?a "\e$(3!H\e(B")
297                    (?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")))
298     (?S "\e$(3$L\e(B" 
299         (?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")
300         (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
301                  (?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")))
302     (?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")))
303 ;;; a
304    ("\e$(3"f\e(B" (?2 "\e$(3#8\e(B"))
305 ;;; b
306    ("\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")
307          (?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")))
308 ;;; c
309    ("\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")
310          (?W "\e$(3"B\e(B" (?a "\e$(3"B\e(B")
311                   (?e "\e$(3"@%n\e(B") (?u "\e$(3"@%r\e(B") (?i "\e$(3"@%o\e(B") (?E "\e$(3"@%q\e(B")))
312 ;;; d
313    ("\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")
314          (?W "\e$(3#\\e(B" (?a "\e$(3#\\e(B")
315                   (?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")))
316 ;;; e
317    ("\e$(3"c\e(B" (?2 "\e$(3#5\e(B") (?a "\e$(3"j\e(B"))
318 ;;; f
319    ("\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")
320          (?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"))
321          (?Y "\e$(3$a\e(B" (?a "\e$(3$a\e(B")))
322 ;;; g
323    ("\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") 
324          (?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"))
325          (?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")))
326 ;;; h
327    ("\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")
328          (?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"))
329          (?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")
330                   (?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"))))
331 ;;; i
332    ("\e$(3"e\e(B" (?2 "\e$(3#7\e(B"))
333 ;;; j
334    ("\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") 
335          (?W "\e$(3#l\e(B" (?a "\e$(3#l\e(B")
336                   (?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")))
337 ;;; k
338    ("\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")
339          (?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"))
340          (?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")))
341 ;;; l
342    ("\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")
343          (?W "\e$(3!0\e(B" (?a "\e$(3!0\e(B")
344                   (?e "\e$(3!.%n\e(B") (?u "\e$(3!.%r\e(B") (?i "\e$(3!.%o\e(B") (?E "\e$(3!.%q\e(B")))
345 ;;; m
346    ("\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")
347          (?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"))
348          (?Y "\e$(3$_\e(B" (?a "\e$(3$_\e(B")))
349 ;;; n
350    ("\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")
351          (?W "\e$(3"Z\e(B" (?a "\e$(3"Z\e(B")
352                   (?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")))
353 ;;; o
354    ("\e$(3"i\e(B" (?2 "\e$(3#;\e(B"))
355 ;;; p
356    ("\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")
357          (?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")))
358 ;;; q
359    ("\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")
360          (?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"))
361          (?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")))
362 ;;; r
363    ("\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")
364          (?W "\e$(3!P\e(B" (?a "\e$(3!P\e(B")
365                   (?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"))
366          (?Y "\e$(3$`\e(B" (?a "\e$(3$`\e(B")))
367 ;;; s
368    ("\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")
369          (?W "\e$(3!X\e(B" (?a "\e$(3!X\e(B")
370                   (?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"))
371          (?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")
372                   (?W "\e$(3!H\e(B" (?a "\e$(3!H\e(B")
373                            (?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"))))
374 ;;; t
375    ("\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")
376          (?W "\e$(3":\e(B" (?a "\e$(3":\e(B")
377                   (?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")))
378 ;;; u
379    ("\e$(3"d\e(B" (?2 "\e$(3#6\e(B"))
380 ;;; v
381    ("\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")
382          (?W "\e$(3"2\e(B" (?a "\e$(3"2\e(B")
383                   (?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")))
384 ;;; w
385    ("\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")
386          (?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")))
387 ;;; x
388    ("\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")
389          (?W "\e$(3!`\e(B" (?a "\e$(3!`\e(B")
390                   (?e "\e$(3!^%n\e(B") (?u "\e$(3!^%r\e(B") (?i "\e$(3!^%o\e(B") (?E "\e$(3!^%q\e(B")))
391 ;;; y
392    ("\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")
393          (?W "\e$(3#T\e(B" (?a "\e$(3#T\e(B")
394                   (?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")))
395 ;;; z
396    ("\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")
397          (?W "\e$(3#D\e(B" (?a "\e$(3#D\e(B")
398                   (?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")))
399 ;;; {   |   }   ~  DEL
400    nil nil nil nil nil
401    ])
402
403 ;;;###autoload
404 (defun ethio-sera-to-fidel-region (beg end &optional secondary force)
405   "Convert the characters in region from SERA to FIDEL.
406 The variable `ethio-primary-language' specifies the primary language
407 and `ethio-secondary-language' specifies the secondary.
408
409 If the 3rd parameter SECONDARY is given and non-nil, assume the region
410 begins begins with the secondary language; otherwise with the primary
411 language.
412
413 If the 4th parameter FORCE is given and non-nil, perform conversion
414 even if the buffer is read-only.
415
416 See also the descriptions of the variables
417 `ethio-use-colon-for-colon' and
418 `ethio-use-three-dot-question'."
419
420   (interactive "r\nP")
421   (save-restriction
422     (narrow-to-region beg end)
423     (ethio-sera-to-fidel-buffer secondary force)))
424
425 ;;;###autoload
426 (defun ethio-sera-to-fidel-buffer (&optional secondary force)
427   "Convert the current buffer from SERA to FIDEL.
428
429 The variable `ethio-primary-language' specifies the primary
430 language and `ethio-secondary-language' specifies the secondary.
431
432 If the 1st optional parameter SECONDARY is non-nil, assume the buffer
433 begins with the secondary language; otherwise with the primary
434 language.
435
436 If the 2nd optional parametr FORCE is non-nil, perform conversion even if the
437 buffer is read-only.
438
439 See also the descriptions of the variables
440 `ethio-use-colon-for-colon' and
441 `ethio-use-three-dot-question'."
442
443   (interactive "P")
444
445   (if (and buffer-read-only
446            (not force)
447            (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
448       (error ""))
449
450   (let ((ethio-primary-language ethio-primary-language)
451         (ethio-secondary-language ethio-secondary-language)
452         (ethio-use-colon-for-colon ethio-use-colon-for-colon)
453         (ethio-use-three-dot-question ethio-use-three-dot-question)
454         ;; The above four variables may be changed temporary
455         ;; by tilde escapes during conversion.  So we bind them to other
456         ;; variables but of the same names.
457         (buffer-read-only nil)
458         (case-fold-search nil)
459         current-language
460         next-language)
461
462     (setq current-language
463           (if secondary
464               ethio-secondary-language
465             ethio-primary-language))
466
467     (goto-char (point-min))
468
469     (while (not (eobp))
470       (setq next-language
471             (cond
472              ((eq current-language 'english)
473               (ethio-sera-to-fidel-english))
474              ((eq current-language 'amharic)
475               (ethio-sera-to-fidel-ethio 'amharic))
476              ((eq current-language 'tigrigna)
477               (ethio-sera-to-fidel-ethio 'tigrigna))
478              (t                         ; we don't know what to do
479               (ethio-sera-to-fidel-english))))
480
481       (setq current-language
482             (cond
483
484              ;; when language tag is explicitly specified
485              ((not (eq next-language 'toggle))
486               next-language)
487
488              ;; found a toggle in a primary language section
489              ((eq current-language ethio-primary-language)
490               ethio-secondary-language)
491
492              ;; found a toggle in a secondary, third, fourth, ...
493              ;; language section
494              (t
495               ethio-primary-language))))
496
497     ;; If ethio-implicit-period-conversion is non-nil, the
498     ;; Ethiopic dot "\e$(3%u\e(B" at the end of an Ethiopic sentence is
499     ;; replaced with the Ethiopic full stop "\e$(3$i\e(B".
500     (if ethio-implicit-period-conversion
501         (progn
502           (goto-char (point-min))
503           (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]\\)"
504                                     nil t)
505             (replace-match "\\1\e$(3$i\e(B\\2"))
506           (goto-char (point-min))
507           (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)
508             (replace-match "\\1\e$(3$i\e(B"))))
509
510     ;; gemination
511     (goto-char (point-min))
512     (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
513       (compose-region
514        (save-excursion (backward-char 2) (point))
515        (point)))
516     ))
517
518 (defun ethio-sera-to-fidel-english nil
519   "Handle English section in SERA to FIDEL conversion.
520 Conversion stops when a language switch is found.  Then delete that
521 switch and return the name of the new language as a symbol."
522   (let ((new-language nil))
523
524     (while (and (not (eobp)) (null new-language))
525       (cond
526
527        ;; if no more "\", nothing to do.
528        ((not (search-forward "\\" nil 0)))
529
530        ;; hereafter point is put after a "\".
531        ;; first delete that "\", then check the following chars
532
533        ;; "\\" :  leave the second "\"
534        ((progn
535           (delete-backward-char 1)
536           (= (following-char) ?\\ ))
537         (forward-char 1))
538
539        ;; "\ " :  delete the following " "
540        ((= (following-char) 32)
541         (delete-char 1)
542         (setq new-language 'toggle))
543
544        ;; a language flag
545        ((setq new-language (ethio-process-language-flag)))
546
547        ;; just a "\" :  not special sequence.
548        (t
549         (setq new-language 'toggle))))
550
551     new-language))
552
553 (defun ethio-sera-to-fidel-ethio (lang)
554   "Handle Ethiopic section in SERA to FIDEL conversion.
555 Conversion stops when a language switch is found.  Then delete that
556 switch and return the name of the new language as a symbol.
557
558 The parameter LANG (symbol, either `amharic' or `tigrigna') affects
559 the conversion of \"a\"."
560
561   (let ((new-language nil)
562         (verbatim nil)
563         start table table2 ch)
564
565     (setcar (aref ethio-sera-to-fidel-table ?a)
566             (if (eq lang 'tigrigna) "\e$(3"f\e(B" "\e$(3"c\e(B"))     
567
568     (while (and (not (eobp)) (null new-language))
569       (setq ch (following-char))
570       (cond
571
572        ;; skip from "<" to ">" (or from "&" to ";") if in w3-mode
573        ((and (boundp 'sera-being-called-by-w3)
574              sera-being-called-by-w3
575              (or (= ch ?<) (= ch ?&)))
576         (search-forward (if (= ch ?<) ">" ";")
577                         nil 0))
578
579        ;; leave non-ASCII characters as they are
580        ((>= ch 128)
581         (forward-char 1))
582
583        ;; ethiopic digits
584        ((looking-at "`[1-9][0-9]*")
585         (delete-char 1)
586         (ethio-convert-digit))
587
588        ;; if not seeing a "\", do sera to fidel conversion
589        ((/= ch ?\\ )
590         (setq start (point))
591         (forward-char 1)
592         (setq table (aref ethio-sera-to-fidel-table ch))
593         (while (setq table2 (cdr (assoc (following-char) table)))
594           (setq table table2)
595           (forward-char 1))
596         (if (setq ch (car table))
597             (progn
598               (delete-region start (point))
599               (if (stringp ch)
600                   (insert ch)
601                 (insert (eval ch))))))
602
603        ;; if control reaches here, we must be looking at a "\"
604
605        ;; verbatim mode
606        (verbatim
607         (if (looking-at "\\\\~! ?")
608
609             ;; "\~!" or "\~! ".  switch to non-verbatim mode
610             (progn
611               (replace-match "")
612               (setq verbatim nil))
613
614           ;; "\" but not "\~!" nor "\~! ".  skip the current "\".
615           (forward-char 1)))
616
617        ;; hereafter, non-verbatim mode and looking at a "\"
618        ;; first delete that "\", then check the following chars.
619
620        ;; "\ " : delete the following " "
621        ((progn
622           (delete-char 1)
623           (setq ch (following-char))
624           (= ch 32))
625         (delete-char 1)
626         (setq new-language 'toggle))
627
628        ;; "\~!" or "\~! " : switch to verbatim mode
629        ((looking-at "~! ?")
630         (replace-match "")
631         (setq verbatim t))
632
633        ;; a language flag
634        ((setq new-language (ethio-process-language-flag)))
635
636        ;; "\~" but not "\~!" nor a language flag
637        ((= ch ?~)
638         (delete-char 1)
639         (ethio-tilde-escape))
640
641        ;; ASCII punctuation escape.  skip
642        ((looking-at "\\(,\\|\\.\\|;\\|:\\|'\\|`\\|\?\\|\\\\\\)+")
643         (goto-char (match-end 0)))
644
645        ;; "\", but not special sequence
646        (t
647         (setq new-language 'toggle))))
648
649     new-language))
650
651 (defun ethio-process-language-flag nil
652   "Process a language flag of the form \"~lang\" or \"~lang1~lang2\".
653
654 If looking at \"~lang1~lang2\", set `ethio-primary-language' and
655 `ethio-une-secondary-language' based on \"lang1\" and \"lang2\".
656 Then delete the language flag \"~lang1~lang2\" from the buffer.
657 Return value is the new primary language.
658
659 If looking at \"~lang\", delete that language flag \"~lang\" from the
660 buffer and return that language.  In this case
661 `ethio-primary-language' and `ethio-uni-secondary-language'
662 are left unchanged.
663
664 If an unsupported language flag is found, just return nil without
665 changing anything."
666
667   (let (lang1 lang2)
668     (cond
669
670      ;; ~lang1~lang2
671      ((and (looking-at
672             "~\\([a-z][a-z][a-z]?\\)~\\([a-z][a-z][a-z]?\\)[ \t\n\\]")
673            (setq lang1
674                  (ethio-flag-to-language
675                   (buffer-substring (match-beginning 1) (match-end 1))))
676            (setq lang2
677                  (ethio-flag-to-language
678                   (buffer-substring (match-beginning 2) (match-end 2)))))
679       (setq ethio-primary-language lang1
680             ethio-secondary-language lang2)
681       (delete-region (point) (match-end 2))
682       (if (= (following-char) 32)
683           (delete-char 1))
684       ethio-primary-language)
685
686      ;; ~lang
687      ((and (looking-at "~\\([a-z][a-z][a-z]?\\)[ \t\n\\]")
688            (setq lang1
689                  (ethio-flag-to-language
690                   (buffer-substring (match-beginning 1) (match-end 1)))))
691       (delete-region (point) (match-end 1))
692       (if (= (following-char) 32)
693           (delete-char 1))
694       lang1)
695
696      ;; otherwise
697      (t
698       nil))))
699
700 (defun ethio-tilde-escape nil
701   "Handle a SERA tilde escape in Ethiopic section and delete it.
702 Delete the escape even it is not recognised."
703
704   (let ((p (point)) command)
705     (skip-chars-forward "^ \t\n\\\\")
706     (setq command (buffer-substring p (point)))
707     (delete-region p (point))
708     (if (= (following-char) 32)
709         (delete-char 1))
710
711     (cond
712
713      ;; \~-:
714      ((string= command "-:")
715       (setq ethio-use-colon-for-colon t))
716
717      ;; \~`:
718      ((string= command "`:")
719       (setq ethio-use-colon-for-colon nil))
720
721      ;; \~?
722      ((string= command "?")
723       (setq ethio-use-three-dot-question nil))
724
725      ;; \~`|
726      ((string= command "`|")
727       (setq ethio-use-three-dot-question t))
728
729      ;; \~e
730      ((string= command "e")
731       (insert "\e$(3%j\e(B"))
732
733      ;; \~E
734      ((string= command "E")
735       (insert "\e$(3%k\e(B"))
736
737      ;; \~a
738      ((string= command "a")
739       (insert "\e$(3%l\e(B"))
740
741      ;; \~A
742      ((string= command "A")
743       (insert "\e$(3%m\e(B"))
744
745      ;; \~X
746      ((string= command "X")
747       (insert "\e$(3%i\e(B"))
748
749      ;; unsupported tilde escape
750      (t
751       nil))))
752
753 (defun ethio-flag-to-language (flag)
754   (cond
755    ((or (string= flag "en") (string= flag "eng")) 'english)
756    ((or (string= flag "ti") (string= flag "tir")) 'tigrigna)
757    ((or (string= flag "am") (string= flag "amh")) 'amharic)
758    (t nil)))
759   
760 (defun ethio-convert-digit nil
761   "Convert Arabic digits to Ethiopic digits."
762   (let (ch z)
763     (while (and (>= (setq ch (following-char)) ?1)
764                 (<= ch ?9))
765       (delete-char 1)
766
767       ;; count up following zeros
768       (setq z 0)
769       (while (= (following-char) ?0)
770         (delete-char 1)
771         (setq z (1+ z)))
772
773       (cond
774
775        ;; first digit is 10, 20, ..., or 90
776        ((= (mod z 2) 1)
777         (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)))
778         (setq z (1- z)))
779
780        ;; first digit is 2, 3, ..., or 9
781        ((/= ch ?1)
782         (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))))
783
784        ;; single 1
785        ((= z 0)
786         (insert "\e$(3$p\e(B")))
787
788       ;; 100
789       (if (= (mod z 4) 2)
790           (insert "\e$(3%$\e(B"))
791
792       ;; 10000
793       (insert-char ?\e$(3%%\e(B (/ z 4)))))
794
795 ;;;###autoload
796 (defun ethio-sera-to-fidel-mail-or-marker (&optional arg)
797   "Execute ethio-sera-to-fidel-mail or ethio-sera-to-fidel-marker depending on the current major mode.
798 If in rmail-mode or in mail-mode, execute the former; otherwise latter."
799
800   (interactive "P")
801   (if (or (eq major-mode 'rmail-mode)
802           (eq major-mode 'mail-mode))
803       (ethio-sera-to-fidel-mail (prefix-numeric-value arg))
804     (ethio-sera-to-fidel-marker arg)))
805
806 ;;;###autoload
807 (defun ethio-sera-to-fidel-mail (&optional arg)
808   "Convert SERA to FIDEL to read/write mail and news.
809
810 If the buffer contains the markers \"<sera>\" and \"</sera>\",
811 convert the segments between them into FIDEL.
812
813 If invoked interactively and there is no marker, convert the subject field
814 and the body into FIDEL using `ethio-sera-to-fidel-region'."
815
816   (interactive "p")
817   (let ((buffer-read-only nil)
818         border)
819     (save-excursion
820
821       ;; look for the header-body separator
822       (goto-char (point-min))
823       (if (search-forward
824            (if (eq major-mode 'rmail-mode)
825                "\n\n" (concat "\n" mail-header-separator "\n"))
826            nil t)
827           (setq border (point))
828         (error "header separator not found"))
829
830       ;; note that the point is placed at the border
831       (if (or (re-search-forward "^<sera>$" nil t)
832               (progn
833                 (goto-char (point-min))
834                 (re-search-forward "^Subject: <sera>" border t)))
835
836           ;; there are markers
837           (progn
838             ;; we start with the body so that the border will not change
839             ;; use "^<sera>\n" instead of "^<sera>$" not to leave a blank line
840             (goto-char border)
841             (while (re-search-forward "^<sera>\n" nil t)
842               (replace-match "")
843               (ethio-sera-to-fidel-region
844                (point)
845                (progn
846                  (if (re-search-forward "^</sera>\n" nil 0)
847                      (replace-match ""))
848                  (point))))
849             ;; now process the subject
850             (goto-char (point-min))
851             (if (re-search-forward "^Subject: <sera>" border t)
852                 (ethio-sera-to-fidel-region
853                  (progn (delete-backward-char 6) (point))
854                  (progn
855                    (if (re-search-forward "</sera>$" (line-end-position) 0)
856                        (replace-match ""))
857                    (point)))))
858
859         ;; in case there are no marks but invoked interactively
860         (if arg
861             (progn
862               (ethio-sera-to-fidel-region border (point-max))
863               (goto-char (point-min))
864               (if (re-search-forward "^Subject: " border t)
865                   (ethio-sera-to-fidel-region (point) (line-end-position))))))
866
867       ;; adjust the rmail marker
868       (if (eq major-mode 'rmail-mode)
869           (set-marker
870            (aref rmail-message-vector (1+ rmail-current-message))
871            (point-max))))))
872
873 ;;;###autoload
874 (defun ethio-sera-to-fidel-marker (&optional force)
875   "Convert the regions surrounded by \"<sera>\" and \"</sera>\" from SERA to FIDEL.
876 Assume that each region begins with `ethio-primary-language'.
877 The markers \"<sera>\" and \"</sera>\" themselves are not deleted."
878   (interactive "P")
879   (if (and buffer-read-only
880            (not force)
881            (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
882       (error ""))
883   (save-excursion
884     (goto-char (point-min))
885     (while (re-search-forward "<sera>" nil t)
886       (ethio-sera-to-fidel-region
887        (point)
888        (if (re-search-forward "</sera>" nil t)
889            (match-beginning 0)
890          (point-max))
891        nil
892        'force))))
893
894 ;;
895 ;; FIDEL to SERA
896 ;;
897
898 (defconst ethio-fidel-to-sera-map
899  [ "he"  "hu"  "hi"  "ha"  "hE"  "h"  "ho"    ""       ;;   0 - 7
900    "le"  "lu"  "li"  "la"  "lE"  "l"  "lo"  "lWa"      ;;   8
901    "He"  "Hu"  "Hi"  "Ha"  "HE"  "H"  "Ho"  "HWa"      ;;  16
902    "me"  "mu"  "mi"  "ma"  "mE"  "m"  "mo"  "mWa"      ;;  24
903   "`se" "`su" "`si" "`sa" "`sE" "`s" "`so" "`sWa"      ;;  32
904    "re"  "ru"  "ri"  "ra"  "rE"  "r"  "ro"  "rWa"      ;;  40
905    "se"  "su"  "si"  "sa"  "sE"  "s"  "so"  "sWa"      ;;  48
906    "xe"  "xu"  "xi"  "xa"  "xE"  "x"  "xo"  "xWa"      ;;  56
907    "qe"  "qu"  "qi"  "qa"  "qE"  "q"  "qo"    ""       ;;  64
908   "qWe"   ""  "qWi" "qWa" "qWE"  "qW'" ""     ""       ;;  72
909    "Qe"  "Qu"  "Qi"  "Qa"  "QE"  "Q"  "Qo"    ""       ;;  80
910   "QWe"   ""  "QWi" "QWa" "QWE"  "QW'" ""     ""       ;;  88
911    "be"  "bu"  "bi"  "ba"  "bE"  "b"  "bo"  "bWa"      ;;  96
912    "ve"  "vu"  "vi"  "va"  "vE"  "v"  "vo"  "vWa"      ;; 104
913    "te"  "tu"  "ti"  "ta"  "tE"  "t"  "to"  "tWa"      ;; 112
914    "ce"  "cu"  "ci"  "ca"  "cE"  "c"  "co"  "cWa"      ;; 120
915   "`he" "`hu" "`hi" "`ha" "`hE" "`h" "`ho"    ""       ;; 128
916   "hWe"   ""  "hWi" "hWa"  "hWE" "hW'" ""     ""       ;; 136
917    "ne"  "nu"  "ni"  "na"  "nE"  "n"  "no"  "nWa"      ;; 144
918    "Ne"  "Nu"  "Ni"  "Na"  "NE"  "N"  "No"  "NWa"      ;; 152
919     "e"   "u"   "i"   "A"   "E"  "I"   "o"   "ea"      ;; 160
920    "ke"  "ku"  "ki"  "ka"  "kE"  "k"  "ko"    ""       ;; 168
921   "kWe"   ""  "kWi" "kWa" "kWE"  "kW'" ""     ""       ;; 176
922    "Ke"  "Ku"  "Ki"  "Ka"  "KE"  "K"  "Ko"    ""       ;; 184
923   "KWe"   ""  "KWi" "KWa" "KWE"  "KW'" ""     ""       ;; 192
924    "we"  "wu"  "wi"  "wa"  "wE"  "w"  "wo"    ""       ;; 200
925    "`e"  "`u"  "`i"  "`a"  "`E" "`I"  "`o"    ""       ;; 208
926    "ze"  "zu"  "zi"  "za"  "zE"  "z"  "zo"  "zWa"      ;; 216
927    "Ze"  "Zu"  "Zi"  "Za"  "ZE"  "Z"  "Zo"  "ZWa"      ;; 224
928    "ye"  "yu"  "yi"  "ya"  "yE"  "y"  "yo"  "yWa"      ;; 232
929    "de"  "du"  "di"  "da"  "dE"  "d"  "do"  "dWa"      ;; 240
930    "De"  "Du"  "Di"  "Da"  "DE"  "D"  "Do"  "DWa"      ;; 248
931    "je"  "ju"  "ji"  "ja"  "jE"  "j"  "jo"  "jWa"      ;; 256
932    "ge"  "gu"  "gi"  "ga"  "gE"  "g"  "go"    ""       ;; 264
933   "gWe"   ""  "gWi" "gWa" "gWE" "gW'"  ""     ""       ;; 272
934    "Ge"  "Gu"  "Gi"  "Ga"  "GE"  "G"  "Go"  "GWa"      ;; 280
935    "Te"  "Tu"  "Ti"  "Ta"  "TE"  "T"  "To"  "TWa"      ;; 288
936    "Ce"  "Cu"  "Ci"  "Ca"  "CE"  "C"  "Co"  "CWa"      ;; 296
937    "Pe"  "Pu"  "Pi"  "Pa"  "PE"  "P"  "Po"  "PWa"      ;; 304
938    "Se"  "Su"  "Si"  "Sa"  "SE"  "S"  "So"  "SWa"      ;; 312
939   "`Se" "`Su" "`Si" "`Sa" "`SE" "`S" "`So"    ""       ;; 320
940    "fe"  "fu"  "fi"  "fa"  "fE"  "f"  "fo"  "fWa"      ;; 328
941    "pe"  "pu"  "pi"  "pa"  "pE"  "p"  "po"  "pWa"      ;; 336
942   "mYa" "rYa" "fYa"   ""    ""   ""    ""     ""       ;; 344
943    " "  " : "  "::"  ","   ";"  "-:"  ":-"   "`?"      ;; 352
944   ":|:"  "1"   "2"   "3"   "4"   "5"   "6"   "7"       ;; 360
945    "8"   "9"   "10"  "20"  "30"  "40" "50"   "60"      ;; 368
946    "70"  "80"  "90" "100" "10000" ""   ""     ""       ;; 376
947   "`qe" "`qu" "`qi" "`qa" "`qE" "`q" "`qo"    ""       ;; 384
948   "mWe" "bWe" "GWe" "fWe" "pWe"  ""    ""     ""       ;; 392
949   "`ke" "`ku" "`ki" "`ka" "`kE" "`k" "`ko"    ""       ;; 400
950   "mWi" "bWi" "GWi" "fWi" "pWi"  ""    ""     ""       ;; 408
951    "Xe"  "Xu"  "Xi"  "Xa"  "XE"  "X"  "Xo"    ""       ;; 416
952   "mWE" "bWE" "GWE" "fWE" "pWE"  ""    ""     ""       ;; 424
953   "`ge" "`gu" "`gi" "`ga" "`gE" "`g" "`go"    ""       ;; 432
954   "mW'" "bW'" "GW'" "fW'" "pW'"  ""    ""     ""       ;; 440
955   "\\~X " "\\~e " "\\~E " "\\~a " "\\~A " "wWe" "wWi" "wWa" ;; 448
956   "wWE" "wW'"  "''"  "`!"  "."  "<<"  ">>"   "?" ])    ;; 456
957
958 (defun ethio-prefer-amharic-p nil
959   (or (eq ethio-primary-language 'amharic)
960       (and (not (eq ethio-primary-language 'tigrigna))
961            (eq ethio-secondary-language 'amharic))))
962
963 (defun ethio-language-to-flag (lang)
964   (cond
965    ((eq lang 'english) "eng")
966    ((eq lang 'tigrigna) "tir")
967    ((eq lang 'amharic) "amh")
968    (t "")))
969
970 ;;;###autoload
971 (defun ethio-fidel-to-sera-region (begin end &optional secondary force)
972   "Replace all the FIDEL characters in the region to the SERA format.
973 The variable `ethio-primary-language' specifies the primary
974 language and `ethio-secondary-language' specifies the secondary.
975
976 If the 3dr parameter SECONDARY is given and non-nil, try to convert
977 the region so that it begins in the secondary language; otherwise with
978 the primary language.
979
980 If the 4th parameter FORCE is given and non-nil, convert even if the
981 buffer is read-only.
982
983 See also the descriptions of the variables
984 `ethio-use-colon-for-colon', `ethio-use-three-dot-question',
985 `ethio-quote-vowel-always' and `ethio-numeric-reduction'."
986
987   (interactive "r\nP")
988   (save-restriction
989     (narrow-to-region begin end)
990     (ethio-fidel-to-sera-buffer secondary force)))
991
992 ;;;###autoload
993 (defun ethio-fidel-to-sera-buffer (&optional secondary force)
994   "Replace all the FIDEL characters in the current buffer to the SERA format.
995 The variable `ethio-primary-language' specifies the primary
996 language and `ethio-secondary-language' specifies the secondary.
997
998 If the 1st optional parameter SECONDARY is non-nil, try to convert the
999 region so that it begins in the secondary language; otherwise with the
1000 primary language.
1001
1002 If the 2nd optional parameter FORCE is non-nil, convert even if the
1003 buffer is read-only.
1004
1005 See also the descriptions of the variables
1006 `ethio-use-colon-for-colon', `ethio-use-three-dot-question',
1007 `ethio-quote-vowel-always' and `ethio-numeric-reduction'."
1008
1009   (interactive "P")
1010   (if (and buffer-read-only
1011            (not force)
1012            (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
1013       (error ""))
1014
1015   (let ((buffer-read-only nil)
1016         (case-fold-search nil)
1017         (lonec nil) ;; t means previous char was a lone consonant
1018         (fidel nil) ;; t means previous char was a FIDEL
1019         (digit nil) ;; t means previous char was an Ethiopic digit
1020         (flag (if (ethio-prefer-amharic-p) "\\~amh " "\\~tir "))
1021         mode ch)
1022
1023     ;; user's preference in transcription
1024     (if ethio-use-colon-for-colon
1025         (progn
1026           (aset ethio-fidel-to-sera-map 353 "`:")
1027           (aset ethio-fidel-to-sera-map 357 ":"))
1028       (aset ethio-fidel-to-sera-map 353 " : ")
1029       (aset ethio-fidel-to-sera-map 357 "-:"))
1030
1031     (if ethio-use-three-dot-question
1032         (progn
1033           (aset ethio-fidel-to-sera-map 359 "?")
1034           (aset ethio-fidel-to-sera-map 463 "`?"))
1035       (aset ethio-fidel-to-sera-map 359 "`?")
1036       (aset ethio-fidel-to-sera-map 463 "?"))
1037
1038     (mapcar
1039      '(lambda (x)
1040         (aset (aref ethio-fidel-to-sera-map x)
1041               2
1042               (if ethio-W-sixth-always ?' ?u)))
1043      '(77 93 141 181 197 277 440 441 442 443 444 457))
1044
1045     (if (ethio-prefer-amharic-p)
1046         (aset ethio-fidel-to-sera-map 160 "a")
1047       (aset ethio-fidel-to-sera-map 160 "e"))
1048     ;; end of user's preference
1049
1050     ;; first, decompose geminated characters
1051     (decompose-region (point-min) (point-max))
1052
1053     ;; main conversion routine
1054     (goto-char (point-min))
1055     (while (not (eobp))
1056       (setq ch (following-char))
1057
1058       (cond                             ; ethiopic, english, neutral
1059
1060        ;; ethiopic character.  must go to ethiopic mode, if not in it.
1061        ((eq (char-charset ch) 'ethiopic)
1062         (setq ch (ethio-char-to-ethiocode ch))
1063         (delete-char 1)
1064         (if (not (eq mode 'ethiopic))
1065             (progn
1066               (insert flag)
1067               (setq mode 'ethiopic)))
1068
1069         (cond                           ; fidel, punc, digit
1070
1071          ;; fidels
1072          ((or (<= ch 346)               ;  he - fYa
1073               (and (>= ch 384) (<= ch 444)) ; `qe - pw
1074               (and (>= ch 453) (<= ch 457))) ; wWe - wW
1075           (if (and (memq ch '(160 161 162 163 164 166 167)) ; (e - ea)
1076                    (or lonec
1077                        (and ethio-quote-vowel-always
1078                             fidel)))
1079               (insert "'"))
1080           (insert (aref ethio-fidel-to-sera-map ch))
1081           (setq lonec (ethio-lone-consonant-p ch)
1082                 fidel t
1083                 digit nil))
1084
1085          ;; punctuations or icons
1086          ((or (and (>= ch 353) (<= ch 360)) ;  : - :|:
1087               (>= ch 458)               ;  '' -  ?
1088               (and (>= ch 448) (<= ch 452))) ;  \~X \~e \~E \~a \~A
1089           (insert (aref ethio-fidel-to-sera-map ch))
1090           (setq lonec nil
1091                 fidel nil
1092                 digit nil))
1093
1094          ;; now CH must be an ethiopic digit
1095
1096          ;; reduction = 0 or not preceded by Ethiopic number(s)
1097          ((or (= ethio-numeric-reduction 0)
1098               (not digit))
1099           (insert "`" (aref ethio-fidel-to-sera-map ch))
1100           (setq lonec nil
1101                 fidel nil
1102                 digit t))
1103
1104          ;; reduction = 2 and following 10s, 100s, 10000s 
1105          ((and (= ethio-numeric-reduction 2)
1106                (memq ch '(370 379 380)))
1107           (insert (substring (aref ethio-fidel-to-sera-map ch) 1))
1108           (setq lonec nil
1109                 fidel nil
1110                 digit t))
1111
1112          ;; ordinary following digits
1113          (t
1114           (insert (aref ethio-fidel-to-sera-map ch))
1115           (setq lonec nil
1116                 fidel nil
1117                 digit t))))
1118
1119        ;; english character.  must go to english mode, if not in it.
1120        ((or (and (>= ch ?a) (<= ch ?z))
1121             (and (>= ch ?A) (<= ch ?Z)))
1122         (if (not (eq mode 'english))
1123             (insert "\\~eng "))
1124         (forward-char 1)
1125         (setq mode 'english
1126               lonec nil
1127               fidel nil
1128               digit nil))
1129
1130        ;; ch can appear both in ethiopic section and in english section.
1131        (t
1132
1133         ;; we must decide the mode, if not decided yet
1134         (if (null mode)
1135             (progn
1136               (setq mode
1137                     (if secondary
1138                         ethio-secondary-language
1139                       ethio-primary-language))
1140               (if (eq mode 'english)
1141                   (insert "\\~eng ")
1142                 (insert flag)
1143                 (setq mode 'ethiopic)))) ; tigrigna & amharic --> ethiopic
1144
1145         (cond                           ; \ , eng-mode , punc , w3 , other
1146
1147          ;; backslash is always quoted
1148          ((= ch ?\\ )
1149           (insert "\\")
1150           (forward-char 1))
1151
1152          ;; nothing to do if in english mode
1153          ((eq mode 'english)
1154           (forward-char 1))
1155
1156          ;; now we must be in ethiopic mode and seeing a non-"\"
1157
1158          ;; ascii punctuations in ethiopic mode
1159          ((looking-at "[,.;:'`?]+")
1160           (insert "\\")
1161           (goto-char (1+ (match-end 0)))) ; because we inserted one byte (\)
1162
1163          ;; skip from "<" to ">" (or from "&" to ";") if called from w3
1164          ((and (boundp 'sera-being-called-by-w3)
1165                sera-being-called-by-w3
1166                (or (= ch ?<) (= ch ?&)))
1167           (search-forward (if (= ch ?<) ">" ";")
1168                           nil 0))
1169
1170          ;; neutral character.  no need to quote.  just skip it.
1171          (t
1172           (forward-char 1)))
1173
1174         (setq lonec nil
1175               fidel nil
1176               digit nil)))
1177     ;; end of main conversion routine
1178     )))
1179
1180 (defun ethio-lone-consonant-p (ethiocode)
1181   "If ETHIOCODE is an Ethiopic lone consonant, return t."
1182   (or (and (< ethiocode 344) (= (% ethiocode 8) 5))
1183
1184       ;;                     `q  `k   X  `g  mW  bW  GW  fW  pW  wW
1185       (memq ethiocode '(389 405 421 437 440 441 442 443 444 457))))
1186
1187 ;;;###autoload
1188 (defun ethio-fidel-to-sera-mail-or-marker (&optional arg)
1189   "Execute ethio-fidel-to-sera-mail or ethio-fidel-to-sera-marker depending on the current major mode.
1190 If in rmail-mode or in mail-mode, execute the former; otherwise latter."
1191
1192   (interactive "P")
1193   (if (or (eq major-mode 'rmail-mode)
1194           (eq major-mode 'mail-mode))
1195       (ethio-fidel-to-sera-mail)
1196     (ethio-fidel-to-sera-marker arg)))
1197
1198 ;;;###autoload
1199 (defun ethio-fidel-to-sera-mail nil
1200   "Convert FIDEL to SERA to read/write mail and news.
1201
1202 If the body contains at least one Ethiopic character,
1203  1) insert the string \"<sera>\" at the beginning of the body,
1204  2) insert \"</sera>\" at the end of the body, and
1205  3) convert the body into SERA.
1206
1207 The very same procedure applies to the subject field, too."
1208
1209   (interactive)
1210   (let ((buffer-read-only nil)
1211         border)
1212     (save-excursion
1213
1214       ;; look for the header-body separator
1215       (goto-char (point-min))
1216       (if (search-forward
1217            (if (eq major-mode 'rmail-mode)
1218                "\n\n" (concat "\n" mail-header-separator "\n"))
1219            nil t)
1220           (setq border (point))
1221         (error "header separator not found"))
1222                              
1223       ;; process body first not to change the border
1224       ;; note that the point is already at the border
1225       (if (re-search-forward "\\ce" nil t)
1226           (progn
1227             (ethio-fidel-to-sera-region border (point-max))
1228             (goto-char border)
1229             (insert "<sera>")
1230             (goto-char (point-max))
1231             (insert "</sera>")))
1232
1233       ;; process subject
1234       (goto-char (point-min))
1235       (if (re-search-forward "^Subject: " border t)
1236           (let ((beg (point))
1237                 (end (line-end-position)))
1238             (if (re-search-forward "\\ce" end t)
1239                 (progn
1240                   (ethio-fidel-to-sera-region beg end)
1241                   (goto-char beg)
1242                   (insert "<sera>")
1243                   (end-of-line)
1244                   (insert "</sera>")))))
1245
1246       ;; adjust the rmail marker
1247       (if (eq major-mode 'rmail-mode)
1248           (set-marker
1249            (aref rmail-message-vector (1+ rmail-current-message))
1250            (point-max))))))
1251
1252 ;;;###autoload
1253 (defun ethio-fidel-to-sera-marker (&optional force)
1254   "Convert the regions surrounded by \"<sera>\" and \"</sera>\" from FIDEL to SERA.
1255 The markers \"<sera>\" and \"</sera>\" themselves are not deleted."
1256
1257   (interactive "P")
1258   (if (and buffer-read-only
1259            (not force)
1260            (not (y-or-n-p "Buffer is read-only.  Force to convert? ")))
1261       (error ""))
1262   (save-excursion
1263     (goto-char (point-min))
1264     (while (re-search-forward "<sera>" nil t)
1265       (ethio-fidel-to-sera-region
1266        (point)
1267        (if (re-search-forward "</sera>" nil t)
1268            (match-beginning 0)
1269          (point-max))
1270        nil
1271        'force))))
1272
1273 ;;
1274 ;; vowel modification
1275 ;;
1276
1277 ;;;###autoload
1278 (defun ethio-modify-vowel nil
1279   "Modify the vowel of the FIDEL that is under the cursor."
1280   (interactive)
1281   (let ((ch (following-char))
1282         (composite nil)                 ; geminated or not
1283         newch base vowel modulo)
1284
1285     (cond
1286      ;; in case of gemination
1287      ((eq (char-charset ch) 'composition)
1288       (setq ch (string-to-char (decompose-composite-char ch))
1289             composite t))
1290      ;; neither gemination nor fidel
1291      ((not (eq (char-charset ch) 'ethiopic))
1292       (error "Not a valid character.")))
1293
1294     ;; set frequently referred character features
1295     (setq ch     (ethio-char-to-ethiocode ch)
1296           base   (* (/ ch 8) 8)
1297           modulo (% ch 8))
1298
1299     (if (or (and (>= ch 344) (<= ch 380)) ;; mYa - `10000
1300             (and (>= ch 448) (<= ch 452)) ;; \~X - \~A
1301             (>= ch 458))                  ;; private punctuations
1302         (error "Not a valid character."))
1303
1304     (setq
1305      newch
1306      (cond
1307
1308       ;; first standalone vowels
1309       ((= base 160)
1310        (if (ethio-prefer-amharic-p)
1311            (message "Modify vowel to: [auiAEIoW\"] ")
1312          (message "Modify vowel to: [euiAEIoW\"] "))
1313        (setq vowel (read-char))
1314        (cond
1315         ((= vowel ?e) 160)
1316         ((= vowel ?u) 161)
1317         ((= vowel ?i) 162)
1318         ((= vowel ?A) 163)
1319         ((= vowel ?E) 164)
1320         ((= vowel ?I) 165)
1321         ((= vowel ?o) 166)
1322         ((= vowel ?W) 167)
1323         ((= vowel ?a) (if (ethio-prefer-amharic-p) 160 163))
1324         ((= vowel ?\") (setq composite t) ch)
1325         (t nil)))
1326
1327       ;; second standalone vowels
1328       ((= base 208)
1329        (message "Modify vowel to: [euiaEIo\"] ")
1330        (setq vowel (read-char))
1331        (cond
1332         ((= vowel ?e) 208)
1333         ((= vowel ?u) 209)
1334         ((= vowel ?i) 210)
1335         ((= vowel ?a) 211)
1336         ((= vowel ?E) 212)
1337         ((= vowel ?I) 213)
1338         ((= vowel ?o) 214)
1339         ((= vowel ?\") (setq composite t) ch)
1340         (t nil)))
1341
1342       ;; 12-form consonants, *W* form
1343       ((memq base '(72 88 136 176 192 272)) ; qW QW hW kW KW gW
1344        (message "Modify vowel to: [euiaE'\"] ")
1345        (setq vowel (read-char))
1346        (cond
1347         ((= vowel ?e) base)
1348         ((= vowel ?u) (+ base 5))
1349         ((= vowel ?i) (+ base 2))
1350         ((= vowel ?a) (+ base 3))
1351         ((= vowel ?E) (+ base 4))
1352         ((= vowel ?') (+ base 5))
1353         ((= vowel ?\") (setq composite t) ch)
1354         (t nil)))
1355
1356       ;; extended 12-form consonants, mWa bWa GWa fWa pWa
1357       ((= ch 31)                        ; mWa
1358        (message "Modify vowel to: [euiaE'\"] ")
1359        (setq vowel (read-char))
1360        (cond
1361         ((= vowel ?e) 392)
1362         ((= vowel ?u) 440)
1363         ((= vowel ?i) 408)
1364         ((= vowel ?a) ch)
1365         ((= vowel ?E) 424)
1366         ((= vowel ?') 440)
1367         ((= vowel ?\") (setq composite t) ch)
1368         (t nil)))
1369       ((= ch 103)                       ; bWa
1370        (message "Modify vowel to: [euiaE'\"] ")
1371        (setq vowel (read-char))
1372        (cond
1373         ((= vowel ?e) 393)
1374         ((= vowel ?u) 441)
1375         ((= vowel ?i) 409)
1376         ((= vowel ?a) ch)
1377         ((= vowel ?E) 425)
1378         ((= vowel ?') 441)
1379         ((= vowel ?\") (setq composite t) ch)
1380         (t nil)))
1381       ((= ch 287)                       ; GWa
1382        (message "Modify vowel to: [euiaE'\"] ")
1383        (setq vowel (read-char))
1384        (cond
1385         ((= vowel ?e) 394)
1386         ((= vowel ?u) 442)
1387         ((= vowel ?i) 410)
1388         ((= vowel ?a) ch)
1389         ((= vowel ?E) 426)
1390         ((= vowel ?') 442)
1391         ((= vowel ?\") (setq composite t) ch)
1392         (t nil)))
1393       ((= ch 335)                       ; fWa
1394        (message "Modify vowel to: [euiaE'\"] ")
1395        (setq vowel (read-char))
1396        (cond
1397         ((= vowel ?e) 395)
1398         ((= vowel ?u) 443)
1399         ((= vowel ?i) 411)
1400         ((= vowel ?a) ch)
1401         ((= vowel ?E) 427)
1402         ((= vowel ?') 443)
1403         ((= vowel ?\") (setq composite t) ch)
1404         (t nil)))
1405       ((= ch 343)                       ; pWa
1406        (message "Modify vowel to: [euiaE'\"] ")
1407        (setq vowel (read-char))
1408        (cond
1409         ((= vowel ?e) 396)
1410         ((= vowel ?u) 444)
1411         ((= vowel ?i) 412)
1412         ((= vowel ?a) ch)
1413         ((= vowel ?E) 428)
1414         ((= vowel ?') 444)
1415         ((= vowel ?\") (setq composite t) ch)
1416         (t nil)))
1417
1418       ;; extended 12-form consonatns, mW* bW* GW* fW* pW*
1419       ((memq base '(392 408 424 440))   ; *We *Wi *WE *W
1420        (message "Modify vowel to: [eiEau'\"] ")
1421        (setq vowel (read-char))
1422        (cond
1423         ((= vowel ?e) (+ 392 modulo))
1424         ((= vowel ?i) (+ 408 modulo))
1425         ((= vowel ?E) (+ 424 modulo))
1426         ((= vowel ?a) (cond
1427                        ((= modulo 0)  31) ; mWa
1428                        ((= modulo 1) 103) ; bWa
1429                        ((= modulo 2) 287) ; GWa
1430                        ((= modulo 3) 335) ; fWa
1431                        ((= modulo 4) 343) ; pWa
1432                        (t nil)))        ; never reach here
1433         ((= vowel ?') (+ 440 modulo))
1434         ((= vowel ?u) (+ 440 modulo))
1435         ((= vowel ?\") (setq composite t) ch)
1436         (t nil)))
1437
1438       ((and (>= ch 453) (<= ch 457))    ; wWe wWi wWa wWE wW
1439        (message "Modify vowel to: [eiaE'u\"] ")
1440        (setq vowel (read-char))
1441        (cond
1442         ((= vowel ?e) 453)
1443         ((= vowel ?i) 454)
1444         ((= vowel ?a) 455)
1445         ((= vowel ?E) 456)
1446         ((= vowel ?') 457)
1447         ((= vowel ?u) 457)
1448         ((= vowel ?\") (setq composite t) ch)
1449         (t nil)))
1450
1451       ;; 7-form consonants, or
1452       ;; first 7 of 8-form consonants
1453       ((<= modulo 6)
1454        (message "Modify vowel to: [euiaE'o\"] ")
1455        (setq vowel (read-char))
1456        (cond
1457         ((= vowel ?e) base)
1458         ((= vowel ?u) (+ base 1))
1459         ((= vowel ?i) (+ base 2))
1460         ((= vowel ?a) (+ base 3))
1461         ((= vowel ?E) (+ base 4))
1462         ((= vowel ?') (+ base 5))
1463         ((= vowel ?o) (+ base 6))
1464         ((= vowel ?\") (setq composite t) ch)
1465         (t nil)))
1466
1467       ;; otherwise
1468       (t
1469        nil)))
1470
1471     (cond
1472
1473      ;; could not get new character
1474      ((null newch)
1475       (error "Invalid vowel"))
1476
1477      ;; vowel changed on a composite Fidel
1478      (composite
1479       (delete-char 1)
1480       (insert
1481        (compose-string
1482         (concat (char-to-string (ethio-ethiocode-to-char newch))        "\e$(3%s\e(B"))))
1483
1484      ;; simple vowel modification
1485      (t
1486       (delete-char 1)
1487       (insert (ethio-ethiocode-to-char newch))))))
1488
1489 (defun ethio-ethiocode-to-char (ethiocode)
1490   (make-char
1491    'ethiopic
1492    (+ (/ ethiocode 94) 33)
1493    (+ (mod ethiocode 94) 33)))
1494
1495 (defun ethio-char-to-ethiocode (ch)
1496   (and (eq (char-charset ch) 'ethiopic)
1497        (let ((char-components (split-char ch)))
1498          (+ (* (- (nth 1 char-components) 33) 94)
1499             (- (nth 2 char-components) 33)))))
1500
1501 ;;
1502 ;; space replacement
1503 ;;
1504
1505 ;;;###autoload
1506 (defun ethio-replace-space (ch begin end)
1507   "Replace ASCII spaces with Ethiopic word separators in the region.
1508
1509 In the specified region, replace word separators surrounded by two
1510 Ethiopic characters, depending on the first parameter CH, which should
1511 be 1, 2, or 3.
1512
1513 If CH = 1, word separator will be replaced with an ASCII space.
1514 If CH = 2, with two ASCII spaces.
1515 If CH = 3, with the Ethiopic colon-like word separator.
1516
1517 The second and third parameters BEGIN and END specify the region."
1518
1519   (interactive "*cReplace spaces to: 1 (sg col), 2 (dbl col), 3 (Ethiopic)\nr")
1520   (if (not (memq ch '(?1 ?2 ?3)))
1521       (error ""))
1522   (save-excursion
1523     (save-restriction
1524       (narrow-to-region begin end)
1525
1526       (cond
1527        ((= ch ?1)
1528         ;; an Ethiopic word separator --> an ASCII space
1529         (goto-char (point-min))
1530         (while (search-forward "\e$(3$h\e(B" nil t)
1531           (replace-match " " nil t))
1532
1533         ;; two ASCII spaces between Ethiopic characters --> an ASCII space
1534         (goto-char (point-min))
1535         (while (re-search-forward "\\(\\ce\\)  \\(\\ce\\)" nil t)
1536           (replace-match "\\1 \\2")
1537           (goto-char (match-beginning 2))))
1538
1539        ((= ch ?2)
1540         ;; An Ethiopic word separator --> two ASCII spaces
1541         (goto-char (point-min))
1542         (while (search-forward "\e$(3$h\e(B" nil t)
1543           (replace-match "  "))
1544
1545         ;; An ASCII space between Ethiopic characters --> two ASCII spaces
1546         (goto-char (point-min))
1547         (while (re-search-forward "\\(\\ce\\) \\(\\ce\\)" nil t)
1548           (replace-match "\\1  \\2")
1549           (goto-char (match-beginning 2))))
1550
1551        (t
1552         ;; One or two ASCII spaces between Ethiopic characters
1553         ;;   --> An Ethiopic word separator
1554         (goto-char (point-min))
1555         (while (re-search-forward "\\(\\ce\\)  ?\\(\\ce\\)" nil t)
1556           (replace-match "\\1\e$(3$h\e(B\\2")
1557           (goto-char (match-beginning 2)))
1558
1559         ;; Three or more ASCII spaces between Ethiopic characters
1560         ;;   --> An Ethiopic word separator + (N - 2) ASCII spaces
1561         (goto-char (point-min))
1562         (while (re-search-forward "\\(\\ce\\)  \\( *\\ce\\)" nil t)
1563           (replace-match "\\1\e$(3$h\e(B\\2")
1564           (goto-char (match-beginning 2))))))))
1565
1566 ;;
1567 ;; special icons
1568 ;;
1569
1570 ;;;###autoload
1571 (defun ethio-input-special-character (arg)
1572   "Allow the user to input special characters."
1573   (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")
1574   (cond
1575    ((= arg ?1)
1576     (insert "\e$(3%j\e(B"))
1577    ((= arg ?2)
1578     (insert "\e$(3%k\e(B"))
1579    ((= arg ?3)
1580     (insert "\e$(3%l\e(B"))
1581    ((= arg ?4)
1582     (insert "\e$(3%m\e(B"))
1583    ((= arg ?5)
1584     (insert "\e$(3%i\e(B"))
1585    (t
1586     (error ""))))
1587
1588 ;;
1589 ;; TeX support
1590 ;;
1591
1592 (defconst ethio-fidel-to-tex-map
1593  [ "heG"  "huG"  "hiG"  "haG"  "hEG"   "hG"  "hoG"      ""     ;;   0 - 7
1594    "leG"  "luG"  "liG"  "laG"  "lEG"   "lG"  "loG"  "lWaG"     ;;   8
1595    "HeG"  "HuG"  "HiG"  "HaG"  "HEG"   "HG"  "HoG"  "HWaG"     ;;  16
1596    "meG"  "muG"  "miG"  "maG"  "mEG"   "mG"  "moG"  "mWaG"     ;;  24
1597   "sseG" "ssuG" "ssiG" "ssaG" "ssEG"  "ssG" "ssoG" "ssWaG"     ;;  32
1598    "reG"  "ruG"  "riG"  "raG"  "rEG"   "rG"  "roG"  "rWaG"     ;;  40
1599    "seG"  "suG"  "siG"  "saG"  "sEG"   "sG"  "soG"  "sWaG"     ;;  48
1600    "xeG"  "xuG"  "xiG"  "xaG"  "xEG"   "xG"  "xoG"  "xWaG"     ;;  56
1601    "qeG"  "quG"  "qiG"  "qaG"  "qEG"   "qG"  "qoG"      ""     ;;  64
1602   "qWeG"     "" "qWiG" "qWaG" "qWEG"  "qWG"     ""      ""     ;;  72
1603    "QeG"  "QuG"  "QiG"  "QaG"  "QEG"   "QG"  "QoG"      ""     ;;  80
1604   "QWeG"     "" "QWiG" "QWaG" "QWEG"  "QWG"     ""      ""     ;;  88
1605    "beG"  "buG"  "biG"  "baG"  "bEG"   "bG"  "boG"  "bWaG"     ;;  96
1606    "veG"  "vuG"  "viG"  "vaG"  "vEG"   "vG"  "voG"  "vWaG"     ;; 104
1607    "teG"  "tuG"  "tiG"  "taG"  "tEG"   "tG"  "toG"  "tWaG"     ;; 112
1608    "ceG"  "cuG"  "ciG"  "caG"  "cEG"   "cG"  "coG"  "cWaG"     ;; 120
1609   "hheG" "hhuG" "hhiG" "hhaG" "hhEG"  "hhG" "hhoG"      ""     ;; 128
1610   "hWeG"     "" "hWiG" "hWaG" "hWEG"  "hWG"     ""      ""     ;; 136
1611    "neG"  "nuG"  "niG"  "naG"  "nEG"   "nG"  "noG"  "nWaG"     ;; 144
1612    "NeG"  "NuG"  "NiG"  "NaG"  "NEG"   "NG"  "NoG"  "NWaG"     ;; 152
1613     "eG"   "uG"   "iG"   "AG"   "EG"   "IG"   "oG"   "eaG"     ;; 160
1614    "keG"  "kuG"  "kiG"  "kaG"  "kEG"   "kG"  "koG"      ""     ;; 168
1615   "kWeG"     "" "kWiG" "kWaG" "kWEG"  "kWG"     ""      ""     ;; 176
1616    "KeG"  "KuG"  "KiG"  "KaG"  "KEG"   "KG"  "KoG"      ""     ;; 184
1617   "KWeG"     "" "KWiG" "KWaG" "KWEG"  "KWG"     ""      ""     ;; 192
1618    "weG"  "wuG"  "wiG"  "waG"  "wEG"   "wG"  "woG"      ""     ;; 200
1619    "eeG"  "uuG"  "iiG"  "aaG"  "EEG"  "IIG"  "ooG"      ""     ;; 208
1620    "zeG"  "zuG"  "ziG"  "zaG"  "zEG"   "zG"  "zoG"  "zWaG"     ;; 216
1621    "ZeG"  "ZuG"  "ZiG"  "ZaG"  "ZEG"   "ZG"  "ZoG"  "ZWaG"     ;; 224
1622    "yeG"  "yuG"  "yiG"  "yaG"  "yEG"   "yG"  "yoG"  "yWaG"     ;; 232
1623    "deG"  "duG"  "diG"  "daG"  "dEG"   "dG" "doG"   "dWaG"     ;; 240
1624    "DeG"  "DuG"  "DiG"  "DaG"  "DEG"   "DG"  "DoG"  "DWaG"     ;; 248
1625    "jeG"  "juG"  "jiG"  "jaG"  "jEG"   "jG"  "joG"  "jWaG"     ;; 256
1626    "geG"  "guG"  "giG"  "gaG"  "gEG"   "gG"  "goG"     ""      ;; 264
1627   "gWeG"     "" "gWiG" "gWaG" "gWEG"  "gWG"     ""     ""      ;; 272
1628    "GeG"  "GuG"  "GiG"  "GaG"  "GEG"   "GG"  "GoG"  "GWaG"     ;; 280
1629    "TeG"  "TuG"  "TiG"  "TaG"  "TEG"   "TG"  "ToG"  "TWaG"     ;; 288
1630    "CeG"  "CuG"  "CiG"  "CaG"  "CEG"   "CG"  "CoG"  "CWaG"     ;; 296
1631    "PeG"  "PuG"  "PiG"  "PaG"  "PEG"   "PG"  "PoG"  "PWaG"     ;; 304
1632    "SeG"  "SuG"  "SiG"  "SaG"  "SEG"   "SG"  "SoG"  "SWaG"     ;; 312
1633   "SSeG" "SSuG" "SSiG" "SSaG" "SSEG"  "SSG" "SSoG"      ""     ;; 320
1634    "feG"  "fuG"  "fiG"  "faG"  "fEG"   "fG"  "foG"  "fWaG"     ;; 328
1635    "peG"  "puG"  "piG"  "paG"  "pEG"   "pG"  "poG"  "pWaG"     ;; 336
1636   "mYaG" "rYaG" "fYaG"     ""     ""     ""     ""      ""     ;; 344
1637       "" "spaceG" "periodG" "commaG"                           ;; 352
1638   "semicolonG" "colonG" "precolonG" "oldqmarkG"                ;; 356
1639   "pbreakG" "andG" "huletG" "sostG" "aratG" "amstG" "sadstG" "sabatG"  ;; 360
1640   "smntG" "zeteNG" "asrG" "heyaG" "selasaG" "arbaG" "hemsaG" "slsaG"   ;; 368
1641   "sebaG" "semanyaG" "zeTanaG" "metoG" "asrxiG" "" "" ""               ;; 376
1642   "qqeG" "qquG" "qqiG" "qqaG" "qqEG" "qqG" "qqoG"    ""      ;; 384
1643   "mWeG" "bWeG" "GWeG" "fWeG" "pWeG"    ""     ""    ""      ;; 392
1644   "kkeG" "kkuG" "kkiG" "kkaG" "kkEG" "kkG" "kkoG"    ""      ;; 400
1645   "mWiG" "bWiG" "GWiG" "fWiG" "pWiG"    ""     ""    ""      ;; 408
1646    "XeG"  "XuG" "GXiG"  "XaG"  "XEG"  "XG"  "XoG"    ""      ;; 416
1647   "mWEG" "bWEG" "GWEG" "fWEG" "pWEG"    ""     ""    ""      ;; 424
1648   "ggeG" "gguG" "ggiG" "ggaG" "ggEG" "ggG" "ggoG"    ""      ;; 432
1649    "mWG" "bWG"   "GWG"  "fWG"  "pWG"    ""     ""    ""      ;; 440
1650   "ornamentG" "flandG" "iflandG" "africaG"                       ;; 448
1651   "iafricaG" "wWeG" "wWiG" "wWaG"                            ;; 452
1652   "wWEG"  "wWG" "" "slaqG" "dotG" "lquoteG" "rquoteG" "qmarkG" ])  ;; 456
1653
1654 ;;
1655 ;; To make tex-to-fidel mapping.
1656 ;; The following code makes
1657 ;;     (get 'ethio-tex-command-he 'ethio-fidel-char)  ==>  ?\e$(3!!\e(B
1658 ;; etc.
1659 ;;
1660
1661 (let ((i 0) str)
1662   (while (< i (length ethio-fidel-to-tex-map))
1663     (setq str (aref ethio-fidel-to-tex-map i))
1664     (if (not (string= str ""))
1665         (put
1666          (intern (concat "ethio-tex-command-" (aref ethio-fidel-to-tex-map i)))
1667          'ethio-fidel-char
1668          (ethio-ethiocode-to-char i)))
1669     (setq i (1+ i))))
1670
1671 ;;;###autoload
1672 (defun ethio-fidel-to-tex-buffer nil
1673   "Convert each fidel characters in the current buffer into a fidel-tex command.
1674 Each command is always surrounded by braces."
1675   (interactive)
1676   (let ((buffer-read-only nil))
1677
1678     ;; Isolated gemination marks need special treatement
1679     (goto-char (point-min))
1680     (while (search-forward "\e$(3%s\e(B" nil t)
1681       (replace-match "\\geminateG{}" t t))
1682
1683     ;; First, decompose geminations
1684     ;; Here we assume that each composed character consists of
1685     ;; one Ethiopic character and the Ethiopic gemination mark.
1686     (decompose-region (point-min) (point-max))
1687
1688     ;; Special treatment for geminated characters
1689     ;; The geminated character (la'') will be "\geminateG{\la}".
1690     (goto-char (point-min))
1691     (while (search-forward "\e$(3%s\e(B" nil t)
1692       (delete-backward-char 1)
1693       (backward-char 1)
1694       (insert "\\geminateG")
1695       (forward-char 1))
1696
1697     ;; Ethiopic characters to TeX macros
1698     (goto-char (point-min))
1699     (while (re-search-forward "\\ce" nil t)
1700       (insert
1701        "{\\"
1702        (aref ethio-fidel-to-tex-map
1703              (prog1 (ethio-char-to-ethiocode (preceding-char))
1704                (backward-delete-char 1)))
1705        "}"))
1706     (goto-char (point-min))
1707     (set-buffer-modified-p nil)))
1708
1709 ;;;###autoload
1710 (defun ethio-tex-to-fidel-buffer nil
1711   "Convert fidel-tex commands in the current buffer into fidel chars."
1712   (interactive)
1713   (let ((buffer-read-only nil)
1714         (p) (ch))
1715
1716     ;; Special treatment for gemination
1717     ;; "\geminateG{\la}" or "\geminateG{{\la}}" will be "\la\e$(3%s\e(B"
1718     ;; "\geminateG{}" remains unchanged.
1719     (goto-char (point-min))
1720     (while (re-search-forward "\\\\geminateG{\\(\\\\[a-zA-Z]+\\)}" nil t)
1721       (replace-match "\\1\e$(3%s\e(B"))
1722
1723     ;; TeX macros to Ethiopic characters
1724     (goto-char (point-min))
1725     (while (search-forward "\\" nil t)
1726       (setq p (point))
1727       (skip-chars-forward "a-zA-Z")
1728       (setq ch
1729             (get (intern (concat "ethio-tex-command-"
1730                                  (buffer-substring p (point))))
1731                  'ethio-fidel-char))
1732       (if ch
1733           (progn
1734             (delete-region (1- p) (point)) ; don't forget the preceding "\"
1735             (if (and (= (preceding-char) ?{)
1736                      (= (following-char) ?}))
1737                 (progn
1738                   (backward-delete-char 1)
1739                   (delete-char 1)))
1740             (insert ch))))
1741
1742     ;; compose geminated characters
1743     (goto-char (point-min))
1744     (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
1745       (compose-region
1746        (save-excursion (backward-char 2) (point))
1747        (point)))
1748
1749     ;; Now it's time to convert isolated gemination marks.
1750     (goto-char (point-min))
1751     (while (search-forward "\\geminateG{}" nil t)
1752       (replace-match "\e$(3%s\e(B"))
1753
1754     (goto-char (point-min))
1755     (set-buffer-modified-p nil)))
1756
1757 ;;
1758 ;; Java support
1759 ;;
1760
1761 ;;;###autoload
1762 (defun ethio-fidel-to-java-buffer nil
1763   "Convert Ethiopic characters into the Java escape sequences.
1764
1765 Each escape sequence is of the form \\uXXXX, where XXXX is the
1766 character's codepoint (in hex) in Unicode.
1767
1768 If `ethio-java-save-lowercase' is non-nil, use [0-9a-f].
1769 Otherwise, [0-9A-F]."
1770   (let ((ucode))
1771
1772     ;; first, decompose geminations
1773     (decompose-region (point-min) (point-max))
1774
1775     (goto-char (point-min))
1776     (while (re-search-forward "\\ce" nil t)
1777       (setq ucode (+ #x1200 (ethio-char-to-ethiocode (preceding-char))))
1778       (if (> ucode #x13bc)
1779           (setq ucode (+ ucode 59952)))
1780       (delete-backward-char 1)
1781       (if ethio-java-save-lowercase
1782           (insert (format "\\u%4x" ucode))
1783         (insert (upcase (format "\\u%4x" ucode)))))))
1784
1785 ;;;###autoload
1786 (defun ethio-java-to-fidel-buffer nil
1787   "Convert the Java escape sequences into corresponding Ethiopic characters."
1788   (let ((ucode))
1789     (goto-char (point-min))
1790     (while (re-search-forward "\\\\u\\([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\\)" nil t)
1791       (setq ucode
1792             (read
1793              (concat
1794               "?\\x"
1795               (buffer-substring (match-beginning 1) (match-end 1)))))
1796       (cond
1797        ((and (>= ucode #x1200) (<= ucode #x13bc))
1798         (replace-match "")
1799         (insert (ethio-ethiocode-to-char (- ucode #x1200))))
1800        ((and (>= ucode #xfdf1) (<= ucode #xfdff))
1801         (replace-match "")
1802         (insert (ethio-ethiocode-to-char (- ucode 64560))))
1803        (t
1804         nil)))
1805     
1806     ;; gemination
1807     (goto-char (point-min))
1808     (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
1809       (compose-region
1810        (save-excursion (backward-char 2) (point))
1811        (point)))
1812     ))
1813
1814 ;;
1815 ;; file I/O hooks
1816 ;;
1817
1818 ;;;###autoload
1819 (defun ethio-find-file nil
1820   "Transcribe file content into Ethiopic dependig on filename suffix."
1821   (cond
1822
1823    ((string-match "\\.sera$" (buffer-file-name))
1824     (save-excursion
1825       (ethio-sera-to-fidel-buffer nil 'force)
1826       (set-buffer-modified-p nil)))
1827
1828    ((string-match "\\.html$" (buffer-file-name))
1829     (let ((sera-being-called-by-w3 t))
1830       (save-excursion
1831         (ethio-sera-to-fidel-marker 'force)
1832         (goto-char (point-min))
1833         (while (re-search-forward "&[lr]aquote;" nil t)
1834           (if (= (char-after (1+ (match-beginning 0))) ?l)
1835               (replace-match "\e$(3%v\e(B")
1836             (replace-match "\e$(3%w\e(B")))
1837         (set-buffer-modified-p nil))))
1838
1839    ((string-match "\\.tex$" (buffer-file-name))
1840     (save-excursion
1841       (ethio-tex-to-fidel-buffer)
1842       (set-buffer-modified-p nil)))
1843
1844    ((string-match "\\.java$" (buffer-file-name))
1845     (save-excursion
1846       (ethio-java-to-fidel-buffer)
1847       (set-buffer-modified-p nil)))
1848
1849    (t
1850     nil)))
1851
1852 ;;;###autoload
1853 (defun ethio-write-file nil
1854   "Transcribe Ethiopic characters in ASCII depending on the file extension."
1855   (cond
1856
1857    ((string-match "\\.sera$" (buffer-file-name))
1858     (save-excursion
1859       (ethio-fidel-to-sera-buffer nil 'force)
1860       (goto-char (point-min))
1861       (ethio-record-user-preference)
1862       (set-buffer-modified-p nil)))
1863
1864    ((string-match "\\.html$" (buffer-file-name))
1865     (save-excursion
1866       (let ((sera-being-called-by-w3 t)
1867             (lq (aref ethio-fidel-to-sera-map 461))
1868             (rq (aref ethio-fidel-to-sera-map 462)))
1869         (aset ethio-fidel-to-sera-map 461 "&laquote;")
1870         (aset ethio-fidel-to-sera-map 462 "&raquote;")
1871         (ethio-fidel-to-sera-marker 'force)
1872         (goto-char (point-min))
1873         (if (search-forward "<sera>" nil t)
1874             (ethio-record-user-preference))
1875         (aset ethio-fidel-to-sera-map 461 lq)
1876         (aset ethio-fidel-to-sera-map 462 rq)
1877         (set-buffer-modified-p nil))))
1878
1879    ((string-match "\\.tex$" (buffer-file-name))
1880     (save-excursion
1881       (ethio-fidel-to-tex-buffer)
1882       (set-buffer-modified-p nil)))
1883
1884    ((string-match "\\.java$" (buffer-file-name))
1885     (save-excursion
1886       (ethio-fidel-to-java-buffer)
1887       (set-buffer-modified-p nil)))
1888
1889    (t
1890     nil)))
1891
1892 (defun ethio-record-user-preference nil
1893   (if (looking-at "\\\\~\\(tir?\\|amh?\\) ")
1894       (goto-char (match-end 0))
1895     (insert (if (ethio-prefer-amharic-p) "\\~amh " "\\~tir ")))
1896   (insert (if ethio-use-colon-for-colon "\\~-: " "\\~`: ")
1897           (if ethio-use-three-dot-question "\\~`| " "\\~`? ")))
1898
1899 ;;
1900 ;; Ethiopic word separator vs. ASCII space
1901 ;;
1902
1903 (defvar ethio-prefer-ascii-space t)
1904 (make-variable-buffer-local 'ethio-prefer-ascii-space)
1905
1906 (defun ethio-toggle-space nil
1907   "Toggle ASCII space and Ethiopic separator for keyboard input."
1908   (interactive)
1909   (setq ethio-prefer-ascii-space
1910         (not ethio-prefer-ascii-space))
1911   (force-mode-line-update))
1912
1913 (defun ethio-insert-space (arg)
1914   "Insert ASCII spaces or Ethiopic word separators depending on context.
1915
1916 If the current word separator (indicated in mode-line) is the ASCII space,
1917 insert an ASCII space.  With ARG, insert that many ASCII spaces.
1918
1919 If the current word separator is the colon-like Ethiopic word
1920 separator and the point is preceded by `an Ethiopic punctuation mark
1921 followed by zero or more ASCII spaces', then insert also an ASCII
1922 space.  With ARG, insert that many ASCII spaces.
1923
1924 Otherwise, insert a colon-like Ethiopic word separator.  With ARG, insert that
1925 many Ethiopic word separators."
1926
1927   (interactive "*p")
1928   (cond
1929    (ethio-prefer-ascii-space
1930     (insert-char 32 arg))
1931    ((save-excursion
1932       (skip-chars-backward " ")
1933       (memq (preceding-char)
1934             '(?\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)))
1935     (insert-char 32 arg))
1936    (t
1937     (insert-char ?\e$(3$h\e(B arg))))
1938
1939 (defun ethio-insert-ethio-space (arg)
1940   "Insert the Ethiopic word delimiter (the colon-like character).
1941 With ARG, insert that many delimiters."
1942   (interactive "*p")
1943   (insert-char ?\e$(3$h\e(B arg))
1944
1945 ;;
1946 ;; Ethiopic punctuation vs. ASCII punctuation
1947 ;;
1948
1949 (defvar ethio-prefer-ascii-punctuation nil)
1950 (make-variable-buffer-local 'ethio-prefer-ascii-punctuation)
1951
1952 (defun ethio-toggle-punctuation nil
1953   "Toggle Ethiopic punctuations and ASCII punctuations for keyboard input."
1954   (interactive)
1955   (setq ethio-prefer-ascii-punctuation
1956         (not ethio-prefer-ascii-punctuation))
1957   (let* ((keys '("." ".." "..." "," ",," ";" ";;" ":" "::" ":::" "*" "**"))
1958          (puncs
1959           (if ethio-prefer-ascii-punctuation
1960               '(?. [".."] ["..."] ?, [",,"] ?\; [";;"] ?: ["::"] [":::"] ?* ["**"])
1961             '(?\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))))
1962     (while keys
1963       (quail-defrule (car keys) (car puncs) "ethiopic")
1964       (setq keys (cdr keys)
1965             puncs (cdr puncs)))
1966     (force-mode-line-update)))
1967
1968 ;;
1969 ;; Gemination
1970 ;;
1971
1972 (defun ethio-gemination nil
1973   "Compose the character before the point with the Ethiopic gemination mark.
1974 If the character is already composed, decompose it and remove the gemination
1975 mark."
1976   (interactive "*")
1977   (cond
1978    ((eq (char-charset (preceding-char)) 'ethiopic)
1979     (insert "\e$(3%s\e(B")
1980     (compose-region
1981      (save-excursion (backward-char 2) (point))
1982      (point))
1983     (forward-char 1))
1984    ((eq (char-charset (preceding-char)) 'leading-code-composition)
1985     (decompose-region
1986      (save-excursion (backward-char 1) (point))
1987      (point))
1988     (delete-backward-char 1))
1989    (t
1990     (error ""))))
1991
1992 ;;
1993 (provide 'ethio-util)
1994
1995 ;;; ethio-util.el ends here