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