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