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