(integer_value): Fix typo ('>' -> '<') and calculation of length
[m17n/m17n-lib.git] / src / input.c
1 /* input.c -- input method module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nInputMethod
25     @brief API for Input method.
26
27     An input method is an object to enable inputting various
28     characters.  An input method is identified by a pair of symbols,
29     LANGUAGE and NAME.  This pair decides a input method driver of the
30     input method.  An input method driver is a set of functions for
31     handling the input method.  There are two kinds of input methods;
32     internal one and foreign one.
33
34     <ul>
35     <li> Internal Input Method
36
37     An internal input method has non @c Mnil LANGUAGE, and the body is
38     defined in the m17n database by the tag <Minput_method, LANGUAGE,
39     NAME>.  For this kind of input methods, the m17n library uses two
40     predefined input method drivers, one for CUI use and the other for
41     GUI use.  Those driver utilize the input processing engine
42     provided by the m17n library itself.  The m17n database may
43     provides an input method that is not only for a specific language.
44     The database uses @c Mt as LANGUAGE of such an input method.
45
46     An internal input method accepts an input key which is a symbol
47     associated with an input event.  As there is no way for the @c
48     m17n @c library to know how input events are represented in an
49     application program, an application programmer have to convert an
50     input event to an input key by himself.  See the documentation of
51     the function minput_event_to_key () for the detail.
52
53     <li> Foreign Input Method
54
55     A foreign input method has @c Mnil LANGUAGE, and the body is
56     defined in an external resources (e.g. XIM of X Window System).
57     For this kind of input methods, the symbol NAME must have a
58     property of key @c Minput_driver, and the value must be a pointer
59     to an input method driver.  Therefore, by preparing a proper
60     driver, any kind of input method can be treated in the framework
61     of the @c m17n @c library.
62
63     For convenience, the m17n-X library provides an input method
64     driver that enables the input style of OverTheSpot for XIM, and
65     stores @c Minput_driver property of the symbol @c Mxim with a
66     pointer to the driver.  See the documentation of m17n GUI API for
67     the detail.
68
69     </ul>
70
71     PROCESSING FLOW
72
73     The typical processing flow of handling an input method is: 
74
75      @li open an input method
76      @li create an input context for the input method
77      @li filter an input key
78      @li look up a produced text in the input context  */
79
80 /*=*/
81 /***ja
82     @addtogroup m17nInputMethod
83     @brief ÆþÎϥ᥽¥Ã¥ÉÍÑAPI.
84
85     ÆþÎϥ᥽¥Ã¥É¤Ï¿ÍͤÊʸ»ú¤òÆþÎϤ¹¤ë¤¿¤á¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£ÆþÎÏ¥á
86     ¥½¥Ã¥É¤Ï¥·¥ó¥Ü¥ë LANGUAGE ¤È NAME ¤ÎÁȤˤè¤Ã¤Æ¼±Ê̤µ¤ì¡¢¤³¤ÎÁȤˤè¤Ã
87     ¤ÆÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤¬·è¤Þ¤ë¡£ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤È¤Ï¤¢¤ëÆþÎÏ¥á
88     ¥½¥Ã¥É¤ò°·¤¦¤¿¤á¤Î´Ø¿ô¤Î½¸¤Þ¤ê¤Ç¤¢¤ë¡£ ÆþÎϥ᥽¥Ã¥É¤Ë¤ÏÆâÉô¥á¥½¥Ã
89     ¥É¤È³°Éô¥á¥½¥Ã¥É¤ÎÆóÄ̤꤬¤¢¤ë¡£
90
91     <ul> 
92     <li> ÆâÉôÆþÎϥ᥽¥Ã¥É
93
94     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï LANGUAGE ¤¬ @c Mnil °Ê³°¤Î¤â¤Î¤Ç¤¢¤ê¡¢ËÜÂΤÏ
95     m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë <Minput_method, LANGUAGE, NAME>¤È¤¤¤¦¥¿¥°ÉÕ¤­
96     ¤ÇÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤ËÂФ·¤Æ¡¢m17n ¥é¥¤¥Ö¥é¥ê¤Ë
97     ¤ÏCUIÍѤÈGUIÍѤ½¤ì¤¾¤ì¤ÎÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤¬¤¢¤é¤«¤¸¤á½àÈ÷¤µ¤ì¤Æ
98     ¤¤¤ë¡£¤³¤ì¤é¤Î¥É¥é¥¤¥Ð¤Ïm17n¥é¥¤¥Ö¥é¥ê¼«¿È¤ÎÆþÎϽèÍý¥¨¥ó¥¸¥ó¤òÍøÍÑ
99     ¤¹¤ë¡£m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤Ï¡¢ÆÃÄê¤Î¸À¸ìÀìÍѤǤʤ¤ÆþÎϥ᥽¥Ã¥É¤âÄê
100     µÁ¤¹¤ë¤³¤È¤¬¤Ç¤­¡¢¤½¤Î¤è¤¦¤ÊÆþÎϥ᥽¥Ã¥É¤Î LANGUAGE ¤Ï @c Mt ¤Ç¤¢
101     ¤ë¡£
102
103     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï¡¢¥æ¡¼¥¶¤ÎÆþÎÏ¥¤¥Ù¥ó¥È¤ËÂбþ¤·¤¿¥·¥ó¥Ü¥ë¤Ç¤¢¤ëÆþ
104     ÎÏ¥­¡¼¤ò¼õ¤±¼è¤ë¡£@c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÏÆþÎÏ¥¤¥Ù¥ó¥È¤¬¥¢¥×¥ê¥±¡¼
105     ¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ç¤É¤¦É½¸½¤µ¤ì¤Æ¤¤¤ë¤«¤òÃΤë½Ñ¤ò»ý¤¿¤Ê¤¤¤Î¤Ç¡¢ÆþÎÏ
106     ¥¤¥Ù¥ó¥È¤«¤éÆþÎÏ¥­¡¼¤Ø¤ÎÊÑ´¹¤Ï¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥Þ¤ÎÀÕǤ¤Ç¹Ô
107     ¤ï¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï´Ø¿ô minput_event_to_key () ¤ÎÀâ
108     ÌÀ¤ò»²¾È¡£
109
110     <li> ³°ÉôÆþÎϥ᥽¥Ã¥É
111
112     ³°ÉôÆþÎϥ᥽¥Ã¥É¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢ËÜÂΤϳ°Éô¤Î
113     ¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê¤É¡£) 
114     ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï@c Minput_driver ¤ò¥­¡¼
115     ¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç
116     ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤·¤¿¤¬¤Ã¤Æ¡¢Å¬Àڤʥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢
117     ¤¤¤«¤Ê¤ë¼ïÎà¤ÎÆþÎϥ᥽¥Ã¥É¤â @c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÎÏÈÁȤÎÃæ¤Ç°·
118     ¤¦»ö¤¬¤Ç¤­¤ë¡£
119
120     ÍøÊØÀ­¤Î¤¿¤á¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤Ï XIM ¤Î OverTheSpot ¤ÎÆþÎÏ¥¹¥¿¥¤¥ë
121     ¤ò¼Â¸½¤¹¤ëÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤òÄ󶡤·¡¢¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î @c
122     Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý¤·
123     ¤Æ¤¤¤ë¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï m17n GUI API ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
124
125     </ul> 
126
127     ½èÍý¤Îή¤ì
128
129     ÆþÎϥ᥽¥Ã¥É½èÍý¤Îŵ·¿Åª¤Ê½èÍý¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
130     
131     @li ÆþÎϥ᥽¥Ã¥É¤Î¥ª¡¼¥×¥ó
132     @li ¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ÎÀ¸À®
133     @li ÆþÎÏ¥¤¥Ù¥ó¥È¤Î¥Õ¥£¥ë¥¿
134     @li ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ç¤ÎÀ¸À®¥Æ¥­¥¹¥È¤Î¸¡º÷     */
135
136 /*=*/
137
138 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
139 /*** @addtogroup m17nInternal
140      @{ */
141
142 #include <stdio.h>
143 #include <string.h>
144
145 #include "config.h"
146
147 #ifdef HAVE_DLFCN_H
148 #include <dlfcn.h>
149 #endif
150
151 #include "m17n-gui.h"
152 #include "m17n-misc.h"
153 #include "internal.h"
154 #include "mtext.h"
155 #include "input.h"
156 #include "symbol.h"
157 #include "plist.h"
158
159 static int mdebug_mask = MDEBUG_INPUT;
160
161 static MSymbol Minput_method;
162
163 /** Symbols to load an input method data.  */
164 static MSymbol Mtitle, Mmacro, Mmodule, Mstate;
165
166 /** Symbols for actions.  */
167 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
168 static MSymbol Mselect, Mshow, Mhide;
169 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
170
171 static MSymbol Mcandidate_list, Mcandidate_index;
172
173 static MSymbol Minit, Mfini;
174
175 /** Symbols for key events.  */
176 static MSymbol one_char_symbol[256];
177
178 static MSymbol M_key_alias;
179
180 /** Structure to hold a map.  */
181
182 struct MIMMap
183 {
184   /** List of actions to take when we reach the map.  In a root map,
185       the actions are executed only when there's no more key.  */
186   MPlist *map_actions;
187
188   /** List of deeper maps.  If NULL, this is a terminal map.  */
189   MPlist *submaps;
190
191   /** List of actions to take when we leave the map successfully.  In
192       a root map, the actions are executed only when none of submaps
193       handle the current key.  */
194   MPlist *branch_actions;
195 };
196
197 typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
198
199 typedef struct
200 {
201   void *handle;
202   MPlist *func_list;            /* function name vs (MIMExternalFunc *) */
203 } MIMExternalModule;
204
205 struct MIMState
206 {
207   /** Name of the state.  */
208   MSymbol name;
209
210   /** Title of the state, or NULL.  */
211   MText *title;
212
213   /** Key translation map of the state.  Built by merging all maps of
214       branches.  */
215   MIMMap *map;
216 };
217
218
219 static int
220 marker_code (MSymbol sym)
221 {
222   char *name;
223
224   if (sym == Mnil)
225     return -1;
226   name = MSYMBOL_NAME (sym);
227   return ((name[0] == '@'
228            && ((name[1] >= '0' && name[1] <= '9')
229                || name[1] == '<' || name[1] == '>'
230                || name[1] == '=' || name[1] == '+' || name[1] == '-'
231                || name[1] == '[' || name[1] == ']')
232            && name[2] == '\0')
233           ? name[1] : -1);
234 }
235
236 int
237 integer_value (MInputContext *ic, MPlist *arg)
238 {
239   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
240   int code;
241   MText *preedit = ic->preedit;
242   int len = mtext_nchars (preedit);
243
244   if (MPLIST_INTEGER_P (arg))
245     return MPLIST_INTEGER (arg);
246   code = marker_code (MPLIST_SYMBOL (arg));
247   if (code < 0)
248     return (int) mplist_get (ic_info->vars, MPLIST_SYMBOL (arg));
249   if (code >= '0' && code <= '9')
250     code -= '0';
251   else if (code == '=')
252     code = ic->cursor_pos;
253   else if (code == '-' || code == '[')
254     code = ic->cursor_pos - 1;
255   else if (code == '+' || code == ']')
256     code = ic->cursor_pos + 1;
257   else if (code == '<')
258     code = 0;
259   else if (code == '>')
260     code = len;
261   return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
262 }
263
264
265 /* Parse PLIST as an action list while modifying the list to regularize
266    actions.  PLIST should have this form:
267       PLIST ::= ( (ACTION-NAME ACTION-ARG *) *).
268    Return 0 if successfully parsed, otherwise return -1.  */
269
270 static int
271 parse_action_list (MPlist *plist, MPlist *macros)
272 {
273   MPLIST_DO (plist, plist)
274     {
275       if (MPLIST_MTEXT_P (plist))
276         {
277           /* This is a short form of (insert MTEXT).  */
278           /* if (mtext_nchars (MPLIST_MTEXT (plist)) == 0)
279              MERROR (MERROR_IM, -1); */
280         }
281       else if (MPLIST_PLIST_P (plist)
282                && (MPLIST_MTEXT_P (MPLIST_PLIST (plist))
283                    || MPLIST_PLIST_P (MPLIST_PLIST (plist))))
284         {
285           MPlist *pl;
286
287           /* This is a short form of (insert (GROUPS *)).  */
288           MPLIST_DO (pl, MPLIST_PLIST (plist))
289             {
290               if (MPLIST_PLIST_P (pl))
291                 {
292                   MPlist *elt;
293
294                   MPLIST_DO (elt, MPLIST_PLIST (pl))
295                     if (! MPLIST_MTEXT_P (elt)
296                         || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
297                       MERROR (MERROR_IM, -1);
298                 }
299               else
300                 {
301                   if (! MPLIST_MTEXT_P (pl)
302                       || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
303                     MERROR (MERROR_IM, -1);
304                 }
305             }
306         }
307       else if (MPLIST_INTEGER_P (plist))
308         {
309           int c = MPLIST_INTEGER (plist);
310
311           if (c < 0 || c > MCHAR_MAX)
312             MERROR (MERROR_IM, -1);
313         }
314       else if (MPLIST_PLIST_P (plist)
315                && MPLIST_SYMBOL_P (MPLIST_PLIST (plist)))
316         {
317           MPlist *pl = MPLIST_PLIST (plist);
318           MSymbol action_name = MPLIST_SYMBOL (pl);
319
320           pl = MPLIST_NEXT (pl);
321
322           if (action_name == Minsert)
323             {
324               if (MPLIST_MTEXT_P (pl))
325                 {
326                   if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
327                     MERROR (MERROR_IM, -1);
328                 }
329               else if (MPLIST_PLIST_P (pl))
330                 {
331                   MPLIST_DO (pl, pl)
332                     {
333                       if (MPLIST_PLIST_P (pl))
334                         {
335                           MPlist *elt;
336
337                           MPLIST_DO (elt, MPLIST_PLIST (pl))
338                             if (! MPLIST_MTEXT_P (elt)
339                                 || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
340                               MERROR (MERROR_IM, -1);
341                         }
342                       else
343                         {
344                           if (! MPLIST_MTEXT_P (pl)
345                               || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
346                             MERROR (MERROR_IM, -1);
347                         }
348                     }
349                 }
350               else if (! MPLIST_SYMBOL_P (pl))
351                 MERROR (MERROR_IM, -1); 
352             }
353           else if (action_name == Mselect
354                    || action_name == Mdelete
355                    || action_name == Mmove)
356             {
357               if (! MPLIST_SYMBOL_P (pl)
358                   && ! MPLIST_INTEGER_P (pl))
359                 MERROR (MERROR_IM, -1);
360             }
361           else if (action_name == Mmark
362                    || action_name == Mcall
363                    || action_name == Mshift)
364             {
365               if (! MPLIST_SYMBOL_P (pl))
366                 MERROR (MERROR_IM, -1);
367             }
368           else if (action_name == Mshow || action_name == Mhide
369                    || action_name == Mundo)
370             {
371               if (! MPLIST_TAIL_P (pl))
372                 MERROR (MERROR_IM, -1);
373             }
374           else if (action_name == Mpushback)
375             {
376               if (! MPLIST_INTEGER_P (pl))
377                 MERROR (MERROR_IM, -1);
378             }
379           else if (action_name == Mset || action_name == Madd
380                    || action_name == Msub || action_name == Mmul
381                    || action_name == Mdiv)
382             {
383               if (! (MPLIST_SYMBOL_P (pl)
384                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
385                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
386                 MERROR (MERROR_IM, -1);
387             }
388           else if (action_name == Mequal || action_name == Mless
389                    || action_name == Mgreater)
390             {
391               if (! ((MPLIST_INTEGER_P (pl) || MPLIST_SYMBOL_P (pl))
392                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
393                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
394                 MERROR (MERROR_IM, -1);
395               pl = MPLIST_NEXT (MPLIST_NEXT (pl));
396               if (! MPLIST_PLIST_P (pl))
397                 MERROR (MERROR_IM, -1);
398               if (parse_action_list (MPLIST_PLIST (pl), macros) < 0)
399                 MERROR (MERROR_IM, -1);
400               pl = MPLIST_NEXT (pl);
401               if (MPLIST_PLIST_P (pl)
402                   && parse_action_list (MPLIST_PLIST (pl), macros) < 0)
403                 MERROR (MERROR_IM, -1);
404             }
405           else if (! macros || ! mplist_get (macros, action_name))
406             MERROR (MERROR_IM, -1);
407         }
408       else
409         MERROR (MERROR_IM, -1);
410     }
411
412   return 0;
413 }
414
415
416 /* Load a translation into MAP from PLIST.
417    PLIST has this form:
418       PLIST ::= ( KEYSEQ MAP-ACTION * )  */
419
420 static int
421 load_translation (MIMMap *map, MPlist *plist, MPlist *branch_actions,
422                   MPlist *macros)
423 {
424   MSymbol *keyseq;
425   int len, i;
426
427   if (MPLIST_MTEXT_P (plist))
428     {
429       MText *mt = MPLIST_MTEXT (plist);
430
431       len = mtext_nchars (mt);
432       if (len == 0 || len != mtext_nbytes (mt))
433         MERROR (MERROR_IM, -1);
434       keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len);
435       for (i = 0; i < len; i++)
436         keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]];
437     }
438   else if (MPLIST_PLIST_P (plist))
439     {
440       MPlist *elt = MPLIST_PLIST (plist);
441           
442       len = MPLIST_LENGTH (elt);
443       if (len == 0)
444         MERROR (MERROR_IM, -1);
445       keyseq = (MSymbol *) alloca (sizeof (int) * len);
446       for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
447         {
448           if (MPLIST_INTEGER_P (elt))
449             {
450               int c = MPLIST_INTEGER (elt);
451
452               if (c < 0 || c >= 0x100)
453                 MERROR (MERROR_IM, -1);
454               keyseq[i] = one_char_symbol[c];
455             }
456           else if (MPLIST_SYMBOL_P (elt))
457             keyseq[i] = MPLIST_SYMBOL (elt);
458           else
459             MERROR (MERROR_IM, -1);
460         }
461     }
462   else
463     MERROR (MERROR_IM, -1);
464
465   for (i = 0; i < len; i++)
466     {
467       MIMMap *deeper = NULL;
468
469       if (map->submaps)
470         deeper = mplist_get (map->submaps, keyseq[i]);
471       else
472         map->submaps = mplist ();
473       if (! deeper)
474         {
475           /* Fixme: It is better to make all deeper maps at once.  */
476           MSTRUCT_CALLOC (deeper, MERROR_IM);
477           mplist_put (map->submaps, keyseq[i], deeper);
478         }
479       map = deeper;
480     }
481
482   /* We reach a terminal map.  */
483   if (map->map_actions
484       || map->branch_actions)
485     /* This map is already defined.  We avoid overriding it.  */
486     return 0;
487
488   plist = MPLIST_NEXT (plist);
489   if (! MPLIST_TAIL_P (plist))
490     {
491       if (parse_action_list (plist, macros) < 0)
492         MERROR (MERROR_IM, -1);
493       map->map_actions = plist;
494       M17N_OBJECT_REF (plist);
495     }
496   if (branch_actions)
497     {
498       map->branch_actions = branch_actions;
499       M17N_OBJECT_REF (branch_actions);
500     }
501
502   return 0;
503 }
504
505 /* Load a branch from PLIST into MAP.  PLIST has this form:
506       PLIST ::= ( MAP-NAME BRANCH-ACTION * )
507    MAPS is a plist of raw maps.
508    STATE is the current state.  */
509
510 static int
511 load_branch (MPlist *plist, MPlist *maps, MIMMap *map, MPlist *macros)
512 {
513   MSymbol map_name;
514   MPlist *branch_actions;
515
516   if (! MPLIST_SYMBOL_P (plist))
517     MERROR (MERROR_IM, -1);
518   map_name = MPLIST_SYMBOL (plist);
519   plist = MPLIST_NEXT (plist);
520   if (MPLIST_TAIL_P (plist))
521     branch_actions = NULL;
522   else if (parse_action_list (plist, macros) < 0)
523     MERROR (MERROR_IM, -1);
524   else
525     branch_actions = plist;
526   if (map_name == Mnil)
527     {
528       map->branch_actions = branch_actions;
529       if (branch_actions)
530         M17N_OBJECT_REF (branch_actions);
531     }
532   else if (map_name == Mt)
533     {
534       map->map_actions = branch_actions;
535       if (branch_actions)
536         M17N_OBJECT_REF (branch_actions);
537     }
538   else
539     {
540       plist = (MPlist *) mplist_get (maps, map_name);
541       if (! plist || ! MPLIST_PLIST_P (plist))
542         MERROR (MERROR_IM, -1);
543       MPLIST_DO (plist, plist)
544         if (! MPLIST_PLIST_P (plist)
545             || (load_translation (map, MPLIST_PLIST (plist), branch_actions,
546                                   macros)
547                 < 0))
548           MERROR (MERROR_IM, -1);
549     }
550
551   return 0;
552 }
553
554 /* Load a macro from PLIST into MACROS.
555    PLIST has this from:
556       PLIST ::= ( MACRO-NAME ACTION * )
557    MACROS is a plist of macro names vs action list.  */
558 static int
559 load_macros (MPlist *plist, MPlist *macros)
560 {
561   MSymbol name; 
562
563   if (! MPLIST_SYMBOL_P (plist))
564     MERROR (MERROR_IM, -1);
565   name = MPLIST_SYMBOL (plist);
566   plist = MPLIST_NEXT (plist);
567   if (MPLIST_TAIL_P (plist)
568       || parse_action_list (plist, macros) < 0)
569     MERROR (MERROR_IM, -1);
570   mplist_put (macros, name, plist);
571   M17N_OBJECT_REF (plist);
572   return 0;
573 }
574
575 /* Load an external module from PLIST into EXTERNALS.
576    PLIST has this form:
577       PLIST ::= ( MODULE-NAME FUNCTION * )
578    EXTERNALS is a plist of MODULE-NAME vs (MIMExternalModule *).  */
579
580 #ifndef DLOPEN_SHLIB_EXT
581 #define DLOPEN_SHLIB_EXT ".so"
582 #endif
583
584 static int
585 load_external_module (MPlist *plist, MPlist *externals)
586 {
587   void *handle;
588   MSymbol module;
589   char *module_file;
590   MIMExternalModule *external;
591   MPlist *func_list;
592   void *func;
593
594   if (MPLIST_MTEXT_P (plist))
595     module = msymbol ((char *) MTEXT_DATA (MPLIST_MTEXT (plist)));
596   else if (MPLIST_SYMBOL_P (plist))
597     module = MPLIST_SYMBOL (plist);
598   module_file = alloca (strlen (MSYMBOL_NAME (module))
599                         + strlen (DLOPEN_SHLIB_EXT) + 1);
600   sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
601
602   handle = dlopen (module_file, RTLD_NOW);
603   if (! handle)
604     {
605       fprintf (stderr, "%s\n", dlerror ());
606       MERROR (MERROR_IM, -1);
607     }
608   func_list = mplist ();
609   MPLIST_DO (plist, MPLIST_NEXT (plist))
610     {
611       if (! MPLIST_SYMBOL_P (plist))
612         MERROR_GOTO (MERROR_IM, err_label);
613       func = dlsym (handle, MSYMBOL_NAME (MPLIST_SYMBOL (plist)));
614       if (! func)
615         MERROR_GOTO (MERROR_IM, err_label);
616       mplist_add (func_list, MPLIST_SYMBOL (plist), func);
617     }
618
619   MSTRUCT_MALLOC (external, MERROR_IM);
620   external->handle = handle;
621   external->func_list = func_list;
622   mplist_add (externals, module, external);
623   return 0;
624
625  err_label:
626   dlclose (handle);
627   M17N_OBJECT_UNREF (func_list);
628   return -1;
629 }
630
631
632 /** Load a state from PLIST into a newly allocated state object.
633     PLIST has this form:
634       PLIST ::= ( STATE-NAME STATE-TITLE ? BRANCH * )
635       BRANCH ::= ( MAP-NAME BRANCH-ACTION * )
636    MAPS is a plist of defined maps.
637    Return the state object.  */
638
639 static MIMState *
640 load_state (MPlist *plist, MPlist *maps, MSymbol language, MPlist *macros)
641 {
642   MIMState *state;
643
644   MSTRUCT_CALLOC (state, MERROR_IM);
645   if (! MPLIST_SYMBOL_P (plist))
646     MERROR (MERROR_IM, NULL);
647   state->name = MPLIST_SYMBOL (plist);
648   plist = MPLIST_NEXT (plist);
649   if (MPLIST_MTEXT_P (plist))
650     {
651       state->title = MPLIST_MTEXT (plist);
652       mtext_put_prop (state->title, 0, mtext_nchars (state->title),
653                       Mlanguage, language);
654       M17N_OBJECT_REF (state->title);
655       plist = MPLIST_NEXT (plist);
656     }
657   MSTRUCT_CALLOC (state->map, MERROR_IM);
658   MPLIST_DO (plist, plist)
659     if (! MPLIST_PLIST_P (plist)
660         || load_branch (MPLIST_PLIST (plist), maps, state->map, macros) < 0)
661       MERROR (MERROR_IM, NULL);
662   return state;
663 }
664
665
666 static void
667 free_map (MIMMap *map)
668 {
669   MPlist *plist;
670
671   M17N_OBJECT_UNREF (map->map_actions);
672   if (map->submaps)
673     {
674       MPLIST_DO (plist, map->submaps)
675         free_map ((MIMMap *) MPLIST_VAL (plist));
676       M17N_OBJECT_UNREF (map->submaps);
677     }
678   M17N_OBJECT_UNREF (map->branch_actions);
679   free (map);
680 }
681
682 /* Load an input method from PLIST into IM_INTO, and return it.  */
683
684 static int
685 load_input_method (MSymbol language, MSymbol name, MPlist *plist,
686                    MInputMethodInfo *im_info)
687 {
688   MText *title = NULL;
689   MPlist *maps = NULL;
690   MPlist *states = NULL;
691   MPlist *externals = NULL;
692   MPlist *macros = NULL;
693   MPlist *elt;
694
695   for (; MPLIST_PLIST_P (plist); plist = MPLIST_NEXT (plist))
696     {
697       elt = MPLIST_PLIST (plist);
698       if (! MPLIST_SYMBOL_P (elt))
699         MERROR_GOTO (MERROR_IM, err);
700       if (MPLIST_SYMBOL (elt) == Mtitle)
701         {
702           elt = MPLIST_NEXT (elt);
703           if (MPLIST_MTEXT_P (elt))
704             {
705               title = MPLIST_MTEXT (elt);
706               M17N_OBJECT_REF (title);
707             }
708           else
709             MERROR_GOTO (MERROR_IM, err);
710         }
711       else if (MPLIST_SYMBOL (elt) == Mmap)
712         {
713           maps = mplist__from_alist (MPLIST_NEXT (elt));
714           if (! maps)
715             MERROR_GOTO (MERROR_IM, err);
716         }
717       else if (MPLIST_SYMBOL (elt) == Mmacro)
718         {
719           macros = mplist ();
720           MPLIST_DO (elt, MPLIST_NEXT (elt))
721           {
722             if (! MPLIST_PLIST_P (elt)
723                 || load_macros (MPLIST_PLIST (elt), macros) < 0)
724               MERROR_GOTO (MERROR_IM, err);
725           }
726         }
727       else if (MPLIST_SYMBOL (elt) == Mmodule)
728         {
729           externals = mplist ();
730           MPLIST_DO (elt, MPLIST_NEXT (elt))
731           {
732             if (! MPLIST_PLIST_P (elt)
733                 || load_external_module (MPLIST_PLIST (elt), externals) < 0)
734               MERROR_GOTO (MERROR_IM, err);
735           }
736         }
737       else if (MPLIST_SYMBOL (elt) == Mstate)
738         {
739           states = mplist ();
740           MPLIST_DO (elt, MPLIST_NEXT (elt))
741           {
742             MIMState *state;
743
744             if (! MPLIST_PLIST_P (elt))
745               MERROR_GOTO (MERROR_IM, err);
746             state = load_state (MPLIST_PLIST (elt), maps, language, macros);
747             if (! state)
748               MERROR_GOTO (MERROR_IM, err);
749             mplist_put (states, state->name, state);
750           }
751         }
752     }
753
754   if (maps)
755     {
756       MPLIST_DO (elt, maps)
757         M17N_OBJECT_UNREF (MPLIST_VAL (elt));
758       M17N_OBJECT_UNREF (maps);
759     }
760   if (! title)
761     title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name),
762                              MTEXT_FORMAT_US_ASCII);
763   im_info->title = title;
764   im_info->externals = externals;
765   im_info->macros = macros;
766   im_info->states = states;
767   return 0;
768
769  err:
770   if (maps)
771     {
772       MPLIST_DO (elt, maps)
773         M17N_OBJECT_UNREF (MPLIST_VAL (elt));
774       M17N_OBJECT_UNREF (maps);
775     }
776   if (title)
777     M17N_OBJECT_UNREF (title);
778   if (states)
779     {
780       MPLIST_DO (plist, states)
781       {
782         MIMState *state = (MIMState *) MPLIST_VAL (plist);
783
784         if (state->title)
785           M17N_OBJECT_UNREF (state->title);
786         if (state->map)
787           free_map (state->map);
788         free (state);
789       }
790       M17N_OBJECT_UNREF (states);
791     }
792   if (externals)
793     {
794       MPLIST_DO (plist, externals)
795       {
796         MIMExternalModule *external = MPLIST_VAL (plist);
797
798         dlclose (external->handle);
799         M17N_OBJECT_UNREF (external->func_list);
800         free (external);
801         MPLIST_KEY (plist) = Mt;
802       }
803       M17N_OBJECT_UNREF (externals);
804     }
805   return -1;
806 }
807
808 \f
809
810 static int take_action_list (MInputContext *ic, MPlist *action_list);
811
812 static void
813 shift_state (MInputContext *ic, MSymbol state_name)
814 {
815   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
816   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
817   MIMState *state;
818
819   /* Find a state to shift to.  If not found, shift to the initial
820      state.  */
821   state = (MIMState *) mplist_get (im_info->states, state_name);
822   if (! state)
823     state = (MIMState *) MPLIST_VAL (im_info->states);
824
825   MDEBUG_PRINT1 ("\n[IM] state-shift (%s)", MSYMBOL_NAME (state->name));
826
827   /* Enter the new state.  */
828   ic_info->state = state;
829   ic_info->map = state->map;
830   ic_info->state_key_head = ic_info->key_head;
831   if (state == (MIMState *) MPLIST_VAL (im_info->states))
832     {
833       /* We have shifted to the initial state.  */
834       MPlist *p;
835
836       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
837                              Mcandidate_list, NULL, 0);
838       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
839                              Mcandidate_index, NULL, 0);
840       mtext_cat (ic->produced, ic->preedit);
841       if ((mdebug__flag & mdebug_mask)
842           && mtext_nchars (ic->produced) > 0)
843         {
844           int i;
845
846           MDEBUG_PRINT (" (produced");
847             for (i = 0; i < mtext_nchars (ic->produced); i++)
848               MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
849           MDEBUG_PRINT (")");
850         }
851       mtext_reset (ic->preedit);
852       ic->candidate_list = NULL;
853       ic->candidate_show = 0;
854       ic->preedit_changed = ic->candidates_changed = 1;
855       MPLIST_DO (p, ic_info->markers)
856         MPLIST_VAL (p) = 0;
857       MPLIST_DO (p, ic_info->vars)
858         MPLIST_VAL (p) = 0;
859       ic->cursor_pos = 0;
860       memmove (ic_info->keys, ic_info->keys + ic_info->state_key_head,
861                sizeof (int) * (ic_info->used - ic_info->state_key_head));
862       ic_info->used -= ic_info->state_key_head;
863       ic_info->state_key_head = ic_info->key_head = 0;
864     }
865   mtext_cpy (ic_info->preedit_saved, ic->preedit);
866   ic_info->state_pos = ic->cursor_pos;
867   ic->status = state->title;
868   if (! ic->status)
869     ic->status = im_info->title;
870   ic->status_changed = 1;
871   if (ic_info->key_head == ic_info->used
872       && ic_info->map == ic_info->state->map
873       && ic_info->map->map_actions)
874     {
875       MDEBUG_PRINT (" init-actions:");
876       take_action_list (ic, ic_info->map->map_actions);
877     }
878 }
879
880 /* Find a candidate group that contains a candidate number INDEX from
881    PLIST.  Set START_INDEX to the first candidate number of the group,
882    END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
883    candidate group number if they are non-NULL.  If INDEX is -1, find
884    the last candidate group.  */
885
886 static MPlist *
887 find_candidates_group (MPlist *plist, int index,
888                        int *start_index, int *end_index, int *group_index)
889 {
890   int i = 0, gidx = 0, len;
891
892   MPLIST_DO (plist, plist)
893     {
894       if (MPLIST_MTEXT_P (plist))
895         len = mtext_nchars (MPLIST_MTEXT (plist));
896       else
897         len = mplist_length (MPLIST_PLIST (plist));
898       if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
899           : i + len > index)
900         {
901           if (start_index)
902             *start_index = i;
903           if (end_index)
904             *end_index = i + len;
905           if (group_index)
906             *group_index = gidx;
907           return plist;
908         }
909       i += len;
910       gidx++;
911     }
912   return NULL;
913 }
914
915 static void
916 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
917 {
918   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
919   MPlist *markers;
920   int nchars = mt ? mtext_nchars (mt) : 1;
921
922   if (mt)
923     mtext_ins (ic->preedit, pos, mt);
924   else
925     mtext_ins_char (ic->preedit, pos, c, 1);
926   MPLIST_DO (markers, ic_info->markers)
927     if (MPLIST_INTEGER (markers) > pos)
928       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
929   if (ic->cursor_pos >= pos)
930     ic->cursor_pos += nchars;
931   ic->preedit_changed = 1;
932 }
933
934
935 static void
936 preedit_delete (MInputContext *ic, int from, int to)
937 {
938   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
939   MPlist *markers;
940
941   mtext_del (ic->preedit, from, to);
942   MPLIST_DO (markers, ic_info->markers)
943     {
944       if (MPLIST_INTEGER (markers) > to)
945         MPLIST_VAL (markers)
946           = (void *) (MPLIST_INTEGER (markers) - (to - from));
947       else if (MPLIST_INTEGER (markers) > from);
948         MPLIST_VAL (markers) = (void *) from;
949     }
950   if (ic->cursor_pos >= to)
951     ic->cursor_pos -= to - from;
952   else if (ic->cursor_pos > from)
953     ic->cursor_pos = from;
954   ic->preedit_changed = 1;
955 }
956
957
958 static int
959 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
960 {
961   int code = marker_code (sym);
962
963   if (mt && (code == '[' || code == ']'))
964     {
965       int pos = current;
966
967       if (code == '[' && current > 0)
968         {
969           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
970               && pos > 0)
971             current = pos;
972         }
973       else if (code == ']' && current < mtext_nchars (mt))
974         {
975           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
976             current = pos;
977         }
978       return current;
979     }
980   if (code >= 0)
981     return (code == '<' ? 0
982             : code == '>' ? limit
983             : code == '-' ? current - 1
984             : code == '+' ? current + 1
985             : code == '=' ? current
986             : code - '0' > limit ? limit
987             : code - '0');
988   if (! ic)  
989     return 0;
990   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
991 }
992
993 static void
994 update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
995 {
996   int from = mtext_property_start (prop);
997   int to = mtext_property_end (prop);
998   int start;
999   MPlist *candidate_list = mtext_property_value (prop);
1000   MPlist *group = find_candidates_group (candidate_list, idx, &start,
1001                                          NULL, NULL);
1002   int ingroup_index = idx - start;
1003   MText *mt;
1004
1005   preedit_delete (ic, from, to);
1006   if (MPLIST_MTEXT_P (group))
1007     {
1008       mt = MPLIST_MTEXT (group);
1009       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
1010       to = from + 1;
1011     }
1012   else
1013     {
1014       int i;
1015       MPlist *plist;
1016
1017       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
1018            i++, plist = MPLIST_NEXT (plist));
1019       mt = MPLIST_MTEXT (plist);
1020       preedit_insert (ic, from, mt, 0);
1021       to = from + mtext_nchars (mt);
1022     }
1023   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
1024   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
1025   ic->cursor_pos = to;
1026 }
1027
1028
1029 static int
1030 take_action_list (MInputContext *ic, MPlist *action_list)
1031 {
1032   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1033   MPlist *candidate_list = ic->candidate_list;
1034   int candidate_index = ic->candidate_index;
1035   int candidate_show = ic->candidate_show;
1036   MTextProperty *prop;
1037
1038   MPLIST_DO (action_list, action_list)
1039     {
1040       MPlist *action;
1041       MSymbol name;
1042       MPlist *args;
1043
1044       if (MPLIST_MTEXT_P (action_list)
1045           || MPLIST_INTEGER_P (action_list))
1046         name = Minsert, args = action_list;
1047       else if (MPLIST_PLIST_P (action_list)
1048                && (MPLIST_MTEXT_P (MPLIST_PLIST (action_list))
1049                    || MPLIST_PLIST_P (MPLIST_PLIST (action_list))))
1050         name = Minsert, args = action_list;
1051       else
1052         {
1053           action = MPLIST_PLIST (action_list);
1054           name = MPLIST_SYMBOL (action);
1055           args = MPLIST_NEXT (action);
1056         }
1057
1058       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
1059       if (name == Minsert)
1060         {
1061           if (MPLIST_MTEXT_P (args))
1062             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
1063           else if (MPLIST_INTEGER_P (args))
1064             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
1065           else if (MPLIST_SYMBOL_P (args))
1066             {
1067               int c = integer_value (ic, args);
1068
1069               if (c >= 0 && c <= MCHAR_MAX)
1070                 preedit_insert (ic, ic->cursor_pos, NULL, c);
1071             }
1072           else
1073             {
1074               MText *mt;
1075               int len;
1076
1077               args = MPLIST_PLIST (args);
1078               if (MPLIST_MTEXT_P (args))
1079                 {
1080                   preedit_insert (ic, ic->cursor_pos, NULL,
1081                                   mtext_ref_char (MPLIST_MTEXT (args), 0));
1082                   len = 1;
1083                 }
1084               else
1085                 {
1086                   mt = MPLIST_MTEXT (MPLIST_PLIST (args));
1087                   preedit_insert (ic, ic->cursor_pos, mt, 0);
1088                   len = mtext_nchars (mt);
1089                 }
1090               mtext_put_prop (ic->preedit,
1091                               ic->cursor_pos - len, ic->cursor_pos,
1092                               Mcandidate_list, args);
1093               mtext_put_prop (ic->preedit,
1094                               ic->cursor_pos - len, ic->cursor_pos,
1095                               Mcandidate_index, (void *) 0);
1096             }
1097         }
1098       else if (name == Mselect)
1099         {
1100           int start, end;
1101           int code, idx, gindex;
1102           int pos = ic->cursor_pos;
1103           MPlist *group;
1104
1105           if (pos == 0
1106               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
1107                                                Mcandidate_list)))
1108             continue;
1109           if (MPLIST_SYMBOL_P (args))
1110             {
1111               code = marker_code (MPLIST_SYMBOL (args));
1112               if (code < 0)
1113                 continue;
1114             }
1115           else
1116             code = -1;
1117           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
1118           group = find_candidates_group (mtext_property_value (prop), idx,
1119                                          &start, &end, &gindex);
1120
1121           if (code != '[' && code != ']')
1122             {
1123               idx = (start
1124                      + (code >= 0
1125                         ? new_index (NULL, ic->candidate_index - start,
1126                                      end - start - 1, MPLIST_SYMBOL (args),
1127                                      NULL)
1128                         : MPLIST_INTEGER (args)));
1129               if (idx < 0)
1130                 {
1131                   find_candidates_group (mtext_property_value (prop), -1,
1132                                          NULL, &end, NULL);
1133                   idx = end - 1;
1134                 }
1135               else if (idx >= end
1136                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
1137                 idx = 0;
1138             }
1139           else
1140             {
1141               int ingroup_index = idx - start;
1142               int len;
1143
1144               group = mtext_property_value (prop);
1145               len = mplist_length (group);
1146               if (code == '[')
1147                 {
1148                   gindex--;
1149                   if (gindex < 0)
1150                     gindex = len - 1;;
1151                 }
1152               else
1153                 {
1154                   gindex++;
1155                   if (gindex >= len)
1156                     gindex = 0;
1157                 }
1158               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
1159                 idx += (MPLIST_MTEXT_P (group)
1160                         ? mtext_nchars (MPLIST_MTEXT (group))
1161                         : mplist_length (MPLIST_PLIST (group)));
1162               len = (MPLIST_MTEXT_P (group)
1163                      ? mtext_nchars (MPLIST_MTEXT (group))
1164                      : mplist_length (MPLIST_PLIST (group)));
1165               if (ingroup_index >= len)
1166                 ingroup_index = len - 1;
1167               idx += ingroup_index;
1168             }
1169           update_candidate (ic, prop, idx);
1170         }
1171       else if (name == Mshow)
1172         ic->candidate_show = 1;
1173       else if (name == Mhide)
1174         ic->candidate_show = 0;
1175       else if (name == Mdelete)
1176         {
1177           int len = mtext_nchars (ic->preedit);
1178           int to = (MPLIST_SYMBOL_P (args)
1179                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1180                                  ic->preedit)
1181                     : MPLIST_INTEGER (args));
1182
1183           if (to < 0)
1184             to = 0;
1185           else if (to > len)
1186             to = len;
1187           if (to < ic->cursor_pos)
1188             preedit_delete (ic, to, ic->cursor_pos);
1189           else if (to > ic->cursor_pos)
1190             preedit_delete (ic, ic->cursor_pos, to);
1191         }
1192       else if (name == Mmove)
1193         {
1194           int len = mtext_nchars (ic->preedit);
1195           int pos
1196             = (MPLIST_SYMBOL_P (args)
1197                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1198                             ic->preedit)
1199                : MPLIST_INTEGER (args));
1200
1201           if (pos < 0)
1202             pos = 0;
1203           else if (pos > len)
1204             pos = len;
1205           if (pos != ic->cursor_pos)
1206             {
1207               ic->cursor_pos = pos;
1208               ic->preedit_changed = 1;
1209             }
1210         }
1211       else if (name == Mmark)
1212         {
1213           int code = marker_code (MPLIST_SYMBOL (args));
1214
1215           if (code < 0)
1216             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
1217                         (void *) ic->cursor_pos);
1218         }
1219       else if (name == Mpushback)
1220         {
1221           int num = MPLIST_INTEGER (args);
1222
1223           if (num > 0)
1224             ic_info->key_head -= num;
1225           else
1226             ic_info->key_head = num;
1227           if (ic_info->key_head > ic_info->used)
1228             ic_info->key_head = ic_info->used;
1229         }
1230       else if (name == Mcall)
1231         {
1232           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1233           MIMExternalFunc func = NULL;
1234           MSymbol module, func_name;
1235           MPlist *func_args, *val;
1236           int ret = 0;
1237
1238           module = MPLIST_SYMBOL (args);
1239           args = MPLIST_NEXT (args);
1240           func_name = MPLIST_SYMBOL (args);
1241
1242           if (im_info->externals)
1243             {
1244               MIMExternalModule *external
1245                 = (MIMExternalModule *) mplist_get (im_info->externals,
1246                                                     module);
1247               if (external)
1248                 func = (MIMExternalFunc) mplist_get (external->func_list,
1249                                                      func_name);
1250             }
1251           if (! func)
1252             continue;
1253           func_args = mplist ();
1254           mplist_add (func_args, Mt, ic);
1255           MPLIST_DO (args, MPLIST_NEXT (args))
1256             {
1257               int code;
1258
1259               if (MPLIST_KEY (args) == Msymbol
1260                   && MPLIST_KEY (args) != Mnil
1261                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
1262                 {
1263                   code = new_index (ic, ic->cursor_pos, 
1264                                     mtext_nchars (ic->preedit),
1265                                     MPLIST_SYMBOL (args), ic->preedit);
1266                   mplist_add (func_args, Minteger, (void *) code);
1267                 }
1268               else
1269                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
1270             }
1271           val = (func) (func_args);
1272           M17N_OBJECT_UNREF (func_args);
1273           if (val && ! MPLIST_TAIL_P (val))
1274             ret = take_action_list (ic, val);
1275           M17N_OBJECT_UNREF (val);
1276           if (ret < 0)
1277             return ret;
1278         }
1279       else if (name == Mshift)
1280         {
1281           shift_state (ic, MPLIST_SYMBOL (args));
1282         }
1283       else if (name == Mundo)
1284         {
1285           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1286           int unhandle = 0;
1287
1288           mtext_reset (ic->preedit);
1289           mtext_reset (ic_info->preedit_saved);
1290           ic->cursor_pos = ic_info->state_pos = 0;
1291           ic_info->state_key_head = ic_info->key_head = 0;
1292           ic_info->used -= 2;
1293           if (ic_info->used < 0)
1294             {
1295               ic_info->used = 0;
1296               unhandle = 1;
1297             }
1298           shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1299           if (unhandle)
1300             return -1;
1301           break;
1302         }
1303       else if (name == Mset || name == Madd || name == Msub
1304                || name == Mmul || name == Mdiv)
1305         {
1306           MSymbol sym = MPLIST_SYMBOL (args);
1307           int val1 = (int) mplist_get (ic_info->vars, sym), val2;
1308
1309           args = MPLIST_NEXT (args);
1310           val2 = integer_value (ic, args);
1311           if (name == Mset)
1312             val1 = val2;
1313           else if (name == Madd)
1314             val1 += val2;
1315           else if (name == Msub)
1316             val1 -= val2;
1317           else if (name == Mmul)
1318             val1 *= val2;
1319           else
1320             val1 /= val2;
1321           mplist_put (ic_info->vars, sym, (void *) val1);
1322           MDEBUG_PRINT2 ("(%s=%d)", MSYMBOL_NAME (sym), val1);
1323         }
1324       else if (name == Mequal || name == Mless || name == Mgreater)
1325         {
1326           int val1, val2;
1327           MPlist *actions1, *actions2;
1328           int ret = 0;
1329
1330           val1 = integer_value (ic, args);
1331           args = MPLIST_NEXT (args);
1332           val2 = integer_value (ic, args);
1333           args = MPLIST_NEXT (args);
1334           actions1 = MPLIST_PLIST (args);
1335           args = MPLIST_NEXT (args);
1336           if (MPLIST_TAIL_P (args))
1337             actions2 = NULL;
1338           else
1339             actions2 = MPLIST_PLIST (args);
1340           if (name == Mequal ? val1 == val2
1341               : name == Mless ? val1 < val2
1342               : val1 > val2)
1343             ret = take_action_list (ic, actions1);
1344           else if (actions2)
1345             ret = take_action_list (ic, actions2);
1346           if (ret < 0)
1347             return ret;
1348         }
1349       else
1350         {
1351           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1352           MPlist *actions;
1353
1354           if (im_info->macros
1355               && (actions = mplist_get (im_info->macros, name)))
1356             {
1357               if (take_action_list (ic, actions) < 0)
1358                 return -1;
1359             };
1360         }
1361     }
1362
1363   prop = NULL;
1364   ic->candidate_list = NULL;
1365   if (ic->cursor_pos > 0
1366       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
1367                                      Mcandidate_list)))
1368     {
1369       ic->candidate_list = mtext_property_value (prop);
1370       ic->candidate_index
1371         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
1372                                 Mcandidate_index);
1373       ic->candidate_from = mtext_property_start (prop);
1374       ic->candidate_to = mtext_property_end (prop);
1375     }
1376
1377   ic->candidates_changed |= (candidate_list != ic->candidate_list
1378                              || candidate_index != ic->candidate_index
1379                              || candidate_show != ic->candidate_show);
1380   return 0;
1381 }
1382
1383
1384 /* Handle the input key KEY in the current state and map specified in
1385    the input context IC.  If KEY is handled correctly, return 0.
1386    Otherwise, return -1.  */
1387
1388 static int
1389 handle_key (MInputContext *ic)
1390 {
1391   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1392   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1393   MIMMap *map = ic_info->map;
1394   MIMMap *submap = NULL;
1395   MSymbol key = ic_info->keys[ic_info->key_head];
1396   int i;
1397
1398   MDEBUG_PRINT2 ("[IM] handle `%s' in state %s", 
1399                  MSYMBOL_NAME (key), MSYMBOL_NAME (ic_info->state->name));
1400
1401   if (map->submaps)
1402     {
1403       submap = mplist_get (map->submaps, key);
1404       if (! submap && (key = msymbol_get (key, M_key_alias)) != Mnil)
1405         submap = mplist_get (map->submaps, key);
1406     }
1407
1408   if (submap)
1409     {
1410       MDEBUG_PRINT (" submap-found");
1411       mtext_cpy (ic->preedit, ic_info->preedit_saved);
1412       ic->cursor_pos = ic_info->state_pos;
1413       ic_info->key_head++;
1414       ic_info->map = map = submap;
1415       if (map->map_actions)
1416         {
1417           MDEBUG_PRINT (" map-actions:");
1418           if (take_action_list (ic, map->map_actions) < 0)
1419             return -1;
1420         }
1421       else if (map->submaps)
1422         {
1423           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
1424             {
1425               MSymbol key = ic_info->keys[i];
1426               char *name = msymbol_name (key);
1427
1428               if (! name[0] || ! name[1])
1429                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
1430             }
1431           ic->preedit_changed = 1;
1432         }
1433
1434       /* If this is the terminal map or we have shifted to another
1435          state, perform branch actions (if any).  */
1436       if (! map->submaps || map != ic_info->map)
1437         {
1438           if (map->branch_actions)
1439             {
1440               MDEBUG_PRINT (" branch-actions:");
1441               if (take_action_list (ic, map->branch_actions) < 0)
1442                 return -1;
1443             }
1444           /* If MAP is still not the root map, shift to the current
1445              state.  */
1446           if (ic_info->map != ic_info->state->map)
1447             shift_state (ic, ic_info->state->name);
1448         }
1449       MDEBUG_PRINT ("\n");
1450     }
1451   else
1452     {
1453       /* MAP can not handle KEY.  */
1454
1455       /* If MAP is the root map of the initial state, it means that
1456          the current input method can not handle KEY.  */
1457       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
1458         {
1459           MDEBUG_PRINT (" unhandled\n");
1460           return -1;
1461         }
1462
1463       if (map != ic_info->state->map)
1464         {
1465           /* If MAP is not the root map... */
1466           /* If MAP has branch actions, perform them.  */
1467           if (map->branch_actions)
1468             {
1469               MDEBUG_PRINT (" branch-actions:");
1470               take_action_list (ic, map->branch_actions);
1471             }
1472           /* If MAP is still not the root map, shift to the current
1473              state. */
1474           if (ic_info->map != ic_info->state->map)
1475             {
1476               shift_state (ic, ic_info->state->name);
1477               /* If MAP has branch_actions, perform them.  */
1478               if (ic_info->map->branch_actions)
1479                 {
1480                   MDEBUG_PRINT (" init-actions:");
1481                   take_action_list (ic, ic_info->map->branch_actions);
1482                 }
1483             }
1484         }
1485       else
1486         {
1487           /* MAP is the root map, perform branch actions (if any) or
1488              shift to the initial state.  */
1489           if (map->branch_actions)
1490             {
1491               MDEBUG_PRINT (" branch-actions:");
1492               take_action_list (ic, map->branch_actions);
1493             }
1494           else
1495             shift_state (ic,
1496                          ((MIMState *) MPLIST_VAL (im_info->states))->name);
1497         }
1498       MDEBUG_PRINT ("\n");
1499     }
1500   return 0;
1501 }
1502
1503 static void
1504 reset_ic (MInputContext *ic, MSymbol ignore)
1505 {
1506   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1507   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1508
1509   if (im_info->states)
1510     /* Shift to the initial state.  */
1511     shift_state (ic, Mnil);
1512   else
1513     ic_info->state = NULL;
1514   MLIST_RESET (ic_info);
1515   ic_info->map = ic_info->state ? ic_info->state->map : NULL;
1516   ic_info->state_key_head = ic_info->key_head = 0;
1517   ic->cursor_pos = ic_info->state_pos = 0;
1518   ic->status = ic_info->state ? ic_info->state->title : NULL;
1519   if (! ic->status)
1520     ic->status = im_info->title;
1521   ic->candidate_list = NULL;
1522   ic->candidate_show = 0;
1523   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 1;
1524   if (ic_info->map && ic_info->map->map_actions)
1525     take_action_list (ic, ic_info->map->map_actions);
1526 }
1527
1528 static int
1529 open_im (MInputMethod *im)
1530 {
1531   MDatabase *mdb;
1532   MInputMethodInfo *im_info;
1533   MPlist *plist;
1534   int result;
1535
1536   mdb = mdatabase_find (Minput_method, im->language, im->name, Mnil);
1537   if (! mdb)
1538     return -1;
1539   plist = mdatabase_load (mdb);
1540   if (! plist)
1541     MERROR (MERROR_IM, -1);
1542   MSTRUCT_CALLOC (im_info, MERROR_IM);
1543   im->info = im_info;
1544   result = load_input_method (im->language, im->name, plist, im_info);
1545   M17N_OBJECT_UNREF (plist);
1546   if (result < 0)
1547     MERROR (MERROR_IM, -1);
1548   return 0;
1549 }
1550
1551 static void
1552 close_im (MInputMethod *im)
1553 {
1554   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1555   MPlist *plist;
1556
1557   if (im_info->title)
1558     M17N_OBJECT_UNREF (im_info->title);
1559   if (im_info->states)
1560     {
1561       MPLIST_DO (plist, im_info->states)
1562         {
1563           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1564
1565           if (state->title)
1566             M17N_OBJECT_UNREF (state->title);
1567           if (state->map)
1568             free_map (state->map);
1569           free (state);
1570         }
1571       M17N_OBJECT_UNREF (im_info->states);
1572     }
1573
1574   if (im_info->macros)
1575     {
1576       MPLIST_DO (plist, im_info->macros)
1577         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1578       M17N_OBJECT_UNREF (im_info->macros);
1579     }
1580
1581   if (im_info->externals)
1582     {
1583       MPLIST_DO (plist, im_info->externals)
1584         {
1585           MIMExternalModule *external = MPLIST_VAL (plist);
1586
1587           dlclose (external->handle);
1588           M17N_OBJECT_UNREF (external->func_list);
1589           free (external);
1590           MPLIST_KEY (plist) = Mt;
1591         }
1592       M17N_OBJECT_UNREF (im_info->externals);
1593     }
1594   free (im_info);
1595   im->info = NULL;
1596 }
1597
1598
1599 static int
1600 create_ic (MInputContext *ic)
1601 {
1602   MInputMethod *im = ic->im;
1603   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1604   MInputContextInfo *ic_info;
1605
1606   if (ic->info)
1607     ic_info = (MInputContextInfo *) ic->info;
1608   else
1609     {
1610       MSTRUCT_CALLOC (ic_info, MERROR_IM);
1611       ic->info = ic_info;
1612     }
1613   MLIST_INIT1 (ic_info, keys, 8);
1614   ic_info->markers = mplist ();
1615   ic_info->vars = mplist ();
1616   ic_info->preedit_saved = mtext ();
1617   if (im_info->externals)
1618     {
1619       MPlist *func_args = mplist (), *plist;
1620
1621       mplist_add (func_args, Mt, ic);
1622       MPLIST_DO (plist, im_info->externals)
1623         {
1624           MIMExternalModule *external = MPLIST_VAL (plist);
1625           MIMExternalFunc func
1626             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
1627
1628           if (func)
1629             (func) (func_args);
1630         }
1631       M17N_OBJECT_UNREF (func_args);
1632     }
1633   reset_ic (ic, Mnil);
1634   return 0;
1635 }
1636
1637 static void
1638 destroy_ic (MInputContext *ic)
1639 {
1640   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1641   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1642
1643   if (im_info->externals)
1644     {
1645       MPlist *func_args = mplist (), *plist;
1646
1647       mplist_add (func_args, Mt, ic);
1648       MPLIST_DO (plist, im_info->externals)
1649         {
1650           MIMExternalModule *external = MPLIST_VAL (plist);
1651           MIMExternalFunc func
1652             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
1653
1654           if (func)
1655             (func) (func_args);
1656         }
1657       M17N_OBJECT_UNREF (func_args);
1658     }
1659   MLIST_FREE1 (ic_info, keys);
1660   M17N_OBJECT_UNREF (ic_info->preedit_saved);
1661   M17N_OBJECT_UNREF (ic_info->markers);
1662   M17N_OBJECT_UNREF (ic_info->vars);
1663   free (ic->info);
1664 }
1665
1666
1667 /** Handle the input key KEY in the current state and map of IC->info.
1668     If KEY is handled but no text is produced, return 0, otherwise
1669     return 1.
1670
1671     Ignore ARG.  */
1672
1673 static int
1674 filter (MInputContext *ic, MSymbol key, void *arg)
1675 {
1676   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1677   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1678   int i = 0;
1679
1680   if (! ic_info->state)
1681     {
1682       ic_info->key_unhandled = 1;
1683       return 0;
1684     }
1685   mtext_reset (ic->produced);
1686   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
1687   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
1688   ic_info->key_unhandled = 0;
1689   do {
1690     if (handle_key (ic) < 0)
1691       {
1692         /* KEY was not handled.  Reset the status and break the
1693            loop.  */
1694         reset_ic (ic, Mnil);
1695         /* This forces returning 1.  */
1696         ic_info->key_unhandled = 1;
1697         break;
1698       }
1699     if (i++ == 100)
1700       {
1701         mdebug_hook ();
1702         reset_ic (ic, Mnil);
1703         ic_info->key_unhandled = 1;
1704         break;
1705       }
1706     /* Break the loop if all keys were handled.  */
1707   } while (ic_info->key_head < ic_info->used);
1708
1709   /* If the current map is the root of the initial state, we should
1710      produce any preedit text in ic->produced.  */
1711   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
1712       && mtext_nchars (ic->preedit) > 0)
1713     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1714
1715   if (mtext_nchars (ic->produced) > 0)
1716     {
1717       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
1718
1719       if (lang != Mnil)
1720         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
1721                         Mlanguage, ic->im->language);
1722     }
1723
1724   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
1725 }
1726
1727
1728 /** Return 1 if the last event or key was not handled, otherwise
1729     return 0.
1730
1731     There is no need of looking up because ic->produced should already
1732     contain the produced text (if any).
1733
1734     Ignore KEY.  */
1735
1736 static int
1737 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
1738 {
1739   mtext_cat (mt, ic->produced);
1740   mtext_reset (ic->produced);
1741   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
1742 }
1743
1744 /* Support functions for mdebug_dump_im.  */
1745
1746 static void
1747 dump_im_map (MPlist *map_list, int indent)
1748 {
1749   char *prefix;
1750   MSymbol key = MPLIST_KEY (map_list);
1751   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
1752
1753   prefix = (char *) alloca (indent + 1);
1754   memset (prefix, 32, indent);
1755   prefix[indent] = '\0';
1756
1757   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
1758   if (map->map_actions)
1759     mdebug_dump_plist (map->map_actions, indent + 2);
1760   if (map->submaps)
1761     {
1762       MPLIST_DO (map_list, map->submaps)
1763         {
1764           fprintf (stderr, "\n%s  ", prefix);
1765           dump_im_map (map_list, indent + 2);
1766         }
1767     }
1768   if (map->branch_actions)
1769     {
1770       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
1771       mdebug_dump_plist (map->branch_actions, indent + 4);
1772       fprintf (stderr, ")");      
1773     }
1774   fprintf (stderr, ")");
1775 }
1776
1777
1778 static void
1779 dump_im_state (MIMState *state, int indent)
1780 {
1781   char *prefix;
1782   MPlist *map_list;
1783
1784   prefix = (char *) alloca (indent + 1);
1785   memset (prefix, 32, indent);
1786   prefix[indent] = '\0';
1787
1788   fprintf (stderr, "(%s", msymbol_name (state->name));
1789   if (state->map->submaps)
1790     {
1791       MPLIST_DO (map_list, state->map->submaps)
1792         {
1793           fprintf (stderr, "\n%s  ", prefix);
1794           dump_im_map (map_list, indent + 2);
1795         }
1796     }
1797   fprintf (stderr, ")");
1798 }
1799
1800 \f
1801
1802 int
1803 minput__init ()
1804 {
1805   char *key_names[32]
1806     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1807         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
1808         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1809         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
1810   char buf[6], buf2[256];
1811   int i;
1812
1813   Minput_method = msymbol ("input-method");
1814   Minput_driver = msymbol ("input-driver");
1815   Mtitle = msymbol ("title");
1816   Mmacro = msymbol ("macro");
1817   Mmodule = msymbol ("module");
1818   Mmap = msymbol ("map");
1819   Mstate = msymbol ("state");
1820   Minsert = msymbol ("insert");
1821   Mdelete = msymbol ("delete");
1822   Mmove = msymbol ("move");
1823   Mmark = msymbol ("mark");
1824   Mpushback = msymbol ("pushback");
1825   Mundo = msymbol ("undo");
1826   Mcall = msymbol ("call");
1827   Mshift = msymbol ("shift");
1828   Mselect = msymbol ("select");
1829   Mshow = msymbol ("show");
1830   Mhide = msymbol ("hide");
1831   Mset = msymbol ("set");
1832   Madd = msymbol ("add");
1833   Msub = msymbol ("sub");
1834   Mmul = msymbol ("mul");
1835   Mdiv = msymbol ("div");
1836   Mequal = msymbol ("=");
1837   Mless = msymbol ("<");
1838   Mgreater = msymbol (">");
1839
1840   Minput_preedit_start = msymbol ("input-preedit-start");
1841   Minput_preedit_done = msymbol ("input-preedit-done");
1842   Minput_preedit_draw = msymbol ("input-preedit-draw");
1843   Minput_status_start = msymbol ("input-status-start");
1844   Minput_status_done = msymbol ("input-status-done");
1845   Minput_status_draw = msymbol ("input-status-draw");
1846   Minput_candidates_start = msymbol ("input-candidates-start");
1847   Minput_candidates_done = msymbol ("input-candidates-done");
1848   Minput_candidates_draw = msymbol ("input-candidates-draw");
1849   Minput_set_spot = msymbol ("input-set-spot");
1850   Minput_toggle = msymbol ("input-toggle");
1851   Minput_reset = msymbol ("input-reset");
1852
1853   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
1854   Mcandidate_index = msymbol ("  candidate-index");
1855
1856   Minit = msymbol ("init");
1857   Mfini = msymbol ("fini");
1858
1859   M_key_alias = msymbol ("  key-alias");
1860
1861   buf[0] = 'C';
1862   buf[1] = '-';
1863   buf[3] = '\0';
1864   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
1865     {
1866       one_char_symbol[i] = msymbol (buf);
1867       if (key_names[i])
1868         msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (key_names[i]));
1869     }
1870   for (buf[2] = i; i < 127; i++, buf[2]++)
1871     one_char_symbol[i] = msymbol (buf + 2);
1872   one_char_symbol[i++] = msymbol ("Delete");
1873   buf[2] = 'M';
1874   buf[3] = '-';
1875   buf[5] = '\0';
1876   buf2[0] = 'M';
1877   buf2[1] = '-';
1878   for (buf[4] = '@'; i < 160; i++, buf[4]++)
1879     {
1880       one_char_symbol[i] = msymbol (buf);
1881       if (key_names[i - 128])
1882         {
1883           strcpy (buf2 + 2, key_names[i - 128]);
1884           msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (buf2));
1885         }
1886     }
1887   for (buf[4] = i - 128; i < 255; i++, buf[4]++)
1888     one_char_symbol[i] = msymbol (buf + 2);
1889   one_char_symbol[i] = msymbol ("M-Delete");
1890
1891   minput_default_driver.open_im = open_im;
1892   minput_default_driver.close_im = close_im;
1893   minput_default_driver.create_ic = create_ic;
1894   minput_default_driver.destroy_ic = destroy_ic;
1895   minput_default_driver.filter = filter;
1896   minput_default_driver.lookup = lookup;
1897   minput_default_driver.callback_list = mplist ();
1898   mplist_put (minput_default_driver.callback_list, Minput_reset,
1899               (void *) reset_ic);
1900   minput_driver = &minput_default_driver;
1901   return 0;
1902 }
1903
1904 void
1905 minput__fini ()
1906 {
1907   if (minput_default_driver.callback_list)
1908     {
1909       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
1910       minput_default_driver.callback_list = NULL;
1911     }
1912   if (minput_driver->callback_list)
1913     {
1914       M17N_OBJECT_UNREF (minput_driver->callback_list);
1915       minput_driver->callback_list = NULL;
1916     }
1917 }
1918
1919 void
1920 minput__callback (MInputContext *ic, MSymbol command)
1921 {
1922   if (ic->im->driver.callback_list)
1923     {
1924       MInputCallbackFunc func
1925         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
1926                                            command);
1927
1928       if (func)
1929         (func) (ic, command);
1930     }
1931 }
1932
1933 MSymbol
1934 minput__char_to_key (int c)
1935 {
1936   if (c < 0 || c >= 0x100)
1937     return Mnil;
1938
1939   return one_char_symbol[c];
1940 }
1941
1942 /*** @} */
1943 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1944
1945 \f
1946 /* External API */
1947
1948 /*** @addtogroup m17nInputMethod */
1949 /*** @{ */
1950 /*=*/
1951
1952 /***en
1953     @name Variables: Predefined symbols for callback commands.
1954
1955     These are the predefined symbols that are used as the @c COMMAND
1956     argument of callback functions of an input method driver (see
1957     #MInputDriver::callback_list ).  */ 
1958 /***ja
1959     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
1960
1961     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND °ú¿ô¤È¤·
1962     ¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
1963       */ 
1964 /*** @{ */ 
1965 /*=*/
1966
1967 MSymbol Minput_preedit_start;
1968 MSymbol Minput_preedit_done;
1969 MSymbol Minput_preedit_draw;
1970 MSymbol Minput_status_start;
1971 MSymbol Minput_status_done;
1972 MSymbol Minput_status_draw;
1973 MSymbol Minput_candidates_start;
1974 MSymbol Minput_candidates_done;
1975 MSymbol Minput_candidates_draw;
1976 MSymbol Minput_set_spot;
1977 MSymbol Minput_toggle;
1978 MSymbol Minput_reset;
1979 /*** @} */
1980 /*=*/
1981
1982 /***en
1983     @brief The default driver for internal input methods.
1984
1985     The variable #minput_default_driver is the default driver for
1986     internal input methods.
1987
1988     The member MInputDriver::open_im () searches the m17n database for
1989     an input method that matches the tag \< #Minput_method, $LANGUAGE,
1990     $NAME\> and loads it.
1991
1992     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
1993     programmers responsibility to set it to a plist of proper callback
1994     functions.  Otherwise, no feedback information (e.g. preedit text)
1995     can be shown to users.
1996
1997     The macro M17N_INIT () sets the variable #minput_driver to the
1998     pointer to this driver so that all internal input methods use it.
1999
2000     Therefore, unless @c minput_driver is set differently, the driver
2001     dependent arguments $ARG of the functions whose name begin with
2002     "minput_" are all ignored.  */
2003
2004 /***ja
2005     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
2006
2007     ÆþÎϥɥ饤¥Ð #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë
2008     ¥È¤Î¥É¥é¥¤¥Ð¤Ç¤¢¤ë¡£
2009
2010     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
2011     \< #Minput_method, $LANGUAGE, $NAME\> ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢
2012     ¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
2013
2014     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ê¤Î¤Ç¡¢¥×¥í¥°¥é
2015     ¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ, Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist ¤ËÀßÄꤷ¤Ê¤¯¤Æ
2016     ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊó¤¬
2017     ¥æ¡¼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
2018
2019     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
2020     ¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
2021
2022     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
2023     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
2024
2025 MInputDriver minput_default_driver;
2026 /*=*/
2027
2028 /***en
2029     @brief The driver for internal input methods.
2030
2031     The variable #minput_driver is a pointer to the input method
2032     driver that is used by internal input methods.  The macro
2033     M17N_INIT () initializes it to a pointer to #minput_default_driver
2034     (if <m17n.h> is included) or to #minput_gui_driver (if
2035     <m17n-gui.h> is included).  */ 
2036 /***ja
2037     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
2038
2039     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
2040     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥íM17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
2041     ¥¿¤ò #minput_default_driver (<m17n.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Þ¤¿¤Ï 
2042     #minput_gui_driver ( <m17n-gui.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
2043
2044 MInputDriver *minput_driver;
2045
2046 MSymbol Minput_driver;
2047
2048 /*=*/
2049
2050 /***en
2051     @brief Open an input method.
2052
2053     The minput_open_im () function opens an input method that matches
2054     language $LANGUAGE and name $NAME, and returns a pointer to the
2055     input method object newly allocated.
2056
2057     This function at first decides an driver for the input method as
2058     below.
2059
2060     If $LANGUAGE is not #Mnil, the driver pointed by the variable
2061     #minput_driver is used.
2062
2063     If $LANGUAGE is #Mnil and $NAME has #Minput_driver property, the
2064     driver pointed to by the property value is used to open the input
2065     method.  If $NAME has no such property, @c NULL is returned.
2066
2067     Then, the member MInputDriver::open_im () of the driver is
2068     called.  
2069
2070     $ARG is set in the member @c arg of the structure MInputMethod so
2071     that the driver can refer to it.  */
2072
2073 /***ja
2074     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
2075
2076     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME ¤Ë¹çÃפ¹¤ëÆþ
2077     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯
2078     ¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
2079     
2080     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
2081
2082     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë
2083     ¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
2084
2085     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ò»ý
2086     ¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþ
2087     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£$NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì
2088     ¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2089
2090     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
2091
2092     $ARG ¤Ï¡¢¥É¥é¥¤¥Ð¤¬»²¾È¤Ç¤­¤ë¤è¤¦¤Ë¡¢¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð 
2093     @c arg ¤ËÀßÄꤵ¤ì¤ë¡£
2094
2095     @latexonly \IPAlabel{minput_open} @endlatexonly
2096
2097 */
2098
2099 MInputMethod *
2100 minput_open_im (MSymbol language, MSymbol name, void *arg)
2101 {
2102   MInputMethod *im;
2103   MInputDriver *driver;
2104
2105   if (language)
2106     driver = minput_driver;
2107   else
2108     {
2109       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
2110       if (! driver)
2111         MERROR (MERROR_IM, NULL);
2112     }
2113
2114   MSTRUCT_CALLOC (im, MERROR_IM);
2115   im->language = language;
2116   im->name = name;
2117   im->arg = arg;
2118   im->driver = *driver;
2119   if ((*im->driver.open_im) (im) < 0)
2120     {
2121       free (im);
2122       return NULL;
2123     }
2124   return im;
2125 }
2126
2127 /*=*/
2128
2129 /***en
2130     @brief Close an input method.
2131
2132     The minput_close_im () function closes the input method $IM, which
2133     must have been created by minput_open_im ().  */
2134
2135 /***ja
2136     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
2137
2138     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£¤³¤Î
2139     ÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì
2140     ¤Ð¤Ê¤é¤Ê¤¤¡£  */
2141
2142 void
2143 minput_close_im (MInputMethod *im)
2144 {
2145   (*im->driver.close_im) (im);
2146   free (im);
2147 }
2148
2149 /*=*/
2150
2151 /***en
2152     @brief Create an input context.
2153
2154     The minput_create_ic () function creates an input context object
2155     associated with input method $IM, and calls callback functions
2156     corresponding to #Minput_preedit_start, #Minput_status_start, and
2157     #Minput_status_draw in this order.
2158
2159     @return
2160
2161     If an input context is successfully created, minput_create_ic ()
2162     returns a pointer to it.  Otherwise it returns @c NULL.  */
2163
2164 /***ja
2165     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
2166
2167     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯
2168     ¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢ #Minput_preedit_start,
2169     #Minput_status_start, #Minput_status_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
2170     ¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2171
2172     @return
2173
2174     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () ¤Ï¤½¤ÎÆþÎÏ¥³
2175     ¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2176       */
2177
2178 MInputContext *
2179 minput_create_ic (MInputMethod *im, void *arg)
2180 {
2181   MInputContext *ic;
2182
2183   MSTRUCT_CALLOC (ic, MERROR_IM);
2184   ic->im = im;
2185   ic->arg = arg;
2186   ic->preedit = mtext ();
2187   ic->candidate_list = NULL;
2188   ic->produced = mtext ();
2189   ic->spot.x = ic->spot.y = 0;
2190   ic->active = 1;
2191   ic->plist = mplist ();
2192   if ((*im->driver.create_ic) (ic) < 0)
2193     {
2194       M17N_OBJECT_UNREF (ic->preedit);
2195       M17N_OBJECT_UNREF (ic->produced);
2196       M17N_OBJECT_UNREF (ic->plist);
2197       free (ic);
2198       return NULL;
2199     };
2200
2201   if (im->driver.callback_list)
2202     {
2203       minput__callback (ic, Minput_preedit_start);
2204       minput__callback (ic, Minput_status_start);
2205       minput__callback (ic, Minput_status_draw);
2206     }
2207
2208   return ic;
2209 }
2210
2211 /*=*/
2212
2213 /***en
2214     @brief Destroy an input context.
2215
2216     The minput_destroy_ic () function destroys the input context $IC,
2217     which must have been created by minput_create_ic ().  It calls
2218     callback functions corresponding to #Minput_preedit_done,
2219     #Minput_status_done, and #Minput_candidates_done in this order.  */
2220
2221 /***ja
2222     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
2223
2224     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£¤³
2225     ¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê
2226     ¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï#Minput_preedit_done,
2227     #Minput_status_done, #Minput_candidates_done ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò
2228     ¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2229   */
2230
2231 void
2232 minput_destroy_ic (MInputContext *ic)
2233 {
2234   if (ic->im->driver.callback_list)
2235     {
2236       minput__callback (ic, Minput_preedit_done);
2237       minput__callback (ic, Minput_status_done);
2238       minput__callback (ic, Minput_candidates_done);
2239     }
2240   (*ic->im->driver.destroy_ic) (ic);
2241   M17N_OBJECT_UNREF (ic->preedit);
2242   M17N_OBJECT_UNREF (ic->produced);
2243   M17N_OBJECT_UNREF (ic->plist);
2244   free (ic);
2245 }
2246
2247 /*=*/
2248
2249 /***en
2250     @brief Filter an input key.
2251
2252     The minput_filter () function filters input key $KEY according to
2253     input context $IC, and calls callback functions corresponding to
2254     #Minput_preedit_draw, #Minput_status_draw, and
2255     #Minput_candidates_draw if the preedit text, the status, and the
2256     current candidate are changed respectively.
2257
2258     @return
2259     If $KEY is filtered out, this function returns 1.  In that case,
2260     the caller should discard the key.  Otherwise, it returns 0, and
2261     the caller should handle the key, for instance, by calling the
2262     function minput_lookup () with the same key.  */
2263
2264 /***ja
2265     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
2266
2267     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Ë±þ
2268     ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½
2269     ¤·¤¿ºÝ¤Ë¤Ï¤½¤ì¤¾¤ì#Minput_preedit_draw, #Minput_status_draw,
2270     #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
2271
2272     @return 
2273     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¸Æ¤Ó
2274     ½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó
2275     ½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup () ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢
2276     ¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
2277
2278     @latexonly \IPAlabel{minput_filter} @endlatexonly
2279 */
2280
2281 int
2282 minput_filter (MInputContext *ic, MSymbol key, void *arg)
2283 {
2284   int ret;
2285
2286   if (! ic
2287       || ! ic->active)
2288     return 0;
2289   ret = (*ic->im->driver.filter) (ic, key, arg);
2290
2291   if (ic->im->driver.callback_list)
2292     {
2293       if (ic->preedit_changed)
2294         minput__callback (ic, Minput_preedit_draw);
2295       if (ic->status_changed)
2296         minput__callback (ic, Minput_status_draw);
2297       if (ic->candidates_changed)
2298         minput__callback (ic, Minput_candidates_draw);
2299     }
2300   ic->preedit_changed = ic->status_changed = ic->candidates_changed = 0;
2301
2302   return ret;
2303 }
2304
2305 /*=*/
2306
2307 /***en
2308     @brief Lookup a text produced in the input context.
2309
2310     The minput_lookup () function looks up a text in the input context
2311     $IC.  $KEY must be the same one provided to the previous call of
2312     minput_filter ().
2313
2314     If a text was produced by the input method, it is concatenated
2315     to M-text $MT.
2316
2317     This function calls #MInputDriver::lookup .
2318
2319     @return
2320     If $KEY was correctly handled by the input method, this function
2321     returns 0.  Otherwise, returns -1, even in that case, some text
2322     may be produced in $MT.  */
2323
2324 /***ja
2325     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤Î¸¡º÷.
2326
2327     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤ò¸¡º÷¤¹
2328     ¤ë¡£$KEY ¤Ï´Ø¿ôminput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î
2329     ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2330
2331     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
2332     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
2333
2334     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
2335
2336     @return 
2337     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
2338     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸
2339     À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
2340
2341     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
2342
2343 int
2344 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2345 {
2346   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
2347 }
2348 /*=*/
2349
2350 /***en
2351     @brief Set the spot of the input context.
2352
2353     The minput_set_spot () function set the spot of input context $IC
2354     to coordinate ($X, $Y ) with the height $ASCENT and $DESCENT .
2355     The semantics of these values depend on the input method driver.
2356     $FONTSIZE specfies the fontsize of a preedit text in 1/10 point.
2357
2358     For instance, an driver designed to work in CUI environment may
2359     use $X and $Y as column and row numbers, and ignore $ASCENT and
2360     $DESCENT .  An driver designed to work on a window system may
2361     treat $X and $Y as pixel offsets relative to the origin of the
2362     client window, and treat $ASCENT and $DESCENT as ascent and
2363     descent pixels of a line at ($X . $Y ).
2364
2365     $MT and $POS is an M-text and a character position at the spot.
2366     $MT may be @c NULL, in which case, the input method cannot get
2367     information about the text around the spot.  */
2368
2369 /***ja
2370     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë
2371
2372     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂ
2373     É¸ ($X, $Y )¤Ë ¡¢¹â¤µ $ASCENT¡¢ $DESCENT ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤÎ
2374     °ÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£$FONTSIZE ¤Ïpreedit ¥Æ¥­¥¹¥È
2375     ¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
2376
2377     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤Î
2378     ÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿
2379     ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦
2380     ¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
2381     $ASCENT ¤È $DESCENT ¤ò ($X . $Y ) ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯
2382     ¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
2383
2384     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
2385     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë
2386     ´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
2387     */
2388
2389 void
2390 minput_set_spot (MInputContext *ic, int x, int y,
2391                  int ascent, int descent, int fontsize,
2392                  MText *mt, int pos)
2393 {
2394   ic->spot.x = x;
2395   ic->spot.y = y;
2396   ic->spot.ascent = ascent;
2397   ic->spot.descent = descent;
2398   ic->spot.fontsize = fontsize;
2399   ic->spot.mt = mt;
2400   ic->spot.pos = pos;
2401   if (ic->im->driver.callback_list)
2402     minput__callback (ic, Minput_set_spot);
2403 }
2404 /*=*/
2405
2406 /***en
2407     @brief Toggle input method.
2408
2409     The minput_toggle () function toggles the input method associated
2410     with the input context $IC.  */
2411 /***ja
2412     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
2413
2414     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎÏ
2415     ¥á¥½¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
2416     */
2417
2418 void
2419 minput_toggle (MInputContext *ic)
2420 {
2421   if (ic->im->driver.callback_list)
2422     minput__callback (ic, Minput_toggle);
2423   ic->active = ! ic->active;
2424 }
2425
2426 /***en
2427     @brief Reset an input context.
2428
2429     The minput_reset_ic () function resets the input context $IC by
2430     calling a callback functions corresponding to #Minput_reset.  As
2431     the current preediting text is committed to $IC->produce, if
2432     necessary, a program can extract the text from there.  */
2433 /***ja
2434     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
2435
2436     ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
2437     ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¸½ºßÆþÎÏÃæ¤Î
2438     ¥Æ¥­¥¹¥È¤Ï $IC->produced ¤ËÁݤ­½Ð¤µ¤ì¤ë¤Î¤Ç¡¢É¬Íפʤ饢¥×¥ê¥±¡¼¥·¥ç
2439     ¥ó¥×¥í¥°¥é¥à¤Ï¤½¤Î¥Æ¥­¥¹¥È¤ò¤½¤³¤«¤é¼è¤ê½Ð¤»¤ë¡£ */
2440 void
2441 minput_reset_ic (MInputContext *ic)
2442 {
2443   if (ic->im->driver.callback_list)
2444     minput__callback (ic, Minput_reset);
2445 }
2446
2447
2448 /*** @} */
2449 /*=*/
2450 /*** @addtogroup m17nDebug */
2451 /*=*/
2452 /*** @{  */
2453 /*=*/
2454
2455 /***en
2456     @brief Dump an input method.
2457
2458     The mdebug_dump_im () function prints the input method $IM in a
2459     human readable way to the stderr.  $INDENT specifies how many
2460     columns to indent the lines but the first one.
2461
2462     @return
2463     This function returns $IM.  */
2464 /***ja
2465     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
2466
2467     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr ¤Ë¿Í´Ö¤Ë²ÄÆɤÊ
2468     ·Á¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
2469
2470     @return
2471     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
2472
2473 MInputMethod *
2474 mdebug_dump_im (MInputMethod *im, int indent)
2475 {
2476   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2477   char *prefix;
2478
2479   prefix = (char *) alloca (indent + 1);
2480   memset (prefix, 32, indent);
2481   prefix[indent] = '\0';
2482
2483   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
2484            msymbol_name (im->name));
2485   mdebug_dump_mtext (im_info->title, 0, 0);
2486   if (im->name != Mnil)
2487     {
2488       MPlist *state;
2489
2490       MPLIST_DO (state, im_info->states)
2491         {
2492           fprintf (stderr, "\n%s  ", prefix);
2493           dump_im_state (MPLIST_VAL (state), indent + 2);
2494         }
2495     }
2496   fprintf (stderr, ")");
2497   return im;
2498 }
2499
2500 /*** @} */ 
2501
2502 /*
2503   Local Variables:
2504   coding: euc-japan
2505   End:
2506 */