b13eb4da8b5b8cbb27484fb445379e549e3e14dc
[m17n/m17n-lib.git] / src / input.c
1 /* input.c -- input method module.
2    Copyright (C) 2003, 2004, 2005, 2006
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 an 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 its 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 drivers utilize the input processing engine
42     provided by the m17n library itself.  The m17n database may
43     provide input methods that are not limited to a specific language.
44     The database uses @c Mt as LANGUAGE of those input methods.
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 has 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 its body is
56     defined in an external resource (e.g. XIM of X Window System).
57     For this kind of input methods, the symbol NAME must have a
58     property of key @c Minput_driver, and the value must be a pointer
59     to an input method driver.  Therefore, by preparing a proper
60     driver, any kind of input method can be treated in the framework
61     of the @c m17n @c library.
62
63     For convenience, the m17n-X library provides an input method
64     driver that enables the input style of OverTheSpot for XIM, and
65     stores @c Minput_driver property of the symbol @c Mxim with a
66     pointer to the driver.  See the documentation of m17n GUI API for
67     the detail.
68
69     </ul>
70
71     PROCESSING FLOW
72
73     The typical processing flow of handling an input method is: 
74
75      @li open an input method
76      @li create an input context for the input method
77      @li filter an input key
78      @li look up a produced text in the input context  */
79
80 /*=*/
81 /***ja
82     @addtogroup m17nInputMethod
83     @brief ÆþÎϥ᥽¥Ã¥ÉÍÑAPI.
84
85     ÆþÎϥ᥽¥Ã¥É¤Ï¿ÍͤÊʸ»ú¤òÆþÎϤ¹¤ë¤¿¤á¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£
86     ÆþÎϥ᥽¥Ã¥É¤Ï¥·¥ó¥Ü¥ë LANGUAGE ¤È NAME ¤ÎÁȤˤè¤Ã¤Æ¼±Ê̤µ¤ì¡¢
87     ¤³¤ÎÁȹ礻¤Ë¤è¤Ã¤ÆÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤¬·èÄꤹ¤ë¡£
88     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤È¤Ï¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤ò°·¤¦¤¿¤á¤Î´Ø¿ô¤Î½¸¤Þ¤ê¤Ç¤¢¤ë¡£
89     ÆþÎϥ᥽¥Ã¥É¤Ë¤ÏÆâÉô¥á¥½¥Ã¥É¤È³°Éô¥á¥½¥Ã¥É¤ÎÆó¼ïÎब¤¢¤ë¡£
90
91     <ul> 
92     <li> ÆâÉôÆþÎϥ᥽¥Ã¥É
93
94     ÆâÉôÆþÎϥ᥽¥Ã¥É¤È¤Ï LANGUAGE ¤¬ @c Mnil °Ê³°¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂÎ
95     ¤Ïm17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë<Minput_method, LANGUAGE, NAME> ¤È¤¤¤¦¥¿¥°¤òÉÕ
96     ¤±¤ÆÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤ËÂФ·¤Æ¡¢m17n ¥é¥¤¥Ö¥é¥ê¤Ç
97     ¤ÏCUI ÍѤȠGUI ÍѤ½¤ì¤¾¤ì¤ÎÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤ò¤¢¤é¤«¤¸¤áÄêµÁ¤·¤Æ
98     ¤¤¤ë¡£¤³¤ì¤é¤Î¥É¥é¥¤¥Ð¤Ï m17n ¥é¥¤¥Ö¥é¥ê¼«ÂΤÎÆþÎϽèÍý¥¨¥ó¥¸¥ó¤òÍø
99     ÍѤ¹¤ë¡£m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤Ï¡¢ÆÃÄê¤Î¸À¸ìÀìÍѤǤʤ¤ÆþÎϥ᥽¥Ã¥É¤òÄê
100     µÁ¤¹¤ë¤³¤È¤â¤Ç¤­¡¢¤½¤Î¤è¤¦¤ÊÆþÎϥ᥽¥Ã¥É¤Î LANGUAGE ¤Ï @c Mt ¤Ç¤¢¤ë¡£
101
102     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï¡¢¥æ¡¼¥¶¤ÎÆþÎÏ¥¤¥Ù¥ó¥È¤ËÂбþ¤·¤¿¥·¥ó¥Ü¥ë¤Ç¤¢¤ëÆþ
103     ÎÏ¥­¡¼¤ò¼õ¤±¼è¤ë¡£@c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÏÆþÎÏ¥¤¥Ù¥ó¥È¤¬¥¢¥×¥ê¥±¡¼
104     ¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ç¤É¤¦É½¸½¤µ¤ì¤Æ¤¤¤ë¤«¤òÃΤ뤳¤È¤¬¤Ç¤­¤Ê¤¤¤Î¤Ç¡¢Æþ
105     ÎÏ¥¤¥Ù¥ó¥È¤«¤éÆþÎÏ¥­¡¼¤Ø¤ÎÊÑ´¹¤Ï¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥Þ¤ÎÀÕǤ¤Ç
106     ¹Ô¤ï¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï´Ø¿ô minput_event_to_key () ¤Î
107     ÀâÌÀ¤ò»²¾È¡£
108
109     <li> ³°ÉôÆþÎϥ᥽¥Ã¥É
110
111     ³°ÉôÆþÎϥ᥽¥Ã¥É¤È¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂΤϳ°
112     Éô¤Î¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê
113     ¤É¡£) ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï@c Minput_driver ¤ò
114     ¥­¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
115     ¥¿¤Ç¤¢¤ë¡£¤³¤Î¤³¤È¤Ë¤è¤ê¡¢Å¬Àڤʥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢¤¤
116     ¤«¤Ê¤ë¼ïÎà¤ÎÆþÎϥ᥽¥Ã¥É¤â@c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÎÏÈÁȤÎÃæ¤Ç°·¤¦»ö
117     ¤¬¤Ç¤­¤ë¡£
118
119     ÍøÊØÀ­¤Î´ÑÅÀ¤«¤é¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤Ï XIM ¤Î OverTheSpot ¤ÎÆþÎÏ¥¹¥¿
120     ¥¤¥ë¤ò¼Â¸½¤¹¤ëÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤òÄ󶡤·¡¢¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î
121     @c Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý
122     ¤·¤Æ¤¤¤ë¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï m17n GUI API ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
123
124     </ul> 
125
126     ½èÍý¤Îή¤ì
127
128     ÆþÎϥ᥽¥Ã¥É½èÍý¤Îŵ·¿Åª¤Ê½èÍý¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
129     
130     @li ÆþÎϥ᥽¥Ã¥É¤Î¥ª¡¼¥×¥ó
131     @li ¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ÎÀ¸À®
132     @li ÆþÎÏ¥¤¥Ù¥ó¥È¤Î¥Õ¥£¥ë¥¿
133     @li ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ç¤ÎÀ¸À®¥Æ¥­¥¹¥È¤Î¸¡º÷     */
134
135 /*=*/
136
137 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
138 /*** @addtogroup m17nInternal
139      @{ */
140
141 #include <stdio.h>
142 #include <stdlib.h>
143 #include <string.h>
144 #include <sys/types.h>
145 #include <dirent.h>
146 #include <sys/stat.h>
147 #include <unistd.h>
148 #include <time.h>
149
150 #include "config.h"
151
152 #ifdef HAVE_DLFCN_H
153 #include <dlfcn.h>
154 #endif
155
156 #include "m17n-gui.h"
157 #include "m17n-misc.h"
158 #include "internal.h"
159 #include "mtext.h"
160 #include "input.h"
161 #include "symbol.h"
162 #include "plist.h"
163 #include "database.h"
164 #include "charset.h"
165
166 static int mdebug_mask = MDEBUG_INPUT;
167
168 static int fully_initialized;
169
170 static MSymbol Minput_method;
171
172 /** Symbols to load an input method data.  */
173 static MSymbol Mtitle, Mmacro, Mmodule, Mstate, Minclude;
174
175 /** Symbols for actions.  */
176 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
177 static MSymbol Mselect, Mshow, Mhide, Mcommit, Munhandle;
178 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
179 static MSymbol Mless_equal, Mgreater_equal;
180 static MSymbol Mcond;
181 static MSymbol Mplus, Mminus, Mstar, Mslash, Mand, Mor, Mnot;
182
183 /** Special action symbol.  */
184 static MSymbol Mat_reload;
185
186 static MSymbol M_candidates;
187
188 static MSymbol Mcandidate_list, Mcandidate_index;
189
190 static MSymbol Minit, Mfini;
191
192 /** Symbols for variables.  */
193 static MSymbol Mcandidates_group_size, Mcandidates_charset;
194
195 /** Symbols for key events.  */
196 static MSymbol one_char_symbol[256];
197
198 static MSymbol M_key_alias;
199
200 static MSymbol Mdescription, Mcommand, Mvariable, Mglobal, Mconfig;
201
202 /** Structure to hold a map.  */
203
204 struct MIMMap
205 {
206   /** List of actions to take when we reach the map.  In a root map,
207       the actions are executed only when there's no more key.  */
208   MPlist *map_actions;
209
210   /** List of deeper maps.  If NULL, this is a terminal map.  */
211   MPlist *submaps;
212
213   /** List of actions to take when we leave the map successfully.  In
214       a root map, the actions are executed only when none of submaps
215       handle the current key.  */
216   MPlist *branch_actions;
217 };
218
219 typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
220
221 typedef struct
222 {
223   void *handle;
224   MPlist *func_list;            /* function name vs (MIMExternalFunc *) */
225 } MIMExternalModule;
226
227 struct MIMState
228 {
229   M17NObject control;
230
231   /** Name of the state.  */
232   MSymbol name;
233
234   /** Title of the state, or NULL.  */
235   MText *title;
236
237   /** Key translation map of the state.  Built by merging all maps of
238       branches.  */
239   MIMMap *map;
240 };
241
242 #define CUSTOM_FILE "config.mic"
243
244 static MPlist *load_im_info_keys;
245
246 /* List of input method information.  The format is:
247      (LANGUAGE NAME t:IM_INFO ... ... ...)  */
248 static MPlist *im_info_list;
249
250 /* Database for user's customization file.  */
251 static MDatabase *im_custom_mdb;
252
253 /* List of input method information loaded from im_custom_mdb.  The
254    format is the same as im_info_list.  */
255 static MPlist *im_custom_list;
256
257 /* List of input method information configured by
258    minput_config_command and minput_config_variable.  The format is
259    the same as im_info_list.  */
260 static MPlist *im_config_list;
261
262 /* Global input method information.  It points into the element of
263    im_info_list corresponding to LANGUAGE == `nil' and NAME ==
264    `global'.  */
265 static MInputMethodInfo *global_info;
266
267 static int update_global_info (void);
268 static int update_custom_info (void);
269 static MInputMethodInfo *get_im_info (MSymbol, MSymbol, MSymbol, MSymbol);
270
271 \f
272 void
273 fully_initialize ()
274 {
275   char *key_names[32]
276     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
277         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
278         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
279         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
280   char buf[6], buf2[32];
281   int i, j;
282   /* Maximum case: C-M-a, C-M-A, M-Return, C-A-a, C-A-A, A-Return.  */
283   MSymbol alias[7];
284
285   M_key_alias = msymbol ("  key-alias");
286
287   buf[0] = 'C';
288   buf[1] = '-';
289   buf[3] = '\0';
290   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
291     {
292       one_char_symbol[i] = msymbol (buf);
293       if (key_names[i] || (buf[2] >= 'A' && buf[2] <= 'Z'))
294         {
295           j = 0;
296           alias[j++] = one_char_symbol[i];
297           if (key_names[i])
298             {
299               /* Ex: `Escape' == `C-['  */
300               alias[j++] = msymbol (key_names[i]);
301             }
302           if (buf[2] >= 'A' && buf[2] <= 'Z')
303             {
304               /* Ex: `C-a' == `C-A'  */
305               buf[2] += 32;
306               alias[j++] = msymbol (buf);
307               buf[2] -= 32;
308             }
309           /* Establish cyclic alias chain.  */
310           alias[j] = alias[0];
311           while (--j >= 0)
312             msymbol_put (alias[j], M_key_alias, alias[j + 1]);
313         }
314     }
315   buf[0] = 'S';
316   for (i = buf[2] = ' '; i < 127; i++, buf[2]++)
317     {
318       one_char_symbol[i] = msymbol (buf + 2);
319       if (i >= 'A' && i <= 'Z')
320         {
321           /* Ex: `A' == `S-A' == `S-a'.  */
322           alias[0] = alias[3] = one_char_symbol[i];
323           alias[1] = msymbol (buf);
324           buf[2] += 32;
325           alias[2] = msymbol (buf);
326           buf[2] -= 32;
327           for (j = 0; j < 3; j++)
328             msymbol_put (alias[j], M_key_alias, alias[j + 1]);
329         }
330     }
331   buf[0] = 'C';
332
333   alias[0] = alias[2] = one_char_symbol[127] = msymbol ("Delete");
334   alias[1] = msymbol ("C-?");
335   for (j = 0; j < 2; j++)
336     msymbol_put (alias[j], M_key_alias, alias[j + 1]);
337
338   buf[3] = '-';
339   buf[5] = '\0';
340   buf2[1] = '-';
341   for (i = 128, buf[4] = '@'; i < 160; i++, buf[4]++)
342     {
343       j = 0;
344       /* `C-M-a' == `C-A-a' */
345       buf[2] = 'M';
346       alias[j++] = one_char_symbol[i] = msymbol (buf);
347       buf[2] = 'A';
348       alias[j++] = msymbol (buf);
349       if (key_names[i - 128])
350         {
351           /* Ex: `M-Escape' == `A-Escape' == `C-M-['.  */
352           buf2[0] = 'M';
353           strcpy (buf2 + 2, key_names[i - 128]);
354           alias[j++] = msymbol (buf2);
355           buf2[0] = 'A';
356           alias[j++] = msymbol (buf2);
357         }
358       if (buf[4] >= 'A' && buf[4] <= 'Z')
359         {
360           /* Ex: `C-M-a' == `C-M-A'.  */
361           buf[4] += 32;
362           buf[2] = 'M';
363           alias[j++] = msymbol (buf);
364           buf[2] = 'A';
365           alias[j++] = msymbol (buf);
366           buf[4] -= 32;
367         }
368       /* Establish cyclic alias chain.  */
369       alias[j] = alias[0];
370       while (--j >= 0)
371         msymbol_put (alias[j], M_key_alias, alias[j + 1]);
372     }
373   for (i = 160, buf[4] = ' '; i < 256; i++, buf[4]++)
374     {
375       buf[2] = 'M';
376       alias[0] = alias[2] = one_char_symbol[i] = msymbol (buf + 2);
377       buf[2] = 'A';
378       alias[1] = msymbol (buf + 2);
379       for (j = 0; j < 2; j++)
380         msymbol_put (alias[j], M_key_alias, alias[j + 1]);
381     }
382
383   alias[0] = alias[4] = one_char_symbol[255] = msymbol ("M-Delete");
384   alias[1] = msymbol ("A-Delete");
385   alias[2] = msymbol ("C-M-?");
386   alias[3] = msymbol ("C-A-?");
387   for (j = 0; j < 4; j++)
388     msymbol_put (alias[j], M_key_alias, alias[j + 1]);
389
390   Minput_method = msymbol ("input-method");
391   Mtitle = msymbol ("title");
392   Mmacro = msymbol ("macro");
393   Mmodule = msymbol ("module");
394   Mmap = msymbol ("map");
395   Mstate = msymbol ("state");
396   Minclude = msymbol ("include");
397   Minsert = msymbol ("insert");
398   M_candidates = msymbol ("  candidates");
399   Mdelete = msymbol ("delete");
400   Mmove = msymbol ("move");
401   Mmark = msymbol ("mark");
402   Mpushback = msymbol ("pushback");
403   Mundo = msymbol ("undo");
404   Mcall = msymbol ("call");
405   Mshift = msymbol ("shift");
406   Mselect = msymbol ("select");
407   Mshow = msymbol ("show");
408   Mhide = msymbol ("hide");
409   Mcommit = msymbol ("commit");
410   Munhandle = msymbol ("unhandle");
411   Mset = msymbol ("set");
412   Madd = msymbol ("add");
413   Msub = msymbol ("sub");
414   Mmul = msymbol ("mul");
415   Mdiv = msymbol ("div");
416   Mequal = msymbol ("=");
417   Mless = msymbol ("<");
418   Mgreater = msymbol (">");
419   Mless_equal = msymbol ("<=");
420   Mgreater_equal = msymbol (">=");
421   Mcond = msymbol ("cond");
422   Mplus = msymbol ("+");
423   Mminus = msymbol ("-");
424   Mstar = msymbol ("*");
425   Mslash = msymbol ("/");
426   Mand = msymbol ("&");
427   Mor = msymbol ("|");
428   Mnot = msymbol ("!");
429
430   Mat_reload = msymbol ("@reload");
431
432   Mcandidates_group_size = msymbol ("candidates-group-size");
433   Mcandidates_charset = msymbol ("candidates-charset");
434
435   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
436   Mcandidate_index = msymbol ("  candidate-index");
437
438   Minit = msymbol ("init");
439   Mfini = msymbol ("fini");
440
441   Mdescription = msymbol ("description");
442   Mcommand = msymbol ("command");
443   Mvariable = msymbol ("variable");
444   Mglobal = msymbol ("global");
445   Mconfig = msymbol ("config");
446
447   load_im_info_keys = mplist ();
448   mplist_add (load_im_info_keys, Mstate, Mnil);
449   mplist_push (load_im_info_keys, Mmap, Mnil);
450
451   im_info_list = mplist ();
452   im_config_list = im_custom_list = NULL;
453   im_custom_mdb = NULL;
454   update_custom_info ();
455   global_info = NULL;
456   update_global_info ();
457
458   fully_initialized = 1;
459 }
460
461 #define MINPUT__INIT()          \
462   do {                          \
463     if (! fully_initialized)    \
464       fully_initialize ();      \
465   } while (0)
466
467 \f
468 static int
469 marker_code (MSymbol sym)
470 {
471   char *name;
472
473   if (sym == Mnil)
474     return -1;
475   name = MSYMBOL_NAME (sym);
476   return ((name[0] == '@'
477            && ((name[1] >= '0' && name[1] <= '9')
478                || name[1] == '<' || name[1] == '>'
479                || name[1] == '=' || name[1] == '+' || name[1] == '-'
480                || name[1] == '[' || name[1] == ']'
481                || name[1] == '@')
482            && name[2] == '\0')
483           ? name[1] : -1);
484 }
485
486
487 static MPlist *
488 resolve_variable (MInputContextInfo *ic_info, MSymbol var)
489 {
490   MPlist *plist = mplist__assq (ic_info->vars, var);
491
492   if (plist)
493     {
494       plist = MPLIST_PLIST (plist);
495       return MPLIST_NEXT (plist);
496     }
497
498   plist = mplist ();
499   mplist_push (ic_info->vars, Mplist, plist);
500   M17N_OBJECT_UNREF (plist);
501   plist = mplist_add (plist, Msymbol, var);
502   plist = mplist_add (plist, Minteger, (void *) 0);
503   return plist;
504 }
505
506 static MText *
507 get_surrounding_text (MInputContext *ic, int len)
508 {
509   MText *mt = NULL;
510
511   mplist_push (ic->plist, Minteger, (void *) len);
512   if (minput__callback (ic, Minput_get_surrounding_text) >= 0
513       && MPLIST_MTEXT_P (ic->plist))
514     mt = MPLIST_MTEXT (ic->plist);
515   mplist_pop (ic->plist);
516   return mt;
517 }
518
519 static void
520 delete_surrounding_text (MInputContext *ic, int pos)
521 {
522   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
523
524   mplist_push (ic->plist, Minteger, (void *) pos);
525   minput__callback (ic, Minput_delete_surrounding_text);
526   mplist_pop (ic->plist);
527   if (pos < 0)
528     M17N_OBJECT_UNREF (ic_info->preceding_text);
529   else if (pos > 0)
530     M17N_OBJECT_UNREF (ic_info->following_text);
531 }
532
533 static int
534 get_preceding_char (MInputContext *ic, int pos)
535 {
536   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
537   MText *mt;
538   int len;
539
540   if (ic_info->preceding_text)
541     {
542       len = mtext_nchars (ic_info->preceding_text);
543       if (pos <= len)
544         return mtext_ref_char (ic_info->preceding_text, len - pos);
545     }
546   mt = get_surrounding_text (ic, - pos);
547   if (! mt)
548     return -2;
549   len = mtext_nchars (mt);
550   if (ic_info->preceding_text)
551     {
552       if (mtext_nchars (ic_info->preceding_text) < len)
553         {
554           M17N_OBJECT_UNREF (ic_info->preceding_text);
555           ic_info->preceding_text = mt;
556         }
557     }
558   else
559     ic_info->preceding_text = mt;
560   if (pos > len)
561     return -1;
562   return mtext_ref_char (ic_info->preceding_text, len - pos);
563 }
564
565 static int
566 get_following_char (MInputContext *ic, int pos)
567 {
568   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
569   MText *mt;
570   int len;
571
572   if (ic_info->following_text)
573     {
574       len = mtext_nchars (ic_info->following_text);
575       if (pos <= len)
576         return mtext_ref_char (ic_info->following_text, pos - 1);
577     }
578   mt = get_surrounding_text (ic, pos);
579   if (! mt)
580     return -2;
581   len = mtext_nchars (mt);
582   if (ic_info->following_text)
583     {
584       if (mtext_nchars (ic_info->following_text) < len)
585         {
586           M17N_OBJECT_UNREF (ic_info->following_text);
587           ic_info->following_text = mt;
588         }
589     }
590   else
591     ic_info->following_text = mt;
592   if (pos > len)
593     return -1;
594   return mtext_ref_char (ic_info->following_text, pos - 1);
595 }
596
597 static int
598 surrounding_pos (MSymbol sym)
599 {
600   char *name;
601
602   if (sym == Mnil)
603     return 0;
604   name = MSYMBOL_NAME (sym);
605   if ((name[1] == '-' || name[1] == '+')
606       && name[2] >= '1' && name[2] <= '9')
607     return (name[1] == '-' ? - atoi (name + 2) : atoi (name + 2));
608   return 0;
609 }
610
611 static int
612 integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
613 {
614   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
615   int code;
616   MText *preedit = ic->preedit;
617   int len = mtext_nchars (preedit);
618
619   if (value)
620     *value = NULL;
621   if (MPLIST_INTEGER_P (arg))
622     return MPLIST_INTEGER (arg);
623   if (surrounding
624       && (surrounding = surrounding_pos (MPLIST_SYMBOL (arg))) != 0)
625     return (surrounding < 0
626             ? get_preceding_char (ic, - surrounding)
627             : get_following_char (ic, surrounding));
628   code = marker_code (MPLIST_SYMBOL (arg));
629   if (code < 0)
630     {
631       MPlist *val = resolve_variable (ic_info, MPLIST_SYMBOL (arg));
632
633       if (value)
634         *value = val;
635       return (MPLIST_INTEGER_P (val) ? MPLIST_INTEGER (val) : 0);
636     }
637   if (code == '@')
638     return ic_info->key_head;
639   if (code >= '0' && code <= '9')
640     code -= '0';
641   else if (code == '=')
642     code = ic->cursor_pos;
643   else if (code == '-' || code == '[')
644     code = ic->cursor_pos - 1;
645   else if (code == '+' || code == ']')
646     code = ic->cursor_pos + 1;
647   else if (code == '<')
648     code = 0;
649   else if (code == '>')
650     code = len;
651   return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
652 }
653
654 static int
655 parse_expression (MPlist *plist)
656 {
657   MSymbol op;
658
659   if (MPLIST_INTEGER_P (plist) || MPLIST_SYMBOL_P (plist))
660     return 0;
661   if (! MPLIST_PLIST_P (plist))
662     return -1;
663   plist = MPLIST_PLIST (plist);
664   op = MPLIST_SYMBOL (plist);
665   if (op != Mplus && op != Mminus && op != Mstar && op != Mslash
666       && op != Mand && op != Mor && op != Mnot
667       && op != Mless && op != Mgreater && op != Mequal
668       && op != Mless_equal && op != Mgreater_equal)
669     MERROR (MERROR_IM, -1);
670   MPLIST_DO (plist, MPLIST_NEXT (plist))
671     if (parse_expression (plist) < 0)
672       return -1;
673   return 0;
674 }
675
676 static int
677 resolve_expression (MInputContext *ic, MPlist *plist)
678 {
679   int val;
680   MSymbol op;
681   
682   if (MPLIST_INTEGER_P (plist))
683     return MPLIST_INTEGER (plist);
684   if (MPLIST_SYMBOL_P (plist))
685     return integer_value (ic, plist, NULL, 1);
686   if (! MPLIST_PLIST_P (plist))
687     return 0;
688   plist = MPLIST_PLIST (plist);
689   if (! MPLIST_SYMBOL_P (plist))
690     return 0;
691   op = MPLIST_SYMBOL (plist);
692   plist = MPLIST_NEXT (plist);
693   val = resolve_expression (ic, plist);
694   if (op == Mplus)
695     MPLIST_DO (plist, MPLIST_NEXT (plist))
696       val += resolve_expression (ic, plist);
697   else if (op == Mminus)
698     MPLIST_DO (plist, MPLIST_NEXT (plist))
699       val -= resolve_expression (ic, plist);
700   else if (op == Mstar)
701     MPLIST_DO (plist, MPLIST_NEXT (plist))
702       val *= resolve_expression (ic, plist);
703   else if (op == Mslash)
704     MPLIST_DO (plist, MPLIST_NEXT (plist))
705       val /= resolve_expression (ic, plist);
706   else if (op == Mand)
707     MPLIST_DO (plist, MPLIST_NEXT (plist))
708       val &= resolve_expression (ic, plist);
709   else if (op == Mor)
710     MPLIST_DO (plist, MPLIST_NEXT (plist))
711       val |= resolve_expression (ic, plist);
712   else if (op == Mnot)
713     val = ! val;
714   else if (op == Mless)
715     val = val < resolve_expression (ic, MPLIST_NEXT (plist));
716   else if (op == Mequal)
717     val = val == resolve_expression (ic, MPLIST_NEXT (plist));
718   else if (op == Mgreater)
719     val = val > resolve_expression (ic, MPLIST_NEXT (plist));
720   else if (op == Mless_equal)
721     val = val <= resolve_expression (ic, MPLIST_NEXT (plist));
722   else if (op == Mgreater_equal)
723     val = val >= resolve_expression (ic, MPLIST_NEXT (plist));
724   return val;
725 }
726
727 /* Parse PLIST as an action list.  PLIST should have this form:
728       PLIST ::= ( (ACTION-NAME ACTION-ARG *) *).
729    Return 0 if successfully parsed, otherwise return -1.  */
730
731 static int
732 parse_action_list (MPlist *plist, MPlist *macros)
733 {
734   MPLIST_DO (plist, plist)
735     {
736       if (MPLIST_MTEXT_P (plist))
737         {
738           /* This is a short form of (insert MTEXT).  */
739           /* if (mtext_nchars (MPLIST_MTEXT (plist)) == 0)
740              MERROR (MERROR_IM, -1); */
741         }
742       else if (MPLIST_PLIST_P (plist)
743                && (MPLIST_MTEXT_P (MPLIST_PLIST (plist))
744                    || MPLIST_PLIST_P (MPLIST_PLIST (plist))))
745         {
746           MPlist *pl;
747
748           /* This is a short form of (insert (GROUPS *)).  */
749           MPLIST_DO (pl, MPLIST_PLIST (plist))
750             {
751               if (MPLIST_PLIST_P (pl))
752                 {
753                   MPlist *elt;
754
755                   MPLIST_DO (elt, MPLIST_PLIST (pl))
756                     if (! MPLIST_MTEXT_P (elt)
757                         || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
758                       MERROR (MERROR_IM, -1);
759                 }
760               else
761                 {
762                   if (! MPLIST_MTEXT_P (pl)
763                       || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
764                     MERROR (MERROR_IM, -1);
765                 }
766             }
767         }
768       else if (MPLIST_INTEGER_P (plist))
769         {
770           int c = MPLIST_INTEGER (plist);
771
772           if (c < 0 || c > MCHAR_MAX)
773             MERROR (MERROR_IM, -1);
774         }
775       else if (MPLIST_PLIST_P (plist)
776                && MPLIST_SYMBOL_P (MPLIST_PLIST (plist)))
777         {
778           MPlist *pl = MPLIST_PLIST (plist);
779           MSymbol action_name = MPLIST_SYMBOL (pl);
780
781           pl = MPLIST_NEXT (pl);
782
783           if (action_name == Minsert)
784             {
785               if (MPLIST_MTEXT_P (pl))
786                 {
787                   if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
788                     MERROR (MERROR_IM, -1);
789                 }
790               else if (MPLIST_PLIST_P (pl))
791                 {
792                   MPLIST_DO (pl, pl)
793                     {
794                       if (MPLIST_PLIST_P (pl))
795                         {
796                           MPlist *elt;
797
798                           MPLIST_DO (elt, MPLIST_PLIST (pl))
799                             if (! MPLIST_MTEXT_P (elt)
800                                 || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
801                               MERROR (MERROR_IM, -1);
802                         }
803                       else
804                         {
805                           if (! MPLIST_MTEXT_P (pl)
806                               || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
807                             MERROR (MERROR_IM, -1);
808                         }
809                     }
810                 }
811               else if (! MPLIST_SYMBOL_P (pl))
812                 MERROR (MERROR_IM, -1); 
813             }
814           else if (action_name == Mselect
815                    || action_name == Mdelete
816                    || action_name == Mmove)
817             {
818               if (parse_expression (pl) < 0)
819                 return -1;
820             }
821           else if (action_name == Mmark
822                    || action_name == Mcall
823                    || action_name == Mshift)
824             {
825               if (! MPLIST_SYMBOL_P (pl))
826                 MERROR (MERROR_IM, -1);
827             }
828           else if (action_name == Mundo)
829             {
830               if (! MPLIST_TAIL_P (pl))
831                 {
832                   if (! MPLIST_SYMBOL_P (pl)
833                       && (! MPLIST_INTEGER_P (pl)
834                           || MPLIST_INTEGER (pl) == 0))
835                     MERROR (MERROR_IM, -1);                 
836                 }
837             }
838           else if (action_name == Mpushback)
839             {
840               if (MPLIST_MTEXT_P (pl))
841                 {
842                   MText *mt = MPLIST_MTEXT (pl);
843
844                   if (mtext_nchars (mt) != mtext_nbytes (mt))
845                     MERROR (MERROR_IM, -1);                 
846                 }
847               else if (MPLIST_PLIST_P (pl))
848                 {
849                   MPlist *p;
850
851                   MPLIST_DO (p, MPLIST_PLIST (pl))
852                     if (! MPLIST_SYMBOL_P (p))
853                       MERROR (MERROR_IM, -1);
854                 }
855               else if (! MPLIST_INTEGER_P (pl))
856                 MERROR (MERROR_IM, -1);
857             }
858           else if (action_name == Mset || action_name == Madd
859                    || action_name == Msub || action_name == Mmul
860                    || action_name == Mdiv)
861             {
862               if (! MPLIST_SYMBOL_P (pl))
863                 MERROR (MERROR_IM, -1);
864               if (parse_expression (MPLIST_NEXT (pl)) < 0)
865                 return -1;
866             }
867           else if (action_name == Mequal || action_name == Mless
868                    || action_name == Mgreater || action_name == Mless_equal
869                    || action_name == Mgreater_equal)
870             {
871               if (parse_expression (pl) < 0
872                   || parse_expression (MPLIST_NEXT (pl)) < 0)
873                 return -1;
874               pl = MPLIST_NEXT (MPLIST_NEXT (pl));
875               if (! MPLIST_PLIST_P (pl))
876                 MERROR (MERROR_IM, -1);
877               if (parse_action_list (MPLIST_PLIST (pl), macros) < 0)
878                 MERROR (MERROR_IM, -1);
879               pl = MPLIST_NEXT (pl);
880               if (MPLIST_PLIST_P (pl)
881                   && parse_action_list (MPLIST_PLIST (pl), macros) < 0)
882                 MERROR (MERROR_IM, -1);
883             }
884           else if (action_name == Mshow || action_name == Mhide
885                    || action_name == Mcommit || action_name == Munhandle)
886             ;
887           else if (action_name == Mcond)
888             {
889               MPLIST_DO (pl, pl)
890                 if (! MPLIST_PLIST_P (pl))
891                   MERROR (MERROR_IM, -1);
892             }
893           else if (! macros || ! mplist_get (macros, action_name))
894             MERROR (MERROR_IM, -1);
895         }
896       else if (! MPLIST_SYMBOL_P (plist))
897         MERROR (MERROR_IM, -1);
898     }
899
900   return 0;
901 }
902
903 static MPlist *
904 resolve_command (MPlist *cmds, MSymbol command)
905 {
906   MPlist *plist;
907
908   if (! cmds || ! (plist = mplist__assq (cmds, command)))
909     return NULL;
910   plist = MPLIST_PLIST (plist);
911   plist = MPLIST_NEXT (plist);
912   plist = MPLIST_NEXT (plist);
913   return plist;
914 }
915
916 /* Load a translation into MAP from PLIST.
917    PLIST has this form:
918       PLIST ::= ( KEYSEQ MAP-ACTION * )  */
919
920 static int
921 load_translation (MIMMap *map, MPlist *keylist, MPlist *map_actions,
922                   MPlist *branch_actions, MPlist *macros)
923 {
924   MSymbol *keyseq;
925   int len, i;
926
927   if (MPLIST_MTEXT_P (keylist))
928     {
929       MText *mt = MPLIST_MTEXT (keylist);
930
931       len = mtext_nchars (mt);
932       if (MFAILP (len > 0 && len == mtext_nbytes (mt)))
933         return -1;
934       keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len);
935       for (i = 0; i < len; i++)
936         keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]];
937     }
938   else
939     {
940       MPlist *elt;
941           
942       if (MFAILP (MPLIST_PLIST_P (keylist)))
943         return -1;
944       elt = MPLIST_PLIST (keylist);
945       len = MPLIST_LENGTH (elt);
946       if (MFAILP (len > 0))
947         return -1;
948       keyseq = (MSymbol *) alloca (sizeof (int) * len);
949       for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
950         {
951           if (MPLIST_INTEGER_P (elt))
952             {
953               int c = MPLIST_INTEGER (elt);
954
955               if (MFAILP (c >= 0 && c < 0x100))
956                 return -1;
957               keyseq[i] = one_char_symbol[c];
958             }
959           else
960             {
961               if (MFAILP (MPLIST_SYMBOL_P (elt)))
962                 return -1;
963               keyseq[i] = MPLIST_SYMBOL (elt);
964             }
965         }
966     }
967
968   for (i = 0; i < len; i++)
969     {
970       MIMMap *deeper = NULL;
971
972       if (map->submaps)
973         deeper = mplist_get (map->submaps, keyseq[i]);
974       else
975         map->submaps = mplist ();
976       if (! deeper)
977         {
978           /* Fixme: It is better to make all deeper maps at once.  */
979           MSTRUCT_CALLOC (deeper, MERROR_IM);
980           mplist_put (map->submaps, keyseq[i], deeper);
981         }
982       map = deeper;
983     }
984
985   /* We reach a terminal map.  */
986   if (map->map_actions
987       || map->branch_actions)
988     /* This map is already defined.  We avoid overriding it.  */
989     return 0;
990
991   if (! MPLIST_TAIL_P (map_actions))
992     {
993       if (parse_action_list (map_actions, macros) < 0)
994         MERROR (MERROR_IM, -1);
995       map->map_actions = map_actions;
996     }
997   if (branch_actions)
998     {
999       map->branch_actions = branch_actions;
1000       M17N_OBJECT_REF (branch_actions);
1001     }
1002
1003   return 0;
1004 }
1005
1006 /* Load a branch from PLIST into MAP.  PLIST has this form:
1007       PLIST ::= ( MAP-NAME BRANCH-ACTION * )  */
1008
1009 static int
1010 load_branch (MInputMethodInfo *im_info, MPlist *plist, MIMMap *map)
1011 {
1012   MSymbol map_name;
1013   MPlist *branch_actions;
1014
1015   if (MFAILP (MPLIST_SYMBOL_P (plist)))
1016     return -1;
1017   map_name = MPLIST_SYMBOL (plist);
1018   plist = MPLIST_NEXT (plist);
1019   if (MPLIST_TAIL_P (plist))
1020     branch_actions = NULL;
1021   else if (MFAILP (parse_action_list (plist, im_info->macros) >= 0))
1022     return -1;
1023   else
1024     branch_actions = plist;
1025   if (map_name == Mnil)
1026     {
1027       map->branch_actions = branch_actions;
1028       if (branch_actions)
1029         M17N_OBJECT_REF (branch_actions);
1030     }
1031   else if (map_name == Mt)
1032     {
1033       map->map_actions = branch_actions;
1034       if (branch_actions)
1035         M17N_OBJECT_REF (branch_actions);
1036     }
1037   else if (im_info->maps
1038            && (plist = (MPlist *) mplist_get (im_info->maps, map_name)))
1039     {
1040       MPLIST_DO (plist, plist)
1041         {
1042           MPlist *keylist, *map_actions;
1043
1044           if (! MPLIST_PLIST_P (plist))
1045             MERROR (MERROR_IM, -1);
1046           keylist = MPLIST_PLIST (plist);
1047           map_actions = MPLIST_NEXT (keylist);
1048           if (MPLIST_SYMBOL_P (keylist))
1049             {
1050               MSymbol command = MPLIST_SYMBOL (keylist);
1051               MPlist *pl;
1052
1053               if (MFAILP (command != Mat_reload))
1054                 continue;
1055               pl = resolve_command (im_info->configured_cmds, command);
1056               if (MFAILP (pl))
1057                 continue;
1058               MPLIST_DO (pl, pl)
1059                 load_translation (map, pl, map_actions, branch_actions,
1060                                   im_info->macros);
1061             }
1062           else
1063             load_translation (map, keylist, map_actions, branch_actions,
1064                               im_info->macros);
1065         }
1066     }
1067
1068   return 0;
1069 }
1070
1071 /* Load a macro from PLIST into IM_INFO->macros.
1072    PLIST has this from:
1073       PLIST ::= ( MACRO-NAME ACTION * )
1074    IM_INFO->macros is a plist of macro names vs action list.  */
1075
1076 static int
1077 load_macros (MInputMethodInfo *im_info, MPlist *plist)
1078 {
1079   MSymbol name; 
1080   MPlist *pl;
1081
1082   if (! MPLIST_SYMBOL_P (plist))
1083     MERROR (MERROR_IM, -1);
1084   name = MPLIST_SYMBOL (plist);
1085   plist = MPLIST_NEXT (plist);
1086   if (MPLIST_TAIL_P (plist)
1087       || parse_action_list (plist, im_info->macros) < 0)
1088     MERROR (MERROR_IM, -1);
1089   pl = mplist_get (im_info->macros, name);
1090   M17N_OBJECT_UNREF (pl);
1091   mplist_put (im_info->macros, name, plist);
1092   M17N_OBJECT_REF (plist);
1093   return 0;
1094 }
1095
1096 /* Load an external module from PLIST into IM_INFO->externals.
1097    PLIST has this form:
1098       PLIST ::= ( MODULE-NAME FUNCTION * )
1099    IM_INFO->externals is a plist of MODULE-NAME vs (MIMExternalModule *).  */
1100
1101 static int
1102 load_external_module (MInputMethodInfo *im_info, MPlist *plist)
1103 {
1104   void *handle;
1105   MSymbol module;
1106   char *module_file;
1107   MIMExternalModule *external;
1108   MPlist *func_list;
1109   void *func;
1110
1111   if (MPLIST_MTEXT_P (plist))
1112     module = msymbol ((char *) MTEXT_DATA (MPLIST_MTEXT (plist)));
1113   else if (MPLIST_SYMBOL_P (plist))
1114     module = MPLIST_SYMBOL (plist);
1115   module_file = alloca (strlen (MSYMBOL_NAME (module))
1116                         + strlen (DLOPEN_SHLIB_EXT) + 1);
1117   sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
1118
1119   handle = dlopen (module_file, RTLD_NOW);
1120   if (MFAILP (handle))
1121     {
1122       fprintf (stderr, "%s\n", dlerror ());
1123       return -1;
1124     }
1125   func_list = mplist ();
1126   MPLIST_DO (plist, MPLIST_NEXT (plist))
1127     {
1128       if (! MPLIST_SYMBOL_P (plist))
1129         MERROR_GOTO (MERROR_IM, err_label);
1130       func = dlsym (handle, MSYMBOL_NAME (MPLIST_SYMBOL (plist)));
1131       if (MFAILP (func))
1132         goto err_label;
1133       mplist_add (func_list, MPLIST_SYMBOL (plist), func);
1134     }
1135
1136   MSTRUCT_MALLOC (external, MERROR_IM);
1137   external->handle = handle;
1138   external->func_list = func_list;
1139   mplist_add (im_info->externals, module, external);
1140   return 0;
1141
1142  err_label:
1143   dlclose (handle);
1144   M17N_OBJECT_UNREF (func_list);
1145   return -1;
1146 }
1147
1148 static void
1149 free_map (MIMMap *map, int top)
1150 {
1151   MPlist *plist;
1152
1153   if (top)
1154     M17N_OBJECT_UNREF (map->map_actions);
1155   if (map->submaps)
1156     {
1157       MPLIST_DO (plist, map->submaps)
1158         free_map ((MIMMap *) MPLIST_VAL (plist), 0);
1159       M17N_OBJECT_UNREF (map->submaps);
1160     }
1161   M17N_OBJECT_UNREF (map->branch_actions);
1162   free (map);
1163 }
1164
1165 static void
1166 free_state (void *object)
1167 {
1168   MIMState *state = object;
1169
1170   M17N_OBJECT_UNREF (state->title);
1171   if (state->map)
1172     free_map (state->map, 1);
1173   free (state);
1174 }
1175
1176 /** Load a state from PLIST into a newly allocated state object.
1177     PLIST has this form:
1178       PLIST ::= ( STATE-NAME STATE-TITLE ? BRANCH * )
1179       BRANCH ::= ( MAP-NAME BRANCH-ACTION * )
1180    Return the state object.  */
1181
1182 static MIMState *
1183 load_state (MInputMethodInfo *im_info, MPlist *plist)
1184 {
1185   MIMState *state;
1186
1187   if (MFAILP (MPLIST_SYMBOL_P (plist)))
1188     return NULL;
1189   M17N_OBJECT (state, free_state, MERROR_IM);
1190   state->name = MPLIST_SYMBOL (plist);
1191   plist = MPLIST_NEXT (plist);
1192   if (MPLIST_MTEXT_P (plist))
1193     {
1194       state->title = MPLIST_MTEXT (plist);
1195       mtext_put_prop (state->title, 0, mtext_nchars (state->title),
1196                       Mlanguage, im_info->language);
1197       M17N_OBJECT_REF (state->title);
1198       plist = MPLIST_NEXT (plist);
1199     }
1200   MSTRUCT_CALLOC (state->map, MERROR_IM);
1201   MPLIST_DO (plist, plist)
1202     {
1203       if (MFAILP (MPLIST_PLIST_P (plist)))
1204         continue;
1205       load_branch (im_info, MPLIST_PLIST (plist), state->map);
1206     }
1207   return state;
1208 }
1209
1210 /* Return a newly created IM_INFO for an input method specified by
1211    LANUAGE, NAME, and EXTRA.  IM_INFO is stored in PLIST.  */
1212
1213 static MInputMethodInfo *
1214 new_im_info (MDatabase *mdb, MSymbol language, MSymbol name, MSymbol extra,
1215              MPlist *plist)
1216 {
1217   MInputMethodInfo *im_info;
1218   MPlist *elt;
1219
1220   if (name == Mnil && extra == Mnil)
1221     language = Mt, extra = Mglobal;
1222   MSTRUCT_CALLOC (im_info, MERROR_IM);
1223   im_info->mdb = mdb;
1224   im_info->language = language;
1225   im_info->name = name;
1226   im_info->extra = extra;
1227
1228   elt = mplist ();
1229   mplist_add (plist, Mplist, elt);
1230   M17N_OBJECT_UNREF (elt);
1231   elt = mplist_add (elt, Msymbol, language);
1232   elt = mplist_add (elt, Msymbol, name);
1233   elt = mplist_add (elt, Msymbol, extra);
1234   mplist_add (elt, Mt, im_info);
1235
1236   return im_info;
1237 }
1238
1239 static void
1240 fini_im_info (MInputMethodInfo *im_info)
1241 {
1242   MPlist *plist;
1243
1244   M17N_OBJECT_UNREF (im_info->cmds);
1245   M17N_OBJECT_UNREF (im_info->configured_cmds);
1246   M17N_OBJECT_UNREF (im_info->bc_cmds);
1247   M17N_OBJECT_UNREF (im_info->vars);
1248   M17N_OBJECT_UNREF (im_info->configured_vars);
1249   M17N_OBJECT_UNREF (im_info->bc_vars);
1250   M17N_OBJECT_UNREF (im_info->description);
1251   M17N_OBJECT_UNREF (im_info->title);
1252   if (im_info->states)
1253     {
1254       MPLIST_DO (plist, im_info->states)
1255         {
1256           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1257
1258           M17N_OBJECT_UNREF (state);
1259         }
1260       M17N_OBJECT_UNREF (im_info->states);
1261     }
1262
1263   if (im_info->macros)
1264     {
1265       MPLIST_DO (plist, im_info->macros)
1266         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1267       M17N_OBJECT_UNREF (im_info->macros);
1268     }
1269
1270   if (im_info->externals)
1271     {
1272       MPLIST_DO (plist, im_info->externals)
1273         {
1274           MIMExternalModule *external = MPLIST_VAL (plist);
1275
1276           dlclose (external->handle);
1277           M17N_OBJECT_UNREF (external->func_list);
1278           free (external);
1279           MPLIST_KEY (plist) = Mt;
1280         }
1281       M17N_OBJECT_UNREF (im_info->externals);
1282     }
1283   if (im_info->maps)
1284     {
1285       MPLIST_DO (plist, im_info->maps)
1286         {
1287           MPlist *p = MPLIST_PLIST (plist);
1288
1289           M17N_OBJECT_UNREF (p);
1290         }
1291       M17N_OBJECT_UNREF (im_info->maps);
1292     }
1293
1294   im_info->tick = 0;
1295 }
1296
1297 static void
1298 free_im_info (MInputMethodInfo *im_info)
1299 {
1300   fini_im_info (im_info);
1301   free (im_info);
1302 }
1303
1304 static void
1305 free_im_list (MPlist *plist)
1306 {
1307   MPlist *pl, *elt;
1308
1309   MPLIST_DO (pl, plist)
1310     {
1311       MInputMethodInfo *im_info;
1312
1313       elt = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (pl))));
1314       im_info = MPLIST_VAL (elt);
1315       free_im_info (im_info);
1316     }
1317   M17N_OBJECT_UNREF (plist);
1318 }
1319
1320 static MInputMethodInfo *
1321 lookup_im_info (MPlist *plist, MSymbol language, MSymbol name, MSymbol extra)
1322 {
1323   if (name == Mnil && extra == Mnil)
1324     language = Mt, extra = Mglobal;
1325   while ((plist = mplist__assq (plist, language)))
1326     {
1327       MPlist *elt = MPLIST_PLIST (plist);
1328
1329       plist = MPLIST_NEXT (plist);
1330       elt = MPLIST_NEXT (elt);
1331       if (MPLIST_SYMBOL (elt) != name)
1332         continue;
1333       elt = MPLIST_NEXT (elt);
1334       if (MPLIST_SYMBOL (elt) != extra)
1335         continue;
1336       elt = MPLIST_NEXT (elt);
1337       return MPLIST_VAL (elt);
1338     }
1339   return NULL;
1340 }
1341
1342 static void load_im_info (MPlist *, MInputMethodInfo *);
1343
1344 #define get_custom_info(im_info)                                \
1345   (im_custom_list                                               \
1346    ? lookup_im_info (im_custom_list, (im_info)->language,       \
1347                      (im_info)->name, (im_info)->extra)         \
1348    : NULL)
1349
1350 #define get_config_info(im_info)                                \
1351   (im_config_list                                               \
1352    ? lookup_im_info (im_config_list, (im_info)->language,       \
1353                      (im_info)->name, (im_info)->extra)         \
1354    : NULL)
1355
1356 static int
1357 update_custom_info (void)
1358 {
1359   MPlist *plist, *pl;
1360
1361   if (im_custom_mdb)
1362     {
1363       if (mdatabase__check (im_custom_mdb) > 0)
1364         return 1;
1365     }
1366   else
1367     {
1368       MDatabaseInfo *custom_dir_info;
1369       char custom_path[PATH_MAX + 1];
1370
1371       custom_dir_info = MPLIST_VAL (mdatabase__dir_list);
1372       if (! custom_dir_info->filename
1373           || custom_dir_info->len + strlen (CUSTOM_FILE) > PATH_MAX)
1374         return -1;
1375       strcpy (custom_path, custom_dir_info->filename);
1376       strcat (custom_path, CUSTOM_FILE);
1377       im_custom_mdb = mdatabase_define (Minput_method, Mt, Mnil, Mconfig,
1378                                         NULL, custom_path);
1379     }
1380
1381   if (im_custom_list)
1382     {
1383       free_im_list (im_custom_list);
1384       im_custom_list = NULL;
1385     }
1386   plist = mdatabase_load (im_custom_mdb);
1387   if (! plist)
1388     return -1;
1389   im_custom_list = mplist ();
1390
1391   MPLIST_DO (pl, plist)
1392     {
1393       MSymbol language, name, extra;
1394       MInputMethodInfo *im_info;
1395       MPlist *im_data, *p;
1396
1397       if (! MPLIST_PLIST_P (pl))
1398         continue;
1399       p = MPLIST_PLIST (pl);
1400       im_data = MPLIST_NEXT (p);
1401       if (! MPLIST_PLIST_P (p))
1402         continue;
1403       p = MPLIST_PLIST (p);
1404       if (! MPLIST_SYMBOL_P (p)
1405           || MPLIST_SYMBOL (p) != Minput_method)
1406         continue;
1407       p = MPLIST_NEXT (p);
1408       if (! MPLIST_SYMBOL_P (p))
1409         continue;
1410       language = MPLIST_SYMBOL (p);
1411       p = MPLIST_NEXT (p);
1412       if (! MPLIST_SYMBOL_P (p))
1413         continue;
1414       name = MPLIST_SYMBOL (p);
1415       if (language == Mnil || name == Mnil)
1416         continue;
1417       p = MPLIST_NEXT (p);
1418       if (MPLIST_TAIL_P (p))
1419         extra = Mnil;
1420       else if (MPLIST_SYMBOL_P (p))
1421         extra = MPLIST_SYMBOL (p);
1422       else
1423         continue;
1424       im_info = new_im_info (NULL, language, name, extra, im_custom_list);
1425       load_im_info (im_data, im_info);
1426     }
1427   M17N_OBJECT_UNREF (plist);
1428   return 0;
1429 }
1430
1431 static int
1432 update_global_info (void)
1433 {
1434   MPlist *plist;
1435
1436   if (global_info)
1437     {
1438       int ret = mdatabase__check (global_info->mdb);
1439
1440       if (ret)
1441         return ret;
1442       fini_im_info (global_info);
1443     }
1444   else
1445     {
1446       MDatabase *mdb = mdatabase_find (Minput_method, Mt, Mnil, Mglobal);
1447
1448       global_info = new_im_info (mdb, Mt, Mnil, Mglobal, im_info_list);
1449     }
1450   if (! global_info->mdb
1451       || ! (plist = mdatabase_load (global_info->mdb)))
1452     return -1;
1453
1454   load_im_info (plist, global_info);
1455   M17N_OBJECT_UNREF (plist);
1456   return 0;
1457 }
1458
1459
1460 /* Return an IM_INFO for the an method specified by LANGUAGE, NAME,
1461    and EXTRA.  KEY, if not Mnil, tells which kind of information about
1462    the input method is necessary, and the returned IM_INFO may contain
1463    only that information.  */
1464
1465 static MInputMethodInfo *
1466 get_im_info (MSymbol language, MSymbol name, MSymbol extra, MSymbol key)
1467 {
1468   MPlist *plist;
1469   MInputMethodInfo *im_info;
1470   MDatabase *mdb;
1471
1472   if (name == Mnil && extra == Mnil)
1473     language = Mt, extra = Mglobal;
1474   im_info = lookup_im_info (im_info_list, language, name, extra);
1475   if (im_info)
1476     {
1477       if (key == Mnil ? im_info->states != NULL
1478           : key == Mcommand ? im_info->cmds != NULL
1479           : key == Mvariable ? im_info->vars != NULL
1480           : key == Mtitle ? im_info->title != NULL
1481           : key == Mdescription ? im_info->description != NULL
1482           : 1)
1483         /* IM_INFO already contains required information.  */
1484         return im_info;
1485       /* We have not yet loaded required information.  */
1486     }
1487   else
1488     {
1489       mdb = mdatabase_find (Minput_method, language, name, extra);
1490       if (! mdb)
1491         return NULL;
1492       im_info = new_im_info (mdb, language, name, extra, im_info_list);
1493     }
1494
1495   if (key == Mnil)
1496     {
1497       plist = mdatabase_load (im_info->mdb);
1498     }
1499   else
1500     {
1501       mplist_push (load_im_info_keys, key, Mt);
1502       plist = mdatabase__load_for_keys (im_info->mdb, load_im_info_keys);
1503       mplist_pop (load_im_info_keys);
1504     }
1505   im_info->tick = 0;
1506   if (! plist)
1507     MERROR (MERROR_IM, im_info);
1508   update_global_info ();
1509   load_im_info (plist, im_info);
1510   M17N_OBJECT_UNREF (plist);
1511   if (key == Mnil)
1512     {
1513       if (! im_info->cmds)
1514         im_info->cmds = mplist ();
1515       if (! im_info->vars)
1516         im_info->vars = mplist ();
1517     }
1518   if (! im_info->title
1519       && (key == Mnil || key == Mtitle))
1520     im_info->title = (name == Mnil ? mtext ()
1521                       : mtext_from_data (MSYMBOL_NAME (name),
1522                                          MSYMBOL_NAMELEN (name),
1523                                          MTEXT_FORMAT_US_ASCII));
1524   return im_info;
1525 }
1526
1527 /* Check if IM_INFO->mdb is updated or not.  If not updated, return 0.
1528    If updated, but got unloadable, return -1.  Otherwise, update
1529    contents of IM_INFO from the new database, and return 1.  */
1530
1531 static int
1532 reload_im_info (MInputMethodInfo *im_info)
1533 {
1534   int check;
1535   MPlist *plist;
1536
1537   check = mdatabase__check (im_info->mdb);
1538   if (check > 0)
1539     return 0;
1540   if (check < 0)
1541     return -1;
1542   plist = mdatabase_load (im_info->mdb);
1543   if (! plist)
1544     return -1;
1545   fini_im_info (im_info);
1546   load_im_info (plist, im_info);
1547   M17N_OBJECT_UNREF (plist);
1548   return 1;
1549 }
1550
1551 static MInputMethodInfo *
1552 get_im_info_by_tags (MPlist *plist)
1553 {
1554   MSymbol tag[3];
1555   int i;
1556
1557   for (i = 0; i < 3 && MPLIST_SYMBOL_P (plist);
1558        i++, plist = MPLIST_NEXT (plist))
1559     tag[i] = MPLIST_SYMBOL (plist);
1560   if (i < 2)
1561     return NULL;
1562   for (; i < 3; i++)
1563     tag[i] = Mnil;
1564   return get_im_info (tag[0], tag[1], tag[2], Mnil);
1565 }
1566
1567 /* Check KEYSEQ, and return 1 if it is valid as a key sequence, return
1568    0 if not.  */
1569
1570 static int
1571 check_command_keyseq (MPlist *keyseq)
1572 {
1573   if (MPLIST_PLIST_P (keyseq))
1574     {
1575       MPlist *p = MPLIST_PLIST (keyseq);
1576
1577       MPLIST_DO (p, p)
1578         if (! MPLIST_SYMBOL_P (p) && ! MPLIST_INTEGER_P (p))
1579           return 0;
1580       return 1;
1581     }
1582   if (MPLIST_MTEXT_P (keyseq))
1583     {
1584       MText *mt = MPLIST_MTEXT (keyseq);
1585       int i;
1586       
1587       for (i = 0; i < mtext_nchars (mt); i++)
1588         if (mtext_ref_char (mt, i) >= 256)
1589           return 0;
1590       return 1;
1591     }
1592   return 0;
1593 }
1594
1595 /* Load command defitions from PLIST into IM_INFO->cmds.
1596
1597    PLIST is well-formed and has this form;
1598      (command (NAME [DESCRIPTION KEYSEQ ...]) ...)
1599    NAME is a symbol.  DESCRIPTION is an M-text or `nil'.  KEYSEQ is an
1600    M-text or a plist of symbols.
1601
1602    The returned list has the same form, but for each element...
1603
1604    (1) If DESCRIPTION and the rest are omitted, the element is not
1605    stored in the returned list.
1606
1607    (2) If DESCRIPTION is nil, it is complemented by the corresponding
1608    description in global_info->cmds (if any).  */
1609
1610 static void
1611 load_commands (MInputMethodInfo *im_info, MPlist *plist)
1612 {
1613   MPlist *global_cmds = ((im_info->mdb && im_info != global_info)
1614                          ? global_info->cmds : NULL);
1615   MPlist *tail;
1616
1617   im_info->cmds = tail = mplist ();
1618
1619   MPLIST_DO (plist, MPLIST_NEXT (plist))
1620     {
1621       /* PLIST ::= ((NAME DESC KEYSEQ ...) ...) */
1622       MPlist *pl, *p, *global = NULL;
1623       MSymbol name;
1624
1625       if (MFAILP (MPLIST_PLIST_P (plist)))
1626         continue;
1627       pl = MPLIST_PLIST (plist); /* PL ::= (NAME DESC KEYSEQ ...) */
1628       if (MFAILP (MPLIST_SYMBOL_P (pl)))
1629         continue;
1630       name = MPLIST_SYMBOL (pl);
1631       p = MPLIST_NEXT (pl);     /* P ::= (DESC KEYSEQ ...) */
1632       if (global_cmds
1633           && (global = mplist__assq (global_cmds, name)))
1634         {
1635           /* GLOBAL ::= ((NAME DESC ...) ...) */
1636           global = MPLIST_PLIST (global); /* (NAME DESC ...) */
1637           global = MPLIST_NEXT (global);  /* (DESC ...) */
1638         }
1639       if (! MPLIST_MTEXT_P (p))
1640         {
1641           if (global && MPLIST_MTEXT (global))
1642             mplist_set (p, Mtext, MPLIST_MTEXT (global));
1643           else
1644             mplist_set (p, Msymbol, Mnil);
1645         }
1646       p = MPLIST_NEXT (p);
1647       MPLIST_DO (p, p)
1648         if (MFAILP (check_command_keyseq (p)))
1649           break;
1650       if (! MPLIST_TAIL_P (p))
1651         continue;
1652       tail = mplist_add (tail, Mplist, pl);
1653     }
1654 }
1655
1656 static void
1657 config_commands (MInputMethodInfo *im_info)
1658 {
1659   MPlist *tail, *plist;
1660   MInputMethodInfo *custom = NULL, *config = NULL;
1661
1662   M17N_OBJECT_UNREF (im_info->configured_cmds);
1663
1664   if (MPLIST_TAIL_P (im_info->cmds)
1665       || ! im_info->mdb)
1666     return;
1667
1668   im_info->configured_cmds = tail = mplist ();
1669   if ((custom = get_custom_info (im_info)) && ! custom->cmds)
1670     custom = NULL;
1671   if ((config = get_config_info (im_info)) && ! config->cmds)
1672     config = NULL;
1673   MPLIST_DO (plist, im_info->cmds)
1674     {
1675       MPlist *pl = MPLIST_PLIST (plist), *p = NULL;
1676       MSymbol name = MPLIST_SYMBOL (pl);
1677
1678       if (config)
1679         p = mplist__assq (config->cmds, name);
1680       if (! p && custom)
1681         p = mplist__assq (custom->cmds, name);
1682       if (p)
1683         {
1684           p = MPLIST_PLIST (p);
1685           p = MPLIST_NEXT (p);
1686           if (MPLIST_TAIL_P (p))
1687             p = NULL;
1688           else
1689             {
1690               p = MPLIST_NEXT (p);
1691               pl = mplist_copy (pl);
1692             }
1693         }
1694       tail = mplist_add (tail, Mplist, pl);
1695       if (p)
1696         {
1697           M17N_OBJECT_UNREF (pl);
1698           pl = MPLIST_NEXT (pl);
1699           pl = MPLIST_NEXT (pl);
1700           mplist_set (pl, Mnil, NULL);
1701           mplist__conc (pl, p);
1702         }
1703     }
1704 }
1705
1706 /* Check VAL's value against VALID_VALUES, and return 1 if it is
1707    valid, return 0 if not.  */
1708
1709 static int
1710 check_variable_value (MPlist *val, MPlist *valid_values)
1711 {
1712   MSymbol type = MPLIST_KEY (val);
1713
1714   if (type != Minteger && type != Mtext && type != Msymbol)
1715     return 0;
1716   if (MPLIST_TAIL_P (valid_values))
1717     /* No restriction.  Any value is ok.  */
1718     return 1;
1719   if (type == Minteger)
1720     {
1721       int n = MPLIST_INTEGER (val);
1722
1723       MPLIST_DO (valid_values, valid_values)
1724         {
1725           if (MPLIST_INTEGER_P (valid_values))
1726             {
1727               if (n == MPLIST_INTEGER (valid_values))
1728                 break;
1729             }
1730           else if (MPLIST_PLIST_P (valid_values))
1731             {
1732               MPlist *p = MPLIST_PLIST (valid_values);
1733               int min_bound, max_bound;
1734
1735               if (! MPLIST_INTEGER_P (p))
1736                 MERROR (MERROR_IM, 0);
1737               min_bound = MPLIST_INTEGER (p);
1738               p = MPLIST_NEXT (p);
1739               if (! MPLIST_INTEGER_P (p))
1740                 MERROR (MERROR_IM, 0);
1741               max_bound = MPLIST_INTEGER (p);
1742               if (n >= min_bound && n <= max_bound)
1743                 break;
1744             }
1745         }
1746     }
1747   else if (type == Msymbol)
1748     {
1749       MSymbol sym = MPLIST_SYMBOL (val);
1750
1751       MPLIST_DO (valid_values, valid_values)
1752         {
1753           if (! MPLIST_SYMBOL_P (valid_values))
1754             MERROR (MERROR_IM, 0);
1755           if (sym == MPLIST_SYMBOL (valid_values))
1756             break;
1757         }
1758     }
1759   else
1760     {
1761       MText *mt = MPLIST_MTEXT (val);
1762
1763       MPLIST_DO (valid_values, valid_values)
1764         {
1765           if (! MPLIST_MTEXT_P (valid_values))
1766             MERROR (MERROR_IM, 0);
1767           if (mtext_cmp (mt, MPLIST_MTEXT (valid_values)) == 0)
1768             break;
1769         }
1770     }
1771
1772   return (MPLIST_TAIL_P (valid_values));
1773 }
1774
1775 /* Load variable defitions from PLIST into IM_INFO->vars.
1776
1777    PLIST is well-formed and has this form;
1778      ((NAME [DESCRIPTION DEFAULT-VALUE VALID-VALUE ...])
1779       ...)
1780    NAME is a symbol.  DESCRIPTION is an M-text or `nil'.
1781
1782    The returned list has the same form, but for each element...
1783
1784    (1) If DESCRIPTION and the rest are omitted, the element is not
1785    stored in the returned list.
1786
1787    (2) If DESCRIPTION is nil, it is complemented by the corresponding
1788    description in global_info->vars (if any).  */
1789
1790 static void
1791 load_variables (MInputMethodInfo *im_info, MPlist *plist)
1792 {
1793   MPlist *global_vars = ((im_info->mdb && im_info != global_info)
1794                          ? global_info->vars : NULL);
1795   MPlist *tail;
1796
1797   im_info->vars = tail = mplist ();
1798
1799   MPLIST_DO (plist, MPLIST_NEXT (plist))
1800     {
1801       MPlist *pl, *p, *global = NULL;
1802       MSymbol name;
1803       MPlist *valid_values;
1804
1805       if (MFAILP (MPLIST_PLIST_P (plist)))
1806         continue;
1807       pl = MPLIST_PLIST (plist); /* PL ::= (NAME [DESC VALUE VALID ...]) */
1808       if (MFAILP (MPLIST_SYMBOL_P (pl)))
1809         continue;
1810       name = MPLIST_SYMBOL (pl);
1811       p = MPLIST_NEXT (pl);     /* P ::= ([DESC VALUE VALID ...]) */
1812       if (global_vars
1813           && (global = mplist__assq (global_vars, name)))
1814         {
1815           /* GLOBAL ::= ((NAME DESC ...) ...) */
1816           global = MPLIST_PLIST (global); /* GLOBAL ::= (NAME DESC ...) */
1817           global = MPLIST_NEXT (global);  /* GLOBAL ::= (DESC VALUE ...) */
1818         }
1819       if (! MPLIST_MTEXT_P (p))
1820         {
1821           if (global && MPLIST_MTEXT_P (global))
1822             mplist_set (p, Mtext, MPLIST_MTEXT (global));
1823           else
1824             mplist_set (p, Msymbol, Mnil);
1825         }
1826       p = MPLIST_NEXT (p);      /* p ::= ([VALUE VALID ...]) */
1827       if (MPLIST_TAIL_P (p))
1828         {
1829           if (MFAILP (global))
1830             continue;
1831           global = MPLIST_NEXT (global);
1832           mplist__conc (p, global);
1833         }
1834       else
1835         {
1836           if (MFAILP (MPLIST_INTEGER_P (p) || MPLIST_MTEXT_P (p)
1837                       || MPLIST_SYMBOL_P (p)))
1838             continue;
1839           valid_values = MPLIST_NEXT (p);
1840           if (MPLIST_TAIL_P (valid_values)
1841               && global)
1842             {
1843               global = MPLIST_NEXT (global); /* GLOBAL ::= (VALUE VALID ...) */
1844               if (MFAILP (MPLIST_KEY (p) == MPLIST_KEY (global)))
1845                 continue;
1846               valid_values = MPLIST_NEXT (global);
1847               if (! MPLIST_TAIL_P (valid_values))
1848                 mplist__conc (p, valid_values);
1849             }
1850           if (MFAILP (check_variable_value (p, valid_values)))
1851             continue;
1852         }
1853       tail = mplist_add (tail, Mplist, pl);
1854     }
1855 }
1856
1857 /* Return a configured variable definition list based on
1858    IM_INFO->vars.  If a variable in it doesn't contain a value, try to
1859    get it from global_info->vars.  */
1860
1861 static void
1862 config_variables (MInputMethodInfo *im_info)
1863 {
1864   MPlist *tail, *plist;
1865   MInputMethodInfo *custom = NULL, *config = NULL;
1866
1867   M17N_OBJECT_UNREF (im_info->configured_vars);
1868
1869   if (MPLIST_TAIL_P (im_info->vars)
1870       || ! im_info->mdb)
1871     return;
1872
1873   im_info->configured_vars = tail = mplist ();
1874   if ((custom = get_custom_info (im_info)) && ! custom->vars)
1875     custom = NULL;
1876   if ((config = get_config_info (im_info)) && ! config->vars)
1877     config = NULL;
1878
1879   MPLIST_DO (plist, im_info->vars)
1880     {
1881       MPlist *pl = MPLIST_PLIST (plist), *p = NULL;
1882       MSymbol name = MPLIST_SYMBOL (pl);
1883
1884       if (config)
1885         p = mplist__assq (config->vars, name);
1886       if (! p && custom)
1887         p = mplist__assq (custom->vars, name);
1888       if (p)
1889         {
1890           p = MPLIST_PLIST (p);
1891           p = MPLIST_NEXT (p);
1892           if (MPLIST_TAIL_P (p))
1893             p = NULL;
1894           else
1895             {
1896               p = MPLIST_NEXT (p);
1897               pl = mplist_copy (pl);
1898             }
1899         }
1900       tail = mplist_add (tail, Mplist, pl);
1901       if (p)
1902         {
1903           M17N_OBJECT_UNREF (pl);
1904           pl = MPLIST_NEXT (pl);
1905           pl = MPLIST_NEXT (pl);
1906           mplist_set (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1907         }
1908     }
1909 }
1910
1911 /* Load an input method (LANGUAGE NAME) from PLIST into IM_INFO.
1912    CONFIG contains configulation information of the input method.  */
1913
1914 static void
1915 load_im_info (MPlist *plist, MInputMethodInfo *im_info)
1916 {
1917   MPlist *pl, *p;
1918
1919   if (! im_info->cmds && (pl = mplist__assq (plist, Mcommand)))
1920     {
1921       load_commands (im_info, MPLIST_PLIST (pl));
1922       config_commands (im_info);
1923       pl = mplist_pop (pl);
1924       M17N_OBJECT_UNREF (pl);
1925     }
1926
1927   if (! im_info->vars && (pl = mplist__assq (plist, Mvariable)))
1928     {
1929       load_variables (im_info, MPLIST_PLIST (pl));
1930       config_variables (im_info);
1931       pl = mplist_pop (pl);
1932       M17N_OBJECT_UNREF (pl);
1933     }
1934
1935   MPLIST_DO (plist, plist)
1936     if (MPLIST_PLIST_P (plist))
1937       {
1938         MPlist *elt = MPLIST_PLIST (plist);
1939         MSymbol key;
1940
1941         if (MFAILP (MPLIST_SYMBOL_P (elt)))
1942           continue;
1943         key = MPLIST_SYMBOL (elt);
1944         if (key == Mtitle)
1945           {
1946             if (im_info->title)
1947               continue;
1948             elt = MPLIST_NEXT (elt);
1949             if (MFAILP (MPLIST_MTEXT_P (elt)))
1950               continue;
1951             im_info->title = MPLIST_MTEXT (elt);
1952             M17N_OBJECT_REF (im_info->title);
1953           }
1954         else if (key == Mmap)
1955           {
1956             pl = mplist__from_alist (MPLIST_NEXT (elt));
1957             if (MFAILP (pl))
1958               continue;
1959             if (! im_info->maps)
1960               im_info->maps = pl;
1961             else
1962               {
1963                 mplist__conc (im_info->maps, pl);
1964                 M17N_OBJECT_UNREF (pl);
1965               }
1966           }
1967         else if (key == Mmacro)
1968           {
1969             if (! im_info->macros)
1970               im_info->macros = mplist ();
1971             MPLIST_DO (elt, MPLIST_NEXT (elt))
1972               {
1973                 if (MFAILP (MPLIST_PLIST_P (elt)))
1974                   continue;
1975                 load_macros (im_info, MPLIST_PLIST (elt));
1976               }
1977           }
1978         else if (key == Mmodule)
1979           {
1980             if (! im_info->externals)
1981               im_info->externals = mplist ();
1982             MPLIST_DO (elt, MPLIST_NEXT (elt))
1983               {
1984                 if (MFAILP (MPLIST_PLIST_P (elt)))
1985                   continue;
1986                 load_external_module (im_info, MPLIST_PLIST (elt));
1987               }
1988           }
1989         else if (key == Mstate)
1990           {
1991             MPLIST_DO (elt, MPLIST_NEXT (elt))
1992               {
1993                 MIMState *state;
1994
1995                 if (MFAILP (MPLIST_PLIST_P (elt)))
1996                   continue;
1997                 pl = MPLIST_PLIST (elt);
1998                 if (! im_info->states)
1999                   im_info->states = mplist ();
2000                 state = load_state (im_info, MPLIST_PLIST (elt));
2001                 if (MFAILP (state))
2002                   continue;
2003                 mplist_put (im_info->states, state->name, state);
2004               }
2005           }
2006         else if (key == Minclude)
2007           {
2008             /* elt ::= include (tag1 tag2 ...) key item ... */
2009             MSymbol key;
2010             MInputMethodInfo *temp;
2011
2012             elt = MPLIST_NEXT (elt);
2013             if (MFAILP (MPLIST_PLIST_P (elt)))
2014               continue;
2015             temp = get_im_info_by_tags (MPLIST_PLIST (elt));
2016             if (MFAILP (temp))
2017               continue;
2018             elt = MPLIST_NEXT (elt);
2019             if (MFAILP (MPLIST_SYMBOL_P (elt)))
2020               continue;
2021             key = MPLIST_SYMBOL (elt);
2022             elt = MPLIST_NEXT (elt);
2023             if (key == Mmap)
2024               {
2025                 if (! temp->maps || MPLIST_TAIL_P (temp->maps))
2026                   continue;
2027                 if (! im_info->maps)
2028                   im_info->maps = mplist ();
2029                 MPLIST_DO (pl, temp->maps)
2030                   {
2031                     p = MPLIST_VAL (pl);
2032                     MPLIST_ADD_PLIST (im_info->maps, MPLIST_KEY (pl), p);
2033                     M17N_OBJECT_REF (p);
2034                   }
2035               }
2036             else if (key == Mmacro)
2037               {
2038                 if (! temp->macros || MPLIST_TAIL_P (temp->macros))
2039                   continue;
2040                 if (! im_info->macros)
2041                   im_info->macros = mplist ();
2042                 MPLIST_DO (pl, temp->macros)
2043                   {
2044                     p = MPLIST_VAL (pl);
2045                     MPLIST_ADD_PLIST (im_info->macros, MPLIST_KEY (pl), p);
2046                     M17N_OBJECT_REF (p);
2047                   }
2048               }
2049             else if (key == Mstate)
2050               {
2051                 if (! temp->states || MPLIST_TAIL_P (temp->states))
2052                   continue;
2053                 if (! im_info->states)
2054                   im_info->states = mplist ();
2055                 MPLIST_DO (pl, temp->states)
2056                   {
2057                     MIMState *state = MPLIST_VAL (pl);
2058
2059                     mplist_add (im_info->states, MPLIST_KEY (pl), state);
2060                     M17N_OBJECT_REF (state);
2061                   }
2062               }
2063           }
2064         else if (key == Mdescription)
2065           {
2066             if (im_info->description)
2067               continue;
2068             elt = MPLIST_NEXT (elt);
2069             if (MFAILP (MPLIST_MTEXT_P (elt)))
2070               continue;
2071             im_info->description = MPLIST_MTEXT (elt);
2072             M17N_OBJECT_REF (im_info->description);
2073
2074           }
2075       }
2076   im_info->tick = time (NULL);
2077 }
2078
2079 \f
2080
2081 static int take_action_list (MInputContext *ic, MPlist *action_list);
2082 static void preedit_commit (MInputContext *ic);
2083
2084 static void
2085 shift_state (MInputContext *ic, MSymbol state_name)
2086 {
2087   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2088   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2089   MIMState *orig_state = ic_info->state, *state;
2090
2091   /* Find a state to shift to.  If not found, shift to the initial
2092      state.  */
2093   if (state_name == Mt)
2094     {
2095       if (! ic_info->prev_state)
2096         return;
2097       state = ic_info->prev_state;
2098     }
2099   else if (state_name == Mnil)
2100     {
2101       state = (MIMState *) MPLIST_VAL (im_info->states);
2102     }
2103   else
2104     {
2105       state = (MIMState *) mplist_get (im_info->states, state_name);
2106       if (! state)
2107         state = (MIMState *) MPLIST_VAL (im_info->states);
2108     }
2109
2110   MDEBUG_PRINT1 ("\n  [IM] (shift %s)", MSYMBOL_NAME (state->name));
2111
2112   /* Enter the new state.  */
2113   ic_info->state = state;
2114   ic_info->map = state->map;
2115   ic_info->state_key_head = ic_info->key_head;
2116   if (state == (MIMState *) MPLIST_VAL (im_info->states)
2117       && orig_state)
2118     /* We have shifted to the initial state.  */
2119     preedit_commit (ic);
2120   mtext_cpy (ic_info->preedit_saved, ic->preedit);
2121   ic_info->state_pos = ic->cursor_pos;
2122   if (state != orig_state)
2123     {
2124       if (state == (MIMState *) MPLIST_VAL (im_info->states))
2125         ic_info->prev_state = NULL;
2126       else
2127         ic_info->prev_state = orig_state;
2128
2129       if (state->title)
2130         ic->status = state->title;
2131       else
2132         ic->status = im_info->title;
2133       ic->status_changed = 1;
2134       if (ic_info->map == ic_info->state->map
2135           && ic_info->map->map_actions)
2136         {
2137           MDEBUG_PRINT (" init-actions:");
2138           take_action_list (ic, ic_info->map->map_actions);
2139         }
2140     }
2141 }
2142
2143 /* Find a candidate group that contains a candidate number INDEX from
2144    PLIST.  Set START_INDEX to the first candidate number of the group,
2145    END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
2146    candidate group number if they are non-NULL.  If INDEX is -1, find
2147    the last candidate group.  */
2148
2149 static MPlist *
2150 find_candidates_group (MPlist *plist, int index,
2151                        int *start_index, int *end_index, int *group_index)
2152 {
2153   int i = 0, gidx = 0, len;
2154
2155   MPLIST_DO (plist, plist)
2156     {
2157       if (MPLIST_MTEXT_P (plist))
2158         len = mtext_nchars (MPLIST_MTEXT (plist));
2159       else
2160         len = mplist_length (MPLIST_PLIST (plist));
2161       if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
2162           : i + len > index)
2163         {
2164           if (start_index)
2165             *start_index = i;
2166           if (end_index)
2167             *end_index = i + len;
2168           if (group_index)
2169             *group_index = gidx;
2170           return plist;
2171         }
2172       i += len;
2173       gidx++;
2174     }
2175   return NULL;
2176 }
2177
2178 static void
2179 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
2180 {
2181   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
2182   MPlist *markers;
2183   int nchars = mt ? mtext_nchars (mt) : 1;
2184
2185   if (mt)
2186     mtext_ins (ic->preedit, pos, mt);
2187   else
2188     mtext_ins_char (ic->preedit, pos, c, 1);
2189   MPLIST_DO (markers, ic_info->markers)
2190     if (MPLIST_INTEGER (markers) > pos)
2191       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
2192   if (ic->cursor_pos >= pos)
2193     ic->cursor_pos += nchars;
2194   ic->preedit_changed = 1;
2195 }
2196
2197
2198 static void
2199 preedit_delete (MInputContext *ic, int from, int to)
2200 {
2201   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
2202   MPlist *markers;
2203
2204   mtext_del (ic->preedit, from, to);
2205   MPLIST_DO (markers, ic_info->markers)
2206     {
2207       if (MPLIST_INTEGER (markers) > to)
2208         MPLIST_VAL (markers)
2209           = (void *) (MPLIST_INTEGER (markers) - (to - from));
2210       else if (MPLIST_INTEGER (markers) > from);
2211         MPLIST_VAL (markers) = (void *) from;
2212     }
2213   if (ic->cursor_pos >= to)
2214     ic->cursor_pos -= to - from;
2215   else if (ic->cursor_pos > from)
2216     ic->cursor_pos = from;
2217   ic->preedit_changed = 1;
2218 }
2219
2220 static void
2221 preedit_commit (MInputContext *ic)
2222 {
2223   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2224   int preedit_len = mtext_nchars (ic->preedit);
2225
2226   if (preedit_len > 0)
2227     {
2228       MPlist *p;
2229
2230       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
2231                              Mcandidate_list, NULL, 0);
2232       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
2233                              Mcandidate_index, NULL, 0);
2234       mtext_cat (ic->produced, ic->preedit);
2235       if ((mdebug__flag & mdebug_mask)
2236           && mtext_nchars (ic->preedit) > 0)
2237         {
2238           int i;
2239
2240           MDEBUG_PRINT (" (produced");
2241           for (i = 0; i < mtext_nchars (ic->preedit); i++)
2242             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i));
2243           MDEBUG_PRINT (")");
2244         }
2245       mtext_reset (ic->preedit);
2246       mtext_reset (ic_info->preedit_saved);
2247       MPLIST_DO (p, ic_info->markers)
2248         MPLIST_VAL (p) = 0;
2249       ic->cursor_pos = ic_info->state_pos = 0;
2250       ic->preedit_changed = 1;
2251     }
2252   if (ic->candidate_list)
2253     {
2254       M17N_OBJECT_UNREF (ic->candidate_list);
2255       ic->candidate_list = NULL;
2256       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
2257       if (ic->candidate_show)
2258         {
2259           ic->candidate_show = 0;
2260           ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
2261         }
2262     }
2263   memmove (ic_info->keys, ic_info->keys + ic_info->key_head,
2264            sizeof (int) * (ic_info->used - ic_info->key_head));
2265   ic_info->used -= ic_info->key_head;
2266   ic_info->state_key_head = ic_info->key_head = 0;
2267 }
2268
2269 static int
2270 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
2271 {
2272   int code = marker_code (sym);
2273
2274   if (mt && (code == '[' || code == ']'))
2275     {
2276       int pos = current;
2277
2278       if (code == '[' && current > 0)
2279         {
2280           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
2281               && pos > 0)
2282             current = pos;
2283         }
2284       else if (code == ']' && current < mtext_nchars (mt))
2285         {
2286           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
2287             current = pos;
2288         }
2289       return current;
2290     }
2291   if (code >= 0)
2292     return (code == '<' ? 0
2293             : code == '>' ? limit
2294             : code == '-' ? current - 1
2295             : code == '+' ? current + 1
2296             : code == '=' ? current
2297             : code - '0' > limit ? limit
2298             : code - '0');
2299   if (! ic)  
2300     return 0;
2301   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
2302 }
2303
2304 static void
2305 update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
2306 {
2307   int from = mtext_property_start (prop);
2308   int to = mtext_property_end (prop);
2309   int start;
2310   MPlist *candidate_list = mtext_property_value (prop);
2311   MPlist *group = find_candidates_group (candidate_list, idx, &start,
2312                                          NULL, NULL);
2313   int ingroup_index = idx - start;
2314   MText *mt;
2315
2316   preedit_delete (ic, from, to);
2317   if (MPLIST_MTEXT_P (group))
2318     {
2319       mt = MPLIST_MTEXT (group);
2320       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
2321       to = from + 1;
2322     }
2323   else
2324     {
2325       int i;
2326       MPlist *plist;
2327
2328       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
2329            i++, plist = MPLIST_NEXT (plist));
2330       mt = MPLIST_MTEXT (plist);
2331       preedit_insert (ic, from, mt, 0);
2332       to = from + mtext_nchars (mt);
2333     }
2334   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
2335   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
2336   ic->cursor_pos = to;
2337 }
2338
2339 static MCharset *
2340 get_select_charset (MInputContextInfo * ic_info)
2341 {
2342   MPlist *plist = resolve_variable (ic_info, Mcandidates_charset);
2343   MSymbol sym;
2344
2345   if (! MPLIST_VAL (plist))
2346     return NULL;
2347   sym = MPLIST_SYMBOL (plist);
2348   if (sym == Mnil)
2349     return NULL;
2350   return MCHARSET (sym);
2351 }
2352
2353 static MPlist *
2354 adjust_candidates (MPlist *plist, MCharset *charset)
2355 {
2356   MPlist *pl;
2357
2358   /* plist ::= MTEXT ... | PLIST ... */
2359   plist = mplist_copy (plist);
2360   if (MPLIST_MTEXT_P (plist))
2361     {
2362       pl = plist;
2363       while (! MPLIST_TAIL_P (pl))
2364         {
2365           /* pl ::= MTEXT ... */
2366           MText *mt = MPLIST_MTEXT (pl);
2367           int mt_copied = 0;
2368           int i, c;
2369
2370           for (i = mtext_nchars (mt) - 1; i >= 0; i--)
2371             {
2372               c = mtext_ref_char (mt, i);
2373               if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
2374                 {
2375                   if (! mt_copied)
2376                     {
2377                       mt = mtext_dup (mt);
2378                       mplist_set (pl, Mtext, mt);
2379                       M17N_OBJECT_UNREF (mt);
2380                       mt_copied = 1;
2381                     }
2382                   mtext_del (mt, i, i + 1);
2383                 }
2384             }
2385           if (mtext_len (mt) > 0)
2386             pl = MPLIST_NEXT (pl);
2387           else
2388             {
2389               mplist_pop (pl);
2390               M17N_OBJECT_UNREF (mt);
2391             }
2392         }
2393     }
2394   else                          /* MPLIST_PLIST_P (plist) */
2395     {
2396       pl = plist;
2397       while (! MPLIST_TAIL_P (pl))
2398         {
2399           /* pl ::= (MTEXT ...) ... */
2400           MPlist *p = MPLIST_PLIST (pl);
2401           int p_copied = 0;
2402           /* p ::= MTEXT ... */
2403           MPlist *p0 = p;
2404           int n = 0;
2405
2406           while (! MPLIST_TAIL_P (p0))
2407             {
2408               MText *mt = MPLIST_MTEXT (p0);
2409               int i, c;
2410
2411               for (i = mtext_nchars (mt) - 1; i >= 0; i--)
2412                 {
2413                   c = mtext_ref_char (mt, i);
2414                   if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
2415                     break;
2416                 }
2417               if (i < 0)
2418                 {
2419                   p0 = MPLIST_NEXT (p0);
2420                   n++;
2421                 }
2422               else
2423                 {
2424                   if (! p_copied)
2425                     {
2426                       p = mplist_copy (p);
2427                       mplist_set (pl, Mplist, p);
2428                       M17N_OBJECT_UNREF (p);
2429                       p_copied = 1;
2430                       p0 = p;
2431                       while (n-- > 0)
2432                         p0 = MPLIST_NEXT (p0);
2433                     }     
2434                   mplist_pop (p0);
2435                   M17N_OBJECT_UNREF (mt);
2436                 }
2437             }
2438           if (! MPLIST_TAIL_P (p))
2439             pl = MPLIST_NEXT (pl);
2440           else
2441             {
2442               mplist_pop (pl);
2443               M17N_OBJECT_UNREF (p);
2444             }
2445         }
2446     }
2447   if (MPLIST_TAIL_P (plist))
2448     {
2449       M17N_OBJECT_UNREF (plist);
2450       return NULL;
2451     }      
2452   return plist;
2453 }
2454
2455 static MPlist *
2456 get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
2457 {
2458   MCharset *charset = get_select_charset (ic_info);
2459   MPlist *plist;
2460   int column;
2461   int i, len;
2462
2463   plist = resolve_variable (ic_info, Mcandidates_group_size);
2464   column = MPLIST_INTEGER (plist);
2465
2466   plist = MPLIST_PLIST (args);
2467   if (charset)
2468     {
2469       if (! (plist = adjust_candidates (plist, charset)))
2470         return NULL;
2471     }
2472   else
2473     M17N_OBJECT_REF (plist);
2474
2475   if (column > 0)
2476     {
2477       if (MPLIST_MTEXT_P (plist))
2478         {
2479           MText *mt = MPLIST_MTEXT (plist);
2480           MPlist *next = MPLIST_NEXT (plist);
2481
2482           if (MPLIST_TAIL_P (next))
2483             M17N_OBJECT_REF (mt);
2484           else
2485             {
2486               mt = mtext_dup (mt);
2487               while (! MPLIST_TAIL_P (next))
2488                 {
2489                   mt = mtext_cat (mt, MPLIST_MTEXT (next));
2490                   next = MPLIST_NEXT (next);
2491                 }
2492             }
2493           M17N_OBJECT_UNREF (plist);
2494           plist = mplist ();
2495           len = mtext_nchars (mt);
2496           if (len <= column)
2497             mplist_add (plist, Mtext, mt);
2498           else
2499             {
2500               for (i = 0; i < len; i += column)
2501                 {
2502                   int to = (i + column < len ? i + column : len);
2503                   MText *sub = mtext_copy (mtext (), 0, mt, i, to);
2504                                                        
2505                   mplist_add (plist, Mtext, sub);
2506                   M17N_OBJECT_UNREF (sub);
2507                 }
2508             }
2509           M17N_OBJECT_UNREF (mt);
2510         }
2511       else              /* MPLIST_PLIST_P (plist) */
2512         {
2513           MPlist *pl = MPLIST_PLIST (plist), *p;
2514           MPlist *next = MPLIST_NEXT (plist);
2515           int j;
2516
2517           if (MPLIST_TAIL_P (next))
2518             M17N_OBJECT_REF (pl);
2519           else
2520             {
2521               pl = mplist_copy (pl);
2522               while (! MPLIST_TAIL_P (next))
2523                 {
2524                   p = mplist_copy (MPLIST_PLIST (next));
2525                   pl = mplist__conc (pl, p);
2526                   M17N_OBJECT_UNREF (p);
2527                   next = MPLIST_NEXT (next);
2528                 }
2529             }
2530           M17N_OBJECT_UNREF (plist);
2531           plist = mplist ();
2532           len = mplist_length (pl);
2533           if (len <= column)
2534             mplist_add (plist, Mplist, pl);
2535           else
2536             {
2537               MPlist *p0 = pl;
2538
2539               for (i = 0; i < len; i += column)
2540                 {
2541                   p = mplist ();
2542                   mplist_add (plist, Mplist, p);
2543                   M17N_OBJECT_UNREF (p);
2544                   for (j = 0; j < column && i + j < len; j++)
2545                     {
2546                       p = mplist_add (p, Mtext, MPLIST_VAL (p0));
2547                       p0 = MPLIST_NEXT (p0);
2548                     }
2549                 }
2550             }
2551           M17N_OBJECT_UNREF (pl);
2552         }
2553     }
2554
2555   return plist;
2556 }
2557
2558
2559 static MPlist *
2560 regularize_action (MPlist *action_list, MInputContextInfo *ic_info)
2561 {
2562   MPlist *action = NULL;
2563   MSymbol name;
2564   MPlist *args;
2565
2566   if (MPLIST_SYMBOL_P (action_list))
2567     {
2568       MSymbol var = MPLIST_SYMBOL (action_list);
2569       MPlist *p;
2570
2571       MPLIST_DO (p, ic_info->vars)
2572         if (MPLIST_SYMBOL (MPLIST_PLIST (p)) == var)
2573           break;
2574       if (MPLIST_TAIL_P (p))
2575         return NULL;
2576       action = MPLIST_NEXT (MPLIST_PLIST (p));
2577       mplist_set (action_list, MPLIST_KEY (action), MPLIST_VAL (action));
2578     }
2579
2580   if (MPLIST_PLIST_P (action_list))
2581     {
2582       action = MPLIST_PLIST (action_list);
2583       if (MPLIST_SYMBOL_P (action))
2584         {
2585           name = MPLIST_SYMBOL (action);
2586           args = MPLIST_NEXT (action);
2587           if (name == Minsert
2588               && MPLIST_PLIST_P (args))
2589             mplist_set (action, Msymbol, M_candidates);
2590         }
2591       else if (MPLIST_MTEXT_P (action) || MPLIST_PLIST_P (action))
2592         {
2593           action = mplist ();
2594           mplist_push (action, Mplist, MPLIST_VAL (action_list));
2595           mplist_push (action, Msymbol, M_candidates);
2596           mplist_set (action_list, Mplist, action);
2597           M17N_OBJECT_UNREF (action);
2598         }
2599     }
2600   else if (MPLIST_MTEXT_P (action_list) || MPLIST_INTEGER_P (action_list))
2601     {
2602       action = mplist ();
2603       mplist_push (action, MPLIST_KEY (action_list), MPLIST_VAL (action_list));
2604       mplist_push (action, Msymbol, Minsert);
2605       mplist_set (action_list, Mplist, action);
2606       M17N_OBJECT_UNREF (action);
2607     }
2608   return action;
2609 }
2610
2611 /* Perform list of actions in ACTION_LIST for the current input
2612    context IC.  If all actions are performed without error, return 0.
2613    Otherwise, return -1.  */
2614
2615 static int
2616 take_action_list (MInputContext *ic, MPlist *action_list)
2617 {
2618   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2619   MPlist *candidate_list = ic->candidate_list;
2620   int candidate_index = ic->candidate_index;
2621   int candidate_show = ic->candidate_show;
2622   MTextProperty *prop;
2623
2624   MPLIST_DO (action_list, action_list)
2625     {
2626       MPlist *action = regularize_action (action_list, ic_info);
2627       MSymbol name;
2628       MPlist *args;
2629
2630       if (! action)
2631         continue;
2632       name = MPLIST_SYMBOL (action);
2633       args = MPLIST_NEXT (action);
2634
2635       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
2636       if (name == Minsert)
2637         {
2638           if (MPLIST_SYMBOL_P (args))
2639             {
2640               args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
2641               if (! MPLIST_MTEXT_P (args) && ! MPLIST_INTEGER_P (args))
2642                 continue;
2643             }
2644           if (MPLIST_MTEXT_P (args))
2645             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
2646           else                  /* MPLIST_INTEGER_P (args)) */
2647             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
2648         }
2649       else if (name == M_candidates)
2650         {
2651           MPlist *plist = get_candidate_list (ic_info, args);
2652           int len;
2653
2654           if (! plist)
2655             continue;
2656           if (MPLIST_MTEXT_P (plist))
2657             {
2658               preedit_insert (ic, ic->cursor_pos, NULL,
2659                               mtext_ref_char (MPLIST_MTEXT (plist), 0));
2660               len = 1;
2661             }
2662           else
2663             {
2664               MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
2665
2666               preedit_insert (ic, ic->cursor_pos, mt, 0);
2667               len = mtext_nchars (mt);
2668             }
2669           mtext_put_prop (ic->preedit,
2670                           ic->cursor_pos - len, ic->cursor_pos,
2671                           Mcandidate_list, plist);
2672           mtext_put_prop (ic->preedit,
2673                           ic->cursor_pos - len, ic->cursor_pos,
2674                           Mcandidate_index, (void *) 0);
2675           M17N_OBJECT_UNREF (plist);
2676         }
2677       else if (name == Mselect)
2678         {
2679           int start, end;
2680           int code, idx, gindex;
2681           int pos = ic->cursor_pos;
2682           MPlist *group;
2683
2684           if (pos == 0
2685               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
2686                                                Mcandidate_list)))
2687             continue;
2688           if (MPLIST_SYMBOL_P (args))
2689             {
2690               code = marker_code (MPLIST_SYMBOL (args));
2691               if (code < 0)
2692                 continue;
2693             }
2694           else
2695             code = -1;
2696           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
2697           group = find_candidates_group (mtext_property_value (prop), idx,
2698                                          &start, &end, &gindex);
2699
2700           if (code != '[' && code != ']')
2701             {
2702               idx = (start
2703                      + (code >= 0
2704                         ? new_index (NULL, ic->candidate_index - start,
2705                                      end - start - 1, MPLIST_SYMBOL (args),
2706                                      NULL)
2707                         : MPLIST_INTEGER (args)));
2708               if (idx < 0)
2709                 {
2710                   find_candidates_group (mtext_property_value (prop), -1,
2711                                          NULL, &end, NULL);
2712                   idx = end - 1;
2713                 }
2714               else if (idx >= end
2715                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
2716                 idx = 0;
2717             }
2718           else
2719             {
2720               int ingroup_index = idx - start;
2721               int len;
2722
2723               group = mtext_property_value (prop);
2724               len = mplist_length (group);
2725               if (code == '[')
2726                 {
2727                   gindex--;
2728                   if (gindex < 0)
2729                     gindex = len - 1;;
2730                 }
2731               else
2732                 {
2733                   gindex++;
2734                   if (gindex >= len)
2735                     gindex = 0;
2736                 }
2737               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
2738                 idx += (MPLIST_MTEXT_P (group)
2739                         ? mtext_nchars (MPLIST_MTEXT (group))
2740                         : mplist_length (MPLIST_PLIST (group)));
2741               len = (MPLIST_MTEXT_P (group)
2742                      ? mtext_nchars (MPLIST_MTEXT (group))
2743                      : mplist_length (MPLIST_PLIST (group)));
2744               if (ingroup_index >= len)
2745                 ingroup_index = len - 1;
2746               idx += ingroup_index;
2747             }
2748           update_candidate (ic, prop, idx);
2749         }
2750       else if (name == Mshow)
2751         ic->candidate_show = 1;
2752       else if (name == Mhide)
2753         ic->candidate_show = 0;
2754       else if (name == Mdelete)
2755         {
2756           int len = mtext_nchars (ic->preedit);
2757           int pos;
2758           int to;
2759
2760           if (MPLIST_SYMBOL_P (args)
2761               && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
2762             {
2763               delete_surrounding_text (ic, pos);
2764             }
2765           else
2766             {
2767               to = (MPLIST_SYMBOL_P (args)
2768                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
2769                                  ic->preedit)
2770                     : MPLIST_INTEGER (args));
2771               if (to < 0)
2772                 to = 0;
2773               else if (to > len)
2774                 to = len;
2775               MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
2776               if (to < ic->cursor_pos)
2777                 preedit_delete (ic, to, ic->cursor_pos);
2778               else if (to > ic->cursor_pos)
2779                 preedit_delete (ic, ic->cursor_pos, to);
2780             }
2781         }
2782       else if (name == Mmove)
2783         {
2784           int len = mtext_nchars (ic->preedit);
2785           int pos
2786             = (MPLIST_SYMBOL_P (args)
2787                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
2788                             ic->preedit)
2789                : MPLIST_INTEGER (args));
2790
2791           if (pos < 0)
2792             pos = 0;
2793           else if (pos > len)
2794             pos = len;
2795           if (pos != ic->cursor_pos)
2796             {
2797               ic->cursor_pos = pos;
2798               ic->preedit_changed = 1;
2799             }
2800         }
2801       else if (name == Mmark)
2802         {
2803           int code = marker_code (MPLIST_SYMBOL (args));
2804
2805           if (code < 0)
2806             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
2807                         (void *) ic->cursor_pos);
2808         }
2809       else if (name == Mpushback)
2810         {
2811           if (MPLIST_INTEGER_P (args))
2812             {
2813               int num = MPLIST_INTEGER (args);
2814
2815               if (num > 0)
2816                 ic_info->key_head -= num;
2817               else
2818                 ic_info->key_head = num;
2819               if (ic_info->key_head > ic_info->used)
2820                 ic_info->key_head = ic_info->used;
2821             }
2822           else if (MPLIST_MTEXT_P (args))
2823             {
2824               MText *mt = MPLIST_MTEXT (args);
2825               int i, len = mtext_nchars (mt);
2826               MSymbol key;
2827
2828               ic_info->key_head--;
2829               for (i = 0; i < len; i++)
2830                 {
2831                   key = one_char_symbol[MTEXT_DATA (mt)[i]];
2832                   if (ic_info->key_head + i < ic_info->used)
2833                     ic_info->keys[ic_info->key_head + i] = key;
2834                   else
2835                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2836                 }
2837             }
2838           else
2839             {
2840               MPlist *plist = MPLIST_PLIST (args), *pl;
2841               int i = 0;
2842               MSymbol key;
2843
2844               ic_info->key_head--;
2845
2846               MPLIST_DO (pl, plist)
2847                 {
2848                   key = MPLIST_SYMBOL (pl);
2849                   if (ic_info->key_head < ic_info->used)
2850                     ic_info->keys[ic_info->key_head + i] = key;
2851                   else
2852                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2853                   i++;
2854                 }
2855             }
2856         }
2857       else if (name == Mcall)
2858         {
2859           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2860           MIMExternalFunc func = NULL;
2861           MSymbol module, func_name;
2862           MPlist *func_args, *val;
2863           int ret = 0;
2864
2865           module = MPLIST_SYMBOL (args);
2866           args = MPLIST_NEXT (args);
2867           func_name = MPLIST_SYMBOL (args);
2868
2869           if (im_info->externals)
2870             {
2871               MIMExternalModule *external
2872                 = (MIMExternalModule *) mplist_get (im_info->externals,
2873                                                     module);
2874               if (external)
2875                 func = (MIMExternalFunc) mplist_get (external->func_list,
2876                                                      func_name);
2877             }
2878           if (! func)
2879             continue;
2880           func_args = mplist ();
2881           mplist_add (func_args, Mt, ic);
2882           MPLIST_DO (args, MPLIST_NEXT (args))
2883             {
2884               int code;
2885
2886               if (MPLIST_KEY (args) == Msymbol
2887                   && MPLIST_KEY (args) != Mnil
2888                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
2889                 {
2890                   code = new_index (ic, ic->cursor_pos, 
2891                                     mtext_nchars (ic->preedit),
2892                                     MPLIST_SYMBOL (args), ic->preedit);
2893                   mplist_add (func_args, Minteger, (void *) code);
2894                 }
2895               else
2896                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
2897             }
2898           val = (func) (func_args);
2899           M17N_OBJECT_UNREF (func_args);
2900           if (val && ! MPLIST_TAIL_P (val))
2901             ret = take_action_list (ic, val);
2902           M17N_OBJECT_UNREF (val);
2903           if (ret < 0)
2904             return ret;
2905         }
2906       else if (name == Mshift)
2907         {
2908           shift_state (ic, MPLIST_SYMBOL (args));
2909         }
2910       else if (name == Mundo)
2911         {
2912           int intarg = (MPLIST_TAIL_P (args)
2913                         ? ic_info->used - 2
2914                         : integer_value (ic, args, NULL, 0));
2915
2916           mtext_reset (ic->preedit);
2917           mtext_reset (ic_info->preedit_saved);
2918           ic->cursor_pos = ic_info->state_pos = 0;
2919           ic_info->state_key_head = ic_info->key_head = 0;
2920
2921           if (intarg < 0)
2922             ic_info->used += intarg;
2923           else
2924             ic_info->used = intarg;
2925           shift_state (ic, Mnil);
2926           break;
2927         }
2928       else if (name == Mset || name == Madd || name == Msub
2929                || name == Mmul || name == Mdiv)
2930         {
2931           MSymbol sym = MPLIST_SYMBOL (args);
2932           int val1, val2;
2933           MPlist *value;
2934           char *op;
2935
2936           val1 = integer_value (ic, args, &value, 0);
2937           args = MPLIST_NEXT (args);
2938           val2 = resolve_expression (ic, args);
2939           if (name == Mset)
2940             val1 = val2, op = "=";
2941           else if (name == Madd)
2942             val1 += val2, op = "+=";
2943           else if (name == Msub)
2944             val1 -= val2, op = "-=";
2945           else if (name == Mmul)
2946             val1 *= val2, op = "*=";
2947           else
2948             val1 /= val2, op = "/=";
2949           MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
2950                          MSYMBOL_NAME (sym), op, val1, val1);
2951           if (value)
2952             mplist_set (value, Minteger, (void *) val1);
2953         }
2954       else if (name == Mequal || name == Mless || name == Mgreater
2955                || name == Mless_equal || name == Mgreater_equal)
2956         {
2957           int val1, val2;
2958           MPlist *actions1, *actions2;
2959           int ret = 0;
2960
2961           val1 = resolve_expression (ic, args);
2962           args = MPLIST_NEXT (args);
2963           val2 = resolve_expression (ic, args);
2964           args = MPLIST_NEXT (args);
2965           actions1 = MPLIST_PLIST (args);
2966           args = MPLIST_NEXT (args);
2967           if (MPLIST_TAIL_P (args))
2968             actions2 = NULL;
2969           else
2970             actions2 = MPLIST_PLIST (args);
2971           MDEBUG_PRINT3 ("(%d %s %d)? ", val1, MSYMBOL_NAME (name), val2);
2972           if (name == Mequal ? val1 == val2
2973               : name == Mless ? val1 < val2
2974               : name == Mgreater ? val1 > val2
2975               : name == Mless_equal ? val1 <= val2
2976               : val1 >= val2)
2977             {
2978               MDEBUG_PRINT ("ok");
2979               ret = take_action_list (ic, actions1);
2980             }
2981           else
2982             {
2983               MDEBUG_PRINT ("no");
2984               if (actions2)
2985                 ret = take_action_list (ic, actions2);
2986             }
2987           if (ret < 0)
2988             return ret;
2989         }
2990       else if (name == Mcond)
2991         {
2992           int idx = 0;
2993
2994           MPLIST_DO (args, args)
2995             {
2996               MPlist *cond;
2997
2998               idx++;
2999               if (! MPLIST_PLIST (args))
3000                 continue;
3001               cond = MPLIST_PLIST (args);
3002               if (resolve_expression (ic, cond) != 0)
3003                 {
3004                   MDEBUG_PRINT1 ("(%dth)", idx);
3005                   if (take_action_list (ic, MPLIST_NEXT (cond)) < 0)
3006                     return -1;;
3007                   break;
3008                 }
3009             }
3010         }
3011       else if (name == Mcommit)
3012         {
3013           preedit_commit (ic);
3014         }
3015       else if (name == Munhandle)
3016         {
3017           preedit_commit (ic);
3018           return -1;
3019         }
3020       else
3021         {
3022           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3023           MPlist *actions;
3024
3025           if (im_info->macros
3026               && (actions = mplist_get (im_info->macros, name)))
3027             {
3028               if (take_action_list (ic, actions) < 0)
3029                 return -1;
3030             };
3031         }
3032     }
3033
3034   M17N_OBJECT_UNREF (ic->candidate_list);
3035   if (ic->cursor_pos > 0
3036       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
3037                                      Mcandidate_list)))
3038     {
3039       ic->candidate_list = mtext_property_value (prop);
3040       M17N_OBJECT_REF (ic->candidate_list);
3041       ic->candidate_index
3042         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
3043                                 Mcandidate_index);
3044       ic->candidate_from = mtext_property_start (prop);
3045       ic->candidate_to = mtext_property_end (prop);
3046     }
3047
3048   if (candidate_list != ic->candidate_list)
3049     ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3050   if (candidate_index != ic->candidate_index)
3051     ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3052   if (candidate_show != ic->candidate_show)
3053     ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
3054   return 0;
3055 }
3056
3057
3058 /* Handle the input key KEY in the current state and map specified in
3059    the input context IC.  If KEY is handled correctly, return 0.
3060    Otherwise, return -1.  */
3061
3062 static int
3063 handle_key (MInputContext *ic)
3064 {
3065   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3066   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3067   MIMMap *map = ic_info->map;
3068   MIMMap *submap = NULL;
3069   MSymbol key = ic_info->keys[ic_info->key_head];
3070   MSymbol alias = Mnil;
3071   int i;
3072
3073   MDEBUG_PRINT2 ("  [IM] handle `%s' in state %s", 
3074                  msymbol_name (key), MSYMBOL_NAME (ic_info->state->name));
3075
3076   if (map->submaps)
3077     {
3078       submap = mplist_get (map->submaps, key);
3079       alias = key;
3080       while (! submap
3081              && (alias = msymbol_get (alias, M_key_alias))
3082              && alias != key)
3083         submap = mplist_get (map->submaps, alias);
3084     }
3085
3086   if (submap)
3087     {
3088       if (! alias || alias == key)
3089         MDEBUG_PRINT (" submap-found");
3090       else
3091         MDEBUG_PRINT1 (" submap-found (by alias `%s')", MSYMBOL_NAME (alias));
3092       mtext_cpy (ic->preedit, ic_info->preedit_saved);
3093       ic->preedit_changed = 1;
3094       ic->cursor_pos = ic_info->state_pos;
3095       ic_info->key_head++;
3096       ic_info->map = map = submap;
3097       if (map->map_actions)
3098         {
3099           MDEBUG_PRINT (" map-actions:");
3100           if (take_action_list (ic, map->map_actions) < 0)
3101             {
3102               MDEBUG_PRINT ("\n");
3103               return -1;
3104             }
3105         }
3106       else if (map->submaps)
3107         {
3108           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
3109             {
3110               MSymbol key = ic_info->keys[i];
3111               char *name = msymbol_name (key);
3112
3113               if (! name[0] || ! name[1])
3114                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
3115             }
3116         }
3117
3118       /* If this is the terminal map or we have shifted to another
3119          state, perform branch actions (if any).  */
3120       if (! map->submaps || map != ic_info->map)
3121         {
3122           if (map->branch_actions)
3123             {
3124               MDEBUG_PRINT (" branch-actions:");
3125               if (take_action_list (ic, map->branch_actions) < 0)
3126                 {
3127                   MDEBUG_PRINT ("\n");
3128                   return -1;
3129                 }
3130             }
3131           /* If MAP is still not the root map, shift to the current
3132              state.  */
3133           if (ic_info->map != ic_info->state->map)
3134             shift_state (ic, ic_info->state->name);
3135         }
3136     }
3137   else
3138     {
3139       /* MAP can not handle KEY.  */
3140
3141       /* If MAP is the root map of the initial state, it means that
3142          the current input method can not handle KEY.  */
3143       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
3144         {
3145           MDEBUG_PRINT (" unhandled\n");
3146           return -1;
3147         }
3148
3149       if (map != ic_info->state->map)
3150         {
3151           /* If MAP is not the root map... */
3152           /* If MAP has branch actions, perform them.  */
3153           if (map->branch_actions)
3154             {
3155               MDEBUG_PRINT (" branch-actions:");
3156               if (take_action_list (ic, map->branch_actions) < 0)
3157                 {
3158                   MDEBUG_PRINT ("\n");
3159                   return -1;
3160                 }
3161             }
3162           /* If MAP is still not the root map, shift to the current
3163              state. */
3164           if (ic_info->map != ic_info->state->map)
3165             shift_state (ic, ic_info->state->name);
3166         }
3167       else
3168         {
3169           /* MAP is the root map, perform branch actions (if any) or
3170              shift to the initial state.  */
3171           if (map->branch_actions)
3172             {
3173               MDEBUG_PRINT (" branch-actions:");
3174               if (take_action_list (ic, map->branch_actions) < 0)
3175                 {
3176                   MDEBUG_PRINT ("\n");
3177                   return -1;
3178                 }
3179             }
3180           else
3181             shift_state (ic, Mnil);
3182         }
3183     }
3184   MDEBUG_PRINT ("\n");
3185   return 0;
3186 }
3187
3188 /* Initialize IC->ic_info.  */
3189
3190 static void
3191 init_ic_info (MInputContext *ic)
3192 {
3193   MInputMethodInfo *im_info = ic->im->info;
3194   MInputContextInfo *ic_info = ic->info;
3195   MPlist *plist;
3196   
3197   MLIST_INIT1 (ic_info, keys, 8);;
3198
3199   ic_info->markers = mplist ();
3200
3201   ic_info->vars = mplist ();
3202   if (im_info->configured_vars)
3203     MPLIST_DO (plist, im_info->configured_vars)
3204       {
3205         MPlist *pl = MPLIST_PLIST (plist), *p = mplist ();
3206         MSymbol name = MPLIST_SYMBOL (pl);
3207
3208         pl = MPLIST_NEXT (MPLIST_NEXT (pl));
3209         mplist_push (ic_info->vars, Mplist, p);
3210         M17N_OBJECT_UNREF (p);
3211         mplist_add (p, Msymbol, name);
3212         mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
3213       }
3214
3215   if (im_info->externals)
3216     {
3217       MPlist *func_args = mplist (), *plist;
3218
3219       mplist_add (func_args, Mt, ic);
3220       MPLIST_DO (plist, im_info->externals)
3221         {
3222           MIMExternalModule *external = MPLIST_VAL (plist);
3223           MIMExternalFunc func
3224             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
3225
3226           if (func)
3227             (func) (func_args);
3228         }
3229       M17N_OBJECT_UNREF (func_args);
3230     }
3231
3232   ic_info->preedit_saved = mtext ();
3233   ic_info->tick = im_info->tick;
3234 }
3235
3236 /* Finalize IC->ic_info.  */
3237
3238 static void
3239 fini_ic_info (MInputContext *ic)
3240 {
3241   MInputMethodInfo *im_info = ic->im->info;
3242   MInputContextInfo *ic_info = ic->info;
3243
3244   if (im_info->externals)
3245     {
3246       MPlist *func_args = mplist (), *plist;
3247
3248       mplist_add (func_args, Mt, ic);
3249       MPLIST_DO (plist, im_info->externals)
3250         {
3251           MIMExternalModule *external = MPLIST_VAL (plist);
3252           MIMExternalFunc func
3253             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
3254
3255           if (func)
3256             (func) (func_args);
3257         }
3258       M17N_OBJECT_UNREF (func_args);
3259     }
3260
3261   MLIST_FREE1 (ic_info, keys);
3262   M17N_OBJECT_UNREF (ic_info->preedit_saved);
3263   M17N_OBJECT_UNREF (ic_info->markers);
3264   M17N_OBJECT_UNREF (ic_info->vars);
3265   M17N_OBJECT_UNREF (ic_info->preceding_text);
3266   M17N_OBJECT_UNREF (ic_info->following_text);
3267
3268   memset (ic_info, 0, sizeof (MInputContextInfo));
3269 }
3270
3271 static void
3272 re_init_ic (MInputContext *ic, int reload)
3273 {
3274   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3275   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3276   int status_changed, preedit_changed, cursor_pos_changed, candidates_changed;
3277
3278   status_changed = ic_info->state != (MIMState *) MPLIST_VAL (im_info->states);
3279   preedit_changed = mtext_nchars (ic->preedit) > 0;
3280   cursor_pos_changed = ic->cursor_pos > 0;
3281   candidates_changed = 0;
3282   if (ic->candidate_list)
3283     {
3284       candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3285       M17N_OBJECT_UNREF (ic->candidate_list);
3286     }
3287   if (ic->candidate_show)
3288     {
3289       candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
3290       ic->candidate_show = 0;
3291     }
3292   if (ic->candidate_index > 0)
3293     {
3294       candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3295       ic->candidate_index = 0;
3296       ic->candidate_from = ic->candidate_to = 0;
3297     }
3298   if (mtext_nchars (ic->produced) > 0)
3299     mtext_reset (ic->produced);
3300   if (mtext_nchars (ic->preedit) > 0)
3301     mtext_reset (ic->preedit);
3302   ic->cursor_pos = 0;
3303   M17N_OBJECT_UNREF (ic->plist);
3304   ic->plist = mplist ();
3305
3306   fini_ic_info (ic);
3307   if (reload)
3308     reload_im_info (im_info);
3309   init_ic_info (ic);
3310   shift_state (ic, Mnil);
3311   ic->status_changed = status_changed;
3312   ic->preedit_changed = preedit_changed;
3313   ic->cursor_pos_changed = cursor_pos_changed;
3314   ic->candidates_changed = candidates_changed;
3315 }
3316
3317 static void
3318 reset_ic (MInputContext *ic, MSymbol ignore)
3319 {
3320   MDEBUG_PRINT ("\n  [IM] reset\n");
3321   re_init_ic (ic, 0);
3322 }
3323
3324 static int
3325 open_im (MInputMethod *im)
3326 {
3327   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
3328
3329   if (! im_info)
3330     MERROR (MERROR_IM, -1);
3331   im->info = im_info;
3332
3333   return 0;
3334 }
3335
3336 static void
3337 close_im (MInputMethod *im)
3338 {
3339   im->info = NULL;
3340 }
3341
3342 static int
3343 create_ic (MInputContext *ic)
3344 {
3345   MInputContextInfo *ic_info;
3346
3347   MSTRUCT_CALLOC (ic_info, MERROR_IM);
3348   ic->info = ic_info;
3349   init_ic_info (ic);
3350   shift_state (ic, Mnil);
3351   return 0;
3352 }
3353
3354 static void
3355 destroy_ic (MInputContext *ic)
3356 {
3357   fini_ic_info (ic);
3358   free (ic->info);
3359 }
3360
3361 static int
3362 check_reload (MInputContext *ic, MSymbol key)
3363 {
3364   MInputMethodInfo *im_info = ic->im->info;
3365   MPlist *plist = resolve_command (im_info->configured_cmds, Mat_reload);
3366
3367   if (! plist)
3368     {
3369       plist = resolve_command (global_info->configured_cmds, Mat_reload);
3370       if (! plist)
3371         return 0;
3372     }
3373   MPLIST_DO (plist, plist)
3374     {
3375       MSymbol this_key, alias;
3376
3377       if (MPLIST_MTEXT_P (plist))
3378         {
3379           MText *mt = MPLIST_MTEXT (plist);
3380           int c = mtext_ref_char (mt, 0);
3381
3382           if (c >= 256)
3383             continue;
3384           this_key = one_char_symbol[c];
3385         }
3386       else
3387         {
3388           MPlist *pl = MPLIST_PLIST (plist);
3389       
3390           this_key = MPLIST_SYMBOL (pl);
3391         }
3392       alias = this_key;
3393       while (alias != key 
3394              && (alias = msymbol_get (alias, M_key_alias))
3395              && alias != this_key);
3396       if (alias == key)
3397         break;
3398     }
3399   if (MPLIST_TAIL_P (plist))
3400     return 0;
3401
3402   MDEBUG_PRINT ("\n  [IM] reload");
3403   re_init_ic (ic, 1);
3404   return 1;
3405 }
3406
3407
3408 /** Handle the input key KEY in the current state and map of IC->info.
3409     If KEY is handled but no text is produced, return 0, otherwise
3410     return 1.
3411
3412     Ignore ARG.  */
3413
3414 static int
3415 filter (MInputContext *ic, MSymbol key, void *arg)
3416 {
3417   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3418   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3419   int i = 0;
3420
3421   if (check_reload (ic, key))
3422     return 0;
3423
3424   if (! ic_info->state)
3425     {
3426       ic_info->key_unhandled = 1;
3427       return 0;
3428     }
3429   mtext_reset (ic->produced);
3430   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
3431   M17N_OBJECT_UNREF (ic_info->preceding_text);
3432   M17N_OBJECT_UNREF (ic_info->following_text);
3433   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3434   ic_info->key_unhandled = 0;
3435
3436   do {
3437     if (handle_key (ic) < 0)
3438       {
3439         /* KEY was not handled.  Delete it from the current key sequence.  */
3440         if (ic_info->used > 0)
3441           {
3442             memmove (ic_info->keys, ic_info->keys + 1,
3443                      sizeof (int) * (ic_info->used - 1));
3444             ic_info->used--;
3445           }
3446         /* This forces returning 1.  */
3447         ic_info->key_unhandled = 1;
3448         break;
3449       }
3450     if (i++ == 100)
3451       {
3452         mdebug_hook ();
3453         reset_ic (ic, Mnil);
3454         ic_info->key_unhandled = 1;
3455         break;
3456       }
3457     /* Break the loop if all keys were handled.  */
3458   } while (ic_info->key_head < ic_info->used);
3459
3460   /* If the current map is the root of the initial state, we should
3461      produce any preedit text in ic->produced.  */
3462   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
3463       && mtext_nchars (ic->preedit) > 0)
3464     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
3465
3466   if (mtext_nchars (ic->produced) > 0)
3467     {
3468       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
3469
3470       if (lang != Mnil)
3471         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
3472                         Mlanguage, ic->im->language);
3473     }
3474
3475   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
3476 }
3477
3478
3479 /** Return 1 if the last event or key was not handled, otherwise
3480     return 0.
3481
3482     There is no need of looking up because ic->produced should already
3483     contain the produced text (if any).
3484
3485     Ignore KEY.  */
3486
3487 static int
3488 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
3489 {
3490   mtext_cat (mt, ic->produced);
3491   mtext_reset (ic->produced);
3492   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
3493 }
3494
3495 \f
3496 /* Input method command handler.  */
3497
3498 /* List of all (global and local) commands. 
3499    (LANG:(IM-NAME:(COMMAND ...) ...) ...) ...
3500    COMMAND is CMD-NAME:(mtext:DESCRIPTION plist:KEYSEQ ...))
3501    Global commands are stored as (t (t COMMAND ...))  */
3502
3503 \f
3504 /* Input method variable handler.  */
3505
3506
3507 /* Support functions for mdebug_dump_im.  */
3508
3509 static void
3510 dump_im_map (MPlist *map_list, int indent)
3511 {
3512   char *prefix;
3513   MSymbol key = MPLIST_KEY (map_list);
3514   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
3515
3516   prefix = (char *) alloca (indent + 1);
3517   memset (prefix, 32, indent);
3518   prefix[indent] = '\0';
3519
3520   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
3521   if (map->map_actions)
3522     mdebug_dump_plist (map->map_actions, indent + 2);
3523   if (map->submaps)
3524     {
3525       MPLIST_DO (map_list, map->submaps)
3526         {
3527           fprintf (stderr, "\n%s  ", prefix);
3528           dump_im_map (map_list, indent + 2);
3529         }
3530     }
3531   if (map->branch_actions)
3532     {
3533       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
3534       mdebug_dump_plist (map->branch_actions, indent + 4);
3535       fprintf (stderr, ")");      
3536     }
3537   fprintf (stderr, ")");
3538 }
3539
3540
3541 static void
3542 dump_im_state (MIMState *state, int indent)
3543 {
3544   char *prefix;
3545   MPlist *map_list;
3546
3547   prefix = (char *) alloca (indent + 1);
3548   memset (prefix, 32, indent);
3549   prefix[indent] = '\0';
3550
3551   fprintf (stderr, "(%s", msymbol_name (state->name));
3552   if (state->map->submaps)
3553     {
3554       MPLIST_DO (map_list, state->map->submaps)
3555         {
3556           fprintf (stderr, "\n%s  ", prefix);
3557           dump_im_map (map_list, indent + 2);
3558         }
3559     }
3560   fprintf (stderr, ")");
3561 }
3562
3563 \f
3564
3565 int
3566 minput__init ()
3567 {
3568   Minput_driver = msymbol ("input-driver");
3569
3570   Minput_preedit_start = msymbol ("input-preedit-start");
3571   Minput_preedit_done = msymbol ("input-preedit-done");
3572   Minput_preedit_draw = msymbol ("input-preedit-draw");
3573   Minput_status_start = msymbol ("input-status-start");
3574   Minput_status_done = msymbol ("input-status-done");
3575   Minput_status_draw = msymbol ("input-status-draw");
3576   Minput_candidates_start = msymbol ("input-candidates-start");
3577   Minput_candidates_done = msymbol ("input-candidates-done");
3578   Minput_candidates_draw = msymbol ("input-candidates-draw");
3579   Minput_set_spot = msymbol ("input-set-spot");
3580   Minput_focus_move = msymbol ("input-focus-move");
3581   Minput_focus_in = msymbol ("input-focus-in");
3582   Minput_focus_out = msymbol ("input-focus-out");
3583   Minput_toggle = msymbol ("input-toggle");
3584   Minput_reset = msymbol ("input-reset");
3585   Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
3586   Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
3587
3588   minput_default_driver.open_im = open_im;
3589   minput_default_driver.close_im = close_im;
3590   minput_default_driver.create_ic = create_ic;
3591   minput_default_driver.destroy_ic = destroy_ic;
3592   minput_default_driver.filter = filter;
3593   minput_default_driver.lookup = lookup;
3594   minput_default_driver.callback_list = mplist ();
3595   mplist_put (minput_default_driver.callback_list, Minput_reset,
3596               (void *) reset_ic);
3597   minput_driver = &minput_default_driver;
3598
3599   fully_initialized = 0;
3600   return 0;
3601 }
3602
3603 void
3604 minput__fini ()
3605 {
3606   if (fully_initialized)
3607     {
3608       free_im_list (im_info_list);
3609       if (im_custom_list)
3610         free_im_list (im_custom_list);
3611       if (im_config_list)
3612         free_im_list (im_config_list);
3613       M17N_OBJECT_UNREF (load_im_info_keys);
3614     }
3615
3616   M17N_OBJECT_UNREF (minput_default_driver.callback_list);
3617   M17N_OBJECT_UNREF (minput_driver->callback_list);
3618
3619 }
3620
3621 int
3622 minput__callback (MInputContext *ic, MSymbol command)
3623 {
3624   MInputCallbackFunc func;
3625
3626   if (! ic->im->driver.callback_list)
3627     return -1;
3628   func = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
3629                                           command);
3630   if (! func)
3631     return -1;
3632   (func) (ic, command);
3633   return 0;
3634 }
3635
3636 MSymbol
3637 minput__char_to_key (int c)
3638 {
3639   if (c < 0 || c >= 0x100)
3640     return Mnil;
3641
3642   return one_char_symbol[c];
3643 }
3644
3645 /*** @} */
3646 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
3647
3648 \f
3649 /* External API */
3650
3651 /*** @addtogroup m17nInputMethod */
3652 /*** @{ */
3653 /*=*/
3654
3655 /***en
3656     @name Variables: Predefined symbols for callback commands.
3657
3658     These are the predefined symbols that are used as the @c COMMAND
3659     argument of callback functions of an input method driver (see
3660     #MInputDriver::callback_list).  
3661
3662     Most of them don't require extra argument nor return any value;
3663     exceptions are these:
3664
3665     Minput_get_surrounding_text: When a callback function assigned for
3666     this command is called, the first element of #MInputContext::plist
3667     has key #Minteger and the value specifies which portion of the
3668     surrounding text should be retrieved.  If the value is positive,
3669     it specifies the number of characters following the current cursor
3670     position.  If the value is negative, the absolute value specifies
3671     the number of characters preceding the current cursor position.
3672
3673     If the surrounding text is currently supported, the callback
3674     function must set the key of this element to #Mtext and the value
3675     to the retrieved M-text.  The length of the M-text may be shorter
3676     than the requested number of characters, if the available text is
3677     not that long.  The length can be zero in the worst case.  Or, the
3678     length may be longer if an application thinks it's more efficient
3679     to return that length).
3680
3681     If the surrounding text is not currently supported, the callback
3682     function should return without changing the first element of
3683     #MInputContext::plist.
3684
3685     Minput_delete_surrounding_text: When a callback function assigned
3686     for this command is called, the first element of
3687     #MInputContext::plist has key #Minteger and the value specifies
3688     which portion of the surrounding text should be deleted in the
3689     same way as the case of Minput_get_surrounding_text.  The callback
3690     function must delete the specified text.  It should not alter
3691     #MInputContext::plist.  */ 
3692
3693 /***ja
3694     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
3695
3696     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND 
3697     °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
3698       */ 
3699 /*** @{ */ 
3700 /*=*/
3701
3702 MSymbol Minput_preedit_start;
3703 MSymbol Minput_preedit_done;
3704 MSymbol Minput_preedit_draw;
3705 MSymbol Minput_status_start;
3706 MSymbol Minput_status_done;
3707 MSymbol Minput_status_draw;
3708 MSymbol Minput_candidates_start;
3709 MSymbol Minput_candidates_done;
3710 MSymbol Minput_candidates_draw;
3711 MSymbol Minput_set_spot;
3712 MSymbol Minput_toggle;
3713 MSymbol Minput_reset;
3714 MSymbol Minput_get_surrounding_text;
3715 MSymbol Minput_delete_surrounding_text;
3716 /*** @} */
3717
3718 /*=*/
3719
3720 /***en
3721     @name Variables: Predefined symbols for special input events.
3722
3723     These are the predefined symbols that are used as the @c KEY
3724     argument of minput_filter ().  */ 
3725
3726 /*** @{ */ 
3727 /*=*/
3728
3729 MSymbol Minput_focus_out;
3730 MSymbol Minput_focus_in;
3731 MSymbol Minput_focus_move;
3732
3733 /*** @} */
3734
3735 /*=*/
3736
3737 /***en
3738     @brief The default driver for internal input methods.
3739
3740     The variable #minput_default_driver is the default driver for
3741     internal input methods.
3742
3743     The member MInputDriver::open_im () searches the m17n database for
3744     an input method that matches the tag \< #Minput_method, $LANGUAGE,
3745     $NAME\> and loads it.
3746
3747     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
3748     programmers responsibility to set it to a plist of proper callback
3749     functions.  Otherwise, no feedback information (e.g. preedit text)
3750     can be shown to users.
3751
3752     The macro M17N_INIT () sets the variable #minput_driver to the
3753     pointer to this driver so that all internal input methods use it.
3754
3755     Therefore, unless @c minput_driver is set differently, the driver
3756     dependent arguments $ARG of the functions whose name begins with
3757     "minput_" are all ignored.  */
3758
3759 /***ja
3760     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
3761
3762     ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£
3763
3764     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
3765     \< #Minput_method, $LANGUAGE, $NAME\> 
3766     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
3767
3768     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢
3769     ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist
3770     ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit 
3771     ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
3772
3773     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver 
3774     ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
3775
3776     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
3777     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
3778
3779 MInputDriver minput_default_driver;
3780 /*=*/
3781
3782 /***en
3783     @brief The driver for internal input methods.
3784
3785     The variable #minput_driver is a pointer to the input method
3786     driver that is used by internal input methods.  The macro
3787     M17N_INIT () initializes it to a pointer to #minput_default_driver
3788     if <m17n<EM></EM>.h> is included.  */ 
3789 /***ja
3790     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
3791
3792     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
3793     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
3794     ¥¿¤ò#minput_default_driver (<m17n<EM></EM>.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë
3795     »þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
3796
3797 MInputDriver *minput_driver;
3798
3799 MSymbol Minput_driver;
3800
3801 /*=*/
3802
3803 /***en
3804     @brief Open an input method.
3805
3806     The minput_open_im () function opens an input method whose
3807     language and name match $LANGUAGE and $NAME, and returns a pointer
3808     to the input method object newly allocated.
3809
3810     This function at first decides a driver for the input method as
3811     described below.
3812
3813     If $LANGUAGE is not #Mnil, the driver pointed by the variable
3814     #minput_driver is used.
3815
3816     If $LANGUAGE is #Mnil and $NAME has the property #Minput_driver, the
3817     driver pointed to by the property value is used to open the input
3818     method.  If $NAME has no such a property, @c NULL is returned.
3819
3820     Then, the member MInputDriver::open_im () of the driver is
3821     called.  
3822
3823     $ARG is set in the member @c arg of the structure MInputMethod so
3824     that the driver can refer to it.  */
3825
3826 /***ja
3827     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
3828
3829     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME 
3830     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
3831     
3832     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
3833
3834     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver 
3835     ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
3836
3837     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver
3838     ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£
3839     $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
3840
3841     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
3842
3843     $ARG ¤Ï¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£
3844
3845     @latexonly \IPAlabel{minput_open} @endlatexonly
3846
3847 */
3848
3849 MInputMethod *
3850 minput_open_im (MSymbol language, MSymbol name, void *arg)
3851 {
3852   MInputMethod *im;
3853   MInputDriver *driver;
3854
3855   MINPUT__INIT ();
3856
3857   MDEBUG_PRINT2 ("  [IM] opening (%s %s) ... ",
3858                  msymbol_name (language), msymbol_name (name));
3859   if (language)
3860     driver = minput_driver;
3861   else
3862     {
3863       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
3864       if (! driver)
3865         MERROR (MERROR_IM, NULL);
3866     }
3867
3868   MSTRUCT_CALLOC (im, MERROR_IM);
3869   im->language = language;
3870   im->name = name;
3871   im->arg = arg;
3872   im->driver = *driver;
3873   if ((*im->driver.open_im) (im) < 0)
3874     {
3875       MDEBUG_PRINT (" failed\n");
3876       free (im);
3877       return NULL;
3878     }
3879   MDEBUG_PRINT (" ok\n");
3880   return im;
3881 }
3882
3883 /*=*/
3884
3885 /***en
3886     @brief Close an input method.
3887
3888     The minput_close_im () function closes the input method $IM, which
3889     must have been created by minput_open_im ().  */
3890
3891 /***ja
3892     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
3893
3894     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£
3895     ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
3896
3897 void
3898 minput_close_im (MInputMethod *im)
3899 {
3900   MDEBUG_PRINT2 ("  [IM] closing (%s %s) ... ",
3901                  msymbol_name (im->name), msymbol_name (im->language));
3902   (*im->driver.close_im) (im);
3903   free (im);
3904   MDEBUG_PRINT (" done\n");
3905 }
3906
3907 /*=*/
3908
3909 /***en
3910     @brief Create an input context.
3911
3912     The minput_create_ic () function creates an input context object
3913     associated with input method $IM, and calls callback functions
3914     corresponding to #Minput_preedit_start, #Minput_status_start, and
3915     #Minput_status_draw in this order.
3916
3917     @return
3918     If an input context is successfully created, minput_create_ic ()
3919     returns a pointer to it.  Otherwise it returns @c NULL.  */
3920
3921 /***ja
3922     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
3923
3924     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
3925     ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
3926     #Minput_preedit_start, #Minput_status_start, #Minput_status_draw
3927     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
3928
3929     @return
3930     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () 
3931     ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
3932       */
3933
3934 MInputContext *
3935 minput_create_ic (MInputMethod *im, void *arg)
3936 {
3937   MInputContext *ic;
3938
3939   MDEBUG_PRINT2 ("  [IM] creating context (%s %s) ... ",
3940                  msymbol_name (im->name), msymbol_name (im->language));
3941   MSTRUCT_CALLOC (ic, MERROR_IM);
3942   ic->im = im;
3943   ic->arg = arg;
3944   ic->preedit = mtext ();
3945   ic->candidate_list = NULL;
3946   ic->produced = mtext ();
3947   ic->spot.x = ic->spot.y = 0;
3948   ic->active = 1;
3949   ic->plist = mplist ();
3950   if ((*im->driver.create_ic) (ic) < 0)
3951     {
3952       MDEBUG_PRINT (" failed\n");
3953       M17N_OBJECT_UNREF (ic->preedit);
3954       M17N_OBJECT_UNREF (ic->produced);
3955       M17N_OBJECT_UNREF (ic->plist);
3956       free (ic);
3957       return NULL;
3958     };
3959
3960   if (im->driver.callback_list)
3961     {
3962       minput__callback (ic, Minput_preedit_start);
3963       minput__callback (ic, Minput_status_start);
3964       minput__callback (ic, Minput_status_draw);
3965     }
3966
3967   MDEBUG_PRINT (" ok\n");
3968   return ic;
3969 }
3970
3971 /*=*/
3972
3973 /***en
3974     @brief Destroy an input context.
3975
3976     The minput_destroy_ic () function destroys the input context $IC,
3977     which must have been created by minput_create_ic ().  It calls
3978     callback functions corresponding to #Minput_preedit_done,
3979     #Minput_status_done, and #Minput_candidates_done in this order.  */
3980
3981 /***ja
3982     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
3983
3984     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
3985     ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () 
3986     ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï 
3987     #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done 
3988     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
3989   */
3990
3991 void
3992 minput_destroy_ic (MInputContext *ic)
3993 {
3994   MDEBUG_PRINT2 ("  [IM] destroying context (%s %s) ... ",
3995                  msymbol_name (ic->im->name), msymbol_name (ic->im->language));
3996   if (ic->im->driver.callback_list)
3997     {
3998       minput__callback (ic, Minput_preedit_done);
3999       minput__callback (ic, Minput_status_done);
4000       minput__callback (ic, Minput_candidates_done);
4001     }
4002   (*ic->im->driver.destroy_ic) (ic);
4003   M17N_OBJECT_UNREF (ic->preedit);
4004   M17N_OBJECT_UNREF (ic->produced);
4005   M17N_OBJECT_UNREF (ic->plist);
4006   MDEBUG_PRINT (" done\n");
4007   free (ic);
4008 }
4009
4010 /*=*/
4011
4012 /***en
4013     @brief Filter an input key.
4014
4015     The minput_filter () function filters input key $KEY according to
4016     input context $IC, and calls callback functions corresponding to
4017     #Minput_preedit_draw, #Minput_status_draw, and
4018     #Minput_candidates_draw if the preedit text, the status, and the
4019     current candidate are changed respectively.
4020
4021     To make the input method commit the current preedit text (if any)
4022     and shift to the initial state, call this function with #Mnil as
4023     $KEY.
4024
4025     To inform the input method about the focus-out event, call this
4026     function with #Minput_focus_out as $KEY.
4027
4028     To inform the input method about the focus-in event, call this
4029     function with #Minput_focus_in as $KEY.
4030
4031     To inform the input method about the focus-move event (i.e. input
4032     spot change within the same input context), call this function
4033     with #Minput_focus_move as $KEY.
4034
4035     @return
4036     If $KEY is filtered out, this function returns 1.  In that case,
4037     the caller should discard the key.  Otherwise, it returns 0, and
4038     the caller should handle the key, for instance, by calling the
4039     function minput_lookup () with the same key.  */
4040
4041 /***ja
4042     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
4043
4044     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4045     ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
4046     #Minput_preedit_draw, #Minput_status_draw,
4047     #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
4048
4049     @return 
4050     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
4051     ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
4052     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup ()
4053     ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
4054
4055     @latexonly \IPAlabel{minput_filter} @endlatexonly
4056 */
4057
4058 int
4059 minput_filter (MInputContext *ic, MSymbol key, void *arg)
4060 {
4061   int ret;
4062
4063   if (! ic
4064       || ! ic->active)
4065     return 0;
4066   ret = (*ic->im->driver.filter) (ic, key, arg);
4067
4068   if (ic->im->driver.callback_list)
4069     {
4070       if (ic->preedit_changed)
4071         minput__callback (ic, Minput_preedit_draw);
4072       if (ic->status_changed)
4073         minput__callback (ic, Minput_status_draw);
4074       if (ic->candidates_changed)
4075         minput__callback (ic, Minput_candidates_draw);
4076     }
4077
4078   return ret;
4079 }
4080
4081 /*=*/
4082
4083 /***en
4084     @brief Look up a text produced in the input context.
4085
4086     The minput_lookup () function looks up a text in the input context
4087     $IC.  $KEY must be identical to the one that was used in the previous call of
4088     minput_filter ().
4089
4090     If a text was produced by the input method, it is concatenated
4091     to M-text $MT.
4092
4093     This function calls #MInputDriver::lookup .
4094
4095     @return
4096     If $KEY was correctly handled by the input method, this function
4097     returns 0.  Otherwise, it returns -1, even though some text
4098     might be produced in $MT.  */
4099
4100 /***ja
4101     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹.
4102
4103     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£
4104     $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4105
4106     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
4107     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
4108
4109     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
4110
4111     @return 
4112     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
4113     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
4114     ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
4115
4116     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
4117
4118 int
4119 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
4120 {
4121   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
4122 }
4123 /*=*/
4124
4125 /***en
4126     @brief Set the spot of the input context.
4127
4128     The minput_set_spot () function sets the spot of input context $IC
4129     to coordinate ($X, $Y ) with the height specified by $ASCENT and $DESCENT .
4130     The semantics of these values depends on the input method driver.
4131
4132     For instance, a driver designed to work in a CUI environment may
4133     use $X and $Y as the column- and row numbers, and may ignore $ASCENT and
4134     $DESCENT .  A driver designed to work in a window system may
4135     interpret $X and $Y as the pixel offsets relative to the origin of the
4136     client window, and may interpret $ASCENT and $DESCENT as the ascent- and
4137     descent pixels of the line at ($X . $Y ).
4138
4139     $FONTSIZE specifies the fontsize of preedit text in 1/10 point.
4140
4141     $MT and $POS are the M-text and the character position at the spot.
4142     $MT may be @c NULL, in which case, the input method cannot get
4143     information about the text around the spot.  */
4144
4145 /***ja
4146     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë.
4147
4148     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y )
4149     ¤Î°ÌÃ֤ˠ¡¢¹â¤µ $ASCENT¡¢ $DESCENT 
4150     ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£
4151
4152     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y 
4153     ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT 
4154     ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï
4155     $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
4156     $ASCENT ¤È $DESCENT ¤ò ($X . $Y )
4157     ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
4158
4159     $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
4160
4161     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
4162     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
4163     */
4164
4165 void
4166 minput_set_spot (MInputContext *ic, int x, int y,
4167                  int ascent, int descent, int fontsize,
4168                  MText *mt, int pos)
4169 {
4170   ic->spot.x = x;
4171   ic->spot.y = y;
4172   ic->spot.ascent = ascent;
4173   ic->spot.descent = descent;
4174   ic->spot.fontsize = fontsize;
4175   ic->spot.mt = mt;
4176   ic->spot.pos = pos;
4177   if (ic->im->driver.callback_list)
4178     minput__callback (ic, Minput_set_spot);
4179 }
4180 /*=*/
4181
4182 /***en
4183     @brief Toggle input method.
4184
4185     The minput_toggle () function toggles the input method associated
4186     with input context $IC.  */
4187 /***ja
4188     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
4189
4190     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4191     ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
4192     */
4193
4194 void
4195 minput_toggle (MInputContext *ic)
4196 {
4197   if (ic->im->driver.callback_list)
4198     minput__callback (ic, Minput_toggle);
4199   ic->active = ! ic->active;
4200 }
4201
4202 /*=*/
4203
4204 /***en
4205     @brief Reset an input context.
4206
4207     The minput_reset_ic () function resets input context $IC by
4208     calling a callback function corresponding to #Minput_reset.  It
4209     resets the status of $IC to its initial one.  As the
4210     current preedit text is deleted without commitment, if necessary,
4211     call minput_filter () with the arg @r key #Mnil to force the input
4212     method to commit the preedit in advance.  */
4213
4214 /***ja
4215     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
4216
4217     ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
4218     ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢
4219     ¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ë¡£¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹
4220     ¥È¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¤³¤È¤Ê¤¯ºï½ü¤µ¤ì¤ë¤Î¤Ç¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
4221     ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @r key #Mnil ¤Ç¸Æ¤ó¤Ç
4222     ¶¯À©Åª¤Ë¥×¥ê¥¨¥Ç¥£¥Ã¥È¥Æ¥­¥¹¥È¤ò¥³¥ß¥Ã¥È¤µ¤»¤ë¤³¤È¡£  */
4223
4224 void
4225 minput_reset_ic (MInputContext *ic)
4226 {
4227   if (ic->im->driver.callback_list)
4228     minput__callback (ic, Minput_reset);
4229 }
4230
4231 /*=*/
4232
4233 /***en
4234     @brief Get title and icon filename of an input method.
4235
4236     The minput_get_title_icon () function returns a plist containing a
4237     title and icon filename (if any) of an input method specified by
4238     $LANGUAGE and $NAME.
4239
4240     The first element of the plist has key #Mtext and the value is an
4241     M-text of the title for identifying the input method.  The second
4242     element (if any) has key #Mtext and the value is an M-text of the
4243     icon image (absolute) filename for the same purpose.
4244
4245     @return
4246     If there exists a specified input method and it defines an title,
4247     a plist is returned.  Otherwise, NULL is returned.  The caller
4248     must free the plist by m17n_object_unref ().  */
4249
4250 MPlist *
4251 minput_get_title_icon (MSymbol language, MSymbol name)
4252 {
4253   MInputMethodInfo *im_info;
4254   MPlist *plist;
4255   char *file = NULL;
4256   MText *mt;
4257
4258   MINPUT__INIT ();
4259
4260   im_info = get_im_info (language, name, Mnil, Mtitle);
4261   if (! im_info || !im_info->title)
4262     return NULL;
4263   mt = mtext_get_prop (im_info->title, 0, Mtext);
4264   if (mt)
4265     file = mdatabase__find_file ((char *) MTEXT_DATA (mt));
4266   else
4267     {
4268       char *buf = alloca (MSYMBOL_NAMELEN (language) + MSYMBOL_NAMELEN (name)
4269                           + 12);
4270
4271       sprintf (buf, "icons/%s-%s.png", (char *) MSYMBOL_NAME (language), 
4272                (char *) MSYMBOL_NAME (name));
4273       file = mdatabase__find_file (buf);
4274       if (! file && language == Mt)
4275         {
4276           sprintf (buf, "icons/%s.png", (char *) MSYMBOL_NAME (name));
4277           file = mdatabase__find_file (buf);
4278         }
4279     }
4280
4281   plist = mplist ();
4282   mplist_add (plist, Mtext, im_info->title);
4283   if (file)
4284     {
4285       mt = mtext__from_data (file, strlen (file), MTEXT_FORMAT_UTF_8, 1);
4286       free (file);
4287       mplist_add (plist, Mtext, mt);
4288       M17N_OBJECT_UNREF (mt);
4289     }
4290   return plist;
4291 }
4292
4293 /*=*/
4294
4295 /***en
4296     @brief Get description text of an input method.
4297
4298     The minput_get_description () function returns an M-text that
4299     describes the input method specified by $LANGUAGE and $NAME.
4300
4301     @return
4302     If the specified input method has a description text, a pointer to
4303     #MText is returned.  The caller has to free it by m17n_object_unref ().
4304     If the input method does not have a description text, @c NULL is
4305     returned.  */
4306 /***ja
4307     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë.
4308
4309     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
4310     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
4311
4312     @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
4313     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
4314     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
4315     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
4316
4317 MText *
4318 minput_get_description (MSymbol language, MSymbol name)
4319 {
4320   MInputMethodInfo *im_info;
4321
4322   MINPUT__INIT ();
4323
4324   im_info = get_im_info (language, name, Mnil, Mdescription);
4325   if (! im_info || ! im_info->description)
4326     return NULL;
4327   M17N_OBJECT_REF (im_info->description);
4328   return im_info->description;
4329 }
4330
4331 /***en
4332     @brief Get information about input method commands.
4333
4334     The minput_get_commands () function returns information about
4335     input method commands of the input method specified by $LANGUAGE
4336     and $NAME.  An input method command is a pseudo key event to which
4337     one or more actual input key sequences are assigned.
4338
4339     There are two kinds of commands, global and local.  Global
4340     commands are used by multiple input methods for the same purpose,
4341     and have global key assignments.  Local commands are used only by
4342     a specific input method, and have only local key assignments.
4343
4344     Each input method may locally change key assignments for global
4345     commands.  The global key assignment for a global command is
4346     effective only when the current input method does not have local
4347     key assignments for that command.
4348
4349     If $NAME is #Mnil, information about global commands is returned.
4350     In this case $LANGUAGE is ignored.
4351
4352     If $NAME is not #Mnil, information about those commands that have
4353     local key assignments in the input method specified by $LANGUAGE
4354     and $NAME is returned.
4355
4356     @return
4357     If no input method commands are found, this function returns @c NULL.
4358
4359     Otherwise, a pointer to a plist is returned.  The key of each
4360     element in the plist is a symbol representing a command, and the
4361     value is a plist of the form COMMAND-INFO described below.
4362
4363     The first element of COMMAND-INFO has the key #Mtext, and the
4364     value is an M-text describing the command.
4365
4366     If there are no more elements, that means no key sequences are
4367     assigned to the command.  Otherwise, each of the remaining
4368     elements has the key #Mplist, and the value is a plist whose keys are
4369     #Msymbol and values are symbols representing input keys, which are
4370     currently assigned to the command.
4371
4372     As the returned plist is kept in the library, the caller must not
4373     modify nor free it.  */
4374 /***ja
4375     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
4376
4377     ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
4378     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
4379     ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
4380     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
4381
4382     ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
4383     ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
4384     ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
4385     ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
4386
4387     ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
4388     ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
4389     ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
4390     ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
4391
4392     $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
4393     ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
4394
4395     $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
4396     Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
4397     ¤òÊÖ¤¹¡£
4398
4399     @return
4400     ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
4401
4402     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
4403     ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
4404     ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
4405
4406     COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
4407     ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
4408     #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
4409     ¤¤¤³¤È¤Ë¤Ê¤ë¡£
4410
4411     ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
4412     ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
4413     ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
4414     ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
4415     ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
4416
4417     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
4418     ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
4419
4420 MPlist *
4421 minput_get_commands (MSymbol language, MSymbol name)
4422 {
4423   MInputMethodInfo *im_info;
4424   MPlist *cmds;
4425
4426   MINPUT__INIT ();
4427
4428   im_info = get_im_info (language, name, Mnil, Mcommand);
4429   if (! im_info || ! im_info->configured_vars)
4430     return NULL;
4431   M17N_OBJECT_UNREF (im_info->bc_cmds);
4432   im_info->bc_cmds = mplist ();
4433   MPLIST_DO (cmds, im_info->configured_cmds)
4434     {
4435       MPlist *plist = MPLIST_PLIST (cmds);
4436       MPlist *elt = mplist ();
4437
4438       mplist_push (im_info->bc_cmds, Mplist, elt);
4439       mplist_add (elt, MPLIST_SYMBOL (plist),
4440                   mplist_copy (MPLIST_NEXT (plist)));
4441       M17N_OBJECT_UNREF (elt);
4442     }
4443   return im_info->bc_cmds;
4444 }
4445
4446 /***en
4447     @brief Assign a key sequence to an input method command (obsolete).
4448
4449     This function is obsolete.  Use minput_config_command () instead.
4450
4451     The minput_assign_command_keys () function assigns input key
4452     sequence $KEYSEQ to input method command $COMMAND for the input
4453     method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
4454     key sequence is assigned globally no matter what $LANGUAGE is.
4455     Otherwise the key sequence is assigned locally.
4456
4457     Each element of $KEYSEQ must have the key $Msymbol and the value
4458     must be a symbol representing an input key.
4459
4460     $KEYSEQ may be @c NULL, in which case, all assignments are deleted
4461     globally or locally.
4462
4463     This assignment gets effective in a newly opened input method.
4464
4465     @return
4466     If the operation was successful, 0 is returned.  Otherwise -1 is
4467     returned, and #merror_code is set to #MERROR_IM.  */
4468 /***ja
4469     @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
4470
4471     ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
4472     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
4473     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
4474     $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
4475     ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
4476
4477     $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
4478     ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4479
4480     $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
4481     ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
4482
4483     ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
4484     ¸ú¤Ë¤Ê¤ë¡£
4485
4486     @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
4487     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
4488
4489 int
4490 minput_assign_command_keys (MSymbol language, MSymbol name,
4491                             MSymbol command, MPlist *keyseq)
4492 {
4493   int ret;
4494
4495   MINPUT__INIT ();
4496
4497   if (command == Mnil)
4498     MERROR (MERROR_IM, -1);
4499   if (keyseq)
4500     {
4501       MPlist *plist;
4502
4503       if  (! check_command_keyseq (keyseq))
4504         MERROR (MERROR_IM, -1);
4505       plist = mplist ();
4506       mplist_add (plist, Mplist, keyseq);
4507       keyseq = plist;
4508     }  
4509   else
4510     keyseq = mplist ();
4511   ret = minput_config_command (language, name, command, keyseq);
4512   M17N_OBJECT_UNREF (keyseq);
4513   return ret;
4514 }
4515
4516 MPlist *
4517 minput_get_command (MSymbol language, MSymbol name, MSymbol command)
4518 {
4519   MInputMethodInfo *im_info;
4520
4521   MINPUT__INIT ();
4522
4523   im_info = get_im_info (language, name, Mnil, Mcommand);
4524   if (! im_info || ! im_info->configured_cmds)
4525     return NULL;
4526   if (command == Mnil)
4527     return im_info->configured_cmds;
4528   return mplist__assq (im_info->configured_cmds, command);
4529 }
4530
4531 #if EXAMPLE_CODE
4532 /* Return a description of the command COMMAND of the input method
4533    specified by LANGUAGE and NAME.  */
4534 MText *
4535 get_im_command_help (MSymbol language, MSymbol name, MSymbol command)
4536 {
4537   MPlist *cmd = minput_get_command (langauge, name, command);
4538   MPlist *plist;
4539
4540   if (! cmds)
4541     return NULL;
4542   plist = mplist_value (cmds);  /* (NAME DESCRIPTION KEY-SEQ ...) */
4543   plist = mplist_next (plist);  /* (DESCRIPTION KEY-SEQ ...) */
4544   return (MText *) mplist_value (list);
4545 }
4546 #endif
4547
4548 /***en
4549     @brief Configure the key sequence of an input method command.
4550
4551     The minput_config_command () function assigns list of key
4552     sequences $KEYSEQ-LIST to the command $COMMAND for the input
4553     method specified by $LANGUAGE and $NAME.
4554
4555     If $KEYSEQ-LIST is a non-empty plist, it must be a list of key
4556     sequences, and each key sequence must be a plist of key symbols.
4557
4558     If $KEYSEQ is an empty plist, the command become unusable.
4559
4560     If $KEYSEQ is NULL, all configulations of the command for the
4561     input method are canceled, and the default key sequences become
4562     effective.  In that case, if $COMMAND is #Mnil, configurations for
4563     all commands of the input method are canceled.
4564
4565     If $NAME is #Mnil, this function configure the global key sequence
4566     assignments, not that of a specific input method.
4567
4568     The configulation (or the cancelling) takes effect instantly for
4569     the current session even for already opened input methods.  To
4570     make the configulation take effect for the future session, it must
4571     be saved in a per-user customization file by the function
4572     minput_save_config ().
4573
4574     @return
4575     If the operation was successful, this function returns 0,
4576     otherwise returns -1.  The operation fails in these cases:
4577
4578     $KEYSEQ is not in a valid form.
4579
4580     $COMMAND is not available for the input method.
4581
4582     $LANGUAGE and $NAME don't specify an existing input method.
4583
4584     @seealso
4585     minput_get_commands (), minput_save_config ().  */
4586
4587 int
4588 minput_config_command (MSymbol language, MSymbol name, MSymbol command,
4589                        MPlist *keyseq)
4590 {
4591   MInputMethodInfo *im_info, *config;
4592   MPlist *plist;
4593
4594   MINPUT__INIT ();
4595
4596   if (keyseq && ! check_command_keyseq (keyseq))
4597     MERROR (MERROR_IM, -1);
4598   im_info = get_im_info (language, name, Mnil, Mcommand);
4599   if (! im_info)
4600     MERROR (MERROR_IM, -1);
4601   if (command == Mnil)
4602     {
4603       if (keyseq)
4604         MERROR (MERROR_IM, -1);
4605     }
4606   else if (! im_info->cmds
4607            || ! mplist__assq (im_info->cmds, command))
4608     MERROR (MERROR_IM, -1);
4609
4610   config = get_config_info (im_info);
4611   if (! config)
4612     {
4613       if (! im_config_list)
4614         im_config_list = mplist ();
4615       config = new_im_info (NULL, language, name, Mnil, im_config_list);
4616       config->cmds = mplist ();
4617       config->vars = mplist ();
4618     }
4619
4620   if (command == Mnil)
4621     {
4622       MInputMethodInfo *custom = get_custom_info (im_info);
4623
4624       mplist_set (config->cmds, Mnil, NULL);
4625       if (custom && custom->cmds)
4626         {
4627           MPLIST_DO (plist, custom->cmds)
4628             {
4629               command = MPLIST_SYMBOL (MPLIST_PLIST (plist));
4630               plist = mplist ();
4631               mplist_add (plist, Msymbol, command);
4632               mplist_push (config->cmds, Mplist, plist);
4633               M17N_OBJECT_UNREF (plist);
4634             }
4635         }
4636     }
4637   else
4638     {
4639       plist = mplist__assq (config->cmds, command);
4640       if (plist)
4641         {
4642           plist = MPLIST_PLIST (plist); /* (NAME DESC KEY-SEQUENCE ...)  */
4643           plist = MPLIST_NEXT (plist);  /* (DESC ...) */
4644           mplist_set (plist, Mnil, NULL);
4645         }
4646       else
4647         {
4648           plist = mplist ();
4649           mplist_push (config->cmds, Mplist, plist);
4650           M17N_OBJECT_UNREF (plist);
4651           plist = mplist_add (plist, Msymbol, command);
4652         }
4653       if (keyseq)
4654         {
4655           MPlist *pl, *p;
4656
4657           keyseq = mplist_copy (keyseq);
4658           MPLIST_DO (pl, keyseq)
4659             {
4660               p = mplist_copy (MPLIST_VAL (pl));
4661               mplist_set (pl, Mplist, p);
4662               M17N_OBJECT_UNREF (p);
4663             }
4664           plist = mplist_add (plist, Msymbol, Mnil);
4665           mplist__conc (plist, keyseq);
4666           M17N_OBJECT_UNREF (keyseq);
4667         }
4668     }
4669   config_commands (im_info);
4670   im_info->tick = time (NULL);
4671   return 0;
4672 }
4673
4674 #if EXAMPLE_CODE
4675 /* Add "C-x u" to the "start" command of Unicode input method.  */
4676 {
4677   MSymbol start_command = msymbol ("start");
4678   MSymbol unicode = msymbol ("unicode");
4679   MPlist *cmd, *plist, *key_seq_list, *key_seq;
4680
4681   /* At first get the current key-sequence assignment.  */
4682   cmd = mplist_get_command (Mt, unicode, start_command);
4683   if (! cmd)
4684     {
4685       /* The input method doesn't have the command "start".  Here
4686          comes some error handling code.  */
4687     }
4688   /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...).  Extract
4689      the part (KEY-SEQUENCE ...).  */
4690   plist = mplist_next (mplist_next (mplist_value (cmd)));
4691   /* Copy it because we should not modify it directly.  */
4692   key_seq_list = mplist_copy (plist);
4693   m17n_object_unref (cmds);
4694   
4695   key_seq = mplist ();
4696   mplist_add (key_seq, Msymbol, msymbol ("C-x"));
4697   mplist_add (key_seq, Msymbo, msymbol ("u"));
4698   mplist_add (key_seq_list, Mplist, key_seq);
4699   m17n_object_unref (key_seq);
4700
4701   minput_config_command (Mt, unicode, start_command, key_seq_list);
4702   m17n_object_unref (key_seq_list);
4703 }
4704 #endif
4705
4706 /***en
4707     @brief Get a list of variables of an input method (obsolete).
4708
4709     This function is obsolete.  Use minput_get_variable () instead.
4710
4711     The minput_get_variables () function returns a plist (#MPlist) of
4712     variables used to control the behavior of the input method
4713     specified by $LANGUAGE and $NAME.  The plist is @e well-formed
4714     (#m17nPlist) of the following format:
4715
4716 @verbatim
4717     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4718      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4719      ...)
4720 @endverbatim
4721
4722     @c VARNAME is a symbol representing the variable name.
4723
4724     @c DOC-MTEXT is an M-text describing the variable.
4725
4726     @c DEFAULT-VALUE is the default value of the variable.  It is a
4727     symbol, integer, or M-text.
4728
4729     @c VALUEs (if any) specifies the possible values of the variable.
4730     If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
4731     @c TO), where @c FROM and @c TO specifies a range of possible
4732     values.
4733
4734     For instance, suppose an input method has the variables:
4735
4736     @li name:intvar, description:"value is an integer",
4737          initial value:0, value-range:0..3,10,20
4738
4739     @li name:symvar, description:"value is a symbol",
4740          initial value:nil, value-range:a, b, c, nil
4741
4742     @li name:txtvar, description:"value is an M-text",
4743          initial value:empty text, no value-range (i.e. any text)
4744
4745     Then, the returned plist is as follows.
4746
4747 @verbatim
4748     (intvar ("value is an integer" 0 (0 3) 10 20)
4749      symvar ("value is a symbol" nil a b c nil)
4750      txtvar ("value is an M-text" ""))
4751 @endverbatim
4752
4753     @return
4754     If the input method uses any variables, a pointer to #MPlist is
4755     returned.  As the plist is kept in the library, the caller must not
4756     modify nor free it.  If the input method does not use any
4757     variable, @c NULL is returned.  */
4758 /***ja
4759     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
4760
4761     ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
4762     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
4763     (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
4764     ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
4765
4766 @verbatim
4767     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4768      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4769      ...)
4770 @endverbatim
4771
4772     @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
4773
4774     @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
4775
4776     @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
4777     M-text ¤Ç¤¢¤ë¡£
4778
4779     @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
4780     @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
4781     ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
4782
4783     Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
4784
4785     @li name:intvar, ÀâÌÀ:"value is an integer",
4786         ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
4787
4788     @li name:symvar, ÀâÌÀ:"value is a symbol",
4789          ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
4790
4791     @li name:txtvar, ÀâÌÀ:"value is an M-text",
4792         ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
4793
4794     ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
4795
4796 @verbatim
4797     (intvar ("value is an integer" 0 (0 3) 10 20)
4798      symvar ("value is a symbol" nil a b c nil)
4799      txtvar ("value is an M-text" ""))
4800 @endverbatim
4801
4802     @return 
4803     ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
4804     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4805     ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
4806
4807 MPlist *
4808 minput_get_variables (MSymbol language, MSymbol name)
4809 {
4810   MInputMethodInfo *im_info;
4811   MPlist *vars;
4812
4813   MINPUT__INIT ();
4814
4815   im_info = get_im_info (language, name, Mnil, Mvariable);
4816   if (! im_info || ! im_info->configured_vars)
4817     return NULL;
4818
4819   M17N_OBJECT_UNREF (im_info->bc_vars);
4820   im_info->bc_vars = mplist ();
4821   MPLIST_DO (vars, im_info->configured_vars)
4822     {
4823       MPlist *plist = MPLIST_PLIST (vars);
4824       MPlist *elt = mplist ();
4825
4826       mplist_push (im_info->bc_vars, Mplist, elt);
4827       mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
4828       elt = MPLIST_NEXT (elt);
4829       mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
4830       M17N_OBJECT_UNREF (elt);
4831     }
4832   return im_info->bc_vars;
4833 }
4834
4835 /***en
4836     @brief Set the initial value of an input method variable.
4837
4838     The minput_set_variable () function sets the initial value of
4839     input method variable $VARIABLE to $VALUE for the input method
4840     specified by $LANGUAGE and $NAME.
4841
4842     By default, the initial value is 0.
4843
4844     This setting gets effective in a newly opened input method.
4845
4846     @return
4847     If the operation was successful, 0 is returned.  Otherwise -1 is
4848     returned, and #merror_code is set to #MERROR_IM.  */
4849 /***ja
4850     @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
4851
4852     ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
4853     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
4854     ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
4855
4856     ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
4857
4858     ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
4859
4860     @return
4861     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
4862     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
4863
4864 int
4865 minput_set_variable (MSymbol language, MSymbol name,
4866                      MSymbol variable, void *value)
4867 {
4868   MPlist *plist, *pl;
4869   MInputMethodInfo *im_info;
4870   int ret;
4871
4872   MINPUT__INIT ();
4873
4874   if (variable == Mnil)
4875     MERROR (MERROR_IM, -1);
4876   plist = minput_get_variable (language, name, variable);
4877   plist = MPLIST_PLIST (plist);
4878   plist = MPLIST_NEXT (plist);
4879   pl = mplist ();
4880   mplist_add (pl, MPLIST_KEY (plist), value);
4881   ret = minput_config_variable (language, name, variable, pl);
4882   M17N_OBJECT_UNREF (pl);
4883   if (ret == 0)
4884     {
4885       im_info = get_im_info (language, name, Mnil, Mvariable);
4886       im_info->tick = 0;
4887     }
4888   return ret;
4889 }
4890
4891 MPlist *
4892 minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
4893 {
4894   MInputMethodInfo *im_info;
4895
4896   MINPUT__INIT ();
4897
4898   im_info = get_im_info (language, name, Mnil, Mvariable);
4899   if (! im_info || ! im_info->configured_vars)
4900     return NULL;
4901   if (variable == Mnil)
4902     return im_info->configured_vars;
4903   return mplist__assq (im_info->configured_vars, variable);
4904 }
4905
4906 /***en
4907     @brief Configure the value of an input method variable.
4908
4909     The minput_config_variable () function assigns the value $VALUE to
4910     the variable $VARIABLE of the input method specified by $LANGUAGE
4911     and $NAME.
4912
4913     If $VALUE is not NULL, it must be a plist of one element whose key
4914     is #Minteger, #Msymbol, or #Mtext, and the value is of the
4915     corresponding type.
4916
4917     If $VALUE is NULL, configurations for the variable done in the
4918     current session are canceled (except for what saved by
4919     minput_save_config ()).  In that case, if $VARIABLE is #Mnil,
4920     configurations for all variables are canceled.
4921
4922     If $NAME is #Mnil, this function configure the global value, not
4923     that of a specific input method.
4924
4925     The configulation takes effect instantly for the current session
4926     even for already opened input methods.  To make the configulation
4927     take effect for the future session, it must be saved in a per-user
4928     customization file by the function minput_save_config ().
4929
4930     @return If the operation was successful, this function returns 0,
4931     otherwise returns -1.  The operation fails in these cases:
4932
4933     $VALUE is not in a valid form, or the type doesn't much the
4934     definition.
4935
4936     $VARIABLE is not available for the input method.
4937
4938     $LANGUAGE and $NAME don't specify an existing input method.  
4939
4940     @seealso
4941     minput_get_variables (), minput_save_config ().  */
4942
4943 int
4944 minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
4945                         MPlist *value)
4946 {
4947   MInputMethodInfo *im_info, *config;
4948   MPlist *plist;
4949
4950   MINPUT__INIT ();
4951
4952   im_info = get_im_info (language, name, Mnil, Mvariable);
4953   if (! im_info)
4954     MERROR (MERROR_IM, -1);
4955   if (variable == Mnil)
4956     {
4957       if (value)
4958         MERROR (MERROR_IM, -1);
4959     }
4960   else if (! im_info->vars
4961            || ! mplist__assq (im_info->vars, variable))
4962     MERROR (MERROR_IM, -1);
4963
4964   config = get_config_info (im_info);
4965   if (! config)
4966     {
4967       if (! im_config_list)
4968         im_config_list = mplist ();
4969       config = new_im_info (NULL, language, name, Mnil, im_config_list);
4970       config->cmds = mplist ();
4971       config->vars = mplist ();
4972     }
4973
4974   if (variable == Mnil)
4975     {
4976       MInputMethodInfo *custom = get_custom_info (im_info);
4977
4978       mplist_set (config->vars, Mnil, NULL);
4979       if (custom && custom->cmds)
4980         {
4981           MPLIST_DO (plist, custom->vars)
4982             {
4983               variable = MPLIST_SYMBOL (MPLIST_PLIST (plist));
4984               plist = mplist ();
4985               mplist_add (plist, Msymbol, variable);
4986               mplist_push (config->vars, Mplist, plist);
4987               M17N_OBJECT_UNREF (plist);
4988             }
4989         }
4990     }
4991   else
4992     {
4993       plist = mplist__assq (config->vars, variable);
4994       if (plist)
4995         {
4996           plist = MPLIST_PLIST (plist); /* (NAME DESC VALUE) */
4997           plist = MPLIST_NEXT (plist);  /* (DESC VALUE) */
4998           mplist_set (plist, Mnil ,NULL);
4999         }
5000       else
5001         {
5002           plist = mplist ();
5003           mplist_add (config->vars, Mplist, plist);
5004           M17N_OBJECT_UNREF (plist);
5005           plist = mplist_add (plist, Msymbol, variable);
5006         }
5007       if (value)
5008         {
5009           plist = mplist_add (plist, Msymbol, Mnil);
5010           plist = MPLIST_NEXT (plist);
5011           mplist_set (plist, MPLIST_KEY (value), MPLIST_VAL (value));
5012         }
5013     }
5014   config_variables (im_info);
5015   im_info->tick = time (NULL);
5016   return 0;
5017 }
5018
5019 char *
5020 minput_config_file ()
5021 {
5022   MINPUT__INIT ();
5023   return mdatabase__file (im_custom_mdb);
5024 }
5025
5026 int
5027 minput_save_config (void)
5028 {
5029   MPlist *data, *tail, *plist, *p, *elt;
5030   int ret;
5031
5032   MINPUT__INIT ();
5033   ret = mdatabase__lock (im_custom_mdb);
5034   if (ret <= 0)
5035     return ret;
5036   if (! im_config_list)
5037     return 1;
5038   update_custom_info ();
5039   if (! im_custom_list)
5040     im_custom_list = mplist ();
5041   data = tail = mplist ();
5042
5043   MPLIST_DO (plist, im_config_list)
5044     {
5045       MPlist *pl = MPLIST_PLIST (plist);
5046       MSymbol language, name, extra, command, variable;
5047       MInputMethodInfo *custom, *config;
5048
5049       language = MPLIST_SYMBOL (pl);
5050       pl = MPLIST_NEXT (pl);
5051       name = MPLIST_SYMBOL (pl);
5052       pl = MPLIST_NEXT (pl);
5053       extra = MPLIST_SYMBOL (pl);
5054       pl = MPLIST_NEXT (pl);
5055       config = MPLIST_VAL (pl);
5056       custom = get_custom_info (config);
5057       if (! custom)
5058         custom = new_im_info (NULL, language, name, extra, im_custom_list);
5059       if (config->cmds)
5060         MPLIST_DO (pl, config->cmds)
5061           {
5062             elt = MPLIST_PLIST (pl);
5063             command = MPLIST_SYMBOL (elt);
5064             if (custom->cmds)
5065               p = mplist__assq (custom->cmds, command);
5066             else
5067               custom->cmds = mplist (), p = NULL;
5068             elt = MPLIST_NEXT (elt);
5069             if (MPLIST_TAIL_P (elt))
5070               {
5071                 if (p)
5072                   mplist__pop_unref (p);
5073               }
5074             else
5075               {
5076                 elt = MPLIST_NEXT (elt);
5077                 if (p)
5078                   {
5079                     p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5080                     mplist_set (p, Mnil, NULL);
5081                     mplist__conc (p, elt);
5082                   }
5083                 else
5084                   {
5085                     p = MPLIST_PLIST (pl);
5086                     mplist_add (custom->cmds, Mplist, p);
5087                   }
5088               }
5089           }
5090       if (config->vars)
5091         MPLIST_DO (pl, config->vars)
5092           {
5093             elt = MPLIST_PLIST (pl);
5094             variable = MPLIST_SYMBOL (elt);
5095             if (custom->vars)
5096               p = mplist__assq (custom->vars, variable);
5097             else
5098               custom->vars = mplist (), p = NULL;
5099             elt = MPLIST_NEXT (elt);
5100             if (MPLIST_TAIL_P (elt))
5101               {
5102                 if (p)
5103                   mplist__pop_unref (p);
5104               }
5105             else
5106               {
5107                 elt = MPLIST_NEXT (elt);
5108                 if (p)
5109                   {
5110                     p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5111                     mplist_set (p, Mnil, NULL);
5112                     mplist__conc (p, elt);
5113                   }
5114                 else
5115                   {
5116                     p = MPLIST_PLIST (pl);
5117                     mplist_add (custom->vars, Mplist, p);
5118                   }
5119               }
5120           }
5121     }
5122   M17N_OBJECT_UNREF (im_config_list);
5123
5124   MPLIST_DO (plist, im_custom_list)
5125     {
5126       MPlist *pl = MPLIST_PLIST (plist);
5127       MSymbol language, name, extra;
5128       MInputMethodInfo *custom;
5129
5130       language = MPLIST_SYMBOL (pl);
5131       pl  = MPLIST_NEXT (pl);
5132       name = MPLIST_SYMBOL (pl);
5133       pl = MPLIST_NEXT (pl);
5134       extra = MPLIST_SYMBOL (pl);
5135       pl = MPLIST_NEXT (pl);
5136       custom = MPLIST_VAL (pl);
5137       
5138       elt = mplist ();
5139       tail = mplist_add (tail, Mplist, elt);
5140       M17N_OBJECT_UNREF (elt);
5141       pl = mplist ();
5142       elt = mplist_add (elt, Mplist, pl);
5143       M17N_OBJECT_UNREF (pl);
5144       pl = mplist_add (pl, Msymbol, Minput_method);
5145       pl = mplist_add (pl, Msymbol, language);
5146       pl = mplist_add (pl, Msymbol, name);
5147       if (extra != Mnil)
5148         pl = mplist_add (pl, Msymbol, extra);
5149       if (custom->cmds && ! MPLIST_TAIL_P (custom->cmds))
5150         {
5151           pl = mplist ();
5152           elt = mplist_add (elt, Mplist, pl);
5153           M17N_OBJECT_UNREF (pl);
5154           pl = mplist_add (pl, Msymbol, Mcommand);
5155           MPLIST_DO (p, custom->cmds)
5156             pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5157         }
5158       if (custom->vars && ! MPLIST_TAIL_P (custom->vars))
5159         {
5160           pl = mplist ();
5161           elt = mplist_add (elt, Mplist, pl);
5162           M17N_OBJECT_UNREF (pl);
5163           pl = mplist_add (pl, Msymbol, Mvariable);
5164           MPLIST_DO (p, custom->vars)
5165             pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5166         }
5167     }
5168
5169   mplist_push (data, Msymbol, msymbol (";;-*-lisp-*-"));
5170   ret = mdatabase__save (im_custom_mdb, data);
5171   M17N_OBJECT_UNREF (data);
5172   mdatabase__unlock (im_custom_mdb);
5173   return (ret < 0 ? -1 : 1);
5174 }
5175
5176
5177 /*** @} */
5178 /*=*/
5179 /*** @addtogroup m17nDebug */
5180 /*=*/
5181 /*** @{  */
5182 /*=*/
5183
5184 /***en
5185     @brief Dump an input method.
5186
5187     The mdebug_dump_im () function prints the input method $IM in a
5188     human readable way to the stderr.  $INDENT specifies how many
5189     columns to indent the lines but the first one.
5190
5191     @return
5192     This function returns $IM.  */
5193 /***ja
5194     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
5195
5196     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
5197     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
5198
5199     @return
5200     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
5201
5202 MInputMethod *
5203 mdebug_dump_im (MInputMethod *im, int indent)
5204 {
5205   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
5206   char *prefix;
5207
5208   prefix = (char *) alloca (indent + 1);
5209   memset (prefix, 32, indent);
5210   prefix[indent] = '\0';
5211
5212   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
5213            msymbol_name (im->name));
5214   mdebug_dump_mtext (im_info->title, 0, 0);
5215   if (im->name != Mnil)
5216     {
5217       MPlist *state;
5218
5219       MPLIST_DO (state, im_info->states)
5220         {
5221           fprintf (stderr, "\n%s  ", prefix);
5222           dump_im_state (MPLIST_VAL (state), indent + 2);
5223         }
5224     }
5225   fprintf (stderr, ")");
5226   return im;
5227 }
5228
5229 /*** @} */ 
5230
5231 /*
5232   Local Variables:
5233   coding: euc-japan
5234   End:
5235 */