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