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