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