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