1 ;;; ethio-util.el --- utilities for Ethiopic -*- coding: iso-2022-7bit; -*-
3 ;; Copyright (C) 1997, 1998, 2002, 2003, 2004, 2005, 2006, 2007, 2008
4 ;; Free Software Foundation, Inc.
5 ;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
7 ;; National Institute of Advanced Industrial Science and Technology (AIST)
8 ;; Registration Number H14PRO021
10 ;; Keywords: mule, multilingual, Ethiopic
12 ;; This file is part of GNU Emacs.
14 ;; GNU Emacs is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 3, or (at your option)
19 ;; GNU Emacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
29 ;; Author: TAKAHASHI Naoto <ntakahas@m17n.org>
35 (defvar rmail-current-message
)
36 (defvar rmail-message-vector
)
38 ;; Information for exiting Ethiopic environment.
39 (defvar exit-ethiopic-environment-data nil
)
42 (defun setup-ethiopic-environment-internal ()
43 (let ((key-bindings '((" " . ethio-insert-space
)
44 ([?\S-
] . ethio-insert-ethio-space
)
45 ([?\C-
'] . ethio-gemination
)
47 ;; these old bindings conflict
48 ;; with Emacs' binding policy
50 ;; ([f2] . ethio-toggle-space)
51 ;; ([S-f2] . ethio-replace-space) ; as requested
52 ;; ([f3] . ethio-toggle-punctuation)
53 ;; ([f4] . ethio-sera-to-fidel-buffer)
54 ;; ([S-f4] . ethio-sera-to-fidel-region)
55 ;; ([C-f4] . ethio-sera-to-fidel-mail-or-marker)
56 ;; ([f5] . ethio-fidel-to-sera-buffer)
57 ;; ([S-f5] . ethio-fidel-to-sera-region)
58 ;; ([C-f5] . ethio-fidel-to-sera-mail-or-marker)
59 ;; ([f6] . ethio-modify-vowel)
60 ;; ([f7] . ethio-replace-space)
61 ;; ([f8] . ethio-input-special-character)
63 ;; this is the rewritten bindings
65 ([f3] . ethio-fidel-to-sera-buffer)
66 ([S-f3] . ethio-fidel-to-sera-region)
67 ([C-f3] . ethio-fidel-to-sera-mail-or-marker)
68 ([f4] . ethio-sera-to-fidel-buffer)
69 ([S-f4] . ethio-sera-to-fidel-region)
70 ([C-f4] . ethio-sera-to-fidel-mail-or-marker)
71 ([S-f5] . ethio-toggle-punctuation)
72 ([S-f6] . ethio-modify-vowel)
73 ([S-f7] . ethio-replace-space)
74 ([S-f8] . ethio-input-special-character)
75 ([C-f9] . ethio-toggle-space)
76 ([S-f9] . ethio-replace-space) ; as requested
80 (setq kb (car (car key-bindings)))
81 (setq exit-ethiopic-environment-data
82 (cons (cons kb (global-key-binding kb))
83 exit-ethiopic-environment-data))
84 (global-set-key kb (cdr (car key-bindings)))
85 (setq key-bindings (cdr key-bindings))))
87 (add-hook 'quail-activate-hook 'ethio-select-a-translation)
88 (add-hook 'find-file-hook 'ethio-find-file)
89 (add-hook 'write-file-functions 'ethio-write-file)
90 (add-hook 'after-save-hook 'ethio-find-file))
92 (defun exit-ethiopic-environment ()
93 "Exit Ethiopic language environment."
94 (while exit-ethiopic-environment-data
95 (global-set-key (car (car exit-ethiopic-environment-data))
96 (cdr (car exit-ethiopic-environment-data)))
97 (setq exit-ethiopic-environment-data
98 (cdr exit-ethiopic-environment-data)))
100 (remove-hook 'quail-activate-hook 'ethio-select-a-translation)
101 (remove-hook 'find-file-hook 'ethio-find-file)
102 (remove-hook 'write-file-functions 'ethio-write-file)
103 (remove-hook 'after-save-hook 'ethio-find-file))
106 ;; ETHIOPIC UTILITY FUNCTIONS
109 ;; If the filename ends in ".sera", editing is done in fidel
110 ;; but file I/O is done in SERA.
112 ;; If the filename ends in ".java", editing is done in fidel
113 ;; but file I/O is done in the \uXXXX style, where XXXX is
114 ;; the Unicode codepoint for the Ethiopic character.
116 ;; If the filename ends in ".tex", editing is done in fidel
117 ;; but file I/O is done in EthioTeX format.
119 ;; To automatically convert Ethiopic text to SERA format when sending mail,
120 ;; (add-hook 'mail-send-hook 'ethio-fidel-to-sera-mail)
122 ;; To automatically convert SERA format to Ethiopic when receiving mail,
123 ;; (add-hook 'rmail-show-message-hook 'ethio-sera-to-fidel-mail)
125 ;; To automatically convert Ethiopic text to SERA format when posting news,
126 ;; (add-hook 'news-inews-hook 'ethio-fidel-to-sera-mail)
132 (defvar ethio-primary-language 'tigrigna
133 "*Symbol that defines the primary language in SERA --> FIDEL conversion.
134 The value should be one of: `tigrigna', `amharic' or `english'.")
136 (defvar ethio-secondary-language 'english
137 "*Symbol that defines the secondary language in SERA --> FIDEL conversion.
138 The value should be one of: `tigrigna', `amharic' or `english'.")
140 (defvar ethio-use-colon-for-colon nil
141 "*Non-nil means associate ASCII colon with Ethiopic colon.
142 If nil, associate ASCII colon with Ethiopic word separator, i.e., two
143 vertically stacked dots. All SERA <--> FIDEL converters refer this
146 (defvar ethio-use-three-dot-question nil
147 "*Non-nil means associate ASCII question mark with Ethiopic old style question mark (three vertically stacked dots).
148 If nil, associate ASCII question mark with Ethiopic stylized question
149 mark. All SERA <--> FIDEL converters refer this variable.")
151 (defvar ethio-quote-vowel-always nil
152 "*Non-nil means always put an apostrophe before an isolated vowel (except at word initial) in FIDEL --> SERA conversion.
153 If nil, put an apostrophe only between a sixth-form consonant and an
156 (defvar ethio-W-sixth-always nil
157 "*Non-nil means convert the Wu-form of a 12-form consonant to \"W'\" instead of \"Wu\" in FIDEL --> SERA conversion.")
159 (defvar ethio-numeric-reduction 0
160 "*Degree of reduction in converting Ethiopic digits into Arabic digits.
162 For example, ({10}{9}{100}{80}{7}) is converted into:
163 `10`9`100`80`7 if `ethio-numeric-reduction' is 0,
164 `109100807 if `ethio-numeric-reduction' is 1,
165 `10900807 if `ethio-numeric-reduction' is 2.")
167 (defvar ethio-implicit-period-conversion t
168 "*Non-nil means replacing the Ethiopic dot at the end of an Ethiopic sentence
169 with an Ethiopic full stop.")
171 (defvar ethio-java-save-lowercase nil
172 "*Non-nil means save Ethiopic characters in lowercase hex numbers to Java files.
173 If nil, use uppercases.")
179 (defconst ethio-sera-to-fidel-table
181 nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
182 nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil
185 (?: (if ethio-use-colon-for-colon " \e$(3$l\e(B" "\e$(3$h\e(B")
186 (32 (if ethio-use-colon-for-colon " \e$(3$l\e(B " "\e$(3$h\e(B"))
189 (?| (if ethio-use-colon-for-colon " \e$(3$l\e(B|" " \e$(3$h\e(B|")
190 (?: " \e$(3$o\e(B"))))
193 nil nil nil nil nil nil ("" (?' "\e$(3%s\e(B"))
195 nil nil nil nil ("\e$(3$j\e(B") ("-" (?: "\e$(3$l\e(B")) ("\e$(3%u\e(B")
196 ;;; / 0 1 2 3 4 5 6 7 8 9
197 nil nil nil nil nil nil nil nil nil nil nil
199 ((if ethio-use-colon-for-colon "\e$(3$l\e(B" "\e$(3$h\e(B")
200 (32 (if ethio-use-colon-for-colon "\e$(3$l\e(B " "\e$(3$h\e(B"))
203 (?| (if ethio-use-colon-for-colon "\e$(3$l\e(B|" "\e$(3$h\e(B|")
206 ("\e$(3$k\e(B") ("<" (?< "\e$(3%v\e(B")) nil (">" (?> "\e$(3%w\e(B"))
208 ((if ethio-use-three-dot-question "\e$(3$n\e(B" "\e$(3%x\e(B"))
212 ("\e$(3"f\e(B" (?2 "\e$(3#8\e(B"))
214 ("\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")
215 (?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")))
217 ("\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")
218 (?W "\e$(3$6\e(B" (?a "\e$(3$6\e(B")
219 (?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")))
221 ("\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")
222 (?W "\e$(3#d\e(B" (?a "\e$(3#d\e(B")
223 (?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")))
225 ("\e$(3"g\e(B" (?2 "\e$(3#9\e(B"))
227 ("\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")
228 (?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"))
229 (?Y "\e$(3$a\e(B" (?a "\e$(3$a\e(B")))
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$%\e(B")
232 (?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")))
234 ("\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")
235 (?W "\e$(3!8\e(B" (?a "\e$(3!8\e(B")
236 (?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")))
238 ("\e$(3"h\e(B" (?2 "\e$(3#:\e(B"))
240 ("\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")
241 (?W "\e$(3#l\e(B" (?a "\e$(3#l\e(B")
242 (?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")))
244 ("\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")
245 (?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")))
247 ("\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")
248 (?W "\e$(3!0\e(B" (?a "\e$(3!0\e(B")
249 (?e "\e$(3!.%n\e(B") (?u "\e$(3!.%r\e(B") (?i "\e$(3!.%o\e(B") (?E "\e$(3!.%q\e(B")))
251 ("\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")
252 (?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"))
253 (?Y "\e$(3$_\e(B" (?a "\e$(3$_\e(B")))
255 ("\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")
256 (?W "\e$(3"b\e(B" (?a "\e$(3"b\e(B")
257 (?e "\e$(3"`%n\e(B") (?u "\e$(3"`%r\e(B") (?i "\e$(3"`%o\e(B") (?E "\e$(3"`%q\e(B")))
259 ("\e$(3"i\e(B" (?2 "\e$(3#;\e(B"))
261 ("\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")
262 (?W "\e$(3$>\e(B" (?a "\e$(3$>\e(B")
263 (?e "\e$(3$<%n\e(B") (?u "\e$(3$<%r\e(B") (?i "\e$(3$<%o\e(B") (?E "\e$(3$<%q\e(B")))
265 ("\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")
266 (?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")))
268 ("\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")
269 (?W "\e$(3!P\e(B" (?a "\e$(3!P\e(B")
270 (?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"))
271 (?Y "\e$(3$`\e(B" (?a "\e$(3$`\e(B")))
273 ("\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")
274 (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
275 (?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"))
277 (?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")
278 (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
279 (?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"))))
281 ("\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")
282 (?W "\e$(3$.\e(B" (?a "\e$(3$.\e(B")
283 (?e "\e$(3$,%n\e(B") (?u "\e$(3$,%r\e(B") (?i "\e$(3$,%o\e(B") (?E "\e$(3$,%q\e(B")))
285 ("\e$(3"d\e(B" (?2 "\e$(3#6\e(B"))
287 ("\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")
288 (?W "\e$(3"2\e(B" (?a "\e$(3"2\e(B")
289 (?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")))
291 ("\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"))
293 ("\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"))
295 ("\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")
296 (?W "\e$(3#T\e(B" (?a "\e$(3#T\e(B")
297 (?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")))
299 ("\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")
300 (?W "\e$(3#L\e(B" (?a "\e$(3#L\e(B")
301 (?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")))
307 (?? (if ethio-use-three-dot-question "\e$(3%x\e(B" "\e$(3$n\e(B"))
309 (?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")
310 (?E "\e$(3#9\e(B") (?I "\e$(3#:\e(B") (?o "\e$(3#;\e(B") (?O "\e$(3#;\e(B")
312 (?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"))
314 (?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")
315 (?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")))
317 (?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"))
319 (?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")
320 (?W "\e$(3!H\e(B" (?a "\e$(3!H\e(B")
321 (?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")))
323 (?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")
324 (?W "\e$(3$F\e(B" (?a "\e$(3$F\e(B")
325 (?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")))
326 (?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")))
328 ("\e$(3"f\e(B" (?2 "\e$(3#8\e(B"))
330 ("\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")
331 (?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")))
333 ("\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")
334 (?W "\e$(3"B\e(B" (?a "\e$(3"B\e(B")
335 (?e "\e$(3"@%n\e(B") (?u "\e$(3"@%r\e(B") (?i "\e$(3"@%o\e(B") (?E "\e$(3"@%q\e(B")))
337 ("\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")
338 (?W "\e$(3#\\e(B" (?a "\e$(3#\\e(B")
339 (?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")))
341 ("\e$(3"c\e(B" (?2 "\e$(3#5\e(B") (?a "\e$(3"j\e(B"))
343 ("\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")
344 (?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"))
345 (?Y "\e$(3$a\e(B" (?a "\e$(3$a\e(B")))
347 ("\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")
348 (?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"))
349 (?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")))
351 ("\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")
352 (?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"))
353 (?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")
354 (?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"))))
356 ("\e$(3"e\e(B" (?2 "\e$(3#7\e(B"))
358 ("\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")
359 (?W "\e$(3#l\e(B" (?a "\e$(3#l\e(B")
360 (?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")))
362 ("\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")
363 (?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"))
364 (?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")))
366 ("\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")
367 (?W "\e$(3!0\e(B" (?a "\e$(3!0\e(B")
368 (?e "\e$(3!.%n\e(B") (?u "\e$(3!.%r\e(B") (?i "\e$(3!.%o\e(B") (?E "\e$(3!.%q\e(B")))
370 ("\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")
371 (?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"))
372 (?Y "\e$(3$_\e(B" (?a "\e$(3$_\e(B")))
374 ("\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")
375 (?W "\e$(3"Z\e(B" (?a "\e$(3"Z\e(B")
376 (?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")))
378 ("\e$(3"i\e(B" (?2 "\e$(3#;\e(B"))
380 ("\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")
381 (?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")))
383 ("\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")
384 (?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"))
385 (?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")))
387 ("\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")
388 (?W "\e$(3!P\e(B" (?a "\e$(3!P\e(B")
389 (?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"))
390 (?Y "\e$(3$`\e(B" (?a "\e$(3$`\e(B")))
392 ("\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")
393 (?W "\e$(3!X\e(B" (?a "\e$(3!X\e(B")
394 (?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"))
395 (?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")
396 (?W "\e$(3!H\e(B" (?a "\e$(3!H\e(B")
397 (?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"))))
399 ("\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")
400 (?W "\e$(3":\e(B" (?a "\e$(3":\e(B")
401 (?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")))
403 ("\e$(3"d\e(B" (?2 "\e$(3#6\e(B"))
405 ("\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")
406 (?W "\e$(3"2\e(B" (?a "\e$(3"2\e(B")
407 (?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")))
409 ("\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")
410 (?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")))
412 ("\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")
413 (?W "\e$(3!`\e(B" (?a "\e$(3!`\e(B")
414 (?e "\e$(3!^%n\e(B") (?u "\e$(3!^%r\e(B") (?i "\e$(3!^%o\e(B") (?E "\e$(3!^%q\e(B")))
416 ("\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")
417 (?W "\e$(3#T\e(B" (?a "\e$(3#T\e(B")
418 (?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")))
420 ("\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")
421 (?W "\e$(3#D\e(B" (?a "\e$(3#D\e(B")
422 (?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")))
427 ;; To avoid byte-compiler warnings. It should never be set globally.
428 (defvar ethio-sera-being-called-by-w3)
429 ;; This variable will be bound by some third-party package.
430 (defvar sera-being-called-by-w3)
433 (defun ethio-sera-to-fidel-region (beg end &optional secondary force)
434 "Convert the characters in region from SERA to FIDEL.
435 The variable `ethio-primary-language' specifies the primary language
436 and `ethio-secondary-language' specifies the secondary.
438 If the 3rd parameter SECONDARY is given and non-nil, assume the region
439 begins with the secondary language; otherwise with the primary
442 If the 4th parameter FORCE is given and non-nil, perform conversion
443 even if the buffer is read-only.
445 See also the descriptions of the variables
446 `ethio-use-colon-for-colon' and
447 `ethio-use-three-dot-question'."
451 (narrow-to-region beg end)
452 (ethio-sera-to-fidel-buffer secondary force)))
455 (defun ethio-sera-to-fidel-buffer (&optional secondary force)
456 "Convert the current buffer from SERA to FIDEL.
458 The variable `ethio-primary-language' specifies the primary
459 language and `ethio-secondary-language' specifies the secondary.
461 If the 1st optional parameter SECONDARY is non-nil, assume the buffer
462 begins with the secondary language; otherwise with the primary
465 If the 2nd optional parametr FORCE is non-nil, perform conversion even if the
468 See also the descriptions of the variables
469 `ethio-use-colon-for-colon' and
470 `ethio-use-three-dot-question'."
474 (if (and buffer-read-only
476 (not (y-or-n-p "Buffer is read-only. Force to convert? ")))
479 (let ((ethio-primary-language ethio-primary-language)
480 (ethio-secondary-language ethio-secondary-language)
481 (ethio-use-colon-for-colon ethio-use-colon-for-colon)
482 (ethio-use-three-dot-question ethio-use-three-dot-question)
483 ;; The above four variables may be changed temporary
484 ;; by tilde escapes during conversion. So we bind them to other
485 ;; variables but of the same names.
486 (buffer-read-only nil)
487 (case-fold-search nil)
491 (setq current-language
493 ethio-secondary-language
494 ethio-primary-language))
496 (goto-char (point-min))
501 ((eq current-language 'english)
502 (ethio-sera-to-fidel-english))
503 ((eq current-language 'amharic)
504 (ethio-sera-to-fidel-ethio 'amharic))
505 ((eq current-language 'tigrigna)
506 (ethio-sera-to-fidel-ethio 'tigrigna))
507 (t ; we don't know what to do
508 (ethio-sera-to-fidel-english))))
510 (setq current-language
513 ;; when language tag is explicitly specified
514 ((not (eq next-language 'toggle))
517 ;; found a toggle in a primary language section
518 ((eq current-language ethio-primary-language)
519 ethio-secondary-language)
521 ;; found a toggle in a secondary, third, fourth, ...
524 ethio-primary-language))))
526 ;; If ethio-implicit-period-conversion is non-nil, the
527 ;; Ethiopic dot "\e$(3%u\e(B" at the end of an Ethiopic sentence is
528 ;; replaced with the Ethiopic full stop "\e$(3$i\e(B".
529 (if ethio-implicit-period-conversion
531 (goto-char (point-min))
532 (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]\\)"
534 (replace-match "\\1\e$(3$i\e(B\\2"))
535 (goto-char (point-min))
536 (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)
537 (replace-match "\\1\e$(3$i\e(B"))))
540 (goto-char (point-min))
541 (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
543 (save-excursion (backward-char 2) (point))
547 (defun ethio-sera-to-fidel-english nil
548 "Handle English section in SERA to FIDEL conversion.
549 Conversion stops when a language switch is found. Then delete that
550 switch and return the name of the new language as a symbol."
551 (let ((new-language nil))
553 (while (and (not (eobp)) (null new-language))
556 ;; if no more "\", nothing to do.
557 ((not (search-forward "\\" nil 0)))
559 ;; hereafter point is put after a "\".
560 ;; first delete that "\", then check the following chars
562 ;; "\\" : leave the second "\"
564 (delete-backward-char 1)
565 (= (following-char) ?\\ ))
568 ;; "\ " : delete the following " "
569 ((= (following-char) 32)
571 (setq new-language 'toggle))
574 ((setq new-language (ethio-process-language-flag)))
576 ;; just a "\" : not special sequence.
578 (setq new-language 'toggle))))
582 (defun ethio-sera-to-fidel-ethio (lang)
583 "Handle Ethiopic section in SERA to FIDEL conversion.
584 Conversion stops when a language switch is found. Then delete that
585 switch and return the name of the new language as a symbol.
587 The parameter LANG (symbol, either `amharic' or `tigrigna') affects
588 the conversion of \"a\"."
590 (let ((new-language nil)
592 start table table2 ch)
594 (setcar (aref ethio-sera-to-fidel-table ?a)
595 (if (eq lang 'tigrigna) "\e$(3"f\e(B" "\e$(3"c\e(B"))
597 (while (and (not (eobp)) (null new-language))
598 (setq ch (following-char))
601 ;; skip from "<" to ">" (or from "&" to ";") if in w3-mode
602 ((and (or (= ch ?<) (= ch ?&))
603 (or (and (boundp 'ethio-sera-being-called-by-w3)
604 ethio-sera-being-called-by-w3)
605 (and (boundp 'sera-being-called-by-w3)
606 sera-being-called-by-w3)))
607 (search-forward (if (= ch ?<) ">" ";")
610 ;; leave non-ASCII characters as they are
615 ((looking-at "`[1-9][0-9]*")
617 (ethio-convert-digit))
619 ;; if not seeing a "\", do sera to fidel conversion
623 (setq table (aref ethio-sera-to-fidel-table ch))
624 (while (setq table2 (cdr (assoc (following-char) table)))
627 (if (setq ch (car table))
629 (delete-region start (point))
632 (insert (eval ch))))))
634 ;; if control reaches here, we must be looking at a "\"
638 (if (looking-at "\\\\~! ?")
640 ;; "\~!" or "\~! ". switch to non-verbatim mode
645 ;; "\" but not "\~!" nor "\~! ". skip the current "\".
648 ;; hereafter, non-verbatim mode and looking at a "\"
649 ;; first delete that "\", then check the following chars.
651 ;; "\ " : delete the following " "
654 (setq ch (following-char))
657 (setq new-language 'toggle))
659 ;; "\~!" or "\~! " : switch to verbatim mode
665 ((setq new-language (ethio-process-language-flag)))
667 ;; "\~" but not "\~!" nor a language flag
670 (ethio-tilde-escape))
672 ;; ASCII punctuation escape. skip
673 ((looking-at "\\(,\\|\\.\\|;\\|:\\|'\\|`\\|\?\\|\\\\\\)+")
674 (goto-char (match-end 0)))
676 ;; "\", but not special sequence
678 (setq new-language 'toggle))))
682 (defun ethio-process-language-flag nil
683 "Process a language flag of the form \"~lang\" or \"~lang1~lang2\".
685 If looking at \"~lang1~lang2\", set `ethio-primary-language' and
686 `ethio-une-secondary-language' based on \"lang1\" and \"lang2\".
687 Then delete the language flag \"~lang1~lang2\" from the buffer.
688 Return value is the new primary language.
690 If looking at \"~lang\", delete that language flag \"~lang\" from the
691 buffer and return that language. In this case
692 `ethio-primary-language' and `ethio-uni-secondary-language'
695 If an unsupported language flag is found, just return nil without
703 "~\\([a-z][a-z][a-z]?\\)~\\([a-z][a-z][a-z]?\\)[ \t\n\\]")
705 (ethio-flag-to-language
706 (buffer-substring (match-beginning 1) (match-end 1))))
708 (ethio-flag-to-language
709 (buffer-substring (match-beginning 2) (match-end 2)))))
710 (setq ethio-primary-language lang1
711 ethio-secondary-language lang2)
712 (delete-region (point) (match-end 2))
713 (if (= (following-char) 32)
715 ethio-primary-language)
718 ((and (looking-at "~\\([a-z][a-z][a-z]?\\)[ \t\n\\]")
720 (ethio-flag-to-language
721 (buffer-substring (match-beginning 1) (match-end 1)))))
722 (delete-region (point) (match-end 1))
723 (if (= (following-char) 32)
731 (defun ethio-tilde-escape nil
732 "Handle a SERA tilde escape in Ethiopic section and delete it.
733 Delete the escape even it is not recognized."
735 (let ((p (point)) command)
736 (skip-chars-forward "^ \t\n\\\\")
737 (setq command (buffer-substring p (point)))
738 (delete-region p (point))
739 (if (= (following-char) 32)
745 ((string= command "-:")
746 (setq ethio-use-colon-for-colon t))
749 ((string= command "`:")
750 (setq ethio-use-colon-for-colon nil))
753 ((string= command "?")
754 (setq ethio-use-three-dot-question nil))
757 ((string= command "`|")
758 (setq ethio-use-three-dot-question t))
761 ((string= command "e")
762 (insert "\e$(3%j\e(B"))
765 ((string= command "E")
766 (insert "\e$(3%k\e(B"))
769 ((string= command "a")
770 (insert "\e$(3%l\e(B"))
773 ((string= command "A")
774 (insert "\e$(3%m\e(B"))
777 ((string= command "X")
778 (insert "\e$(3%i\e(B"))
780 ;; unsupported tilde escape
784 (defun ethio-flag-to-language (flag)
786 ((or (string= flag "en") (string= flag "eng")) 'english)
787 ((or (string= flag "ti") (string= flag "tir")) 'tigrigna)
788 ((or (string= flag "am") (string= flag "amh")) 'amharic)
791 (defun ethio-convert-digit nil
792 "Convert Arabic digits to Ethiopic digits."
794 (while (and (>= (setq ch (following-char)) ?1)
798 ;; count up following zeros
800 (while (= (following-char) ?0)
806 ;; first digit is 10, 20, ..., or 90
808 (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)))
811 ;; first digit is 2, 3, ..., or 9
813 (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))))
817 (insert "\e$(3$p\e(B")))
821 (insert "\e$(3%$\e(B"))
824 (insert-char ?\e$(3%%\e(B (/ z 4)))))
827 (defun ethio-sera-to-fidel-mail-or-marker (&optional arg)
828 "Execute `ethio-sera-to-fidel-mail' or `ethio-sera-to-fidel-marker' depending on the current major mode.
829 If in rmail-mode or in mail-mode, execute the former; otherwise latter."
832 (if (or (eq major-mode 'rmail-mode)
833 (eq major-mode 'mail-mode))
834 (ethio-sera-to-fidel-mail (prefix-numeric-value arg))
835 (ethio-sera-to-fidel-marker arg)))
838 (defun ethio-sera-to-fidel-mail (&optional arg)
839 "Convert SERA to FIDEL to read/write mail and news.
841 If the buffer contains the markers \"<sera>\" and \"</sera>\",
842 convert the segments between them into FIDEL.
844 If invoked interactively and there is no marker, convert the subject field
845 and the body into FIDEL using `ethio-sera-to-fidel-region'."
848 (let ((buffer-read-only nil)
852 ;; follow RFC822 rules instead of looking for a fixed separator
855 (setq border (point))
857 ;; note that the point is placed at the border
858 (if (or (re-search-forward "^<sera>$" nil t)
860 (goto-char (point-min))
861 (re-search-forward "^Subject: <sera>" border t)))
865 ;; we start with the body so that the border will not change
866 ;; use "^<sera>\n" instead of "^<sera>$" not to leave a blank line
868 (while (re-search-forward "^<sera>\n" nil t)
870 (ethio-sera-to-fidel-region
873 (if (re-search-forward "^</sera>\n" nil 0)
876 ;; now process the subject
877 (goto-char (point-min))
878 (if (re-search-forward "^Subject: <sera>" border t)
879 (ethio-sera-to-fidel-region
880 (progn (delete-backward-char 6) (point))
882 (if (re-search-forward "</sera>$" (line-end-position) 0)
886 ;; in case there are no marks but invoked interactively
889 (ethio-sera-to-fidel-region border (point-max))
890 (goto-char (point-min))
891 (if (re-search-forward "^Subject: " border t)
892 (ethio-sera-to-fidel-region (point) (line-end-position))))))
894 ;; adjust the rmail marker
895 (if (eq major-mode 'rmail-mode)
897 (aref rmail-message-vector (1+ rmail-current-message))
901 (defun ethio-sera-to-fidel-marker (&optional force)
902 "Convert the regions surrounded by \"<sera>\" and \"</sera>\" from SERA to FIDEL.
903 Assume that each region begins with `ethio-primary-language'.
904 The markers \"<sera>\" and \"</sera>\" themselves are not deleted."
906 (if (and buffer-read-only
908 (not (y-or-n-p "Buffer is read-only. Force to convert? ")))
911 (goto-char (point-min))
912 (while (re-search-forward "<sera>" nil t)
913 (ethio-sera-to-fidel-region
915 (if (re-search-forward "</sera>" nil t)
925 (defconst ethio-fidel-to-sera-map
926 [ "he" "hu" "hi" "ha" "hE" "h" "ho" "" ;; 0 - 7
927 "le" "lu" "li" "la" "lE" "l" "lo" "lWa" ;; 8
928 "He" "Hu" "Hi" "Ha" "HE" "H" "Ho" "HWa" ;; 16
929 "me" "mu" "mi" "ma" "mE" "m" "mo" "mWa" ;; 24
930 "`se" "`su" "`si" "`sa" "`sE" "`s" "`so" "`sWa" ;; 32
931 "re" "ru" "ri" "ra" "rE" "r" "ro" "rWa" ;; 40
932 "se" "su" "si" "sa" "sE" "s" "so" "sWa" ;; 48
933 "xe" "xu" "xi" "xa" "xE" "x" "xo" "xWa" ;; 56
934 "qe" "qu" "qi" "qa" "qE" "q" "qo" "" ;; 64
935 "qWe" "" "qWi" "qWa" "qWE" "qW'" "" "" ;; 72
936 "Qe" "Qu" "Qi" "Qa" "QE" "Q" "Qo" "" ;; 80
937 "QWe" "" "QWi" "QWa" "QWE" "QW'" "" "" ;; 88
938 "be" "bu" "bi" "ba" "bE" "b" "bo" "bWa" ;; 96
939 "ve" "vu" "vi" "va" "vE" "v" "vo" "vWa" ;; 104
940 "te" "tu" "ti" "ta" "tE" "t" "to" "tWa" ;; 112
941 "ce" "cu" "ci" "ca" "cE" "c" "co" "cWa" ;; 120
942 "`he" "`hu" "`hi" "`ha" "`hE" "`h" "`ho" "" ;; 128
943 "hWe" "" "hWi" "hWa" "hWE" "hW'" "" "" ;; 136
944 "ne" "nu" "ni" "na" "nE" "n" "no" "nWa" ;; 144
945 "Ne" "Nu" "Ni" "Na" "NE" "N" "No" "NWa" ;; 152
946 "e" "u" "i" "A" "E" "I" "o" "ea" ;; 160
947 "ke" "ku" "ki" "ka" "kE" "k" "ko" "" ;; 168
948 "kWe" "" "kWi" "kWa" "kWE" "kW'" "" "" ;; 176
949 "Ke" "Ku" "Ki" "Ka" "KE" "K" "Ko" "" ;; 184
950 "KWe" "" "KWi" "KWa" "KWE" "KW'" "" "" ;; 192
951 "we" "wu" "wi" "wa" "wE" "w" "wo" "" ;; 200
952 "`e" "`u" "`i" "`a" "`E" "`I" "`o" "" ;; 208
953 "ze" "zu" "zi" "za" "zE" "z" "zo" "zWa" ;; 216
954 "Ze" "Zu" "Zi" "Za" "ZE" "Z" "Zo" "ZWa" ;; 224
955 "ye" "yu" "yi" "ya" "yE" "y" "yo" "yWa" ;; 232
956 "de" "du" "di" "da" "dE" "d" "do" "dWa" ;; 240
957 "De" "Du" "Di" "Da" "DE" "D" "Do" "DWa" ;; 248
958 "je" "ju" "ji" "ja" "jE" "j" "jo" "jWa" ;; 256
959 "ge" "gu" "gi" "ga" "gE" "g" "go" "" ;; 264
960 "gWe" "" "gWi" "gWa" "gWE" "gW'" "" "" ;; 272
961 "Ge" "Gu" "Gi" "Ga" "GE" "G" "Go" "GWa" ;; 280
962 "Te" "Tu" "Ti" "Ta" "TE" "T" "To" "TWa" ;; 288
963 "Ce" "Cu" "Ci" "Ca" "CE" "C" "Co" "CWa" ;; 296
964 "Pe" "Pu" "Pi" "Pa" "PE" "P" "Po" "PWa" ;; 304
965 "Se" "Su" "Si" "Sa" "SE" "S" "So" "SWa" ;; 312
966 "`Se" "`Su" "`Si" "`Sa" "`SE" "`S" "`So" "" ;; 320
967 "fe" "fu" "fi" "fa" "fE" "f" "fo" "fWa" ;; 328
968 "pe" "pu" "pi" "pa" "pE" "p" "po" "pWa" ;; 336
969 "mYa" "rYa" "fYa" "" "" "" "" "" ;; 344
970 " " " : " "::" "," ";" "-:" ":-" "`?" ;; 352
971 ":|:" "1" "2" "3" "4" "5" "6" "7" ;; 360
972 "8" "9" "10" "20" "30" "40" "50" "60" ;; 368
973 "70" "80" "90" "100" "10000" "" "" "" ;; 376
974 "`qe" "`qu" "`qi" "`qa" "`qE" "`q" "`qo" "" ;; 384
975 "mWe" "bWe" "GWe" "fWe" "pWe" "" "" "" ;; 392
976 "`ke" "`ku" "`ki" "`ka" "`kE" "`k" "`ko" "" ;; 400
977 "mWi" "bWi" "GWi" "fWi" "pWi" "" "" "" ;; 408
978 "Xe" "Xu" "Xi" "Xa" "XE" "X" "Xo" "" ;; 416
979 "mWE" "bWE" "GWE" "fWE" "pWE" "" "" "" ;; 424
980 "`ge" "`gu" "`gi" "`ga" "`gE" "`g" "`go" "" ;; 432
981 "mW'" "bW'" "GW'" "fW'" "pW'" "" "" "" ;; 440
982 "\\~X " "\\~e " "\\~E " "\\~a " "\\~A " "wWe" "wWi" "wWa" ;; 448
983 "wWE" "wW'" "''" "`!" "." "<<" ">>" "?" ]) ;; 456
985 (defun ethio-prefer-amharic-p nil
986 (or (eq ethio-primary-language 'amharic)
987 (and (not (eq ethio-primary-language 'tigrigna))
988 (eq ethio-secondary-language 'amharic))))
990 (defun ethio-language-to-flag (lang)
992 ((eq lang 'english) "eng")
993 ((eq lang 'tigrigna) "tir")
994 ((eq lang 'amharic) "amh")
998 (defun ethio-fidel-to-sera-region (begin end &optional secondary force)
999 "Replace all the FIDEL characters in the region to the SERA format.
1000 The variable `ethio-primary-language' specifies the primary
1001 language and `ethio-secondary-language' specifies the secondary.
1003 If the 3dr parameter SECONDARY is given and non-nil, try to convert
1004 the region so that it begins in the secondary language; otherwise with
1005 the primary language.
1007 If the 4th parameter FORCE is given and non-nil, convert even if the
1008 buffer is read-only.
1010 See also the descriptions of the variables
1011 `ethio-use-colon-for-colon', `ethio-use-three-dot-question',
1012 `ethio-quote-vowel-always' and `ethio-numeric-reduction'."
1014 (interactive "r\nP")
1016 (narrow-to-region begin end)
1017 (ethio-fidel-to-sera-buffer secondary force)))
1020 (defun ethio-fidel-to-sera-buffer (&optional secondary force)
1021 "Replace all the FIDEL characters in the current buffer to the SERA format.
1022 The variable `ethio-primary-language' specifies the primary
1023 language and `ethio-secondary-language' specifies the secondary.
1025 If the 1st optional parameter SECONDARY is non-nil, try to convert the
1026 region so that it begins in the secondary language; otherwise with the
1029 If the 2nd optional parameter FORCE is non-nil, convert even if the
1030 buffer is read-only.
1032 See also the descriptions of the variables
1033 `ethio-use-colon-for-colon', `ethio-use-three-dot-question',
1034 `ethio-quote-vowel-always' and `ethio-numeric-reduction'."
1037 (if (and buffer-read-only
1039 (not (y-or-n-p "Buffer is read-only. Force to convert? ")))
1042 (let ((buffer-read-only nil)
1043 (case-fold-search nil)
1044 (lonec nil) ;; t means previous char was a lone consonant
1045 (fidel nil) ;; t means previous char was a FIDEL
1046 (digit nil) ;; t means previous char was an Ethiopic digit
1047 (flag (if (ethio-prefer-amharic-p) "\\~amh " "\\~tir "))
1050 ;; user's preference in transcription
1051 (if ethio-use-colon-for-colon
1053 (aset ethio-fidel-to-sera-map 353 "`:")
1054 (aset ethio-fidel-to-sera-map 357 ":"))
1055 (aset ethio-fidel-to-sera-map 353 " : ")
1056 (aset ethio-fidel-to-sera-map 357 "-:"))
1058 (if ethio-use-three-dot-question
1060 (aset ethio-fidel-to-sera-map 359 "?")
1061 (aset ethio-fidel-to-sera-map 463 "`?"))
1062 (aset ethio-fidel-to-sera-map 359 "`?")
1063 (aset ethio-fidel-to-sera-map 463 "?"))
1067 (aset (aref ethio-fidel-to-sera-map x)
1069 (if ethio-W-sixth-always ?' ?u)))
1070 '(77 93 141 181 197 277 440 441 442 443 444 457))
1072 (if (ethio-prefer-amharic-p)
1073 (aset ethio-fidel-to-sera-map 160 "a")
1074 (aset ethio-fidel-to-sera-map 160 "e"))
1075 ;; end of user's preference
1077 ;; first, decompose geminated characters
1078 (decompose-region (point-min) (point-max))
1080 ;; main conversion routine
1081 (goto-char (point-min))
1083 (setq ch (following-char))
1085 (cond ; ethiopic, english, neutral
1087 ;; ethiopic character. must go to ethiopic mode, if not in it.
1088 ((eq (char-charset ch) 'ethiopic)
1089 (setq ch (ethio-char-to-ethiocode ch))
1091 (if (not (eq mode 'ethiopic))
1094 (setq mode 'ethiopic)))
1096 (cond ; fidel, punc, digit
1099 ((or (<= ch 346) ; he - fYa
1100 (and (>= ch 384) (<= ch 444)) ; `qe - pw
1101 (and (>= ch 453) (<= ch 457))) ; wWe - wW
1102 (if (and (memq ch '(160 161 162 163 164 166 167)) ; (e - ea)
1104 (and ethio-quote-vowel-always
1107 (insert (aref ethio-fidel-to-sera-map ch))
1108 (setq lonec (ethio-lone-consonant-p ch)
1112 ;; punctuations or icons
1113 ((or (and (>= ch 353) (<= ch 360)) ; : - :|:
1114 (>= ch 458) ; '' - ?
1115 (and (>= ch 448) (<= ch 452))) ; \~X \~e \~E \~a \~A
1116 (insert (aref ethio-fidel-to-sera-map ch))
1121 ;; now CH must be an ethiopic digit
1123 ;; reduction = 0 or not preceded by Ethiopic number(s)
1124 ((or (= ethio-numeric-reduction 0)
1126 (insert "`" (aref ethio-fidel-to-sera-map ch))
1131 ;; reduction = 2 and following 10s, 100s, 10000s
1132 ((and (= ethio-numeric-reduction 2)
1133 (memq ch '(370 379 380)))
1134 (insert (substring (aref ethio-fidel-to-sera-map ch) 1))
1139 ;; ordinary following digits
1141 (insert (aref ethio-fidel-to-sera-map ch))
1146 ;; english character. must go to english mode, if not in it.
1147 ((or (and (>= ch ?a) (<= ch ?z))
1148 (and (>= ch ?A) (<= ch ?Z)))
1149 (if (not (eq mode 'english))
1157 ;; ch can appear both in ethiopic section and in english section.
1160 ;; we must decide the mode, if not decided yet
1165 ethio-secondary-language
1166 ethio-primary-language))
1167 (if (eq mode 'english)
1170 (setq mode 'ethiopic)))) ; tigrigna & amharic --> ethiopic
1172 (cond ; \ , eng-mode , punc , w3 , other
1174 ;; backslash is always quoted
1179 ;; nothing to do if in english mode
1183 ;; now we must be in ethiopic mode and seeing a non-"\"
1185 ;; ascii punctuations in ethiopic mode
1186 ((looking-at "[,.;:'`?]+")
1188 (goto-char (1+ (match-end 0)))) ; because we inserted one byte (\)
1190 ;; skip from "<" to ">" (or from "&" to ";") if called from w3
1191 ((and (or (= ch ?<) (= ch ?&))
1192 (or (and (boundp 'ethio-sera-being-called-by-w3)
1193 ethio-sera-being-called-by-w3)
1194 (and (boundp 'sera-being-called-by-w3)
1195 sera-being-called-by-w3)))
1196 (search-forward (if (= ch ?<) ">" ";")
1199 ;; neutral character. no need to quote. just skip it.
1206 ;; end of main conversion routine
1209 (defun ethio-lone-consonant-p (ethiocode)
1210 "If ETHIOCODE is an Ethiopic lone consonant, return t."
1211 (or (and (< ethiocode 344) (= (% ethiocode 8) 5))
1213 ;; `q `k X `g mW bW GW fW pW wW
1214 (memq ethiocode '(389 405 421 437 440 441 442 443 444 457))))
1217 (defun ethio-fidel-to-sera-mail-or-marker (&optional arg)
1218 "Execute `ethio-fidel-to-sera-mail' or `ethio-fidel-to-sera-marker' depending on the current major mode.
1219 If in rmail-mode or in mail-mode, execute the former; otherwise latter."
1222 (if (or (eq major-mode 'rmail-mode)
1223 (eq major-mode 'mail-mode))
1224 (ethio-fidel-to-sera-mail)
1225 (ethio-fidel-to-sera-marker arg)))
1228 (defun ethio-fidel-to-sera-mail nil
1229 "Convert FIDEL to SERA to read/write mail and news.
1231 If the body contains at least one Ethiopic character,
1232 1) insert the string \"<sera>\" at the beginning of the body,
1233 2) insert \"</sera>\" at the end of the body, and
1234 3) convert the body into SERA.
1236 The very same procedure applies to the subject field, too."
1239 (let ((buffer-read-only nil)
1243 ;; follow RFC822 rules instead of looking for a fixed separator
1246 (setq border (point))
1248 ;; process body first not to change the border
1249 ;; note that the point is already at the border
1250 (if (re-search-forward "\\ce" nil t)
1252 (ethio-fidel-to-sera-region border (point-max))
1255 (goto-char (point-max))
1256 (insert "</sera>")))
1259 (goto-char (point-min))
1260 (if (re-search-forward "^Subject: " border t)
1262 (end (line-end-position)))
1263 (if (re-search-forward "\\ce" end t)
1265 (ethio-fidel-to-sera-region beg end)
1269 (insert "</sera>")))))
1271 ;; adjust the rmail marker
1272 (if (eq major-mode 'rmail-mode)
1274 (aref rmail-message-vector (1+ rmail-current-message))
1278 (defun ethio-fidel-to-sera-marker (&optional force)
1279 "Convert the regions surrounded by \"<sera>\" and \"</sera>\" from FIDEL to SERA.
1280 The markers \"<sera>\" and \"</sera>\" themselves are not deleted."
1283 (if (and buffer-read-only
1285 (not (y-or-n-p "Buffer is read-only. Force to convert? ")))
1288 (goto-char (point-min))
1289 (while (re-search-forward "<sera>" nil t)
1290 (ethio-fidel-to-sera-region
1292 (if (re-search-forward "</sera>" nil t)
1299 ;; vowel modification
1303 (defun ethio-modify-vowel nil
1304 "Modify the vowel of the FIDEL that is under the cursor."
1306 (let ((ch (following-char))
1307 (composite nil) ; geminated or not
1308 newch base vowel modulo)
1311 ;; in case of gemination
1312 ((eq (char-charset ch) 'composition)
1313 (setq ch (string-to-char (char-to-string ch))
1315 ;; neither gemination nor fidel
1316 ((not (eq (char-charset ch) 'ethiopic))
1317 (error "Not a valid character")))
1319 ;; set frequently referred character features
1320 (setq ch (ethio-char-to-ethiocode ch)
1324 (if (or (and (>= ch 344) (<= ch 380)) ;; mYa - `10000
1325 (and (>= ch 448) (<= ch 452)) ;; \~X - \~A
1326 (>= ch 458)) ;; private punctuations
1327 (error "Not a valid character"))
1333 ;; first standalone vowels
1335 (if (ethio-prefer-amharic-p)
1336 (message "Modify vowel to: [auiAEIoW\"] ")
1337 (message "Modify vowel to: [euiAEIoW\"] "))
1338 (setq vowel (read-char))
1348 ((= vowel ?a) (if (ethio-prefer-amharic-p) 160 163))
1349 ((= vowel ?\") (setq composite t) ch)
1352 ;; second standalone vowels
1354 (message "Modify vowel to: [euiaEIo\"] ")
1355 (setq vowel (read-char))
1364 ((= vowel ?\") (setq composite t) ch)
1367 ;; 12-form consonants, *W* form
1368 ((memq base '(72 88 136 176 192 272)) ; qW QW hW kW KW gW
1369 (message "Modify vowel to: [euiaE'\"] ")
1370 (setq vowel (read-char))
1373 ((= vowel ?u) (+ base 5))
1374 ((= vowel ?i) (+ base 2))
1375 ((= vowel ?a) (+ base 3))
1376 ((= vowel ?E) (+ base 4))
1377 ((= vowel ?') (+ base 5))
1378 ((= vowel ?\") (setq composite t) ch)
1381 ;; extended 12-form consonants, mWa bWa GWa fWa pWa
1383 (message "Modify vowel to: [euiaE'\"] ")
1384 (setq vowel (read-char))
1392 ((= vowel ?\") (setq composite t) ch)
1395 (message "Modify vowel to: [euiaE'\"] ")
1396 (setq vowel (read-char))
1404 ((= vowel ?\") (setq composite t) ch)
1407 (message "Modify vowel to: [euiaE'\"] ")
1408 (setq vowel (read-char))
1416 ((= vowel ?\") (setq composite t) ch)
1419 (message "Modify vowel to: [euiaE'\"] ")
1420 (setq vowel (read-char))
1428 ((= vowel ?\") (setq composite t) ch)
1431 (message "Modify vowel to: [euiaE'\"] ")
1432 (setq vowel (read-char))
1440 ((= vowel ?\") (setq composite t) ch)
1443 ;; extended 12-form consonatns, mW* bW* GW* fW* pW*
1444 ((memq base '(392 408 424 440)) ; *We *Wi *WE *W
1445 (message "Modify vowel to: [eiEau'\"] ")
1446 (setq vowel (read-char))
1448 ((= vowel ?e) (+ 392 modulo))
1449 ((= vowel ?i) (+ 408 modulo))
1450 ((= vowel ?E) (+ 424 modulo))
1452 ((= modulo 0) 31) ; mWa
1453 ((= modulo 1) 103) ; bWa
1454 ((= modulo 2) 287) ; GWa
1455 ((= modulo 3) 335) ; fWa
1456 ((= modulo 4) 343) ; pWa
1457 (t nil))) ; never reach here
1458 ((= vowel ?') (+ 440 modulo))
1459 ((= vowel ?u) (+ 440 modulo))
1460 ((= vowel ?\") (setq composite t) ch)
1463 ((and (>= ch 453) (<= ch 457)) ; wWe wWi wWa wWE wW
1464 (message "Modify vowel to: [eiaE'u\"] ")
1465 (setq vowel (read-char))
1473 ((= vowel ?\") (setq composite t) ch)
1476 ;; 7-form consonants, or
1477 ;; first 7 of 8-form consonants
1479 (message "Modify vowel to: [euiaE'o\"] ")
1480 (setq vowel (read-char))
1483 ((= vowel ?u) (+ base 1))
1484 ((= vowel ?i) (+ base 2))
1485 ((= vowel ?a) (+ base 3))
1486 ((= vowel ?E) (+ base 4))
1487 ((= vowel ?') (+ base 5))
1488 ((= vowel ?o) (+ base 6))
1489 ((= vowel ?\") (setq composite t) ch)
1498 ;; could not get new character
1500 (error "Invalid vowel"))
1502 ;; vowel changed on a composite Fidel
1507 (concat (char-to-string (ethio-ethiocode-to-char newch)) "\e$(3%s\e(B"))))
1509 ;; simple vowel modification
1512 (insert (ethio-ethiocode-to-char newch))))))
1514 (defun ethio-ethiocode-to-char (ethiocode)
1517 (+ (/ ethiocode 94) 33)
1518 (+ (mod ethiocode 94) 33)))
1520 (defun ethio-char-to-ethiocode (ch)
1521 (and (eq (char-charset ch) 'ethiopic)
1522 (let ((char-components (split-char ch)))
1523 (+ (* (- (nth 1 char-components) 33) 94)
1524 (- (nth 2 char-components) 33)))))
1527 ;; space replacement
1531 (defun ethio-replace-space (ch begin end)
1532 "Replace ASCII spaces with Ethiopic word separators in the region.
1534 In the specified region, replace word separators surrounded by two
1535 Ethiopic characters, depending on the first parameter CH, which should
1538 If CH = 1, word separator will be replaced with an ASCII space.
1539 If CH = 2, with two ASCII spaces.
1540 If CH = 3, with the Ethiopic colon-like word separator.
1542 The second and third parameters BEGIN and END specify the region."
1544 (interactive "*cReplace spaces to: 1 (sg col), 2 (dbl col), 3 (Ethiopic)\nr")
1545 (if (not (memq ch '(?1 ?2 ?3)))
1549 (narrow-to-region begin end)
1553 ;; an Ethiopic word separator --> an ASCII space
1554 (goto-char (point-min))
1555 (while (search-forward "\e$(3$h\e(B" nil t)
1556 (replace-match " " nil t))
1558 ;; two ASCII spaces between Ethiopic characters --> an ASCII space
1559 (goto-char (point-min))
1560 (while (re-search-forward "\\(\\ce\\) \\(\\ce\\)" nil t)
1561 (replace-match "\\1 \\2")
1562 (goto-char (match-beginning 2))))
1565 ;; An Ethiopic word separator --> two ASCII spaces
1566 (goto-char (point-min))
1567 (while (search-forward "\e$(3$h\e(B" nil t)
1568 (replace-match " "))
1570 ;; An ASCII space between Ethiopic characters --> two ASCII spaces
1571 (goto-char (point-min))
1572 (while (re-search-forward "\\(\\ce\\) \\(\\ce\\)" nil t)
1573 (replace-match "\\1 \\2")
1574 (goto-char (match-beginning 2))))
1577 ;; One or two ASCII spaces between Ethiopic characters
1578 ;; --> An Ethiopic word separator
1579 (goto-char (point-min))
1580 (while (re-search-forward "\\(\\ce\\) ?\\(\\ce\\)" nil t)
1581 (replace-match "\\1\e$(3$h\e(B\\2")
1582 (goto-char (match-beginning 2)))
1584 ;; Three or more ASCII spaces between Ethiopic characters
1585 ;; --> An Ethiopic word separator + (N - 2) ASCII spaces
1586 (goto-char (point-min))
1587 (while (re-search-forward "\\(\\ce\\) \\( *\\ce\\)" nil t)
1588 (replace-match "\\1\e$(3$h\e(B\\2")
1589 (goto-char (match-beginning 2))))))))
1596 (defun ethio-input-special-character (arg)
1597 "Allow the user to input special characters."
1598 (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")
1601 (insert "\e$(3%j\e(B"))
1603 (insert "\e$(3%k\e(B"))
1605 (insert "\e$(3%l\e(B"))
1607 (insert "\e$(3%m\e(B"))
1609 (insert "\e$(3%i\e(B"))
1617 (defconst ethio-fidel-to-tex-map
1618 [ "heG" "huG" "hiG" "haG" "hEG" "hG" "hoG" "" ;; 0 - 7
1619 "leG" "luG" "liG" "laG" "lEG" "lG" "loG" "lWaG" ;; 8
1620 "HeG" "HuG" "HiG" "HaG" "HEG" "HG" "HoG" "HWaG" ;; 16
1621 "meG" "muG" "miG" "maG" "mEG" "mG" "moG" "mWaG" ;; 24
1622 "sseG" "ssuG" "ssiG" "ssaG" "ssEG" "ssG" "ssoG" "ssWaG" ;; 32
1623 "reG" "ruG" "riG" "raG" "rEG" "rG" "roG" "rWaG" ;; 40
1624 "seG" "suG" "siG" "saG" "sEG" "sG" "soG" "sWaG" ;; 48
1625 "xeG" "xuG" "xiG" "xaG" "xEG" "xG" "xoG" "xWaG" ;; 56
1626 "qeG" "quG" "qiG" "qaG" "qEG" "qG" "qoG" "" ;; 64
1627 "qWeG" "" "qWiG" "qWaG" "qWEG" "qWG" "" "" ;; 72
1628 "QeG" "QuG" "QiG" "QaG" "QEG" "QG" "QoG" "" ;; 80
1629 "QWeG" "" "QWiG" "QWaG" "QWEG" "QWG" "" "" ;; 88
1630 "beG" "buG" "biG" "baG" "bEG" "bG" "boG" "bWaG" ;; 96
1631 "veG" "vuG" "viG" "vaG" "vEG" "vG" "voG" "vWaG" ;; 104
1632 "teG" "tuG" "tiG" "taG" "tEG" "tG" "toG" "tWaG" ;; 112
1633 "ceG" "cuG" "ciG" "caG" "cEG" "cG" "coG" "cWaG" ;; 120
1634 "hheG" "hhuG" "hhiG" "hhaG" "hhEG" "hhG" "hhoG" "" ;; 128
1635 "hWeG" "" "hWiG" "hWaG" "hWEG" "hWG" "" "" ;; 136
1636 "neG" "nuG" "niG" "naG" "nEG" "nG" "noG" "nWaG" ;; 144
1637 "NeG" "NuG" "NiG" "NaG" "NEG" "NG" "NoG" "NWaG" ;; 152
1638 "eG" "uG" "iG" "AG" "EG" "IG" "oG" "eaG" ;; 160
1639 "keG" "kuG" "kiG" "kaG" "kEG" "kG" "koG" "" ;; 168
1640 "kWeG" "" "kWiG" "kWaG" "kWEG" "kWG" "" "" ;; 176
1641 "KeG" "KuG" "KiG" "KaG" "KEG" "KG" "KoG" "" ;; 184
1642 "KWeG" "" "KWiG" "KWaG" "KWEG" "KWG" "" "" ;; 192
1643 "weG" "wuG" "wiG" "waG" "wEG" "wG" "woG" "" ;; 200
1644 "eeG" "uuG" "iiG" "aaG" "EEG" "IIG" "ooG" "" ;; 208
1645 "zeG" "zuG" "ziG" "zaG" "zEG" "zG" "zoG" "zWaG" ;; 216
1646 "ZeG" "ZuG" "ZiG" "ZaG" "ZEG" "ZG" "ZoG" "ZWaG" ;; 224
1647 "yeG" "yuG" "yiG" "yaG" "yEG" "yG" "yoG" "yWaG" ;; 232
1648 "deG" "duG" "diG" "daG" "dEG" "dG" "doG" "dWaG" ;; 240
1649 "DeG" "DuG" "DiG" "DaG" "DEG" "DG" "DoG" "DWaG" ;; 248
1650 "jeG" "juG" "jiG" "jaG" "jEG" "jG" "joG" "jWaG" ;; 256
1651 "geG" "guG" "giG" "gaG" "gEG" "gG" "goG" "" ;; 264
1652 "gWeG" "" "gWiG" "gWaG" "gWEG" "gWG" "" "" ;; 272
1653 "GeG" "GuG" "GiG" "GaG" "GEG" "GG" "GoG" "GWaG" ;; 280
1654 "TeG" "TuG" "TiG" "TaG" "TEG" "TG" "ToG" "TWaG" ;; 288
1655 "CeG" "CuG" "CiG" "CaG" "CEG" "CG" "CoG" "CWaG" ;; 296
1656 "PeG" "PuG" "PiG" "PaG" "PEG" "PG" "PoG" "PWaG" ;; 304
1657 "SeG" "SuG" "SiG" "SaG" "SEG" "SG" "SoG" "SWaG" ;; 312
1658 "SSeG" "SSuG" "SSiG" "SSaG" "SSEG" "SSG" "SSoG" "" ;; 320
1659 "feG" "fuG" "fiG" "faG" "fEG" "fG" "foG" "fWaG" ;; 328
1660 "peG" "puG" "piG" "paG" "pEG" "pG" "poG" "pWaG" ;; 336
1661 "mYaG" "rYaG" "fYaG" "" "" "" "" "" ;; 344
1662 "" "spaceG" "periodG" "commaG" ;; 352
1663 "semicolonG" "colonG" "precolonG" "oldqmarkG" ;; 356
1664 "pbreakG" "andG" "huletG" "sostG" "aratG" "amstG" "sadstG" "sabatG" ;; 360
1665 "smntG" "zeteNG" "asrG" "heyaG" "selasaG" "arbaG" "hemsaG" "slsaG" ;; 368
1666 "sebaG" "semanyaG" "zeTanaG" "metoG" "asrxiG" "" "" "" ;; 376
1667 "qqeG" "qquG" "qqiG" "qqaG" "qqEG" "qqG" "qqoG" "" ;; 384
1668 "mWeG" "bWeG" "GWeG" "fWeG" "pWeG" "" "" "" ;; 392
1669 "kkeG" "kkuG" "kkiG" "kkaG" "kkEG" "kkG" "kkoG" "" ;; 400
1670 "mWiG" "bWiG" "GWiG" "fWiG" "pWiG" "" "" "" ;; 408
1671 "XeG" "XuG" "GXiG" "XaG" "XEG" "XG" "XoG" "" ;; 416
1672 "mWEG" "bWEG" "GWEG" "fWEG" "pWEG" "" "" "" ;; 424
1673 "ggeG" "gguG" "ggiG" "ggaG" "ggEG" "ggG" "ggoG" "" ;; 432
1674 "mWG" "bWG" "GWG" "fWG" "pWG" "" "" "" ;; 440
1675 "ornamentG" "flandG" "iflandG" "africaG" ;; 448
1676 "iafricaG" "wWeG" "wWiG" "wWaG" ;; 452
1677 "wWEG" "wWG" "" "slaqG" "dotG" "lquoteG" "rquoteG" "qmarkG" ]) ;; 456
1680 ;; To make tex-to-fidel mapping.
1681 ;; The following code makes
1682 ;; (get 'ethio-tex-command-he 'ethio-fidel-char) ==> ?\e$(3!!\e(B
1687 (while (< i (length ethio-fidel-to-tex-map))
1688 (setq str (aref ethio-fidel-to-tex-map i))
1689 (if (not (string= str ""))
1691 (intern (concat "ethio-tex-command-" (aref ethio-fidel-to-tex-map i)))
1693 (ethio-ethiocode-to-char i)))
1697 (defun ethio-fidel-to-tex-buffer nil
1698 "Convert each fidel characters in the current buffer into a fidel-tex command.
1699 Each command is always surrounded by braces."
1701 (let ((buffer-read-only nil))
1703 ;; Isolated gemination marks need special treatement
1704 (goto-char (point-min))
1705 (while (search-forward "\e$(3%s\e(B" nil t)
1706 (replace-match "\\geminateG{}" t t))
1708 ;; First, decompose geminations
1709 ;; Here we assume that each composed character consists of
1710 ;; one Ethiopic character and the Ethiopic gemination mark.
1711 (decompose-region (point-min) (point-max))
1713 ;; Special treatment for geminated characters
1714 ;; The geminated character (la'') will be "\geminateG{\la}".
1715 (goto-char (point-min))
1716 (while (search-forward "\e$(3%s\e(B" nil t)
1717 (delete-backward-char 1)
1719 (insert "\\geminateG")
1722 ;; Ethiopic characters to TeX macros
1723 (goto-char (point-min))
1724 (while (re-search-forward "\\ce" nil t)
1727 (aref ethio-fidel-to-tex-map
1728 (prog1 (ethio-char-to-ethiocode (preceding-char))
1729 (backward-delete-char 1)))
1731 (goto-char (point-min))
1732 (set-buffer-modified-p nil)))
1735 (defun ethio-tex-to-fidel-buffer nil
1736 "Convert fidel-tex commands in the current buffer into fidel chars."
1738 (let ((buffer-read-only nil)
1741 ;; Special treatment for gemination
1742 ;; "\geminateG{\la}" or "\geminateG{{\la}}" will be "\la\e$(3%s\e(B"
1743 ;; "\geminateG{}" remains unchanged.
1744 (goto-char (point-min))
1745 (while (re-search-forward "\\\\geminateG{\\(\\\\[a-zA-Z]+\\)}" nil t)
1746 (replace-match "\\1\e$(3%s\e(B"))
1748 ;; TeX macros to Ethiopic characters
1749 (goto-char (point-min))
1750 (while (search-forward "\\" nil t)
1752 (skip-chars-forward "a-zA-Z")
1754 (get (intern (concat "ethio-tex-command-"
1755 (buffer-substring p (point))))
1759 (delete-region (1- p) (point)) ; don't forget the preceding "\"
1760 (if (and (= (preceding-char) ?{)
1761 (= (following-char) ?}))
1763 (backward-delete-char 1)
1767 ;; compose geminated characters
1768 (goto-char (point-min))
1769 (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
1771 (save-excursion (backward-char 2) (point))
1774 ;; Now it's time to convert isolated gemination marks.
1775 (goto-char (point-min))
1776 (while (search-forward "\\geminateG{}" nil t)
1777 (replace-match "\e$(3%s\e(B"))
1779 (goto-char (point-min))
1780 (set-buffer-modified-p nil)))
1787 (defun ethio-fidel-to-java-buffer nil
1788 "Convert Ethiopic characters into the Java escape sequences.
1790 Each escape sequence is of the form \\uXXXX, where XXXX is the
1791 character's codepoint (in hex) in Unicode.
1793 If `ethio-java-save-lowercase' is non-nil, use [0-9a-f].
1794 Otherwise, [0-9A-F]."
1797 ;; first, decompose geminations
1798 (decompose-region (point-min) (point-max))
1800 (goto-char (point-min))
1801 (while (re-search-forward "\\ce" nil t)
1802 (setq ucode (+ ?\x1200 (ethio-char-to-ethiocode (preceding-char))))
1803 (if (> ucode ?\x13bc)
1804 (setq ucode (+ ucode 59952)))
1805 (delete-backward-char 1)
1806 (if ethio-java-save-lowercase
1807 (insert (format "\\u%4x" ucode))
1808 (insert (upcase (format "\\u%4x" ucode)))))))
1811 (defun ethio-java-to-fidel-buffer nil
1812 "Convert the Java escape sequences into corresponding Ethiopic characters."
1814 (goto-char (point-min))
1815 (while (re-search-forward "\\\\u\\([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]\\)" nil t)
1820 (buffer-substring (match-beginning 1) (match-end 1)))))
1822 ((and (>= ucode ?\x1200) (<= ucode ?\x13bc))
1824 (insert (ethio-ethiocode-to-char (- ucode ?\x1200))))
1825 ((and (>= ucode ?\xfdf1) (<= ucode ?\xfdff))
1827 (insert (ethio-ethiocode-to-char (- ucode 64560))))
1832 (goto-char (point-min))
1833 (while (re-search-forward "\\ce\e$(3%s\e(B" nil 0)
1835 (save-excursion (backward-char 2) (point))
1844 (defun ethio-find-file nil
1845 "Transcribe file content into Ethiopic depending on filename suffix."
1848 ((string-match "\\.sera$" (buffer-file-name))
1850 (ethio-sera-to-fidel-buffer nil 'force)
1851 (set-buffer-modified-p nil)))
1853 ((string-match "\\.html$" (buffer-file-name))
1854 (let ((ethio-sera-being-called-by-w3 t))
1856 (ethio-sera-to-fidel-marker 'force)
1857 (goto-char (point-min))
1858 (while (re-search-forward "&[lr]aquote;" nil t)
1859 (if (= (char-after (1+ (match-beginning 0))) ?l)
1860 (replace-match "\e$(3%v\e(B")
1861 (replace-match "\e$(3%w\e(B")))
1862 (set-buffer-modified-p nil))))
1864 ((string-match "\\.tex$" (buffer-file-name))
1866 (ethio-tex-to-fidel-buffer)
1867 (set-buffer-modified-p nil)))
1869 ((string-match "\\.java$" (buffer-file-name))
1871 (ethio-java-to-fidel-buffer)
1872 (set-buffer-modified-p nil)))
1878 (defun ethio-write-file nil
1879 "Transcribe Ethiopic characters in ASCII depending on the file extension."
1882 ((string-match "\\.sera$" (buffer-file-name))
1884 (ethio-fidel-to-sera-buffer nil 'force)
1885 (goto-char (point-min))
1886 (ethio-record-user-preference)
1887 (set-buffer-modified-p nil)))
1889 ((string-match "\\.html$" (buffer-file-name))
1891 (let ((ethio-sera-being-called-by-w3 t)
1892 (lq (aref ethio-fidel-to-sera-map 461))
1893 (rq (aref ethio-fidel-to-sera-map 462)))
1894 (aset ethio-fidel-to-sera-map 461 "«te;")
1895 (aset ethio-fidel-to-sera-map 462 "»te;")
1896 (ethio-fidel-to-sera-marker 'force)
1897 (goto-char (point-min))
1898 (if (search-forward "<sera>" nil t)
1899 (ethio-record-user-preference))
1900 (aset ethio-fidel-to-sera-map 461 lq)
1901 (aset ethio-fidel-to-sera-map 462 rq)
1902 (set-buffer-modified-p nil))))
1904 ((string-match "\\.tex$" (buffer-file-name))
1906 (ethio-fidel-to-tex-buffer)
1907 (set-buffer-modified-p nil)))
1909 ((string-match "\\.java$" (buffer-file-name))
1911 (ethio-fidel-to-java-buffer)
1912 (set-buffer-modified-p nil)))
1917 (defun ethio-record-user-preference nil
1918 (if (looking-at "\\\\~\\(tir?\\|amh?\\) ")
1919 (goto-char (match-end 0))
1920 (insert (if (ethio-prefer-amharic-p) "\\~amh " "\\~tir ")))
1921 (insert (if ethio-use-colon-for-colon "\\~-: " "\\~`: ")
1922 (if ethio-use-three-dot-question "\\~`| " "\\~`? ")))
1925 ;; Ethiopic word separator vs. ASCII space
1928 (defvar ethio-prefer-ascii-space t)
1929 (make-variable-buffer-local 'ethio-prefer-ascii-space)
1931 (defun ethio-toggle-space nil
1932 "Toggle ASCII space and Ethiopic separator for keyboard input."
1934 (setq ethio-prefer-ascii-space
1935 (not ethio-prefer-ascii-space))
1936 (if (equal current-input-method "ethiopic")
1937 (setq current-input-method-title (quail-title)))
1938 (force-mode-line-update))
1940 (defun ethio-insert-space (arg)
1941 "Insert ASCII spaces or Ethiopic word separators depending on context.
1943 If the current word separator (indicated in mode-line) is the ASCII space,
1944 insert an ASCII space. With ARG, insert that many ASCII spaces.
1946 If the current word separator is the colon-like Ethiopic word
1947 separator and the point is preceded by `an Ethiopic punctuation mark
1948 followed by zero or more ASCII spaces', then insert also an ASCII
1949 space. With ARG, insert that many ASCII spaces.
1951 Otherwise, insert a colon-like Ethiopic word separator. With ARG, insert that
1952 many Ethiopic word separators."
1956 (ethio-prefer-ascii-space
1957 (insert-char 32 arg))
1959 (skip-chars-backward " ")
1960 (memq (preceding-char)
1961 '(?\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)))
1962 (insert-char 32 arg))
1964 (insert-char ?\e$(3$h\e(B arg))))
1966 (defun ethio-insert-ethio-space (arg)
1967 "Insert the Ethiopic word delimiter (the colon-like character).
1968 With ARG, insert that many delimiters."
1970 (insert-char ?\e$(3$h\e(B arg))
1973 ;; Ethiopic punctuation vs. ASCII punctuation
1976 (defvar ethio-prefer-ascii-punctuation nil)
1977 (make-variable-buffer-local 'ethio-prefer-ascii-punctuation)
1979 (defun ethio-toggle-punctuation nil
1980 "Toggle Ethiopic punctuations and ASCII punctuations for keyboard input."
1982 (setq ethio-prefer-ascii-punctuation
1983 (not ethio-prefer-ascii-punctuation))
1984 (let* ((keys '("." ".." "..." "," ",," ";" ";;" ":" "::" ":::" "*" "**"))
1986 (if ethio-prefer-ascii-punctuation
1987 '(?. [".."] ["..."] ?, [",,"] ?\; [";;"] ?: ["::"] [":::"] ?* ["**"])
1988 '(?\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))))
1990 (quail-defrule (car keys) (car puncs) "ethiopic")
1991 (setq keys (cdr keys)
1993 (if (equal current-input-method "ethiopic")
1994 (setq current-input-method-title (quail-title)))
1995 (force-mode-line-update)))
2001 (defun ethio-gemination nil
2002 "Compose the character before the point with the Ethiopic gemination mark.
2003 If the character is already composed, decompose it and remove the gemination
2007 ((eq (char-charset (preceding-char)) 'ethiopic)
2008 (insert "\e$(3%s\e(B")
2010 (save-excursion (backward-char 2) (point))
2013 ((eq (char-charset (preceding-char)) 'leading-code-composition)
2015 (save-excursion (backward-char 1) (point))
2017 (delete-backward-char 1))
2022 (provide 'ethio-util)
2024 ;;; arch-tag: c8feb3d6-39bf-4b0a-b6ef-26f03fbc8140
2025 ;;; ethio-util.el ends here