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