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