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