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