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