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