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