96726baf7e51544996efea5686a73f52de5ba258
[m17n/m17n-lib.git] / src / input.c
1 /* input.c -- input method module.
2    Copyright (C) 2003, 2004, 2005
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 °Ê³°¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂΤÏm17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë
95     <Minput_method, LANGUAGE, NAME> 
96     ¤È¤¤¤¦¥¿¥°¤òÉÕ¤±¤ÆÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£
97     ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤ËÂФ·¤Æ¡¢m17n ¥é¥¤¥Ö¥é¥ê¤Ç¤Ï
98     CUI ÍѤȠGUI ÍѤ½¤ì¤¾¤ì¤ÎÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤ò¤¢¤é¤«¤¸¤áÄêµÁ¤·¤Æ¤¤¤ë¡£
99     ¤³¤ì¤é¤Î¥É¥é¥¤¥Ð¤Ï m17n ¥é¥¤¥Ö¥é¥ê¼«ÂΤÎÆþÎϽèÍý¥¨¥ó¥¸¥ó¤òÍøÍѤ¹¤ë¡£
100     m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤Ï¡¢ÆÃÄê¤Î¸À¸ìÀìÍѤǤʤ¤ÆþÎϥ᥽¥Ã¥É¤òÄêµÁ¤¹¤ë¤³¤È¤â¤Ç¤­¡¢
101     ¤½¤Î¤è¤¦¤ÊÆþÎϥ᥽¥Ã¥É¤Î LANGUAGE ¤Ï @c Mt ¤Ç¤¢¤ë¡£
102
103     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï¡¢¥æ¡¼¥¶¤ÎÆþÎÏ¥¤¥Ù¥ó¥È¤ËÂбþ¤·¤¿¥·¥ó¥Ü¥ë¤Ç¤¢¤ëÆþÎÏ¥­¡¼¤ò¼õ¤±¼è¤ë¡£
104     @c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÏÆþÎÏ¥¤¥Ù¥ó¥È¤¬¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ç¤É¤¦É½¸½¤µ¤ì¤Æ¤¤¤ë¤«¤òÃΤ뤳¤È¤¬¤Ç¤­¤Ê¤¤¤Î¤Ç¡¢
105     ÆþÎÏ¥¤¥Ù¥ó¥È¤«¤éÆþÎÏ¥­¡¼¤Ø¤ÎÊÑ´¹¤Ï¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥Þ¤ÎÀÕǤ¤Ç¹Ô¤ï¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
106     ¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï´Ø¿ô minput_event_to_key () ¤ÎÀâÌÀ¤ò»²¾È¡£
107
108     <li> ³°ÉôÆþÎϥ᥽¥Ã¥É
109
110     ³°ÉôÆþÎϥ᥽¥Ã¥É¤È¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂΤϳ°Éô¤Î¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£
111     ¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê¤É¡£) 
112     ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï@c Minput_driver 
113     ¤ò¥­¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£
114     ¤³¤Î¤³¤È¤Ë¤è¤ê¡¢Å¬Àڤʥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢¤¤¤«¤Ê¤ë¼ïÎà¤ÎÆþÎϥ᥽¥Ã¥É¤â
115     @c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÎÏÈÁȤÎÃæ¤Ç°·¤¦»ö¤¬¤Ç¤­¤ë¡£
116
117     ÍøÊØÀ­¤Î´ÑÅÀ¤«¤é¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤Ï XIM ¤Î OverTheSpot 
118     ¤ÎÆþÎÏ¥¹¥¿¥¤¥ë¤ò¼Â¸½¤¹¤ëÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤òÄ󶡤·¡¢¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î 
119     @c Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý¤·¤Æ¤¤¤ë¡£
120     ¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï m17n GUI API ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
121
122     </ul> 
123
124     ½èÍý¤Îή¤ì
125
126     ÆþÎϥ᥽¥Ã¥É½èÍý¤Îŵ·¿Åª¤Ê½èÍý¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
127     
128     @li ÆþÎϥ᥽¥Ã¥É¤Î¥ª¡¼¥×¥ó
129     @li ¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ÎÀ¸À®
130     @li ÆþÎÏ¥¤¥Ù¥ó¥È¤Î¥Õ¥£¥ë¥¿
131     @li ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ç¤ÎÀ¸À®¥Æ¥­¥¹¥È¤Î¸¡º÷     */
132
133 /*=*/
134
135 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
136 /*** @addtogroup m17nInternal
137      @{ */
138
139 #include <stdio.h>
140 #include <stdlib.h>
141 #include <string.h>
142 #include <sys/types.h>
143 #include <dirent.h>
144 #include <sys/stat.h>
145 #include <unistd.h>
146
147 #include "config.h"
148
149 #ifdef HAVE_DLFCN_H
150 #include <dlfcn.h>
151 #endif
152
153 #include "m17n-gui.h"
154 #include "m17n-misc.h"
155 #include "internal.h"
156 #include "mtext.h"
157 #include "input.h"
158 #include "symbol.h"
159 #include "plist.h"
160 #include "database.h"
161 #include "charset.h"
162
163 static int mdebug_mask = MDEBUG_INPUT;
164
165 static MSymbol Minput_method;
166
167 /** Symbols to load an input method data.  */
168 static MSymbol Mtitle, Mmacro, Mmodule, Mstate, Minclude;
169
170 /** Symbols for actions.  */
171 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
172 static MSymbol Mselect, Mshow, Mhide, Mcommit, Munhandle;
173 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
174 static MSymbol M_candidates;
175
176 static MSymbol Mcandidate_list, Mcandidate_index;
177
178 static MSymbol Minit, Mfini;
179
180 /** Symbols for variables.  */
181 static MSymbol Mcandidates_group_size, Mcandidates_charset;
182
183 /** Symbols for key events.  */
184 static MSymbol one_char_symbol[256];
185
186 static MSymbol M_key_alias;
187
188 static MSymbol M_description, M_command, M_variable;
189
190 /** Structure to hold a map.  */
191
192 struct MIMMap
193 {
194   /** List of actions to take when we reach the map.  In a root map,
195       the actions are executed only when there's no more key.  */
196   MPlist *map_actions;
197
198   /** List of deeper maps.  If NULL, this is a terminal map.  */
199   MPlist *submaps;
200
201   /** List of actions to take when we leave the map successfully.  In
202       a root map, the actions are executed only when none of submaps
203       handle the current key.  */
204   MPlist *branch_actions;
205 };
206
207 typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
208
209 typedef struct
210 {
211   void *handle;
212   MPlist *func_list;            /* function name vs (MIMExternalFunc *) */
213 } MIMExternalModule;
214
215 struct MIMState
216 {
217   M17NObject control;
218
219   /** Name of the state.  */
220   MSymbol name;
221
222   /** Title of the state, or NULL.  */
223   MText *title;
224
225   /** Key translation map of the state.  Built by merging all maps of
226       branches.  */
227   MIMMap *map;
228 };
229
230 /* Lookup keys KEY1,2,3 in the nested plist PLIST, and return the
231    value.  */
232
233 static MPlist *
234 lookup_nested_list (MPlist *plist, MSymbol key1, MSymbol key2, MSymbol key3)
235 {
236   MSymbol key[3];
237   int i;
238
239   key[0] = key1, key[1] = key2, key[2] = key3;
240   for (i = 0; i < 3; i++)
241     {
242       plist = mplist_find_by_value (plist, key[i]);
243       if (! plist)
244         return NULL;
245       plist = MPLIST_NEXT (plist);
246       plist = MPLIST_PLIST (plist);
247     }
248   return plist;
249 }
250
251 /* Set VAL for keys KEY1,2,3 in the nested plist PLIST.  */
252
253 static MPlist *
254 set_nested_list (MPlist *plist, MSymbol key1, MSymbol key2, MSymbol key3,
255                  MPlist *val)
256 {
257   MSymbol key[3];
258   int i;
259   MPlist *pl;
260
261   key[0] = key1, key[1] = key2, key[2] = key3;
262   for (i = 0; i < 3; i++)
263     {
264       pl = mplist_find_by_value (plist, key[i]);
265       if (pl)
266         {
267           pl = MPLIST_NEXT (pl);
268           plist = MPLIST_PLIST (pl);
269         }
270       else
271         {
272           pl = mplist_add (plist, Msymbol, key[i]);
273           plist = mplist ();
274           pl = mplist_add (pl, Mplist, plist);
275           M17N_OBJECT_UNREF (plist);
276         }
277     }
278   mplist_set (pl, Mplist, val);
279   M17N_OBJECT_UNREF (val);
280   return pl;
281 }
282
283 /* Parse PLIST as a value of nested list and return an adjusted list.
284
285    PLIST has this form;
286      (symbol:command
287       plist:(symbol:KEY
288              [ mtext:DESCRIPTION | symbol:nil ]
289              ;; The remaining elements are checked CHECK_FUNC.
290              ...)
291       plist:(symbol:KEY
292              [ mtext:DESCRIPTION | symbol:nil ]
293              ;; The remaining elements are checked CHECK_FUNC.
294              ...)
295       ...)
296
297    GLOBAL is a global list.  If a description text is missing, it is
298    extracted from GLOBAL.
299
300    The return value is a plist of this format:
301      (symbol:KEY
302       plist:([ mtext:DESCRIPTION | symbol:nil ]
303              ...)
304       symbol:KEY
305       plist:([ mtext:DESCRIPTION | symbol:nil ]
306              ...)
307       ...)
308
309    PLIST itself is unref-ed.  */
310
311 static MPlist *
312 parse_nested_list_value (MPlist *plist, MPlist *global, MSymbol key,
313                          int (*check_func) (MPlist *))
314 {
315   MPlist *val, *pl, *p, *p0;
316
317   val = mplist ();
318   if (! MPLIST_PLIST_P (plist))
319     {
320       M17N_OBJECT_UNREF (plist);
321       return val;
322     }
323   pl = MPLIST_PLIST (plist);
324   if (! MPLIST_SYMBOL_P (pl)
325       || MPLIST_SYMBOL (pl) != key)
326     {
327       M17N_OBJECT_UNREF (plist);
328       return val;
329     }
330
331   MPLIST_DO (pl, MPLIST_NEXT (pl))
332     {
333       MSymbol name;
334       MPlist *global_def;
335
336       if (! MPLIST_PLIST_P (pl))
337         continue;
338       p = MPLIST_PLIST (pl);
339       if (! MPLIST_SYMBOL_P (p))
340         continue;
341       name = MPLIST_SYMBOL (p);
342       p = MPLIST_NEXT (p);
343       if (MPLIST_TAIL_P (p))
344         {
345           if (! global)
346             continue;
347           global_def = mplist_find_by_value (global, name);
348           if (! global_def)
349             continue;
350           global_def = MPLIST_PLIST (MPLIST_NEXT (global_def));
351           mplist__conc (p, global_def);
352           global = NULL;
353         }
354       p0 = MPLIST_NEXT (p);
355       if (MPLIST_TAIL_P (p0))
356         {
357           if (! global)
358             continue;
359           global_def = mplist_find_by_value (global, name);
360           if (! global_def)
361             continue;
362           global_def = MPLIST_PLIST (MPLIST_NEXT (global_def));
363           global_def = MPLIST_NEXT (global_def);
364           if (MPLIST_TAIL_P (global_def))
365             continue;
366           mplist__conc (p0, global_def);
367         }
368       if ((*check_func) (p0) < 0)
369         continue;
370       mplist_add (val, Msymbol, name);
371       mplist_add (val, Mplist, p);
372     }
373
374   M17N_OBJECT_UNREF (plist);
375   return val;
376 }
377
378 static MPlist *variable_list, *command_list;
379 static int check_variable_list (MPlist *plist);
380 static int check_command_list (MPlist *plist);
381 static MPlist *load_partial_im_info (MSymbol language, MSymbol name,
382                                      MSymbol extra, MSymbol key);
383
384 static MPlist *
385 get_nested_list (MSymbol language, MSymbol name, MSymbol extra, MSymbol key)
386 {
387   MPlist *total_list;
388   int (*check_func) (MPlist *);
389   MPlist *plist, *global;
390
391   if (key == M_variable)
392     {
393       if (! variable_list)
394         variable_list = mplist ();
395       total_list = variable_list;
396       check_func = check_variable_list;
397     }
398   else
399     {
400       if (! command_list)
401         command_list = mplist ();
402       total_list = command_list;
403       check_func = check_command_list;
404     }
405
406   if (MPLIST_TAIL_P (total_list))
407     {
408       plist = load_partial_im_info (Mt, Mnil, key, key);
409       if (plist)
410         global = parse_nested_list_value (plist, NULL, key, check_func);
411       else
412         global = mplist ();
413       set_nested_list (total_list, Mt, Mnil, key, global);
414     }
415   else
416     global = lookup_nested_list (total_list, Mt, Mnil, key);
417
418   if (name == Mnil)
419     return global;
420
421   plist = lookup_nested_list (total_list, language, name, extra);
422   if (plist)
423     return plist;
424
425   plist = load_partial_im_info (language, name, extra, key);
426   if (plist)
427     plist = parse_nested_list_value (plist, global, key, check_func);
428   else
429     plist = mplist ();
430   set_nested_list (total_list, language, name, extra, plist);
431   return plist;
432 }
433
434 static int
435 marker_code (MSymbol sym)
436 {
437   char *name;
438
439   if (sym == Mnil)
440     return -1;
441   name = MSYMBOL_NAME (sym);
442   return ((name[0] == '@'
443            && ((name[1] >= '0' && name[1] <= '9')
444                || name[1] == '<' || name[1] == '>'
445                || name[1] == '=' || name[1] == '+' || name[1] == '-'
446                || name[1] == '[' || name[1] == ']'
447                || name[1] == '@')
448            && name[2] == '\0')
449           ? name[1] : -1);
450 }
451
452
453 static MPlist *
454 resolve_variable (MInputContextInfo *ic_info, MSymbol var)
455 {
456   MPlist *p;
457
458   MPLIST_DO (p, ic_info->vars)
459     {
460       if (MPLIST_SYMBOL (p) == var)
461         break;
462       p = MPLIST_NEXT (p);
463     }
464   if (MPLIST_TAIL_P (p))
465     {
466       p = ic_info->vars;
467       mplist_push (p, Minteger, (void *) 0);
468       mplist_push (p, Msymbol, var);
469     }
470   return (MPLIST_NEXT (p));
471 }
472
473 static MText *
474 get_surrounding_text (MInputContext *ic, int len)
475 {
476   MText *mt = NULL;
477
478   mplist_push (ic->plist, Minteger, (void *) len);
479   minput__callback (ic, Minput_get_surrounding_text);
480   if (MPLIST_MTEXT_P (ic->plist))
481     {
482       mt = MPLIST_MTEXT (ic->plist);
483       mplist_pop (ic->plist);
484     }
485   return mt;
486 }
487
488 static void
489 delete_surrounding_text (MInputContext *ic, int pos)
490 {
491   mplist_push (ic->plist, Minteger, (void *) pos);
492   minput__callback (ic, Minput_delete_surrounding_text);
493   mplist_pop (ic->plist);
494 }
495
496 static int
497 get_preceding_char (MInputContext *ic, int pos)
498 {
499   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
500   MText *mt;
501   int len;
502
503   if (ic_info->preceding_text)
504     {
505       len = mtext_nchars (ic_info->preceding_text);
506       if (pos <= len)
507         return mtext_ref_char (ic_info->preceding_text, len - pos);
508     }
509   mt = get_surrounding_text (ic, - pos);
510   if (! mt)
511     return -1;
512   len = mtext_nchars (mt);
513   if (ic_info->preceding_text)
514     {
515       if (mtext_nchars (ic_info->preceding_text) < len)
516         {
517           M17N_OBJECT_UNREF (ic_info->preceding_text);
518           ic_info->preceding_text = mt;
519         }
520     }
521   else
522     ic_info->preceding_text = mt;
523   if (pos > len)
524     return -1;
525   return mtext_ref_char (ic_info->preceding_text, len - pos);
526 }
527
528 static int
529 get_following_char (MInputContext *ic, int pos)
530 {
531   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
532   MText *mt;
533   int len;
534
535   if (ic_info->following_text)
536     {
537       len = mtext_nchars (ic_info->following_text);
538       if (pos <= len)
539         return mtext_ref_char (ic_info->following_text, pos - 1);
540     }
541   mt = get_surrounding_text (ic, pos);
542   if (! mt)
543     return -1;
544   len = mtext_nchars (mt);
545   if (ic_info->following_text)
546     {
547       if (mtext_nchars (ic_info->following_text) < len)
548         {
549           M17N_OBJECT_UNREF (ic_info->following_text);
550           ic_info->following_text = mt;
551         }
552     }
553   else
554     ic_info->following_text = mt;
555   if (pos > len)
556     return -1;
557   return mtext_ref_char (ic_info->following_text, pos - 1);
558 }
559
560 static int
561 surrounding_pos (MSymbol sym)
562 {
563   char *name;
564
565   if (sym == Mnil)
566     return 0;
567   name = MSYMBOL_NAME (sym);
568   if ((name[1] == '-' || name[1] == '+')
569       && name[2] >= '1' && name[2] <= '9')
570     return (name[1] == '-' ? - atoi (name + 2) : atoi (name + 2));
571   return 0;
572 }
573
574 static int
575 integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
576 {
577   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
578   int code;
579   MText *preedit = ic->preedit;
580   int len = mtext_nchars (preedit);
581
582   if (value)
583     *value = NULL;
584   if (MPLIST_INTEGER_P (arg))
585     return MPLIST_INTEGER (arg);
586   if (surrounding
587       && (surrounding = surrounding_pos (MPLIST_SYMBOL (arg))) != 0)
588     return (surrounding < 0
589             ? get_preceding_char (ic, - surrounding)
590             : get_following_char (ic, surrounding));
591   code = marker_code (MPLIST_SYMBOL (arg));
592   if (code < 0)
593     {
594       MPlist *val = resolve_variable (ic_info, MPLIST_SYMBOL (arg));
595
596       if (value)
597         *value = val;
598       return (MPLIST_INTEGER_P (val) ? MPLIST_INTEGER (val) : 0);
599     }
600   if (code == '@')
601     return ic_info->key_head;
602   if (code >= '0' && code <= '9')
603     code -= '0';
604   else if (code == '=')
605     code = ic->cursor_pos;
606   else if (code == '-' || code == '[')
607     code = ic->cursor_pos - 1;
608   else if (code == '+' || code == ']')
609     code = ic->cursor_pos + 1;
610   else if (code == '<')
611     code = 0;
612   else if (code == '>')
613     code = len;
614   return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
615 }
616
617
618 /* Parse PLIST as an action list.  PLIST should have this form:
619       PLIST ::= ( (ACTION-NAME ACTION-ARG *) *).
620    Return 0 if successfully parsed, otherwise return -1.  */
621
622 static int
623 parse_action_list (MPlist *plist, MPlist *macros)
624 {
625   MPLIST_DO (plist, plist)
626     {
627       if (MPLIST_MTEXT_P (plist))
628         {
629           /* This is a short form of (insert MTEXT).  */
630           /* if (mtext_nchars (MPLIST_MTEXT (plist)) == 0)
631              MERROR (MERROR_IM, -1); */
632         }
633       else if (MPLIST_PLIST_P (plist)
634                && (MPLIST_MTEXT_P (MPLIST_PLIST (plist))
635                    || MPLIST_PLIST_P (MPLIST_PLIST (plist))))
636         {
637           MPlist *pl;
638
639           /* This is a short form of (insert (GROUPS *)).  */
640           MPLIST_DO (pl, MPLIST_PLIST (plist))
641             {
642               if (MPLIST_PLIST_P (pl))
643                 {
644                   MPlist *elt;
645
646                   MPLIST_DO (elt, MPLIST_PLIST (pl))
647                     if (! MPLIST_MTEXT_P (elt)
648                         || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
649                       MERROR (MERROR_IM, -1);
650                 }
651               else
652                 {
653                   if (! MPLIST_MTEXT_P (pl)
654                       || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
655                     MERROR (MERROR_IM, -1);
656                 }
657             }
658         }
659       else if (MPLIST_INTEGER_P (plist))
660         {
661           int c = MPLIST_INTEGER (plist);
662
663           if (c < 0 || c > MCHAR_MAX)
664             MERROR (MERROR_IM, -1);
665         }
666       else if (MPLIST_PLIST_P (plist)
667                && MPLIST_SYMBOL_P (MPLIST_PLIST (plist)))
668         {
669           MPlist *pl = MPLIST_PLIST (plist);
670           MSymbol action_name = MPLIST_SYMBOL (pl);
671
672           pl = MPLIST_NEXT (pl);
673
674           if (action_name == Minsert)
675             {
676               if (MPLIST_MTEXT_P (pl))
677                 {
678                   if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
679                     MERROR (MERROR_IM, -1);
680                 }
681               else if (MPLIST_PLIST_P (pl))
682                 {
683                   MPLIST_DO (pl, pl)
684                     {
685                       if (MPLIST_PLIST_P (pl))
686                         {
687                           MPlist *elt;
688
689                           MPLIST_DO (elt, MPLIST_PLIST (pl))
690                             if (! MPLIST_MTEXT_P (elt)
691                                 || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
692                               MERROR (MERROR_IM, -1);
693                         }
694                       else
695                         {
696                           if (! MPLIST_MTEXT_P (pl)
697                               || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
698                             MERROR (MERROR_IM, -1);
699                         }
700                     }
701                 }
702               else if (! MPLIST_SYMBOL_P (pl))
703                 MERROR (MERROR_IM, -1); 
704             }
705           else if (action_name == Mselect
706                    || action_name == Mdelete
707                    || action_name == Mmove)
708             {
709               if (! MPLIST_SYMBOL_P (pl)
710                   && ! MPLIST_INTEGER_P (pl))
711                 MERROR (MERROR_IM, -1);
712             }
713           else if (action_name == Mmark
714                    || action_name == Mcall
715                    || action_name == Mshift)
716             {
717               if (! MPLIST_SYMBOL_P (pl))
718                 MERROR (MERROR_IM, -1);
719             }
720           else if (action_name == Mundo)
721             {
722               if (! MPLIST_TAIL_P (pl))
723                 {
724                   if (! MPLIST_SYMBOL_P (pl)
725                       && (! MPLIST_INTEGER_P (pl)
726                           || MPLIST_INTEGER (pl) == 0))
727                     MERROR (MERROR_IM, -1);                 
728                 }
729             }
730           else if (action_name == Mpushback)
731             {
732               if (MPLIST_MTEXT_P (pl))
733                 {
734                   MText *mt = MPLIST_MTEXT (pl);
735
736                   if (mtext_nchars (mt) != mtext_nbytes (mt))
737                     MERROR (MERROR_IM, -1);                 
738                 }
739               else if (MPLIST_PLIST_P (pl))
740                 {
741                   MPlist *p;
742
743                   MPLIST_DO (p, MPLIST_PLIST (pl))
744                     if (! MPLIST_SYMBOL_P (p))
745                       MERROR (MERROR_IM, -1);
746                 }
747               else if (! MPLIST_INTEGER_P (pl))
748                 MERROR (MERROR_IM, -1);
749             }
750           else if (action_name == Mset || action_name == Madd
751                    || action_name == Msub || action_name == Mmul
752                    || action_name == Mdiv)
753             {
754               if (! (MPLIST_SYMBOL_P (pl)
755                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
756                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
757                 MERROR (MERROR_IM, -1);
758             }
759           else if (action_name == Mequal || action_name == Mless
760                    || action_name == Mgreater)
761             {
762               if (! ((MPLIST_INTEGER_P (pl) || MPLIST_SYMBOL_P (pl))
763                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
764                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
765                 MERROR (MERROR_IM, -1);
766               pl = MPLIST_NEXT (MPLIST_NEXT (pl));
767               if (! MPLIST_PLIST_P (pl))
768                 MERROR (MERROR_IM, -1);
769               if (parse_action_list (MPLIST_PLIST (pl), macros) < 0)
770                 MERROR (MERROR_IM, -1);
771               pl = MPLIST_NEXT (pl);
772               if (MPLIST_PLIST_P (pl)
773                   && parse_action_list (MPLIST_PLIST (pl), macros) < 0)
774                 MERROR (MERROR_IM, -1);
775             }
776           else if (action_name == Mshow || action_name == Mhide
777                    || action_name == Mcommit || action_name == Munhandle)
778             ;
779           else if (! macros || ! mplist_get (macros, action_name))
780             MERROR (MERROR_IM, -1);
781         }
782       else
783         MERROR (MERROR_IM, -1);
784     }
785
786   return 0;
787 }
788
789 static MPlist *
790 resolve_command (MSymbol language, MSymbol name, MSymbol command)
791 {
792   MPlist *plist = get_nested_list (language, name, Mnil, M_command);
793
794   if (! plist
795       || ! (plist = mplist_get (plist, command)))
796     return NULL;
797   plist = MPLIST_NEXT (plist);
798   if (! MPLIST_PLIST_P (plist))
799     return NULL;
800   return plist;
801 }
802
803
804
805 /* Load a translation into MAP from PLIST.
806    PLIST has this form:
807       PLIST ::= ( KEYSEQ MAP-ACTION * )  */
808
809 static int
810 load_translation (MIMMap *map, MPlist *keylist, MPlist *map_actions,
811                   MPlist *branch_actions, MPlist *macros)
812 {
813   MSymbol *keyseq;
814   int len, i;
815
816   if (MPLIST_MTEXT_P (keylist))
817     {
818       MText *mt = MPLIST_MTEXT (keylist);
819
820       len = mtext_nchars (mt);
821       if (len == 0 || len != mtext_nbytes (mt))
822         MERROR (MERROR_IM, -1);
823       keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len);
824       for (i = 0; i < len; i++)
825         keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]];
826     }
827   else if (MPLIST_PLIST_P (keylist))
828     {
829       MPlist *elt = MPLIST_PLIST (keylist);
830           
831       len = MPLIST_LENGTH (elt);
832       if (len == 0)
833         MERROR (MERROR_IM, -1);
834       keyseq = (MSymbol *) alloca (sizeof (int) * len);
835       for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
836         {
837           if (MPLIST_INTEGER_P (elt))
838             {
839               int c = MPLIST_INTEGER (elt);
840
841               if (c < 0 || c >= 0x100)
842                 MERROR (MERROR_IM, -1);
843               keyseq[i] = one_char_symbol[c];
844             }
845           else if (MPLIST_SYMBOL_P (elt))
846             keyseq[i] = MPLIST_SYMBOL (elt);
847           else
848             MERROR (MERROR_IM, -1);
849         }
850     }
851   else
852     MERROR (MERROR_IM, -1);
853
854   for (i = 0; i < len; i++)
855     {
856       MIMMap *deeper = NULL;
857
858       if (map->submaps)
859         deeper = mplist_get (map->submaps, keyseq[i]);
860       else
861         map->submaps = mplist ();
862       if (! deeper)
863         {
864           /* Fixme: It is better to make all deeper maps at once.  */
865           MSTRUCT_CALLOC (deeper, MERROR_IM);
866           mplist_put (map->submaps, keyseq[i], deeper);
867         }
868       map = deeper;
869     }
870
871   /* We reach a terminal map.  */
872   if (map->map_actions
873       || map->branch_actions)
874     /* This map is already defined.  We avoid overriding it.  */
875     return 0;
876
877   if (! MPLIST_TAIL_P (map_actions))
878     {
879       if (parse_action_list (map_actions, macros) < 0)
880         MERROR (MERROR_IM, -1);
881       map->map_actions = map_actions;
882     }
883   if (branch_actions)
884     {
885       map->branch_actions = branch_actions;
886       M17N_OBJECT_REF (branch_actions);
887     }
888
889   return 0;
890 }
891
892 /* Load a branch from PLIST into MAP.  PLIST has this form:
893       PLIST ::= ( MAP-NAME BRANCH-ACTION * )
894    MAPS is a plist of raw maps.
895    STATE is the current state.  */
896
897 static int
898 load_branch (MPlist *plist, MPlist *maps, MIMMap *map,
899              MSymbol language, MSymbol name, MPlist *macros)
900 {
901   MSymbol map_name;
902   MPlist *branch_actions;
903
904   if (! MPLIST_SYMBOL_P (plist))
905     MERROR (MERROR_IM, -1);
906   map_name = MPLIST_SYMBOL (plist);
907   plist = MPLIST_NEXT (plist);
908   if (MPLIST_TAIL_P (plist))
909     branch_actions = NULL;
910   else if (parse_action_list (plist, macros) < 0)
911     MERROR (MERROR_IM, -1);
912   else
913     branch_actions = plist;
914   if (map_name == Mnil)
915     {
916       map->branch_actions = branch_actions;
917       if (branch_actions)
918         M17N_OBJECT_REF (branch_actions);
919     }
920   else if (map_name == Mt)
921     {
922       map->map_actions = branch_actions;
923       if (branch_actions)
924         M17N_OBJECT_REF (branch_actions);
925     }
926   else if ((plist = (MPlist *) mplist_get (maps, map_name)))
927     {
928       MPLIST_DO (plist, plist)
929         {
930           MPlist *keylist, *map_actions;
931
932           if (! MPLIST_PLIST_P (plist))
933             MERROR (MERROR_IM, -1);
934           keylist = MPLIST_PLIST (plist);
935           map_actions = MPLIST_NEXT (keylist);
936           if (MPLIST_SYMBOL_P (keylist))
937             {
938               MSymbol command = MPLIST_SYMBOL (keylist);
939               MPlist *pl = resolve_command (language, name, command);
940
941               if (! pl)
942                 return -1;
943               MPLIST_DO (pl, pl)
944                 if (load_translation (map, pl, map_actions, branch_actions,
945                                       macros) < 0)
946                   MERROR (MERROR_IM, -1);
947             }
948           else
949             if (load_translation (map, keylist, map_actions, branch_actions,
950                                   macros) < 0)
951               MERROR (MERROR_IM, -1);
952         }
953     }
954
955   return 0;
956 }
957
958 /* Load a macro from PLIST into MACROS.
959    PLIST has this from:
960       PLIST ::= ( MACRO-NAME ACTION * )
961    MACROS is a plist of macro names vs action list.  */
962 static int
963 load_macros (MPlist *plist, MPlist *macros)
964 {
965   MSymbol name; 
966
967   if (! MPLIST_SYMBOL_P (plist))
968     MERROR (MERROR_IM, -1);
969   name = MPLIST_SYMBOL (plist);
970   plist = MPLIST_NEXT (plist);
971   if (MPLIST_TAIL_P (plist)
972       || parse_action_list (plist, macros) < 0)
973     MERROR (MERROR_IM, -1);
974   mplist_put (macros, name, plist);
975   M17N_OBJECT_REF (plist);
976   return 0;
977 }
978
979 /* Load an external module from PLIST into EXTERNALS.
980    PLIST has this form:
981       PLIST ::= ( MODULE-NAME FUNCTION * )
982    EXTERNALS is a plist of MODULE-NAME vs (MIMExternalModule *).  */
983
984 static int
985 load_external_module (MPlist *plist, MPlist *externals)
986 {
987   void *handle;
988   MSymbol module;
989   char *module_file;
990   MIMExternalModule *external;
991   MPlist *func_list;
992   void *func;
993
994   if (MPLIST_MTEXT_P (plist))
995     module = msymbol ((char *) MTEXT_DATA (MPLIST_MTEXT (plist)));
996   else if (MPLIST_SYMBOL_P (plist))
997     module = MPLIST_SYMBOL (plist);
998   module_file = alloca (strlen (MSYMBOL_NAME (module))
999                         + strlen (DLOPEN_SHLIB_EXT) + 1);
1000   sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
1001
1002   handle = dlopen (module_file, RTLD_NOW);
1003   if (! handle)
1004     {
1005       fprintf (stderr, "%s\n", dlerror ());
1006       MERROR (MERROR_IM, -1);
1007     }
1008   func_list = mplist ();
1009   MPLIST_DO (plist, MPLIST_NEXT (plist))
1010     {
1011       if (! MPLIST_SYMBOL_P (plist))
1012         MERROR_GOTO (MERROR_IM, err_label);
1013       func = dlsym (handle, MSYMBOL_NAME (MPLIST_SYMBOL (plist)));
1014       if (! func)
1015         MERROR_GOTO (MERROR_IM, err_label);
1016       mplist_add (func_list, MPLIST_SYMBOL (plist), func);
1017     }
1018
1019   MSTRUCT_MALLOC (external, MERROR_IM);
1020   external->handle = handle;
1021   external->func_list = func_list;
1022   mplist_add (externals, module, external);
1023   return 0;
1024
1025  err_label:
1026   dlclose (handle);
1027   M17N_OBJECT_UNREF (func_list);
1028   return -1;
1029 }
1030
1031 static void
1032 free_map (MIMMap *map, int top)
1033 {
1034   MPlist *plist;
1035
1036   if (top)
1037     M17N_OBJECT_UNREF (map->map_actions);
1038   if (map->submaps)
1039     {
1040       MPLIST_DO (plist, map->submaps)
1041         free_map ((MIMMap *) MPLIST_VAL (plist), 0);
1042       M17N_OBJECT_UNREF (map->submaps);
1043     }
1044   M17N_OBJECT_UNREF (map->branch_actions);
1045   free (map);
1046 }
1047
1048 static void
1049 free_state (void *object)
1050 {
1051   MIMState *state = object;
1052
1053   if (state->title)
1054     M17N_OBJECT_UNREF (state->title);
1055   if (state->map)
1056     free_map (state->map, 1);
1057   free (state);
1058 }
1059
1060 /** Load a state from PLIST into a newly allocated state object.
1061     PLIST has this form:
1062       PLIST ::= ( STATE-NAME STATE-TITLE ? BRANCH * )
1063       BRANCH ::= ( MAP-NAME BRANCH-ACTION * )
1064    MAPS is a plist of defined maps.
1065    Return the state object.  */
1066
1067 static MIMState *
1068 load_state (MPlist *plist, MPlist *maps, MSymbol language, MSymbol name,
1069             MPlist *macros)
1070 {
1071   MIMState *state;
1072
1073   if (! MPLIST_SYMBOL_P (plist))
1074     MERROR (MERROR_IM, NULL);
1075   M17N_OBJECT (state, free_state, MERROR_IM);
1076   state->name = MPLIST_SYMBOL (plist);
1077   plist = MPLIST_NEXT (plist);
1078   if (MPLIST_MTEXT_P (plist))
1079     {
1080       state->title = MPLIST_MTEXT (plist);
1081       mtext_put_prop (state->title, 0, mtext_nchars (state->title),
1082                       Mlanguage, language);
1083       M17N_OBJECT_REF (state->title);
1084       plist = MPLIST_NEXT (plist);
1085     }
1086   MSTRUCT_CALLOC (state->map, MERROR_IM);
1087   MPLIST_DO (plist, plist)
1088     if (! MPLIST_PLIST_P (plist)
1089         || load_branch (MPLIST_PLIST (plist), maps, state->map, language, name,
1090                         macros) < 0)
1091       MERROR (MERROR_IM, NULL);
1092   return state;
1093 }
1094
1095
1096 static MPlist *im_info_list;
1097
1098 static void
1099 free_im_info (MInputMethodInfo *im_info)
1100 {
1101   MPlist *plist;
1102
1103   if (im_info->title)
1104     M17N_OBJECT_UNREF (im_info->title);
1105   if (im_info->states)
1106     {
1107       MPLIST_DO (plist, im_info->states)
1108         {
1109           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1110
1111           M17N_OBJECT_UNREF (state);
1112         }
1113       M17N_OBJECT_UNREF (im_info->states);
1114     }
1115
1116   if (im_info->macros)
1117     {
1118       MPLIST_DO (plist, im_info->macros)
1119         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1120       M17N_OBJECT_UNREF (im_info->macros);
1121     }
1122
1123   if (im_info->externals)
1124     {
1125       MPLIST_DO (plist, im_info->externals)
1126         {
1127           MIMExternalModule *external = MPLIST_VAL (plist);
1128
1129           dlclose (external->handle);
1130           M17N_OBJECT_UNREF (external->func_list);
1131           free (external);
1132           MPLIST_KEY (plist) = Mt;
1133         }
1134       M17N_OBJECT_UNREF (im_info->externals);
1135     }
1136   if (im_info->maps)
1137     {
1138       MPLIST_DO (plist, im_info->maps)
1139         {
1140           MPlist *p = MPLIST_PLIST (plist);
1141
1142           M17N_OBJECT_UNREF (p);
1143         }
1144       M17N_OBJECT_UNREF (im_info->maps);
1145     }
1146
1147   free (im_info);
1148 }
1149
1150 static MInputMethodInfo *get_im_info (MSymbol language, MSymbol name,
1151                                       MSymbol extra);
1152
1153 static MInputMethodInfo *
1154 get_im_info_by_tags (MPlist *plist)
1155 {
1156   MSymbol tag[3];
1157   int i;
1158
1159   for (i = 0; i < 3 && MPLIST_SYMBOL_P (plist);
1160        i++, plist = MPLIST_NEXT (plist))
1161     tag[i] = MPLIST_SYMBOL (plist);
1162   if (i < 2)
1163     return NULL;
1164   for (; i < 3; i++)
1165     tag[i] = Mnil;
1166   return get_im_info (tag[0], tag[1], tag[2]);
1167 }
1168
1169 /* Load an input method from PLIST into IM_INTO, and return it.  */
1170
1171 static MInputMethodInfo *
1172 load_im_info (MSymbol language, MSymbol name, MPlist *plist)
1173 {
1174   MInputMethodInfo *im_info;
1175   MText *title = NULL;
1176   MPlist *maps = NULL;
1177   MPlist *states = NULL;
1178   MPlist *externals = NULL;
1179   MPlist *macros = NULL;
1180   MPlist *elt;
1181
1182   MSTRUCT_CALLOC (im_info, MERROR_IM);
1183
1184   while (MPLIST_PLIST_P (plist))
1185     {
1186       elt = MPLIST_PLIST (plist);
1187       if (! MPLIST_SYMBOL_P (elt))
1188         MERROR_GOTO (MERROR_IM, err);
1189       if (MPLIST_SYMBOL (elt) == Mtitle)
1190         {
1191           elt = MPLIST_NEXT (elt);
1192           if (! MPLIST_MTEXT_P (elt))
1193             MERROR_GOTO (MERROR_IM, err);
1194           im_info->title = title = MPLIST_MTEXT (elt);
1195           M17N_OBJECT_REF (title);
1196         }
1197       else if (MPLIST_SYMBOL (elt) == Mmap)
1198         {
1199           MPlist *pl = mplist__from_alist (MPLIST_NEXT (elt));
1200
1201           if (! pl)
1202             MERROR_GOTO (MERROR_IM, err);
1203           if (! maps)
1204             im_info->maps = maps = pl;
1205           else
1206             maps = mplist__conc (maps, pl);
1207         }
1208       else if (MPLIST_SYMBOL (elt) == Mmacro)
1209         {
1210           if (! macros)
1211             im_info->macros = macros = mplist ();
1212           MPLIST_DO (elt, MPLIST_NEXT (elt))
1213             {
1214               if (! MPLIST_PLIST_P (elt)
1215                   || load_macros (MPLIST_PLIST (elt), macros) < 0)
1216                 MERROR_GOTO (MERROR_IM, err);
1217             }
1218         }
1219       else if (MPLIST_SYMBOL (elt) == Mmodule)
1220         {
1221           if (! externals)
1222             im_info->externals = externals = mplist ();
1223           MPLIST_DO (elt, MPLIST_NEXT (elt))
1224             {
1225               if (! MPLIST_PLIST_P (elt)
1226                   || load_external_module (MPLIST_PLIST (elt), externals) < 0)
1227                 MERROR_GOTO (MERROR_IM, err);
1228             }
1229         }
1230       else if (MPLIST_SYMBOL (elt) == Mstate)
1231         {
1232           MPLIST_DO (elt, MPLIST_NEXT (elt))
1233             {
1234               MIMState *state;
1235
1236               if (! MPLIST_PLIST_P (elt))
1237                 MERROR_GOTO (MERROR_IM, err);
1238               state = load_state (MPLIST_PLIST (elt), maps, language, name,
1239                                   macros);
1240               if (! state)
1241                 MERROR_GOTO (MERROR_IM, err);
1242               if (! states)
1243                 im_info->states = states = mplist ();
1244               mplist_put (states, state->name, state);
1245             }
1246         }
1247       else if (MPLIST_SYMBOL (elt) == Minclude)
1248         {
1249           /* elt ::= include (tag1 tag2 ...) key item ... */
1250           MSymbol key;
1251           MInputMethodInfo *temp;
1252           MPlist *pl, *p;
1253
1254           elt = MPLIST_NEXT (elt);
1255           if (! MPLIST_PLIST_P (elt))
1256             MERROR_GOTO (MERROR_IM, err);
1257           temp = get_im_info_by_tags (MPLIST_PLIST (elt));
1258           if (! temp)
1259             MERROR_GOTO (MERROR_IM, err);
1260           elt = MPLIST_NEXT (elt);
1261           if (! MPLIST_SYMBOL_P (elt))
1262             MERROR_GOTO (MERROR_IM, err);
1263           key = MPLIST_SYMBOL (elt);
1264           elt = MPLIST_NEXT (elt);
1265           if (key == Mmap)
1266             {
1267               if (! maps)
1268                 im_info->maps = maps = mplist ();
1269               MPLIST_DO (pl, temp->maps)
1270                 {
1271                   p = MPLIST_VAL (pl);
1272                   MPLIST_ADD_PLIST (maps, MPLIST_KEY (pl), p);
1273                   M17N_OBJECT_REF (p);
1274                 }
1275             }
1276           else if (key == Mmacro)
1277             {
1278               if (! macros)
1279                 im_info->macros = macros = mplist ();
1280               MPLIST_DO (pl, temp->macros)
1281                 {
1282                   p = MPLIST_VAL (pl);
1283                   MPLIST_ADD_PLIST (macros, MPLIST_KEY (pl), p);
1284                   M17N_OBJECT_REF (p);
1285                 }
1286             }
1287           else if (key == Mstate)
1288             {
1289               if (! states)
1290                 im_info->states = states = mplist ();
1291               MPLIST_DO (pl, temp->states)
1292                 {
1293                   MIMState *state = MPLIST_VAL (pl);
1294
1295                   mplist_add (states, MPLIST_KEY (pl), state);
1296                   M17N_OBJECT_REF (state);
1297                 }
1298             }
1299           else
1300             MERROR_GOTO (MERROR_IM, err);
1301         }
1302       plist = MPLIST_NEXT (plist);
1303     }
1304
1305   if (! states)
1306     goto err;
1307   if (! title && name)
1308     im_info->title
1309       = title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name),
1310                                  MTEXT_FORMAT_US_ASCII);
1311   return im_info;
1312
1313  err:
1314   free_im_info (im_info);
1315   return NULL;
1316 }
1317
1318 \f
1319
1320 static int take_action_list (MInputContext *ic, MPlist *action_list);
1321 static void preedit_commit (MInputContext *ic);
1322
1323 static void
1324 shift_state (MInputContext *ic, MSymbol state_name)
1325 {
1326   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1327   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1328   MIMState *orig_state = ic_info->state, *state;
1329
1330   /* Find a state to shift to.  If not found, shift to the initial
1331      state.  */
1332   if (state_name == Mt)
1333     {
1334       if (! ic_info->prev_state)
1335         return;
1336       state = ic_info->prev_state;
1337     }
1338   else
1339     {
1340       state = (MIMState *) mplist_get (im_info->states, state_name);
1341       if (! state)
1342         state = (MIMState *) MPLIST_VAL (im_info->states);
1343     }
1344
1345   MDEBUG_PRINT1 ("\n  [IM] (shift %s)", MSYMBOL_NAME (state->name));
1346
1347   /* Enter the new state.  */
1348   ic_info->state = state;
1349   ic_info->map = state->map;
1350   ic_info->state_key_head = ic_info->key_head;
1351   if (state == (MIMState *) MPLIST_VAL (im_info->states))
1352     /* We have shifted to the initial state.  */
1353     preedit_commit (ic);
1354   mtext_cpy (ic_info->preedit_saved, ic->preedit);
1355   ic_info->state_pos = ic->cursor_pos;
1356   if (state != orig_state )
1357     {
1358       if (state == (MIMState *) MPLIST_VAL (im_info->states))
1359         ic_info->prev_state = NULL;
1360       else
1361         ic_info->prev_state = orig_state;
1362
1363       if (state->title)
1364         ic->status = state->title;
1365       else
1366         ic->status = im_info->title;
1367       ic->status_changed = 1;
1368       if (ic_info->map == ic_info->state->map
1369           && ic_info->map->map_actions)
1370         {
1371           MDEBUG_PRINT (" init-actions:");
1372           take_action_list (ic, ic_info->map->map_actions);
1373         }
1374     }
1375 }
1376
1377 /* Find a candidate group that contains a candidate number INDEX from
1378    PLIST.  Set START_INDEX to the first candidate number of the group,
1379    END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
1380    candidate group number if they are non-NULL.  If INDEX is -1, find
1381    the last candidate group.  */
1382
1383 static MPlist *
1384 find_candidates_group (MPlist *plist, int index,
1385                        int *start_index, int *end_index, int *group_index)
1386 {
1387   int i = 0, gidx = 0, len;
1388
1389   MPLIST_DO (plist, plist)
1390     {
1391       if (MPLIST_MTEXT_P (plist))
1392         len = mtext_nchars (MPLIST_MTEXT (plist));
1393       else
1394         len = mplist_length (MPLIST_PLIST (plist));
1395       if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
1396           : i + len > index)
1397         {
1398           if (start_index)
1399             *start_index = i;
1400           if (end_index)
1401             *end_index = i + len;
1402           if (group_index)
1403             *group_index = gidx;
1404           return plist;
1405         }
1406       i += len;
1407       gidx++;
1408     }
1409   return NULL;
1410 }
1411
1412 static void
1413 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
1414 {
1415   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
1416   MPlist *markers;
1417   int nchars = mt ? mtext_nchars (mt) : 1;
1418
1419   if (mt)
1420     mtext_ins (ic->preedit, pos, mt);
1421   else
1422     mtext_ins_char (ic->preedit, pos, c, 1);
1423   MPLIST_DO (markers, ic_info->markers)
1424     if (MPLIST_INTEGER (markers) > pos)
1425       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
1426   if (ic->cursor_pos >= pos)
1427     ic->cursor_pos += nchars;
1428   ic->preedit_changed = 1;
1429 }
1430
1431
1432 static void
1433 preedit_delete (MInputContext *ic, int from, int to)
1434 {
1435   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
1436   MPlist *markers;
1437
1438   mtext_del (ic->preedit, from, to);
1439   MPLIST_DO (markers, ic_info->markers)
1440     {
1441       if (MPLIST_INTEGER (markers) > to)
1442         MPLIST_VAL (markers)
1443           = (void *) (MPLIST_INTEGER (markers) - (to - from));
1444       else if (MPLIST_INTEGER (markers) > from);
1445         MPLIST_VAL (markers) = (void *) from;
1446     }
1447   if (ic->cursor_pos >= to)
1448     ic->cursor_pos -= to - from;
1449   else if (ic->cursor_pos > from)
1450     ic->cursor_pos = from;
1451   ic->preedit_changed = 1;
1452 }
1453
1454 static void
1455 preedit_commit (MInputContext *ic)
1456 {
1457   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1458   int preedit_len = mtext_nchars (ic->preedit);
1459
1460   if (preedit_len > 0)
1461     {
1462       MPlist *p;
1463
1464       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
1465                              Mcandidate_list, NULL, 0);
1466       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
1467                              Mcandidate_index, NULL, 0);
1468       mtext_cat (ic->produced, ic->preedit);
1469       if ((mdebug__flag & mdebug_mask)
1470           && mtext_nchars (ic->produced) > 0)
1471         {
1472           int i;
1473
1474           MDEBUG_PRINT (" (produced");
1475           for (i = 0; i < mtext_nchars (ic->produced); i++)
1476             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
1477           MDEBUG_PRINT (")");
1478         }
1479       mtext_reset (ic->preedit);
1480       mtext_reset (ic_info->preedit_saved);
1481       MPLIST_DO (p, ic_info->markers)
1482         MPLIST_VAL (p) = 0;
1483       ic->cursor_pos = ic_info->state_pos = 0;
1484       ic->preedit_changed = 1;
1485     }
1486   if (ic->candidate_list)
1487     {
1488       M17N_OBJECT_UNREF (ic->candidate_list);
1489       ic->candidate_list = NULL;
1490       ic->candidate_show = 0;
1491       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
1492       if (ic->candidate_show)
1493         {
1494           ic->candidate_show = 0;
1495           ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
1496         }
1497     }
1498
1499   memmove (ic_info->keys, ic_info->keys + ic_info->key_head,
1500            sizeof (int) * (ic_info->used - ic_info->key_head));
1501   ic_info->used -= ic_info->key_head;
1502   ic_info->state_key_head = ic_info->key_head = 0;
1503 }
1504
1505 static int
1506 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
1507 {
1508   int code = marker_code (sym);
1509
1510   if (mt && (code == '[' || code == ']'))
1511     {
1512       int pos = current;
1513
1514       if (code == '[' && current > 0)
1515         {
1516           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
1517               && pos > 0)
1518             current = pos;
1519         }
1520       else if (code == ']' && current < mtext_nchars (mt))
1521         {
1522           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
1523             current = pos;
1524         }
1525       return current;
1526     }
1527   if (code >= 0)
1528     return (code == '<' ? 0
1529             : code == '>' ? limit
1530             : code == '-' ? current - 1
1531             : code == '+' ? current + 1
1532             : code == '=' ? current
1533             : code - '0' > limit ? limit
1534             : code - '0');
1535   if (! ic)  
1536     return 0;
1537   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
1538 }
1539
1540 static void
1541 update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
1542 {
1543   int from = mtext_property_start (prop);
1544   int to = mtext_property_end (prop);
1545   int start;
1546   MPlist *candidate_list = mtext_property_value (prop);
1547   MPlist *group = find_candidates_group (candidate_list, idx, &start,
1548                                          NULL, NULL);
1549   int ingroup_index = idx - start;
1550   MText *mt;
1551
1552   preedit_delete (ic, from, to);
1553   if (MPLIST_MTEXT_P (group))
1554     {
1555       mt = MPLIST_MTEXT (group);
1556       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
1557       to = from + 1;
1558     }
1559   else
1560     {
1561       int i;
1562       MPlist *plist;
1563
1564       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
1565            i++, plist = MPLIST_NEXT (plist));
1566       mt = MPLIST_MTEXT (plist);
1567       preedit_insert (ic, from, mt, 0);
1568       to = from + mtext_nchars (mt);
1569     }
1570   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
1571   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
1572   ic->cursor_pos = to;
1573 }
1574
1575 static MCharset *
1576 get_select_charset (MInputContextInfo * ic_info)
1577 {
1578   MPlist *plist = resolve_variable (ic_info, Mcandidates_charset);
1579   MSymbol sym;
1580
1581   if (! MPLIST_VAL (plist))
1582     return NULL;
1583   sym = MPLIST_SYMBOL (plist);
1584   if (sym == Mnil)
1585     return NULL;
1586   return MCHARSET (sym);
1587 }
1588
1589 static MPlist *
1590 adjust_candidates (MPlist *plist, MCharset *charset)
1591 {
1592   MPlist *pl;
1593
1594   /* plist ::= MTEXT ... | PLIST ... */
1595   plist = mplist_copy (plist);
1596   if (MPLIST_MTEXT_P (plist))
1597     {
1598       pl = plist;
1599       while (! MPLIST_TAIL_P (pl))
1600         {
1601           /* pl ::= MTEXT ... */
1602           MText *mt = MPLIST_MTEXT (pl);
1603           int mt_copied = 0;
1604           int i, c;
1605
1606           for (i = mtext_nchars (mt) - 1; i >= 0; i--)
1607             {
1608               c = mtext_ref_char (mt, i);
1609               if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
1610                 {
1611                   if (! mt_copied)
1612                     {
1613                       mt = mtext_dup (mt);
1614                       mplist_set (pl, Mtext, mt);
1615                       M17N_OBJECT_UNREF (mt);
1616                       mt_copied = 1;
1617                     }
1618                   mtext_del (mt, i, i + 1);
1619                 }
1620             }
1621           if (mtext_len (mt) > 0)
1622             pl = MPLIST_NEXT (pl);
1623           else
1624             {
1625               mplist_pop (pl);
1626               M17N_OBJECT_UNREF (mt);
1627             }
1628         }
1629     }
1630   else                          /* MPLIST_PLIST_P (plist) */
1631     {
1632       pl = plist;
1633       while (! MPLIST_TAIL_P (pl))
1634         {
1635           /* pl ::= (MTEXT ...) ... */
1636           MPlist *p = MPLIST_PLIST (pl);
1637           int p_copied = 0;
1638           /* p ::= MTEXT ... */
1639           MPlist *p0 = p;
1640           int n = 0;
1641
1642           while (! MPLIST_TAIL_P (p0))
1643             {
1644               MText *mt = MPLIST_MTEXT (p0);
1645               int i, c;
1646
1647               for (i = mtext_nchars (mt) - 1; i >= 0; i--)
1648                 {
1649                   c = mtext_ref_char (mt, i);
1650                   if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
1651                     break;
1652                 }
1653               if (i < 0)
1654                 {
1655                   p0 = MPLIST_NEXT (p0);
1656                   n++;
1657                 }
1658               else
1659                 {
1660                   if (! p_copied)
1661                     {
1662                       p = mplist_copy (p);
1663                       mplist_set (pl, Mplist, p);
1664                       M17N_OBJECT_UNREF (p);
1665                       p_copied = 1;
1666                       p0 = p;
1667                       while (n-- > 0)
1668                         p0 = MPLIST_NEXT (p0);
1669                     }     
1670                   mplist_pop (p0);
1671                   M17N_OBJECT_UNREF (mt);
1672                 }
1673             }
1674           if (! MPLIST_TAIL_P (p))
1675             pl = MPLIST_NEXT (pl);
1676           else
1677             {
1678               mplist_pop (pl);
1679               M17N_OBJECT_UNREF (p);
1680             }
1681         }
1682     }
1683   if (MPLIST_TAIL_P (plist))
1684     {
1685       M17N_OBJECT_UNREF (plist);
1686       return NULL;
1687     }      
1688   return plist;
1689 }
1690
1691 static MPlist *
1692 get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
1693 {
1694   MCharset *charset = get_select_charset (ic_info);
1695   MPlist *plist;
1696   int column;
1697   int i, len;
1698
1699   plist = resolve_variable (ic_info, Mcandidates_group_size);
1700   column = MPLIST_INTEGER (plist);
1701
1702   plist = MPLIST_PLIST (args);
1703   if (charset)
1704     {
1705       if (! (plist = adjust_candidates (plist, charset)))
1706         return NULL;
1707     }
1708   else
1709     M17N_OBJECT_REF (plist);
1710
1711   if (column > 0)
1712     {
1713       if (MPLIST_MTEXT_P (plist))
1714         {
1715           MText *mt = MPLIST_MTEXT (plist);
1716           MPlist *next = MPLIST_NEXT (plist);
1717
1718           if (MPLIST_TAIL_P (next))
1719             M17N_OBJECT_REF (mt);
1720           else
1721             {
1722               mt = mtext_dup (mt);
1723               while (! MPLIST_TAIL_P (next))
1724                 {
1725                   mt = mtext_cat (mt, MPLIST_MTEXT (next));
1726                   next = MPLIST_NEXT (next);
1727                 }
1728             }
1729           M17N_OBJECT_UNREF (plist);
1730           plist = mplist ();
1731           len = mtext_nchars (mt);
1732           if (len <= column)
1733             mplist_add (plist, Mtext, mt);
1734           else
1735             {
1736               for (i = 0; i < len; i += column)
1737                 {
1738                   int to = (i + column < len ? i + column : len);
1739                   MText *sub = mtext_copy (mtext (), 0, mt, i, to);
1740                                                        
1741                   mplist_add (plist, Mtext, sub);
1742                   M17N_OBJECT_UNREF (sub);
1743                 }
1744             }
1745           M17N_OBJECT_UNREF (mt);
1746         }
1747       else              /* MPLIST_PLIST_P (plist) */
1748         {
1749           MPlist *pl = MPLIST_PLIST (plist), *p;
1750           MPlist *next = MPLIST_NEXT (plist);
1751           int j;
1752
1753           if (MPLIST_TAIL_P (next))
1754             M17N_OBJECT_REF (pl);
1755           else
1756             {
1757               pl = mplist_copy (pl);
1758               while (! MPLIST_TAIL_P (next))
1759                 {
1760                   p = mplist_copy (MPLIST_PLIST (next));
1761                   pl = mplist__conc (pl, p);
1762                   M17N_OBJECT_UNREF (p);
1763                   next = MPLIST_NEXT (next);
1764                 }
1765             }
1766           M17N_OBJECT_UNREF (plist);
1767           plist = mplist ();
1768           len = mplist_length (pl);
1769           if (len <= column)
1770             mplist_add (plist, Mplist, pl);
1771           else
1772             {
1773               MPlist *p0 = pl;
1774
1775               for (i = 0; i < len; i += column)
1776                 {
1777                   p = mplist ();
1778                   mplist_add (plist, Mplist, p);
1779                   M17N_OBJECT_UNREF (p);
1780                   for (j = 0; j < column && i + j < len; j++)
1781                     {
1782                       p = mplist_add (p, Mtext, MPLIST_VAL (p0));
1783                       p0 = MPLIST_NEXT (p0);
1784                     }
1785                 }
1786             }
1787           M17N_OBJECT_UNREF (pl);
1788         }
1789     }
1790
1791   return plist;
1792 }
1793
1794
1795 static MPlist *
1796 regularize_action (MPlist *action_list)
1797 {
1798   MPlist *action = NULL;
1799   MSymbol name;
1800   MPlist *args;
1801
1802   if (MPLIST_PLIST_P (action_list))
1803     {
1804       action = MPLIST_PLIST (action_list);
1805       if (MPLIST_SYMBOL_P (action))
1806         {
1807           name = MPLIST_SYMBOL (action);
1808           args = MPLIST_NEXT (action);
1809           if (name == Minsert
1810               && MPLIST_PLIST_P (args))
1811             mplist_set (action, Msymbol, M_candidates);
1812         }
1813       else if (MPLIST_MTEXT_P (action) || MPLIST_PLIST_P (action))
1814         {
1815           action = mplist ();
1816           mplist_push (action, Mplist, MPLIST_VAL (action_list));
1817           mplist_push (action, Msymbol, M_candidates);
1818           mplist_set (action_list, Mplist, action);
1819           M17N_OBJECT_UNREF (action);
1820         }
1821     }
1822   else if (MPLIST_MTEXT_P (action_list) || MPLIST_INTEGER_P (action_list))
1823     {
1824       action = mplist ();
1825       mplist_push (action, MPLIST_KEY (action_list), MPLIST_VAL (action_list));
1826       mplist_push (action, Msymbol, Minsert);
1827       mplist_set (action_list, Mplist, action);
1828       M17N_OBJECT_UNREF (action);
1829     }
1830   return action;
1831 }
1832
1833 static int
1834 take_action_list (MInputContext *ic, MPlist *action_list)
1835 {
1836   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1837   MPlist *candidate_list = ic->candidate_list;
1838   int candidate_index = ic->candidate_index;
1839   int candidate_show = ic->candidate_show;
1840   MTextProperty *prop;
1841
1842   MPLIST_DO (action_list, action_list)
1843     {
1844       MPlist *action = regularize_action (action_list);
1845       MSymbol name;
1846       MPlist *args;
1847
1848       if (! action)
1849         continue;
1850       name = MPLIST_SYMBOL (action);
1851       args = MPLIST_NEXT (action);
1852
1853       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
1854       if (name == Minsert)
1855         {
1856           if (MPLIST_SYMBOL_P (args))
1857             {
1858               args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
1859               if (! MPLIST_MTEXT_P (args) && ! MPLIST_INTEGER_P (args))
1860                 continue;
1861             }
1862           if (MPLIST_MTEXT_P (args))
1863             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
1864           else                  /* MPLIST_INTEGER_P (args)) */
1865             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
1866         }
1867       else if (name == M_candidates)
1868         {
1869           MPlist *plist = get_candidate_list (ic_info, args);
1870           int len;
1871
1872           if (! plist)
1873             continue;
1874           if (MPLIST_MTEXT_P (plist))
1875             {
1876               preedit_insert (ic, ic->cursor_pos, NULL,
1877                               mtext_ref_char (MPLIST_MTEXT (plist), 0));
1878               len = 1;
1879             }
1880           else
1881             {
1882               MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
1883
1884               preedit_insert (ic, ic->cursor_pos, mt, 0);
1885               len = mtext_nchars (mt);
1886             }
1887           mtext_put_prop (ic->preedit,
1888                           ic->cursor_pos - len, ic->cursor_pos,
1889                           Mcandidate_list, plist);
1890           mtext_put_prop (ic->preedit,
1891                           ic->cursor_pos - len, ic->cursor_pos,
1892                           Mcandidate_index, (void *) 0);
1893           M17N_OBJECT_UNREF (plist);
1894         }
1895       else if (name == Mselect)
1896         {
1897           int start, end;
1898           int code, idx, gindex;
1899           int pos = ic->cursor_pos;
1900           MPlist *group;
1901
1902           if (pos == 0
1903               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
1904                                                Mcandidate_list)))
1905             continue;
1906           if (MPLIST_SYMBOL_P (args))
1907             {
1908               code = marker_code (MPLIST_SYMBOL (args));
1909               if (code < 0)
1910                 continue;
1911             }
1912           else
1913             code = -1;
1914           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
1915           group = find_candidates_group (mtext_property_value (prop), idx,
1916                                          &start, &end, &gindex);
1917
1918           if (code != '[' && code != ']')
1919             {
1920               idx = (start
1921                      + (code >= 0
1922                         ? new_index (NULL, ic->candidate_index - start,
1923                                      end - start - 1, MPLIST_SYMBOL (args),
1924                                      NULL)
1925                         : MPLIST_INTEGER (args)));
1926               if (idx < 0)
1927                 {
1928                   find_candidates_group (mtext_property_value (prop), -1,
1929                                          NULL, &end, NULL);
1930                   idx = end - 1;
1931                 }
1932               else if (idx >= end
1933                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
1934                 idx = 0;
1935             }
1936           else
1937             {
1938               int ingroup_index = idx - start;
1939               int len;
1940
1941               group = mtext_property_value (prop);
1942               len = mplist_length (group);
1943               if (code == '[')
1944                 {
1945                   gindex--;
1946                   if (gindex < 0)
1947                     gindex = len - 1;;
1948                 }
1949               else
1950                 {
1951                   gindex++;
1952                   if (gindex >= len)
1953                     gindex = 0;
1954                 }
1955               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
1956                 idx += (MPLIST_MTEXT_P (group)
1957                         ? mtext_nchars (MPLIST_MTEXT (group))
1958                         : mplist_length (MPLIST_PLIST (group)));
1959               len = (MPLIST_MTEXT_P (group)
1960                      ? mtext_nchars (MPLIST_MTEXT (group))
1961                      : mplist_length (MPLIST_PLIST (group)));
1962               if (ingroup_index >= len)
1963                 ingroup_index = len - 1;
1964               idx += ingroup_index;
1965             }
1966           update_candidate (ic, prop, idx);
1967         }
1968       else if (name == Mshow)
1969         ic->candidate_show = 1;
1970       else if (name == Mhide)
1971         ic->candidate_show = 0;
1972       else if (name == Mdelete)
1973         {
1974           int len = mtext_nchars (ic->preedit);
1975           int pos;
1976           int to;
1977
1978           if (MPLIST_SYMBOL_P (args)
1979               && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
1980             {
1981               delete_surrounding_text (ic, pos);
1982             }
1983           else
1984             {
1985               to = (MPLIST_SYMBOL_P (args)
1986                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1987                                  ic->preedit)
1988                     : MPLIST_INTEGER (args));
1989               if (to < 0)
1990                 to = 0;
1991               else if (to > len)
1992                 to = len;
1993               if (to < ic->cursor_pos)
1994                 preedit_delete (ic, to, ic->cursor_pos);
1995               else if (to > ic->cursor_pos)
1996                 preedit_delete (ic, ic->cursor_pos, to);
1997             }
1998         }
1999       else if (name == Mmove)
2000         {
2001           int len = mtext_nchars (ic->preedit);
2002           int pos
2003             = (MPLIST_SYMBOL_P (args)
2004                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
2005                             ic->preedit)
2006                : MPLIST_INTEGER (args));
2007
2008           if (pos < 0)
2009             pos = 0;
2010           else if (pos > len)
2011             pos = len;
2012           if (pos != ic->cursor_pos)
2013             {
2014               ic->cursor_pos = pos;
2015               ic->preedit_changed = 1;
2016             }
2017         }
2018       else if (name == Mmark)
2019         {
2020           int code = marker_code (MPLIST_SYMBOL (args));
2021
2022           if (code < 0)
2023             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
2024                         (void *) ic->cursor_pos);
2025         }
2026       else if (name == Mpushback)
2027         {
2028           if (MPLIST_INTEGER_P (args))
2029             {
2030               int num = MPLIST_INTEGER (args);
2031
2032               if (num > 0)
2033                 ic_info->key_head -= num;
2034               else
2035                 ic_info->key_head = num;
2036               if (ic_info->key_head > ic_info->used)
2037                 ic_info->key_head = ic_info->used;
2038             }
2039           else if (MPLIST_MTEXT_P (args))
2040             {
2041               MText *mt = MPLIST_MTEXT (args);
2042               int i, len = mtext_nchars (mt);
2043               MSymbol key;
2044
2045               ic_info->key_head--;
2046               for (i = 0; i < len; i++)
2047                 {
2048                   key = one_char_symbol[MTEXT_DATA (mt)[i]];
2049                   if (ic_info->key_head + i < ic_info->used)
2050                     ic_info->keys[ic_info->key_head + i] = key;
2051                   else
2052                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2053                 }
2054             }
2055           else
2056             {
2057               MPlist *plist = MPLIST_PLIST (args), *pl;
2058               int i = 0;
2059               MSymbol key;
2060
2061               ic_info->key_head--;
2062
2063               MPLIST_DO (pl, plist)
2064                 {
2065                   key = MPLIST_SYMBOL (pl);
2066                   if (ic_info->key_head < ic_info->used)
2067                     ic_info->keys[ic_info->key_head + i] = key;
2068                   else
2069                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2070                   i++;
2071                 }
2072             }
2073         }
2074       else if (name == Mcall)
2075         {
2076           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2077           MIMExternalFunc func = NULL;
2078           MSymbol module, func_name;
2079           MPlist *func_args, *val;
2080           int ret = 0;
2081
2082           module = MPLIST_SYMBOL (args);
2083           args = MPLIST_NEXT (args);
2084           func_name = MPLIST_SYMBOL (args);
2085
2086           if (im_info->externals)
2087             {
2088               MIMExternalModule *external
2089                 = (MIMExternalModule *) mplist_get (im_info->externals,
2090                                                     module);
2091               if (external)
2092                 func = (MIMExternalFunc) mplist_get (external->func_list,
2093                                                      func_name);
2094             }
2095           if (! func)
2096             continue;
2097           func_args = mplist ();
2098           mplist_add (func_args, Mt, ic);
2099           MPLIST_DO (args, MPLIST_NEXT (args))
2100             {
2101               int code;
2102
2103               if (MPLIST_KEY (args) == Msymbol
2104                   && MPLIST_KEY (args) != Mnil
2105                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
2106                 {
2107                   code = new_index (ic, ic->cursor_pos, 
2108                                     mtext_nchars (ic->preedit),
2109                                     MPLIST_SYMBOL (args), ic->preedit);
2110                   mplist_add (func_args, Minteger, (void *) code);
2111                 }
2112               else
2113                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
2114             }
2115           val = (func) (func_args);
2116           M17N_OBJECT_UNREF (func_args);
2117           if (val && ! MPLIST_TAIL_P (val))
2118             ret = take_action_list (ic, val);
2119           M17N_OBJECT_UNREF (val);
2120           if (ret < 0)
2121             return ret;
2122         }
2123       else if (name == Mshift)
2124         {
2125           shift_state (ic, MPLIST_SYMBOL (args));
2126         }
2127       else if (name == Mundo)
2128         {
2129           int intarg = (MPLIST_TAIL_P (args)
2130                         ? ic_info->used - 2
2131                         : integer_value (ic, args, NULL, 0));
2132
2133           mtext_reset (ic->preedit);
2134           mtext_reset (ic_info->preedit_saved);
2135           ic->cursor_pos = ic_info->state_pos = 0;
2136           ic_info->state_key_head = ic_info->key_head = 0;
2137
2138           if (intarg < 0)
2139             ic_info->used += intarg;
2140           else
2141             ic_info->used = intarg;
2142           shift_state (ic, Mnil);
2143           break;
2144         }
2145       else if (name == Mset || name == Madd || name == Msub
2146                || name == Mmul || name == Mdiv)
2147         {
2148           MSymbol sym = MPLIST_SYMBOL (args);
2149           int val1, val2;
2150           MPlist *value;
2151           char *op;
2152
2153           val1 = integer_value (ic, args, &value, 0);
2154           args = MPLIST_NEXT (args);
2155           val2 = integer_value (ic, args, NULL, 1);
2156           if (name == Mset)
2157             val1 = val2, op = "=";
2158           else if (name == Madd)
2159             val1 += val2, op = "+=";
2160           else if (name == Msub)
2161             val1 -= val2, op = "-=";
2162           else if (name == Mmul)
2163             val1 *= val2, op = "*=";
2164           else
2165             val1 /= val2, op = "/=";
2166           MDEBUG_PRINT3 ("(%s %s %d)", MSYMBOL_NAME (sym), op, val1);
2167           if (value)
2168             mplist_set (value, Minteger, (void *) val1);
2169         }
2170       else if (name == Mequal || name == Mless || name == Mgreater)
2171         {
2172           int val1, val2;
2173           MPlist *actions1, *actions2;
2174           int ret = 0;
2175
2176           val1 = integer_value (ic, args, NULL, 1);
2177           args = MPLIST_NEXT (args);
2178           val2 = integer_value (ic, args, NULL, 1);
2179           args = MPLIST_NEXT (args);
2180           actions1 = MPLIST_PLIST (args);
2181           args = MPLIST_NEXT (args);
2182           if (MPLIST_TAIL_P (args))
2183             actions2 = NULL;
2184           else
2185             actions2 = MPLIST_PLIST (args);
2186           MDEBUG_PRINT3 ("(%d %s %d)? ", val1, MSYMBOL_NAME (name), val2);
2187           if (name == Mequal ? val1 == val2
2188               : name == Mless ? val1 < val2
2189               : val1 > val2)
2190             {
2191               MDEBUG_PRINT ("ok");
2192               ret = take_action_list (ic, actions1);
2193             }
2194           else
2195             {
2196               MDEBUG_PRINT ("no");
2197               if (actions2)
2198                 ret = take_action_list (ic, actions2);
2199             }
2200           if (ret < 0)
2201             return ret;
2202         }
2203       else if (name == Mcommit)
2204         {
2205           preedit_commit (ic);
2206         }
2207       else if (name == Munhandle)
2208         {
2209           preedit_commit (ic);
2210           return -1;
2211         }
2212       else
2213         {
2214           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2215           MPlist *actions;
2216
2217           if (im_info->macros
2218               && (actions = mplist_get (im_info->macros, name)))
2219             {
2220               if (take_action_list (ic, actions) < 0)
2221                 return -1;
2222             };
2223         }
2224     }
2225
2226   prop = NULL;
2227   if (ic->candidate_list)
2228     {
2229       M17N_OBJECT_UNREF (ic->candidate_list);
2230       ic->candidate_list = NULL;
2231     }
2232   if (ic->cursor_pos > 0
2233       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
2234                                      Mcandidate_list)))
2235     {
2236       ic->candidate_list = mtext_property_value (prop);
2237       M17N_OBJECT_REF (ic->candidate_list);
2238       ic->candidate_index
2239         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
2240                                 Mcandidate_index);
2241       ic->candidate_from = mtext_property_start (prop);
2242       ic->candidate_to = mtext_property_end (prop);
2243     }
2244
2245   if (candidate_list != ic->candidate_list)
2246     ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
2247   if (candidate_index != ic->candidate_index)
2248     ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
2249   if (candidate_show != ic->candidate_show)
2250     ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
2251   return 0;
2252 }
2253
2254
2255 /* Handle the input key KEY in the current state and map specified in
2256    the input context IC.  If KEY is handled correctly, return 0.
2257    Otherwise, return -1.  */
2258
2259 static int
2260 handle_key (MInputContext *ic)
2261 {
2262   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2263   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2264   MIMMap *map = ic_info->map;
2265   MIMMap *submap = NULL;
2266   MSymbol key = ic_info->keys[ic_info->key_head];
2267   int i;
2268
2269   MDEBUG_PRINT2 ("  [IM] handle `%s' in state %s", 
2270                  MSYMBOL_NAME (key), MSYMBOL_NAME (ic_info->state->name));
2271
2272   if (map->submaps)
2273     {
2274       MSymbol alias;
2275
2276       submap = mplist_get (map->submaps, key);
2277       if (! submap && (alias = msymbol_get (key, M_key_alias)) != Mnil)
2278         submap = mplist_get (map->submaps, alias);
2279     }
2280
2281   if (submap)
2282     {
2283       MDEBUG_PRINT (" submap-found");
2284       mtext_cpy (ic->preedit, ic_info->preedit_saved);
2285       ic->preedit_changed = 1;
2286       ic->cursor_pos = ic_info->state_pos;
2287       ic_info->key_head++;
2288       ic_info->map = map = submap;
2289       if (map->map_actions)
2290         {
2291           MDEBUG_PRINT (" map-actions:");
2292           if (take_action_list (ic, map->map_actions) < 0)
2293             {
2294               MDEBUG_PRINT ("\n");
2295               return -1;
2296             }
2297         }
2298       else if (map->submaps)
2299         {
2300           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
2301             {
2302               MSymbol key = ic_info->keys[i];
2303               char *name = msymbol_name (key);
2304
2305               if (! name[0] || ! name[1])
2306                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
2307             }
2308         }
2309
2310       /* If this is the terminal map or we have shifted to another
2311          state, perform branch actions (if any).  */
2312       if (! map->submaps || map != ic_info->map)
2313         {
2314           if (map->branch_actions)
2315             {
2316               MDEBUG_PRINT (" branch-actions:");
2317               if (take_action_list (ic, map->branch_actions) < 0)
2318                 {
2319                   MDEBUG_PRINT ("\n");
2320                   return -1;
2321                 }
2322             }
2323           /* If MAP is still not the root map, shift to the current
2324              state.  */
2325           if (ic_info->map != ic_info->state->map)
2326             shift_state (ic, ic_info->state->name);
2327         }
2328     }
2329   else
2330     {
2331       /* MAP can not handle KEY.  */
2332
2333       /* If MAP is the root map of the initial state, it means that
2334          the current input method can not handle KEY.  */
2335       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
2336         {
2337           MDEBUG_PRINT (" unhandled\n");
2338           return -1;
2339         }
2340
2341       if (map != ic_info->state->map)
2342         {
2343           /* If MAP is not the root map... */
2344           /* If MAP has branch actions, perform them.  */
2345           if (map->branch_actions)
2346             {
2347               MDEBUG_PRINT (" branch-actions:");
2348               if (take_action_list (ic, map->branch_actions) < 0)
2349                 {
2350                   MDEBUG_PRINT ("\n");
2351                   return -1;
2352                 }
2353             }
2354           /* If MAP is still not the root map, shift to the current
2355              state. */
2356           if (ic_info->map != ic_info->state->map)
2357             {
2358               shift_state (ic, ic_info->state->name);
2359               /* If MAP has branch_actions, perform them.  */
2360               if (ic_info->map->branch_actions)
2361                 {
2362                   MDEBUG_PRINT (" brank-actions:");
2363                   take_action_list (ic, ic_info->map->branch_actions);
2364                 }
2365             }
2366         }
2367       else
2368         {
2369           /* MAP is the root map, perform branch actions (if any) or
2370              shift to the initial state.  */
2371           if (map->branch_actions)
2372             {
2373               MDEBUG_PRINT (" branch-actions:");
2374               if (take_action_list (ic, map->branch_actions) < 0)
2375                 {
2376                   MDEBUG_PRINT ("\n");
2377                   return -1;
2378                 }
2379             }
2380           else
2381             shift_state (ic, Mnil);
2382         }
2383     }
2384   MDEBUG_PRINT ("\n");
2385   return 0;
2386 }
2387
2388 static void
2389 reset_ic (MInputContext *ic, MSymbol ignore)
2390 {
2391   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2392   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2393   MText *status;
2394
2395   MDEBUG_PRINT ("\n  [IM] reset\n");
2396
2397   ic_info->state = (MIMState *) MPLIST_VAL (im_info->states);
2398   ic_info->prev_state = NULL;
2399   ic_info->map = ic_info->state->map;
2400   ic_info->state_key_head = ic_info->key_head;
2401   MLIST_RESET (ic_info);
2402   ic_info->key_unhandled = 0;
2403
2404   if (mtext_nchars (ic->produced) > 0)
2405     mtext_reset (ic->produced);
2406   if (mtext_nchars (ic->preedit) > 0)
2407     {
2408       MPlist *plist;
2409
2410       mtext_reset (ic->preedit);
2411       MPLIST_DO (plist, ic_info->markers)
2412         MPLIST_VAL (plist) = 0;
2413       ic->preedit_changed = 1;
2414     }
2415   if (ic->candidate_show)
2416     {
2417       ic->candidate_show = 0;
2418       ic->candidates_changed = MINPUT_CANDIDATES_SHOW_CHANGED;
2419       if (ic->candidate_list)
2420         {
2421           M17N_OBJECT_UNREF (ic->candidate_list);
2422           ic->candidate_list = NULL;
2423           ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
2424         }
2425     }
2426   mtext_reset (ic_info->preedit_saved);
2427   ic_info->state_pos = ic->cursor_pos = 0;
2428
2429   status = ic_info->state->title ? ic_info->state->title : im_info->title;
2430   if (ic->status != status)
2431     {
2432       ic->status = status;
2433       ic->status_changed = 1;
2434     }
2435 }
2436
2437 static int
2438 open_im (MInputMethod *im)
2439 {
2440   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil);
2441
2442   if (! im_info)
2443     MERROR (MERROR_IM, -1);
2444   im->info = im_info;
2445   im_info->im = im;
2446   return 0;
2447 }
2448
2449 static void
2450 close_im (MInputMethod *im)
2451 {
2452   im->info = NULL;
2453 }
2454
2455 static int
2456 create_ic (MInputContext *ic)
2457 {
2458   MInputMethod *im = ic->im;
2459   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2460   MInputContextInfo *ic_info;
2461   MPlist *plist;
2462
2463   if (ic->info)
2464     ic_info = (MInputContextInfo *) ic->info;
2465   else
2466     {
2467       MSTRUCT_CALLOC (ic_info, MERROR_IM);
2468       ic->info = ic_info;
2469     }
2470   MLIST_INIT1 (ic_info, keys, 8);
2471   ic_info->markers = mplist ();
2472   ic_info->vars = mplist ();
2473   plist = get_nested_list (im->language, im->name, Mnil, M_variable);
2474   MPLIST_DO (plist, plist)
2475     {
2476       MSymbol var = MPLIST_SYMBOL (plist);
2477       MPlist *pl;
2478
2479       plist = MPLIST_NEXT (plist);
2480       pl = MPLIST_PLIST (plist);
2481       pl = MPLIST_NEXT (pl);    /* Skip description.  */
2482       mplist_push (ic_info->vars, MPLIST_KEY (pl), MPLIST_VAL (pl));
2483       mplist_push (ic_info->vars, Msymbol, var);
2484     }
2485
2486   ic_info->preedit_saved = mtext ();
2487   if (im_info->externals)
2488     {
2489       MPlist *func_args = mplist (), *plist;
2490
2491       mplist_add (func_args, Mt, ic);
2492       MPLIST_DO (plist, im_info->externals)
2493         {
2494           MIMExternalModule *external = MPLIST_VAL (plist);
2495           MIMExternalFunc func
2496             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
2497
2498           if (func)
2499             (func) (func_args);
2500         }
2501       M17N_OBJECT_UNREF (func_args);
2502     }
2503   reset_ic (ic, Mnil);
2504   return 0;
2505 }
2506
2507 static void
2508 destroy_ic (MInputContext *ic)
2509 {
2510   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2511   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2512
2513   if (im_info->externals)
2514     {
2515       MPlist *func_args = mplist (), *plist;
2516
2517       mplist_add (func_args, Mt, ic);
2518       MPLIST_DO (plist, im_info->externals)
2519         {
2520           MIMExternalModule *external = MPLIST_VAL (plist);
2521           MIMExternalFunc func
2522             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
2523
2524           if (func)
2525             (func) (func_args);
2526         }
2527       M17N_OBJECT_UNREF (func_args);
2528     }
2529   MLIST_FREE1 (ic_info, keys);
2530   M17N_OBJECT_UNREF (ic_info->preedit_saved);
2531   M17N_OBJECT_UNREF (ic_info->markers);
2532   M17N_OBJECT_UNREF (ic_info->vars);
2533   M17N_OBJECT_UNREF (ic_info->preceding_text);
2534   M17N_OBJECT_UNREF (ic_info->following_text);
2535   free (ic->info);
2536 }
2537
2538
2539 /** Handle the input key KEY in the current state and map of IC->info.
2540     If KEY is handled but no text is produced, return 0, otherwise
2541     return 1.
2542
2543     Ignore ARG.  */
2544
2545 static int
2546 filter (MInputContext *ic, MSymbol key, void *arg)
2547 {
2548   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2549   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2550   int i = 0;
2551
2552   if (! ic_info->state)
2553     {
2554       ic_info->key_unhandled = 1;
2555       return 0;
2556     }
2557   mtext_reset (ic->produced);
2558   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
2559   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2560   ic_info->key_unhandled = 0;
2561   do {
2562     if (handle_key (ic) < 0)
2563       {
2564         /* KEY was not handled.  Delete it from the current key sequence.  */
2565         if (ic_info->used > 0)
2566           {
2567             memmove (ic_info->keys, ic_info->keys + 1,
2568                      sizeof (int) * (ic_info->used - 1));
2569             ic_info->used--;
2570           }
2571         /* This forces returning 1.  */
2572         ic_info->key_unhandled = 1;
2573         break;
2574       }
2575     if (i++ == 100)
2576       {
2577         mdebug_hook ();
2578         reset_ic (ic, Mnil);
2579         ic_info->key_unhandled = 1;
2580         break;
2581       }
2582     /* Break the loop if all keys were handled.  */
2583   } while (ic_info->key_head < ic_info->used);
2584
2585   /* If the current map is the root of the initial state, we should
2586      produce any preedit text in ic->produced.  */
2587   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
2588       && mtext_nchars (ic->preedit) > 0)
2589     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
2590
2591   if (mtext_nchars (ic->produced) > 0)
2592     {
2593       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
2594
2595       if (lang != Mnil)
2596         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
2597                         Mlanguage, ic->im->language);
2598     }
2599
2600   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
2601 }
2602
2603
2604 /** Return 1 if the last event or key was not handled, otherwise
2605     return 0.
2606
2607     There is no need of looking up because ic->produced should already
2608     contain the produced text (if any).
2609
2610     Ignore KEY.  */
2611
2612 static int
2613 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2614 {
2615   mtext_cat (mt, ic->produced);
2616   mtext_reset (ic->produced);
2617   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
2618 }
2619
2620 static MPlist *load_im_info_keys;
2621
2622 static MPlist *
2623 load_partial_im_info (MSymbol language, MSymbol name,
2624                       MSymbol extra, MSymbol key)
2625 {
2626   MDatabase *mdb;
2627   MPlist *plist;
2628
2629   if (language == Mnil)
2630     MERROR (MERROR_IM, NULL);
2631   mdb = mdatabase_find (Minput_method, language, name, extra);
2632   if (! mdb)
2633     MERROR (MERROR_IM, NULL);
2634
2635   mplist_push (load_im_info_keys, key, Mt);
2636   plist = mdatabase__load_for_keys (mdb, load_im_info_keys);
2637   mplist_pop (load_im_info_keys);
2638   return plist;
2639 }
2640
2641
2642 static MInputMethodInfo *
2643 get_im_info (MSymbol language, MSymbol name, MSymbol extra)
2644 {
2645   MDatabase *mdb;
2646   MPlist *plist;
2647   MInputMethodInfo *im_info = NULL;
2648
2649   if (language == Mnil)
2650     MERROR (MERROR_IM, NULL);
2651   mdb = mdatabase_find (Minput_method, language, name, extra);
2652   if (! mdb)
2653     MERROR (MERROR_IM, NULL);
2654
2655   if (! im_info_list)
2656     im_info_list = mplist ();
2657   else if ((plist = mplist_find_by_value (im_info_list, mdb)))
2658     {
2659       if (mdatabase__check (mdb))
2660         {
2661           plist = MPLIST_NEXT (plist);
2662           im_info = MPLIST_VAL (plist);
2663           return im_info;
2664         }
2665       mplist_pop (plist);
2666       free_im_info (MPLIST_VAL (plist));
2667       mplist_pop (plist);
2668     }
2669
2670   plist = mdatabase_load (mdb);
2671   if (! plist)
2672     MERROR (MERROR_IM, NULL);
2673   im_info = load_im_info (language, name, plist);
2674   M17N_OBJECT_UNREF (plist);
2675   if (! im_info)
2676     MERROR (MERROR_IM, NULL);
2677   mplist_push (im_info_list, Mt, im_info);
2678   mplist_push (im_info_list, Mt, mdb);
2679   return im_info;
2680 }
2681
2682 \f
2683 /* Input method command handler.  */
2684
2685 /* List of all (global and local) commands. 
2686    (LANG:(IM-NAME:(COMMAND ...) ...) ...) ...
2687    COMMAND is CMD-NAME:(mtext:DESCRIPTION plist:KEYSEQ ...))
2688    Global commands are storead as (t (t COMMAND ...))  */
2689
2690 /* Check if PLIST is a valid command key sequence.
2691    PLIST must be NULL or:
2692    [ symbol:KEY | integer:KEY ] ...  */
2693
2694 static int
2695 check_command_keyseq (MPlist *plist)
2696 {
2697   if (! plist)
2698     return 0;
2699   MPLIST_DO (plist, plist)
2700     {
2701       if (MPLIST_SYMBOL_P (plist))
2702         continue;
2703       else if (MPLIST_INTEGER_P (plist))
2704         {
2705           int n = MPLIST_INTEGER (plist);
2706
2707           if (n < 0 || n > 9)
2708             return -1;
2709           MPLIST_KEY (plist) = Msymbol;
2710           MPLIST_VAL (plist) = one_char_symbol['0' + 9];
2711         }
2712       else
2713         return -1;
2714     }
2715   return 0;
2716 }
2717
2718 /* Check if PLIST has this form:
2719      ([ plist:([ symbol:KEY | integer:KEY ]) | mtext:KEYSEQ ]
2720       ...)
2721    If the form of PLIST matches, return 0, otherwise return -1.  */
2722
2723 static int
2724 check_command_list (MPlist *plist)
2725 {
2726   MPLIST_DO (plist, plist)
2727     {
2728       if (MPLIST_PLIST_P (plist))
2729         {
2730           MPlist *pl = MPLIST_PLIST (plist);
2731
2732           MPLIST_DO (pl, pl)
2733             if (! MPLIST_SYMBOL_P (pl) && ! MPLIST_INTEGER_P (pl))
2734               return -1;
2735         }
2736       else if (! MPLIST_MTEXT_P (plist))
2737         return -1;
2738     }
2739   return 0;
2740 }
2741
2742
2743 \f
2744 /* Input method variable handler.  */
2745
2746 /* Check if PLIST has this form:
2747      (TYPE:VAL   ;; TYPE ::= integer | mtext | symbol
2748       VALID-VALUE
2749       ...)
2750    If the form of PLIST matches, return 0, otherwise return -1.  */
2751
2752 static int
2753 check_variable_list (MPlist *plist)
2754 {
2755   MSymbol type = MPLIST_KEY (plist);
2756   MPlist *p; 
2757
2758   if (type != Minteger && type != Mtext && type != Msymbol)
2759     return -1;
2760   MPLIST_DO (plist, MPLIST_NEXT (plist))
2761     {
2762       if (type == Minteger && MPLIST_PLIST_P (plist))
2763         {
2764           MPLIST_DO (p, MPLIST_PLIST (plist))
2765             if (! MPLIST_INTEGER_P (p))
2766               return -1;
2767         }
2768       else if (type != MPLIST_KEY (plist))
2769         return -1;
2770     }
2771   return 0;
2772 }
2773
2774 /* Support functions for mdebug_dump_im.  */
2775
2776 static void
2777 dump_im_map (MPlist *map_list, int indent)
2778 {
2779   char *prefix;
2780   MSymbol key = MPLIST_KEY (map_list);
2781   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
2782
2783   prefix = (char *) alloca (indent + 1);
2784   memset (prefix, 32, indent);
2785   prefix[indent] = '\0';
2786
2787   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
2788   if (map->map_actions)
2789     mdebug_dump_plist (map->map_actions, indent + 2);
2790   if (map->submaps)
2791     {
2792       MPLIST_DO (map_list, map->submaps)
2793         {
2794           fprintf (stderr, "\n%s  ", prefix);
2795           dump_im_map (map_list, indent + 2);
2796         }
2797     }
2798   if (map->branch_actions)
2799     {
2800       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
2801       mdebug_dump_plist (map->branch_actions, indent + 4);
2802       fprintf (stderr, ")");      
2803     }
2804   fprintf (stderr, ")");
2805 }
2806
2807
2808 static void
2809 dump_im_state (MIMState *state, int indent)
2810 {
2811   char *prefix;
2812   MPlist *map_list;
2813
2814   prefix = (char *) alloca (indent + 1);
2815   memset (prefix, 32, indent);
2816   prefix[indent] = '\0';
2817
2818   fprintf (stderr, "(%s", msymbol_name (state->name));
2819   if (state->map->submaps)
2820     {
2821       MPLIST_DO (map_list, state->map->submaps)
2822         {
2823           fprintf (stderr, "\n%s  ", prefix);
2824           dump_im_map (map_list, indent + 2);
2825         }
2826     }
2827   fprintf (stderr, ")");
2828 }
2829
2830 \f
2831
2832 int
2833 minput__init ()
2834 {
2835   char *key_names[32]
2836     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2837         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
2838         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2839         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
2840   char buf[6], buf2[256];
2841   int i;
2842   MPlist *plist;
2843
2844   Minput_method = msymbol ("input-method");
2845   Minput_driver = msymbol ("input-driver");
2846   Mtitle = msymbol ("title");
2847   Mmacro = msymbol ("macro");
2848   Mmodule = msymbol ("module");
2849   Mmap = msymbol ("map");
2850   Mstate = msymbol ("state");
2851   Minclude = msymbol ("include");
2852   Minsert = msymbol ("insert");
2853   M_candidates = msymbol ("  candidates");
2854   Mdelete = msymbol ("delete");
2855   Mmove = msymbol ("move");
2856   Mmark = msymbol ("mark");
2857   Mpushback = msymbol ("pushback");
2858   Mundo = msymbol ("undo");
2859   Mcall = msymbol ("call");
2860   Mshift = msymbol ("shift");
2861   Mselect = msymbol ("select");
2862   Mshow = msymbol ("show");
2863   Mhide = msymbol ("hide");
2864   Mcommit = msymbol ("commit");
2865   Munhandle = msymbol ("unhandle");
2866   Mset = msymbol ("set");
2867   Madd = msymbol ("add");
2868   Msub = msymbol ("sub");
2869   Mmul = msymbol ("mul");
2870   Mdiv = msymbol ("div");
2871   Mequal = msymbol ("=");
2872   Mless = msymbol ("<");
2873   Mgreater = msymbol (">");
2874
2875   Mcandidates_group_size = msymbol ("candidates-group-size");
2876   Mcandidates_charset = msymbol ("candidates-charset");
2877
2878   Minput_preedit_start = msymbol ("input-preedit-start");
2879   Minput_preedit_done = msymbol ("input-preedit-done");
2880   Minput_preedit_draw = msymbol ("input-preedit-draw");
2881   Minput_status_start = msymbol ("input-status-start");
2882   Minput_status_done = msymbol ("input-status-done");
2883   Minput_status_draw = msymbol ("input-status-draw");
2884   Minput_candidates_start = msymbol ("input-candidates-start");
2885   Minput_candidates_done = msymbol ("input-candidates-done");
2886   Minput_candidates_draw = msymbol ("input-candidates-draw");
2887   Minput_set_spot = msymbol ("input-set-spot");
2888   Minput_focus_move = msymbol ("input-focus-move");
2889   Minput_focus_in = msymbol ("input-focus-in");
2890   Minput_focus_out = msymbol ("input-focus-out");
2891   Minput_toggle = msymbol ("input-toggle");
2892   Minput_reset = msymbol ("input-reset");
2893   Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
2894   Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
2895
2896   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
2897   Mcandidate_index = msymbol ("  candidate-index");
2898
2899   Minit = msymbol ("init");
2900   Mfini = msymbol ("fini");
2901
2902   M_key_alias = msymbol ("  key-alias");
2903   M_description = msymbol ("description");
2904   M_command = msymbol ("command");
2905   M_variable = msymbol ("variable");
2906
2907   load_im_info_keys = mplist ();
2908   plist = mplist_add (load_im_info_keys, Mstate, Mnil);
2909
2910   buf[0] = 'C';
2911   buf[1] = '-';
2912   buf[3] = '\0';
2913   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
2914     {
2915       MSymbol alias;
2916
2917       one_char_symbol[i] = msymbol (buf);
2918       if (key_names[i])
2919         {
2920           alias = msymbol (key_names[i]);
2921           msymbol_put (one_char_symbol[i], M_key_alias,  alias);
2922         }
2923       else
2924         alias = one_char_symbol[i];
2925       buf[2] += (i == 0) ? -32 : 32;
2926       msymbol_put (alias, M_key_alias,  msymbol (buf));
2927       buf[2] -= (i == 0) ? -32 : 32;
2928     }
2929   for (buf[2] = i; i < 127; i++, buf[2]++)
2930     one_char_symbol[i] = msymbol (buf + 2);
2931   one_char_symbol[i++] = msymbol ("Delete");
2932   buf[2] = 'M';
2933   buf[3] = '-';
2934   buf[5] = '\0';
2935   buf2[0] = 'M';
2936   buf2[1] = '-';
2937   for (buf[4] = '@'; i < 160; i++, buf[4]++)
2938     {
2939       one_char_symbol[i] = msymbol (buf);
2940       if (key_names[i - 128])
2941         {
2942           strcpy (buf2 + 2, key_names[i - 128]);
2943           msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (buf2));
2944         }
2945     }
2946   for (buf[4] = i - 128; i < 255; i++, buf[4]++)
2947     one_char_symbol[i] = msymbol (buf + 2);
2948   one_char_symbol[i] = msymbol ("M-Delete");
2949
2950   command_list = variable_list = NULL;
2951
2952   minput_default_driver.open_im = open_im;
2953   minput_default_driver.close_im = close_im;
2954   minput_default_driver.create_ic = create_ic;
2955   minput_default_driver.destroy_ic = destroy_ic;
2956   minput_default_driver.filter = filter;
2957   minput_default_driver.lookup = lookup;
2958   minput_default_driver.callback_list = mplist ();
2959   mplist_put (minput_default_driver.callback_list, Minput_reset,
2960               (void *) reset_ic);
2961   minput_driver = &minput_default_driver;
2962   return 0;
2963 }
2964
2965 void
2966 minput__fini ()
2967 {
2968   if (command_list)
2969     {
2970       M17N_OBJECT_UNREF (command_list);
2971       command_list = NULL;
2972     }
2973   if (variable_list)
2974     {
2975       M17N_OBJECT_UNREF (variable_list);
2976       variable_list = NULL;
2977     }
2978
2979   if (minput_default_driver.callback_list)
2980     {
2981       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
2982       minput_default_driver.callback_list = NULL;
2983     }
2984   if (minput_driver->callback_list)
2985     {
2986       M17N_OBJECT_UNREF (minput_driver->callback_list);
2987       minput_driver->callback_list = NULL;
2988     }
2989
2990   if (im_info_list)
2991     {
2992       while (! MPLIST_TAIL_P (im_info_list))
2993         {
2994           /* Pop (t . mdb) */
2995           mplist_pop (im_info_list);
2996           free_im_info ((MInputMethodInfo *) MPLIST_VAL (im_info_list));
2997           /* Pop (t . im_info) */
2998           mplist_pop (im_info_list);
2999         }
3000       M17N_OBJECT_UNREF (im_info_list);
3001       im_info_list = NULL;
3002     }
3003  
3004   M17N_OBJECT_UNREF (load_im_info_keys);
3005 }
3006
3007 void
3008 minput__callback (MInputContext *ic, MSymbol command)
3009 {
3010   if (ic->im->driver.callback_list)
3011     {
3012       MInputCallbackFunc func
3013         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
3014                                            command);
3015
3016       if (func)
3017         (func) (ic, command);
3018     }
3019 }
3020
3021 MSymbol
3022 minput__char_to_key (int c)
3023 {
3024   if (c < 0 || c >= 0x100)
3025     return Mnil;
3026
3027   return one_char_symbol[c];
3028 }
3029
3030 /*** @} */
3031 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
3032
3033 \f
3034 /* External API */
3035
3036 /*** @addtogroup m17nInputMethod */
3037 /*** @{ */
3038 /*=*/
3039
3040 /***en
3041     @name Variables: Predefined symbols for callback commands.
3042
3043     These are the predefined symbols that are used as the @c COMMAND
3044     argument of callback functions of an input method driver (see
3045     #MInputDriver::callback_list ).  
3046
3047     Most of them don't require extra argument nor return any value;
3048     exceptions are these:
3049
3050     Minput_get_surrounding_text: When a callback function assigned for
3051     this command is called, the first element of #MInputContext::plist
3052     has key #Msymbol and the value specifies which portion of the
3053     surrounding text should be retrieved.  If the value is positive,
3054     it specifies the number of characters following the current cursor
3055     position.  If the value is negative, the absolute value specifies
3056     the number of characters preceding the current cursor position.
3057     The callback function must set the key of this element to #Mtext
3058     and the value to the retrived M-text (whose length may be shorter
3059     than the requested number of characters if the available text is
3060     not that long, or it may be longer if an application thinks it's
3061     more efficient to return that length).
3062
3063     Minput_delete_surrounding_text: When a callback function assigned
3064     for this command is called, the first element of
3065     #MInputContext::plist has key #Msymbol and the value specifies
3066     which portion of the surrounding text should be deleted in the
3067     same way as the case of Minput_get_surrounding_text.  The callback
3068     function must delete the specified text.  It should not alter
3069     #MInputContext::plist.  */ 
3070
3071 /***ja
3072     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
3073
3074     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND 
3075     °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
3076       */ 
3077 /*** @{ */ 
3078 /*=*/
3079
3080 MSymbol Minput_preedit_start;
3081 MSymbol Minput_preedit_done;
3082 MSymbol Minput_preedit_draw;
3083 MSymbol Minput_status_start;
3084 MSymbol Minput_status_done;
3085 MSymbol Minput_status_draw;
3086 MSymbol Minput_candidates_start;
3087 MSymbol Minput_candidates_done;
3088 MSymbol Minput_candidates_draw;
3089 MSymbol Minput_set_spot;
3090 MSymbol Minput_toggle;
3091 MSymbol Minput_reset;
3092 MSymbol Minput_get_surrounding_text;
3093 MSymbol Minput_delete_surrounding_text;
3094 /*** @} */
3095
3096 /*=*/
3097
3098 /***en
3099     @name Variables: Predefined symbols for special input events.
3100
3101     These are the predefined symbols that are used as the @c KEY
3102     argument of minput_filter ().  */ 
3103
3104 /*** @{ */ 
3105 /*=*/
3106
3107 MSymbol Minput_focus_out;
3108 MSymbol Minput_focus_in;
3109 MSymbol Minput_focus_move;
3110
3111 /*** @} */
3112
3113 /*=*/
3114
3115 /***en
3116     @brief The default driver for internal input methods.
3117
3118     The variable #minput_default_driver is the default driver for
3119     internal input methods.
3120
3121     The member MInputDriver::open_im () searches the m17n database for
3122     an input method that matches the tag \< #Minput_method, $LANGUAGE,
3123     $NAME\> and loads it.
3124
3125     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
3126     programmers responsibility to set it to a plist of proper callback
3127     functions.  Otherwise, no feedback information (e.g. preedit text)
3128     can be shown to users.
3129
3130     The macro M17N_INIT () sets the variable #minput_driver to the
3131     pointer to this driver so that all internal input methods use it.
3132
3133     Therefore, unless @c minput_driver is set differently, the driver
3134     dependent arguments $ARG of the functions whose name begin with
3135     "minput_" are all ignored.  */
3136
3137 /***ja
3138     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
3139
3140     ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£
3141
3142     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
3143     \< #Minput_method, $LANGUAGE, $NAME\> 
3144     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
3145
3146     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢
3147     ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist
3148     ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit 
3149     ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
3150
3151     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver 
3152     ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
3153
3154     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
3155     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
3156
3157 MInputDriver minput_default_driver;
3158 /*=*/
3159
3160 /***en
3161     @brief The driver for internal input methods.
3162
3163     The variable #minput_driver is a pointer to the input method
3164     driver that is used by internal input methods.  The macro
3165     M17N_INIT () initializes it to a pointer to #minput_default_driver
3166     if <m17n<EM></EM>.h> is included.  */ 
3167 /***ja
3168     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
3169
3170     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
3171     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
3172     ¥¿¤ò#minput_default_driver (<m17n<EM></EM>.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë
3173     »þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
3174
3175 MInputDriver *minput_driver;
3176
3177 MSymbol Minput_driver;
3178
3179 /*=*/
3180
3181 /***en
3182     @brief Open an input method.
3183
3184     The minput_open_im () function opens an input method that matches
3185     language $LANGUAGE and name $NAME, and returns a pointer to the
3186     input method object newly allocated.
3187
3188     This function at first decides an driver for the input method as
3189     below.
3190
3191     If $LANGUAGE is not #Mnil, the driver pointed by the variable
3192     #minput_driver is used.
3193
3194     If $LANGUAGE is #Mnil and $NAME has #Minput_driver property, the
3195     driver pointed to by the property value is used to open the input
3196     method.  If $NAME has no such property, @c NULL is returned.
3197
3198     Then, the member MInputDriver::open_im () of the driver is
3199     called.  
3200
3201     $ARG is set in the member @c arg of the structure MInputMethod so
3202     that the driver can refer to it.  */
3203
3204 /***ja
3205     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
3206
3207     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME 
3208     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
3209     
3210     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
3211
3212     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver 
3213     ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
3214
3215     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver
3216     ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£
3217     $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
3218
3219     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
3220
3221     $ARG ¤Ï¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£
3222
3223     @latexonly \IPAlabel{minput_open} @endlatexonly
3224
3225 */
3226
3227 MInputMethod *
3228 minput_open_im (MSymbol language, MSymbol name, void *arg)
3229 {
3230   MInputMethod *im;
3231   MInputDriver *driver;
3232
3233   MDEBUG_PRINT2 ("  [IM] opening (%s %s) ... ",
3234          msymbol_name (language), msymbol_name (name));
3235   if (language)
3236     driver = minput_driver;
3237   else
3238     {
3239       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
3240       if (! driver)
3241         MERROR (MERROR_IM, NULL);
3242     }
3243
3244   MSTRUCT_CALLOC (im, MERROR_IM);
3245   im->language = language;
3246   im->name = name;
3247   im->arg = arg;
3248   im->driver = *driver;
3249   if ((*im->driver.open_im) (im) < 0)
3250     {
3251       MDEBUG_PRINT (" failed\n");
3252       free (im);
3253       return NULL;
3254     }
3255   MDEBUG_PRINT (" ok\n");
3256   return im;
3257 }
3258
3259 /*=*/
3260
3261 /***en
3262     @brief Close an input method.
3263
3264     The minput_close_im () function closes the input method $IM, which
3265     must have been created by minput_open_im ().  */
3266
3267 /***ja
3268     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
3269
3270     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£
3271     ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
3272
3273 void
3274 minput_close_im (MInputMethod *im)
3275 {
3276   MDEBUG_PRINT2 ("  [IM] closing (%s %s) ... ",
3277                  msymbol_name (im->name), msymbol_name (im->language));
3278   (*im->driver.close_im) (im);
3279   free (im);
3280   MDEBUG_PRINT (" done\n");
3281 }
3282
3283 /*=*/
3284
3285 /***en
3286     @brief Create an input context.
3287
3288     The minput_create_ic () function creates an input context object
3289     associated with input method $IM, and calls callback functions
3290     corresponding to #Minput_preedit_start, #Minput_status_start, and
3291     #Minput_status_draw in this order.
3292
3293     @return
3294
3295     If an input context is successfully created, minput_create_ic ()
3296     returns a pointer to it.  Otherwise it returns @c NULL.  */
3297
3298 /***ja
3299     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
3300
3301     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
3302     ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
3303     #Minput_preedit_start, #Minput_status_start, #Minput_status_draw
3304     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
3305
3306     @return
3307
3308     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () 
3309     ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
3310       */
3311
3312 MInputContext *
3313 minput_create_ic (MInputMethod *im, void *arg)
3314 {
3315   MInputContext *ic;
3316
3317   MDEBUG_PRINT2 ("  [IM] creating context (%s %s) ... ",
3318                  msymbol_name (im->name), msymbol_name (im->language));
3319   MSTRUCT_CALLOC (ic, MERROR_IM);
3320   ic->im = im;
3321   ic->arg = arg;
3322   ic->preedit = mtext ();
3323   ic->candidate_list = NULL;
3324   ic->produced = mtext ();
3325   ic->spot.x = ic->spot.y = 0;
3326   ic->active = 1;
3327   ic->plist = mplist ();
3328   if ((*im->driver.create_ic) (ic) < 0)
3329     {
3330       MDEBUG_PRINT (" failed\n");
3331       M17N_OBJECT_UNREF (ic->preedit);
3332       M17N_OBJECT_UNREF (ic->produced);
3333       M17N_OBJECT_UNREF (ic->plist);
3334       free (ic);
3335       return NULL;
3336     };
3337
3338   if (im->driver.callback_list)
3339     {
3340       minput__callback (ic, Minput_preedit_start);
3341       minput__callback (ic, Minput_status_start);
3342       minput__callback (ic, Minput_status_draw);
3343     }
3344
3345   MDEBUG_PRINT (" ok\n");
3346   return ic;
3347 }
3348
3349 /*=*/
3350
3351 /***en
3352     @brief Destroy an input context.
3353
3354     The minput_destroy_ic () function destroys the input context $IC,
3355     which must have been created by minput_create_ic ().  It calls
3356     callback functions corresponding to #Minput_preedit_done,
3357     #Minput_status_done, and #Minput_candidates_done in this order.  */
3358
3359 /***ja
3360     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
3361
3362     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
3363     ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () 
3364     ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï 
3365     #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done 
3366     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
3367   */
3368
3369 void
3370 minput_destroy_ic (MInputContext *ic)
3371 {
3372   MDEBUG_PRINT2 ("  [IM] destroying context (%s %s) ... ",
3373                  msymbol_name (ic->im->name), msymbol_name (ic->im->language));
3374   if (ic->im->driver.callback_list)
3375     {
3376       minput__callback (ic, Minput_preedit_done);
3377       minput__callback (ic, Minput_status_done);
3378       minput__callback (ic, Minput_candidates_done);
3379     }
3380   (*ic->im->driver.destroy_ic) (ic);
3381   M17N_OBJECT_UNREF (ic->preedit);
3382   M17N_OBJECT_UNREF (ic->produced);
3383   M17N_OBJECT_UNREF (ic->plist);
3384   MDEBUG_PRINT (" done\n");
3385   free (ic);
3386 }
3387
3388 /*=*/
3389
3390 /***en
3391     @brief Filter an input key.
3392
3393     The minput_filter () function filters input key $KEY according to
3394     input context $IC, and calls callback functions corresponding to
3395     #Minput_preedit_draw, #Minput_status_draw, and
3396     #Minput_candidates_draw if the preedit text, the status, and the
3397     current candidate are changed respectively.
3398
3399     To make the input method commit the current preedit text (if any)
3400     and shift to the initial state, call this function with #Mnil as
3401     $KEY.
3402
3403     To inform the input method about the focus-out event, call this
3404     function with #Minput_focus_out as $KEY.
3405
3406     To inform the input method about the focus-in event, call this
3407     function with #Minput_focus_in as $KEY.
3408
3409     To inform the input method about the focus-move event (i.e. input
3410     spot change within the same input context), call this function
3411     with #Minput_focus_move as $KEY.
3412
3413     @return
3414     If $KEY is filtered out, this function returns 1.  In that case,
3415     the caller should discard the key.  Otherwise, it returns 0, and
3416     the caller should handle the key, for instance, by calling the
3417     function minput_lookup () with the same key.  */
3418
3419 /***ja
3420     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
3421
3422     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
3423     ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
3424     #Minput_preedit_draw, #Minput_status_draw,
3425     #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
3426
3427     @return 
3428     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
3429     ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
3430     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup ()
3431     ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
3432
3433     @latexonly \IPAlabel{minput_filter} @endlatexonly
3434 */
3435
3436 int
3437 minput_filter (MInputContext *ic, MSymbol key, void *arg)
3438 {
3439   int ret;
3440
3441   if (! ic
3442       || ! ic->active)
3443     return 0;
3444   ret = (*ic->im->driver.filter) (ic, key, arg);
3445
3446   if (ic->im->driver.callback_list)
3447     {
3448       if (ic->preedit_changed)
3449         minput__callback (ic, Minput_preedit_draw);
3450       if (ic->status_changed)
3451         minput__callback (ic, Minput_status_draw);
3452       if (ic->candidates_changed)
3453         minput__callback (ic, Minput_candidates_draw);
3454     }
3455
3456   return ret;
3457 }
3458
3459 /*=*/
3460
3461 /***en
3462     @brief Look up a text produced in the input context.
3463
3464     The minput_lookup () function looks up a text in the input context
3465     $IC.  $KEY must be the same one provided to the previous call of
3466     minput_filter ().
3467
3468     If a text was produced by the input method, it is concatenated
3469     to M-text $MT.
3470
3471     This function calls #MInputDriver::lookup .
3472
3473     @return
3474     If $KEY was correctly handled by the input method, this function
3475     returns 0.  Otherwise, returns -1, even in that case, some text
3476     may be produced in $MT.  */
3477
3478 /***ja
3479     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹.
3480
3481     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£
3482     $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3483
3484     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
3485     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
3486
3487     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
3488
3489     @return 
3490     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
3491     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
3492     ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
3493
3494     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
3495
3496 int
3497 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
3498 {
3499   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
3500 }
3501 /*=*/
3502
3503 /***en
3504     @brief Set the spot of the input context.
3505
3506     The minput_set_spot () function set the spot of input context $IC
3507     to coordinate ($X, $Y ) with the height specified by $ASCENT and $DESCENT .
3508     The semantics of these values depend on the input method driver.
3509
3510     For instance, a driver designed to work in a CUI environment may
3511     use $X and $Y as column and row numbers, and ignore $ASCENT and
3512     $DESCENT .  A driver designed to work in a window system may
3513     interpret $X and $Y as pixel offsets relative to the origin of the
3514     client window, and may interpret $ASCENT and $DESCENT as the ascent- and
3515     descent pixels of the line at ($X . $Y ).
3516
3517     $FONTSIZE specifies the fontsize of preedit text in 1/10 point.
3518
3519     $MT and $POS is the M-text and the character position at the spot.
3520     $MT may be @c NULL, in which case, the input method cannot get
3521     information about the text around the spot.  */
3522
3523 /***ja
3524     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë.
3525
3526     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y )
3527     ¤Î°ÌÃ֤ˠ¡¢¹â¤µ $ASCENT¡¢ $DESCENT 
3528     ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£
3529
3530     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y 
3531     ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT 
3532     ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï
3533     $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
3534     $ASCENT ¤È $DESCENT ¤ò ($X . $Y )
3535     ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
3536
3537     $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
3538
3539     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
3540     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
3541     */
3542
3543 void
3544 minput_set_spot (MInputContext *ic, int x, int y,
3545                  int ascent, int descent, int fontsize,
3546                  MText *mt, int pos)
3547 {
3548   ic->spot.x = x;
3549   ic->spot.y = y;
3550   ic->spot.ascent = ascent;
3551   ic->spot.descent = descent;
3552   ic->spot.fontsize = fontsize;
3553   ic->spot.mt = mt;
3554   ic->spot.pos = pos;
3555   if (ic->im->driver.callback_list)
3556     minput__callback (ic, Minput_set_spot);
3557 }
3558 /*=*/
3559
3560 /***en
3561     @brief Toggle input method.
3562
3563     The minput_toggle () function toggles the input method associated
3564     with input context $IC.  */
3565 /***ja
3566     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
3567
3568     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
3569     ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
3570     */
3571
3572 void
3573 minput_toggle (MInputContext *ic)
3574 {
3575   if (ic->im->driver.callback_list)
3576     minput__callback (ic, Minput_toggle);
3577   ic->active = ! ic->active;
3578 }
3579
3580 /***en
3581     @brief Reset an input context.
3582
3583     The minput_reset_ic () function resets input context $IC by
3584     calling a callback function corresponding to #Minput_reset.  It
3585     resets the status of $IC to the one of just after created.  As the
3586     current preedit text is deleted without commitment, if necessary,
3587     call minput_filter () with the arg @r key #Mnil to force the input
3588     method to commit the preedit in advance.  */
3589
3590 /***ja
3591     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
3592
3593     ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset 
3594     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
3595     ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ê¡¢¤·¤¿¤¬¤Ã¤Æ¡¢¤â¤·¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹¥È¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¡£
3596     É¬Íפʤé¤Ð¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï minput_lookup () 
3597     ¤òÆɤó¤Ç¤½¤Î¥³¥ß¥Ã¥È¤µ¤ì¤¿¥Æ¥­¥¹¥È¤ò¼è¤ê½Ð¤¹¤³¤È¤¬¤Ç¤­¡¢¤½¤ÎºÝ¡¢
3598     minput_lookup () ¤Î°ú¿ô @c KEY ¤È @c ARG 
3599     ¤Ï̵»ë¤µ¤ì¤ë¡£ */
3600 void
3601 minput_reset_ic (MInputContext *ic)
3602 {
3603   if (ic->im->driver.callback_list)
3604     minput__callback (ic, Minput_reset);
3605 }
3606
3607 /***en
3608     @brief Get description text of an input method.
3609
3610     The minput_get_description () function returns an M-text that
3611     describes the input method specified by $LANGUAGE and $NAME.
3612
3613     @return
3614     If the specified input method has a description text, a pointer to
3615     #MText is returned.  A caller have to free it by m17n_object_unref ().
3616     If the input method does not have a description text, @c NULL is
3617     returned.  */
3618 /***ja
3619     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë.
3620
3621     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
3622     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
3623
3624     @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
3625     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
3626     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
3627     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
3628
3629 MText *
3630 minput_get_description (MSymbol language, MSymbol name)
3631 {
3632   MPlist *plist = load_partial_im_info (language, name, Mnil, M_description);
3633   MPlist *pl;
3634   MText *mt;
3635
3636   if (! plist)
3637     return NULL;
3638   pl = MPLIST_PLIST (plist);
3639   pl = MPLIST_NEXT (pl);
3640   if (MPLIST_MTEXT_P (pl))
3641     {
3642       mt = MPLIST_MTEXT (pl);
3643       M17N_OBJECT_REF (mt);
3644     }
3645   M17N_OBJECT_UNREF (plist);
3646   return mt;
3647 }
3648
3649 /***en
3650     @brief Get information about input method commands.
3651
3652     The minput_get_commands () function returns information about
3653     input method commands of the input method specified by $LANGUAGE
3654     and $NAME.  An input method command is a pseudo key event to which
3655     one or more actual input key sequences are assigned.
3656
3657     There are two kinds of commands, global and local.  Global
3658     commands are used by multiple input methods for the same purpose,
3659     and have global key assignments.  Local commands are used only in
3660     a specific input method, and have only local key assignments.
3661
3662     Each input method may locally change key assignments for global
3663     commands.  A global key assignment for a global command are
3664     effective only when the current input method does not have local
3665     key assignments for that command.
3666
3667     If $NAME is #Mnil, information about global commands is returned.
3668     In this case $LANGUAGE is ignored.
3669
3670     If $NAME is not #Mnil, information about those commands that have
3671     local key assignments in the input method specified by $LANGUAGE
3672     and $NAME is returned.
3673
3674     @return
3675     If no input method commands are found, this function returns @c NULL.
3676
3677     Otherwise, a pointer to a plist is returned.  The key of each
3678     element in the plist is a symbol representing a command, and the
3679     value is a plist of the form COMMAND-INFO described below.
3680
3681     The first element of COMMAND-INFO has the key #Mtext, and the
3682     value is an M-text describing the command.
3683
3684     If there are no more elements, that means no key sequences are
3685     assigned to the command.  Otherwise, each of the remaining
3686     elements has the key #Mplist, and the value is a plist whose keys are
3687     #Msymbol and values are symbols representing input keys, which are
3688     currently assigned to the command.
3689
3690     As the returned plist is kept in the library, the caller must not
3691     modify nor free it.  */
3692 /***ja
3693     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
3694
3695     ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
3696     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
3697     ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
3698     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
3699
3700     ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
3701     ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
3702     ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
3703     ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
3704
3705     ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
3706     ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
3707     ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
3708     ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
3709
3710     $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
3711     ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
3712
3713     $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
3714     Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
3715     ¤òÊÖ¤¹¡£
3716
3717     @return
3718     ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
3719
3720     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
3721     ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
3722     ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
3723
3724     COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
3725     ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
3726     #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
3727     ¤¤¤³¤È¤Ë¤Ê¤ë¡£
3728
3729     ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
3730     ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
3731     ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
3732     ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
3733     ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
3734
3735     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
3736     ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
3737
3738 MPlist *
3739 minput_get_commands (MSymbol language, MSymbol name)
3740 {
3741   MPlist *plist = get_nested_list (language, name, Mnil, M_command);
3742
3743   return (MPLIST_TAIL_P (plist) ? NULL : plist);
3744 }
3745
3746 /***en
3747     @brief Assign a key sequence to an input method command.
3748
3749     The minput_assign_command_keys () function assigns input key
3750     sequence $KEYSEQ to input method command $COMMAND for the input
3751     method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
3752     key sequence is assigned globally no matter what $LANGUAGE is.
3753     Otherwise the key sequence is assigned locally.
3754
3755     Each element of $KEYSEQ must have the key $Msymbol and the value
3756     must be a symbol representing an input key.
3757
3758     $KEYSEQ may be @c NULL, in which case, all assignments are deleted
3759     globally or locally.
3760
3761     This assignment gets effective in a newly opened input method.
3762
3763     @return
3764     If the operation was successful, 0 is returned.  Otherwise -1 is
3765     returned, and #merror_code is set to #MERROR_IM.  */
3766 /***ja
3767     @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
3768
3769     ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
3770     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
3771     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
3772     $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
3773     ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
3774
3775     $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
3776     ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3777
3778     $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
3779     ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
3780
3781     ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
3782     ¸ú¤Ë¤Ê¤ë¡£
3783
3784     @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
3785     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
3786
3787 int
3788 minput_assign_command_keys (MSymbol language, MSymbol name,
3789                             MSymbol command, MPlist *keyseq)
3790 {
3791   MPlist *plist, *pl, *p;
3792
3793   if (check_command_keyseq (keyseq) < 0
3794       || ! (plist = get_nested_list (language, name, Mnil, M_command)))
3795     MERROR (MERROR_IM, -1);
3796   pl = mplist_get (plist, command);
3797   if (pl)
3798     {
3799       pl = MPLIST_NEXT (pl);
3800       if (! keyseq)
3801         while ((p = mplist_pop (pl)))
3802           M17N_OBJECT_UNREF (p);
3803       else
3804         {
3805           keyseq = mplist_copy (keyseq);
3806           mplist_push (pl, Mplist, keyseq);
3807           M17N_OBJECT_UNREF (keyseq);
3808         }
3809     }
3810   else
3811     {
3812       if (name == Mnil)
3813         MERROR (MERROR_IM, -1);
3814       if (! keyseq)
3815         return 0;
3816       /* Get global commands.  */
3817       pl = get_nested_list (Mnil, Mnil, Mnil, M_command);
3818       pl = mplist_get (pl, command);
3819       if (! pl)
3820         MERROR (MERROR_IM, -1);
3821       p = mplist ();
3822       mplist_add (p, Mtext, mplist_value (pl));
3823       keyseq = mplist_copy (keyseq);
3824       mplist_add (p, Mplist, keyseq);
3825       M17N_OBJECT_UNREF (keyseq);
3826       mplist_push (plist, command, p);
3827     }
3828   return 0;
3829 }
3830
3831 /***en
3832     @brief Get a list of variables of an input method.
3833
3834     The minput_get_variables () function returns a plist (#MPlist) of
3835     variables used to control the behavior of the input method
3836     specified by $LANGUAGE and $NAME.  The key of an element of the
3837     plist is a symbol representing a variable, and the value is a
3838     plist of the form VAR-INFO (described below) that carries the
3839     information about the variable.
3840
3841     The first element of VAR-INFO has the key #Mtext or #Msymbol.  If
3842     the key is #Mtext, the value is an M-text describing the variable.
3843     If the key is #Msymbol, that value is #Mnil which means the
3844     variable has no description text.
3845
3846     The second element of VAR-INFO is for the value of the variable.
3847     The key is #Minteger, #Msymbol, or #Mtext, and the value is an
3848     integer, a symbol, or an M-text, respectively.  The variable is
3849     set to this value when an input context is created for the input
3850     method.
3851
3852     If there are no more elements, the variable can take any value
3853     that matches with the above type.  Otherwise, the remaining
3854     elements of VAR-INFO are to specify valid values of the variable.
3855
3856     If the type of the variable is integer, the following elements
3857     have the key #Minteger or #Mplist.  If it is #Minteger, the value
3858     is a valid integer value.  If it is #Mplist, the value is a plist
3859     of two of elements.  Both of them have the key #Minteger, and
3860     values are the minimum and maximum bounds of the valid value
3861     range.
3862
3863     If the type of the variable is symbol or M-text, the following
3864     elements of the plist have the key #Msymbol or #Mtext,
3865     respectively, and the value must be a valid one.
3866
3867     For instance, suppose an input method has the variables:
3868
3869     @li name:intvar, description:"value is an integer",
3870          initial value:0, value-range:0..3,10,20
3871
3872     @li name:symvar, description:"value is a symbol",
3873          initial value:nil, value-range:a, b, c, nil
3874
3875     @li name:txtvar, description:"value is an M-text",
3876          initial value:empty text, no value-range (i.e. any text)
3877
3878     Then, the returned plist has this form ('X:Y' means X is a key and Y is
3879     a value, and '(...)' means a plist):
3880
3881 @verbatim
3882     plist:(intvar:(mtext:"value is an integer"
3883                    integer:0
3884                    plist:(integer:0 integer:3)
3885                    integer:10
3886                    integer:20))
3887            symvar:(mtext:"value is a symbol"
3888                    symbol:nil
3889                    symbol:a
3890                    symbol:b
3891                    symbol:c
3892                    symbol:nil))
3893            txtvar:(mtext:"value is an M-text"
3894                    mtext:""))
3895 @endverbatim
3896
3897     @return
3898     If the input method uses any variables, a pointer to #MPlist is
3899     returned.  As the plist is kept in the library, a caller must not
3900     modify nor free it.  If the input method does not use any
3901     variable, @c NULL is returned.  */
3902 /***ja
3903     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
3904
3905     ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME 
3906     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È 
3907     (#MPlist) ¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤΥ­¡¼¤ÏÊÑ¿ô¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
3908     ³ÆÍ×ÁǤÎÃͤϲ¼µ­¤Î VAR-INFO 
3909     ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ê¡¢³ÆÊÑ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤ò¼¨¤·¤Æ¤¤¤ë¡£
3910
3911     VAR-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼¤¬
3912     #Mtext ¤Ê¤é¡¢ÃͤϤ½¤ÎÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬ #Msymbol
3913     ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤ÎÊÑ¿ô¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê¤¤¤³¤È¤Ë¤Ê¤ë¡£
3914
3915     VAR-INFO ¤ÎÂèÆóÍ×ÁǤÏÊÑ¿ô¤ÎÃͤò¼¨¤¹¡£¥­¡¼¤Ï #Minteger, #Msymbol,
3916     #Mtext ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ê¡¢ÃͤϤ½¤ì¤¾¤ìÀ°¿ôÃÍ¡¢¥·¥ó¥Ü¥ë¡¢M-text  ¤Ç¤¢¤ë¡£
3917     ¤³¤ÎÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎÏ¥³¥ó¥Æ¥¹¥È¤¬ºî¤é¤ì¤ë»þÅÀ¤Ç¤Ï¡¢ÊÑ¿ô¤Ï¤³¤ÎÃͤËÀßÄꤵ¤ì¤Æ¤¤¤ë¡£
3918
3919     VAR-INFO ¤Ë¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢ÊÑ¿ô¤Ï¾åµ­¤Î·¿¤Ë¹çÃפ¹¤ë¸Â¤ê¤É¤Î¤è¤¦¤ÊÃͤò¤È¤ë¤³¤È¤â¤Ç¤­¤ë¡£
3920     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢VAR-INFO ¤Î»Ä¤ê¤ÎÍ×ÁǤˤè¤Ã¤ÆÊÑ¿ô¤ÎÍ­¸ú¤ÊÃͤ¬»ØÄꤵ¤ì¤ë¡£
3921
3922     ÊÑ¿ô¤Î·¿¤¬À°¿ô¤Ç¤¢¤ì¤Ð¡¢¤½¤ì°Ê¹ß¤ÎÍ×ÁǤϠ#Minteger ¤« #Mplist 
3923     ¤ò¥­¡¼¤È¤·¤Æ»ý¤Ä¡£ #Minteger ¤Ç¤¢¤ì¤Ð¡¢ÃͤÏÍ­¸ú¤ÊÃͤò¼¨¤¹À°¿ôÃͤǤ¢¤ë¡£
3924     #Mplist ¤Ç¤¢¤ì¤Ð¡¢ÃͤÏÆó¤Ä¤ÎÍ×ÁǤò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ê¡¢³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ
3925     #Minteger ¤ò¡¢ÃͤȤ·¤Æ¤½¤ì¤¾¤ìÍ­¸ú¤ÊÃͤξå¸ÂÃͤȲ¼¸ÂÃͤò¤È¤ë¡£
3926
3927     ÊÑ¿ô¤Î·¿¤¬¥·¥ó¥Ü¥ë¤« M-text ¤Ç¤¢¤ì¤Ð¡¢¤½¤ì°Ê¹ß¤ÎÍ×ÁǤϥ­¡¼¤È¤·¤Æ¤½¤ì¤¾¤ì
3928     #Msymbol ¤« #Mtext ¤ò»ý¤Á¡¢ÃͤϤ½¤Î·¿¤Ë¹çÃפ¹¤ë¤â¤Î¤Ç¤¢¤ë¡£
3929
3930     Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
3931
3932     @li name:intvar, ÀâÌÀ:"value is an integer",
3933         ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
3934
3935     @li name:symvar, ÀâÌÀ:"value is a symbol",
3936          ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
3937
3938     @li name:txtvar, ÀâÌÀ:"value is an M-text",
3939         ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
3940
3941     ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£¡Ê'X:Y' ¤È¤¤¤¦µ­Ë¡¤Ï X 
3942     ¤¬¥­¡¼¤Ç Y ¤¬ÃͤǤ¢¤ë¤³¤È¤ò¡¢¤Þ¤¿ '(...)' ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¼¨¤¹¡£¡Ë
3943
3944 @verbatim
3945     plist:(intvar:(mtext:"value is an integer"
3946                    integer:0
3947                    plist:(integer:0 integer:3)
3948                    integer:10
3949                    integer:20))
3950            symvar:(mtext:"value is a symbol"
3951                    symbol:nil
3952                    symbol:a
3953                    symbol:b
3954                    symbol:c
3955                    symbol:nil))
3956            txtvar:(mtext:"value is an M-text"
3957                    mtext:""))
3958 @endverbatim
3959
3960     @return 
3961     ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤ÎÊÑ¿ô¤òÊÖ¤¹¡£
3962     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3963     ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
3964
3965 MPlist *
3966 minput_get_variables (MSymbol language, MSymbol name)
3967 {
3968   MPlist *plist = get_nested_list (language, name, Mnil, M_variable);
3969
3970   return (MPLIST_TAIL_P (plist) ? NULL : plist);
3971 }
3972
3973 /***en
3974     @brief Set the initial value of an input method variable.
3975
3976     The minput_set_variable () function sets the initial value of
3977     input method variable $VARIABLE to $VALUE for the input method
3978     specified by $LANGUAGE and $NAME.
3979
3980     By default, the initial value is 0.
3981
3982     This setting gets effective in a newly opened input method.
3983
3984     @return
3985     If the operation was successful, 0 is returned.  Otherwise -1 is
3986     returned, and #merror_code is set to #MERROR_IM.  */
3987 /***ja
3988     @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
3989
3990     ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
3991     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
3992     ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
3993
3994     ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
3995
3996     ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
3997
3998     @return
3999     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
4000     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
4001
4002 int
4003 minput_set_variable (MSymbol language, MSymbol name,
4004                      MSymbol variable, void *value)
4005 {
4006   MPlist *plist, *val_element, *range_element;
4007   MSymbol type;
4008
4009   plist = get_nested_list (language, name, Mnil, M_variable);
4010   if (! plist)
4011     MERROR (MERROR_IM, -1);
4012   plist = mplist_find_by_value (plist, variable);
4013   if (! plist)
4014     MERROR (MERROR_IM, -1);
4015   plist = MPLIST_PLIST (MPLIST_NEXT (plist));
4016   val_element = MPLIST_NEXT (plist);
4017   type = MPLIST_KEY (val_element);
4018   range_element = MPLIST_NEXT (val_element);
4019     
4020   if (! MPLIST_TAIL_P (range_element))
4021     {
4022       if (type == Minteger)
4023         {
4024           int val = (int) value, this_val;
4025       
4026           MPLIST_DO (plist, range_element)
4027             {
4028               this_val = (int) MPLIST_VAL (plist);
4029               if (MPLIST_PLIST_P (plist))
4030                 {
4031                   int min_bound, max_bound;
4032                   MPlist *pl = MPLIST_PLIST (plist);
4033
4034                   min_bound = (int) MPLIST_VAL (pl);
4035                   pl = MPLIST_NEXT (pl);
4036                   max_bound = (int) MPLIST_VAL (pl);
4037                   if (val >= min_bound && val <= max_bound)
4038                     break;
4039                 }
4040               else if (val == this_val)
4041                 break;
4042             }
4043           if (MPLIST_TAIL_P (plist))
4044             MERROR (MERROR_IM, -1);
4045         }
4046       else if (type == Msymbol)
4047         {
4048           MPLIST_DO (plist, range_element)
4049             if (MPLIST_SYMBOL (plist) == (MSymbol) value)
4050               break;
4051           if (MPLIST_TAIL_P (plist))
4052             MERROR (MERROR_IM, -1);
4053         }
4054       else                      /* type == Mtext */
4055         {
4056           MPLIST_DO (plist, range_element)
4057             if (mtext_cmp (MPLIST_MTEXT (plist), (MText *) value) == 0)
4058               break;
4059           if (MPLIST_TAIL_P (plist))
4060             MERROR (MERROR_IM, -1);
4061           M17N_OBJECT_REF (value);
4062         }
4063     }
4064
4065   mplist_set (val_element, type, value);
4066   return 0;
4067 }
4068
4069 /*** @} */
4070 /*=*/
4071 /*** @addtogroup m17nDebug */
4072 /*=*/
4073 /*** @{  */
4074 /*=*/
4075
4076 /***en
4077     @brief Dump an input method.
4078
4079     The mdebug_dump_im () function prints the input method $IM in a
4080     human readable way to the stderr.  $INDENT specifies how many
4081     columns to indent the lines but the first one.
4082
4083     @return
4084     This function returns $IM.  */
4085 /***ja
4086     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
4087
4088     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
4089     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
4090
4091     @return
4092     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
4093
4094 MInputMethod *
4095 mdebug_dump_im (MInputMethod *im, int indent)
4096 {
4097   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
4098   char *prefix;
4099
4100   prefix = (char *) alloca (indent + 1);
4101   memset (prefix, 32, indent);
4102   prefix[indent] = '\0';
4103
4104   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
4105            msymbol_name (im->name));
4106   mdebug_dump_mtext (im_info->title, 0, 0);
4107   if (im->name != Mnil)
4108     {
4109       MPlist *state;
4110
4111       MPLIST_DO (state, im_info->states)
4112         {
4113           fprintf (stderr, "\n%s  ", prefix);
4114           dump_im_state (MPLIST_VAL (state), indent + 2);
4115         }
4116     }
4117   fprintf (stderr, ")");
4118   return im;
4119 }
4120
4121 /*** @} */ 
4122
4123 /*
4124   Local Variables:
4125   coding: euc-japan
4126   End:
4127 */