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