(Mpop): New variable.
[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 = MPLIST_NEXT (config);
1782     }
1783   else if (custom_cmds && (custom = mplist__assq (custom_cmds, name)))
1784     {
1785       custom = MPLIST_NEXT (MPLIST_PLIST (custom));
1786       if (! MPLIST_TAIL_P (custom))
1787         {
1788           status = Mcustomized;
1789           keyseq = MPLIST_NEXT (custom);
1790         }
1791     }
1792   
1793   plist = mplist ();
1794   mplist_add (plist, Msymbol, name);
1795   if (description)
1796     mplist_add (plist, MPLIST_KEY (description), MPLIST_VAL (description));
1797   else
1798     mplist_add (plist, Msymbol, Mnil);
1799   mplist_add (plist, Msymbol, status);
1800   mplist__conc (plist, keyseq);
1801   return plist;
1802 }
1803
1804 static void
1805 config_all_commands (MInputMethodInfo *im_info)
1806 {
1807   MPlist *global_cmds, *custom_cmds, *config_cmds;
1808   MInputMethodInfo *temp;
1809   MPlist *tail, *plist;
1810
1811   M17N_OBJECT_UNREF (im_info->configured_cmds);
1812
1813   if (MPLIST_TAIL_P (im_info->cmds)
1814       || ! im_info->mdb)
1815     return;
1816
1817   global_cmds = im_info != global_info ? global_info->cmds : NULL;
1818   custom_cmds = ((temp = get_custom_info (im_info)) ? temp->cmds : NULL);
1819   config_cmds = ((temp = get_config_info (im_info)) ? temp->cmds : NULL);
1820
1821   im_info->configured_cmds = tail = mplist ();
1822   MPLIST_DO (plist, im_info->cmds)
1823     {
1824       MPlist *pl = config_command (MPLIST_PLIST (plist),
1825                                    global_cmds, custom_cmds, config_cmds);
1826       if (pl)
1827         {
1828           tail = mplist_add (tail, Mplist, pl);
1829           M17N_OBJECT_UNREF (pl);
1830         }
1831     }
1832 }
1833
1834 /* Check VAL's value against VALID_VALUES, and return 1 if it is
1835    valid, return 0 if not.  */
1836
1837 static int
1838 check_variable_value (MPlist *val, MPlist *global)
1839 {
1840   MSymbol type = MPLIST_KEY (val);
1841   MPlist *valids = MPLIST_NEXT (val);
1842
1843   if (type != Minteger && type != Mtext && type != Msymbol)
1844     return 0;
1845   if (global)
1846     {
1847       if (MPLIST_KEY (global) != Mt
1848           && MPLIST_KEY (global) != MPLIST_KEY (val))
1849         return 0;
1850       if (MPLIST_TAIL_P (valids))
1851         valids = MPLIST_NEXT (global);
1852     }
1853   if (MPLIST_TAIL_P (valids))
1854     return 1;
1855
1856   if (type == Minteger)
1857     {
1858       int n = MPLIST_INTEGER (val);
1859
1860       MPLIST_DO (valids, valids)
1861         {
1862           if (MPLIST_INTEGER_P (valids))
1863             {
1864               if (n == MPLIST_INTEGER (valids))
1865                 break;
1866             }
1867           else if (MPLIST_PLIST_P (valids))
1868             {
1869               MPlist *p = MPLIST_PLIST (valids);
1870               int min_bound, max_bound;
1871
1872               if (! MPLIST_INTEGER_P (p))
1873                 MERROR (MERROR_IM, 0);
1874               min_bound = MPLIST_INTEGER (p);
1875               p = MPLIST_NEXT (p);
1876               if (! MPLIST_INTEGER_P (p))
1877                 MERROR (MERROR_IM, 0);
1878               max_bound = MPLIST_INTEGER (p);
1879               if (n >= min_bound && n <= max_bound)
1880                 break;
1881             }
1882         }
1883     }
1884   else if (type == Msymbol)
1885     {
1886       MSymbol sym = MPLIST_SYMBOL (val);
1887
1888       MPLIST_DO (valids, valids)
1889         {
1890           if (! MPLIST_SYMBOL_P (valids))
1891             MERROR (MERROR_IM, 0);
1892           if (sym == MPLIST_SYMBOL (valids))
1893             break;
1894         }
1895     }
1896   else
1897     {
1898       MText *mt = MPLIST_MTEXT (val);
1899
1900       MPLIST_DO (valids, valids)
1901         {
1902           if (! MPLIST_MTEXT_P (valids))
1903             MERROR (MERROR_IM, 0);
1904           if (mtext_cmp (mt, MPLIST_MTEXT (valids)) == 0)
1905             break;
1906         }
1907     }
1908
1909   return (! MPLIST_TAIL_P (valids));
1910 }
1911
1912 /* Load variable defitions from PLIST into IM_INFO->vars.
1913
1914    PLIST is well-formed and has this form;
1915      ((NAME [DESCRIPTION DEFAULT-VALUE VALID-VALUE ...])
1916       ...)
1917    NAME is a symbol.  DESCRIPTION is an M-text or `nil'.
1918
1919    The returned list has the same form, but for each element...
1920
1921    (1) If DESCRIPTION and the rest are omitted, the element is not
1922    stored in the returned list.
1923
1924    (2) If DESCRIPTION is nil, it is complemented by the corresponding
1925    description in global_info->vars (if any).  */
1926
1927 static void
1928 load_variables (MInputMethodInfo *im_info, MPlist *plist)
1929 {
1930   MPlist *global_vars = ((im_info->mdb && im_info != global_info)
1931                          ? global_info->vars : NULL);
1932   MPlist *tail;
1933
1934   im_info->vars = tail = mplist ();
1935   MPLIST_DO (plist, MPLIST_NEXT (plist))
1936     {
1937       MPlist *pl, *p;
1938
1939       if (MFAILP (MPLIST_PLIST_P (plist)))
1940         continue;
1941       pl = MPLIST_PLIST (plist); /* PL ::= (NAME DESC VALUE VALID ...) */
1942       if (MFAILP (MPLIST_SYMBOL_P (pl)))
1943         continue;
1944       if (im_info == global_info)
1945         {
1946           /* Loading a global variable.  */
1947           p = MPLIST_NEXT (pl);
1948           if (MPLIST_TAIL_P (p))
1949             mplist_add (p, Msymbol, Mnil);
1950           else
1951             {
1952               if (! check_description (p))
1953                 mplist_set (p, Msymbol, Mnil);
1954               p = MPLIST_NEXT (p);
1955               if (MFAILP (! MPLIST_TAIL_P (p)
1956                           && check_variable_value (p, NULL)))
1957                 mplist_set (p, Mt, NULL);
1958             }
1959         }
1960       else if (im_info->mdb)
1961         {
1962           /* Loading a local variable.  */
1963           MSymbol name = MPLIST_SYMBOL (pl);
1964           MPlist *global = NULL;
1965
1966           if (global_vars
1967               && (p = mplist__assq (global_vars, name)))
1968             {
1969               /* P ::= ((NAME DESC ...) ...) */
1970               p = MPLIST_PLIST (p); /* P ::= (NAME DESC ...) */
1971               global = MPLIST_NEXT (p); /* P ::= (DESC VALUE ...) */
1972               global = MPLIST_NEXT (global); /* P ::= (VALUE ...) */
1973             }
1974
1975           p = MPLIST_NEXT (pl); /* P ::= (DESC VALUE VALID ...) */
1976           if (! MPLIST_TAIL_P (p))
1977             {
1978               if (! check_description (p))
1979                 mplist_set (p, Msymbol, Mnil);
1980               p = MPLIST_NEXT (p); /* P ::= (VALUE VALID ...) */
1981               if (MFAILP (! MPLIST_TAIL_P (p)))
1982                 mplist_set (p, Mt, NULL);
1983               else
1984                 {
1985                   MPlist *valid_values = MPLIST_NEXT (p);
1986
1987                   if (! MPLIST_TAIL_P (valid_values)
1988                       ? MFAILP (check_variable_value (p, NULL))
1989                       : global && MFAILP (check_variable_value (p, global)))
1990                     mplist_set (p, Mt, NULL);
1991                 }
1992             }
1993         }
1994       else
1995         {
1996           /* Loading a variable customization.  */
1997           p = MPLIST_NEXT (pl); /* P ::= (nil VALUE) */
1998           if (MFAILP (! MPLIST_TAIL_P (p)))
1999             continue;
2000           p = MPLIST_NEXT (p);  /* P ::= (VALUE) */
2001           if (MFAILP (MPLIST_INTEGER_P (p) || MPLIST_SYMBOL_P (p)
2002                       || MPLIST_MTEXT_P (p)))
2003             continue;
2004         }
2005       tail = mplist_add (tail, Mplist, pl);
2006     }
2007 }
2008
2009 static MPlist *
2010 config_variable (MPlist *plist, MPlist *global_vars, MPlist *custom_vars,
2011                  MPlist *config_vars)
2012 {
2013   MPlist *global = NULL, *custom = NULL, *config = NULL;
2014   MSymbol name = MPLIST_SYMBOL (plist);
2015   MSymbol status;
2016   MPlist *description = NULL, *value, *valids;
2017
2018   if (global_vars)
2019     {
2020       global = mplist__assq (global_vars, name);
2021       if (global)
2022         global = MPLIST_NEXT (MPLIST_PLIST (global)); /* (DESC VALUE ...) */
2023     }
2024
2025   plist = MPLIST_NEXT (plist);
2026   if (MPLIST_MTEXT_P (plist) || MPLIST_PLIST_P (plist))
2027     description = plist;
2028   else if (global)
2029     description = global;
2030   if (global)
2031     global = MPLIST_NEXT (global); /* (VALUE VALIDS ...) */
2032
2033   if (MPLIST_TAIL_P (plist))
2034     {
2035       /* Inherit from global (if any).  */
2036       if (global)
2037         {
2038           value = global;
2039           if (MPLIST_KEY (value) == Mt)
2040             value = NULL;
2041           valids = MPLIST_NEXT (global);
2042           status = Minherited;
2043         }
2044       else
2045         {
2046           value = NULL;
2047           valids = NULL;
2048           status = Mnil;
2049           plist = NULL;
2050         }
2051     }
2052   else
2053     {
2054       value = plist = MPLIST_NEXT (plist);
2055       valids = MPLIST_NEXT (value);
2056       if (MPLIST_KEY (value) == Mt)
2057         value = NULL;
2058       if (! MPLIST_TAIL_P (valids))
2059         global = NULL;
2060       else if (global)
2061         valids = MPLIST_NEXT (global);
2062       status = Mnil;
2063     }
2064
2065   if (config_vars && (config = mplist__assq (config_vars, name)))
2066     {
2067       status = Mconfigured;
2068       config = MPLIST_NEXT (MPLIST_PLIST (config));
2069       if (! MPLIST_TAIL_P (config))
2070         {
2071           value = MPLIST_NEXT (config);
2072           if (MFAILP (check_variable_value (value, global ? global : plist)))
2073             value = NULL;
2074         }
2075     }
2076   else if (custom_vars && (custom = mplist__assq (custom_vars, name)))
2077     {
2078       custom = MPLIST_NEXT (MPLIST_PLIST (custom));
2079       if (! MPLIST_TAIL_P (custom))
2080         {
2081           value = MPLIST_NEXT (custom);
2082           if (MFAILP (check_variable_value (value, global ? global : plist)))
2083             value = NULL;
2084           status = Mcustomized;
2085         }
2086     }
2087   
2088   plist = mplist ();
2089   mplist_add (plist, Msymbol, name);
2090   if (description)
2091     mplist_add (plist, MPLIST_KEY (description), MPLIST_VAL (description));
2092   else
2093     mplist_add (plist, Msymbol, Mnil);
2094   mplist_add (plist, Msymbol, status);
2095   if (value)
2096     mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value));
2097   else
2098     mplist_add (plist, Mt, NULL);
2099   if (valids && ! MPLIST_TAIL_P (valids))
2100     mplist__conc (plist, valids);
2101   return plist;
2102 }
2103
2104 /* Return a configured variable definition list based on
2105    IM_INFO->vars.  If a variable in it doesn't contain a value, try to
2106    get it from global_info->vars.  */
2107
2108 static void
2109 config_all_variables (MInputMethodInfo *im_info)
2110 {
2111   MPlist *global_vars, *custom_vars, *config_vars;
2112   MInputMethodInfo *temp;
2113   MPlist *tail, *plist;
2114
2115   M17N_OBJECT_UNREF (im_info->configured_vars);
2116
2117   if (MPLIST_TAIL_P (im_info->vars)
2118       || ! im_info->mdb)
2119     return;
2120
2121   global_vars = im_info != global_info ? global_info->vars : NULL;
2122   custom_vars = ((temp = get_custom_info (im_info)) ? temp->vars : NULL);
2123   config_vars = ((temp = get_config_info (im_info)) ? temp->vars : NULL);
2124
2125   im_info->configured_vars = tail = mplist ();
2126   MPLIST_DO (plist, im_info->vars)
2127     {
2128       MPlist *pl = config_variable (MPLIST_PLIST (plist),
2129                                     global_vars, custom_vars, config_vars);
2130       if (pl)
2131         {
2132           tail = mplist_add (tail, Mplist, pl);
2133           M17N_OBJECT_UNREF (pl);
2134         }
2135     }
2136 }
2137
2138 /* Load an input method (LANGUAGE NAME) from PLIST into IM_INFO.
2139    CONFIG contains configuration information of the input method.  */
2140
2141 static void
2142 load_im_info (MPlist *plist, MInputMethodInfo *im_info)
2143 {
2144   MPlist *pl, *p;
2145
2146   if (! im_info->cmds && (pl = mplist__assq (plist, Mcommand)))
2147     {
2148       load_commands (im_info, MPLIST_PLIST (pl));
2149       config_all_commands (im_info);
2150       pl = mplist_pop (pl);
2151       M17N_OBJECT_UNREF (pl);
2152     }
2153
2154   if (! im_info->vars && (pl = mplist__assq (plist, Mvariable)))
2155     {
2156       load_variables (im_info, MPLIST_PLIST (pl));
2157       config_all_variables (im_info);
2158       pl = mplist_pop (pl);
2159       M17N_OBJECT_UNREF (pl);
2160     }
2161
2162   MPLIST_DO (plist, plist)
2163     if (MPLIST_PLIST_P (plist))
2164       {
2165         MPlist *elt = MPLIST_PLIST (plist);
2166         MSymbol key;
2167
2168         if (MFAILP (MPLIST_SYMBOL_P (elt)))
2169           continue;
2170         key = MPLIST_SYMBOL (elt);
2171         if (key == Mtitle)
2172           {
2173             if (im_info->title)
2174               continue;
2175             elt = MPLIST_NEXT (elt);
2176             if (MFAILP (MPLIST_MTEXT_P (elt)))
2177               continue;
2178             im_info->title = MPLIST_MTEXT (elt);
2179             M17N_OBJECT_REF (im_info->title);
2180           }
2181         else if (key == Mmap)
2182           {
2183             pl = mplist__from_alist (MPLIST_NEXT (elt));
2184             if (MFAILP (pl))
2185               continue;
2186             if (! im_info->maps)
2187               im_info->maps = pl;
2188             else
2189               {
2190                 mplist__conc (im_info->maps, pl);
2191                 M17N_OBJECT_UNREF (pl);
2192               }
2193           }
2194         else if (key == Mmacro)
2195           {
2196             if (! im_info->macros)
2197               im_info->macros = mplist ();
2198             MPLIST_DO (elt, MPLIST_NEXT (elt))
2199               {
2200                 if (MFAILP (MPLIST_PLIST_P (elt)))
2201                   continue;
2202                 load_macros (im_info, MPLIST_PLIST (elt));
2203               }
2204           }
2205         else if (key == Mmodule)
2206           {
2207             if (! im_info->externals)
2208               im_info->externals = mplist ();
2209             MPLIST_DO (elt, MPLIST_NEXT (elt))
2210               {
2211                 if (MFAILP (MPLIST_PLIST_P (elt)))
2212                   continue;
2213                 load_external_module (im_info, MPLIST_PLIST (elt));
2214               }
2215           }
2216         else if (key == Mstate)
2217           {
2218             MPLIST_DO (elt, MPLIST_NEXT (elt))
2219               {
2220                 MIMState *state;
2221
2222                 if (MFAILP (MPLIST_PLIST_P (elt)))
2223                   continue;
2224                 pl = MPLIST_PLIST (elt);
2225                 if (! im_info->states)
2226                   im_info->states = mplist ();
2227                 state = load_state (im_info, MPLIST_PLIST (elt));
2228                 if (MFAILP (state))
2229                   continue;
2230                 mplist_put (im_info->states, state->name, state);
2231               }
2232           }
2233         else if (key == Minclude)
2234           {
2235             /* elt ::= include (tag1 tag2 ...) key item ... */
2236             MSymbol key;
2237             MInputMethodInfo *temp;
2238
2239             elt = MPLIST_NEXT (elt);
2240             if (MFAILP (MPLIST_PLIST_P (elt)))
2241               continue;
2242             temp = get_im_info_by_tags (MPLIST_PLIST (elt));
2243             if (MFAILP (temp))
2244               continue;
2245             elt = MPLIST_NEXT (elt);
2246             if (MFAILP (MPLIST_SYMBOL_P (elt)))
2247               continue;
2248             key = MPLIST_SYMBOL (elt);
2249             elt = MPLIST_NEXT (elt);
2250             if (key == Mmap)
2251               {
2252                 if (! temp->maps || MPLIST_TAIL_P (temp->maps))
2253                   continue;
2254                 if (! im_info->maps)
2255                   im_info->maps = mplist ();
2256                 MPLIST_DO (pl, temp->maps)
2257                   {
2258                     p = MPLIST_VAL (pl);
2259                     MPLIST_ADD_PLIST (im_info->maps, MPLIST_KEY (pl), p);
2260                     M17N_OBJECT_REF (p);
2261                   }
2262               }
2263             else if (key == Mmacro)
2264               {
2265                 if (! temp->macros || MPLIST_TAIL_P (temp->macros))
2266                   continue;
2267                 if (! im_info->macros)
2268                   im_info->macros = mplist ();
2269                 MPLIST_DO (pl, temp->macros)
2270                   {
2271                     p = MPLIST_VAL (pl);
2272                     MPLIST_ADD_PLIST (im_info->macros, MPLIST_KEY (pl), p);
2273                     M17N_OBJECT_REF (p);
2274                   }
2275               }
2276             else if (key == Mstate)
2277               {
2278                 if (! temp->states || MPLIST_TAIL_P (temp->states))
2279                   continue;
2280                 if (! im_info->states)
2281                   im_info->states = mplist ();
2282                 MPLIST_DO (pl, temp->states)
2283                   {
2284                     MIMState *state = MPLIST_VAL (pl);
2285
2286                     mplist_add (im_info->states, MPLIST_KEY (pl), state);
2287                     M17N_OBJECT_REF (state);
2288                   }
2289               }
2290           }
2291         else if (key == Mdescription)
2292           {
2293             if (im_info->description)
2294               continue;
2295             elt = MPLIST_NEXT (elt);
2296             if (! check_description (elt))
2297               continue;
2298             im_info->description = MPLIST_MTEXT (elt);
2299             M17N_OBJECT_REF (im_info->description);
2300           }
2301       }
2302   im_info->tick = time (NULL);
2303 }
2304
2305 \f
2306
2307 static int take_action_list (MInputContext *ic, MPlist *action_list);
2308 static void preedit_commit (MInputContext *ic);
2309
2310 static void
2311 shift_state (MInputContext *ic, MSymbol state_name)
2312 {
2313   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2314   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2315   MIMState *orig_state = ic_info->state, *state;
2316
2317   /* Find a state to shift to.  If not found, shift to the initial
2318      state.  */
2319   if (state_name == Mt)
2320     {
2321       if (! ic_info->prev_state)
2322         return;
2323       state = ic_info->prev_state;
2324     }
2325   else if (state_name == Mnil)
2326     {
2327       state = (MIMState *) MPLIST_VAL (im_info->states);
2328     }
2329   else
2330     {
2331       state = (MIMState *) mplist_get (im_info->states, state_name);
2332       if (! state)
2333         state = (MIMState *) MPLIST_VAL (im_info->states);
2334     }
2335
2336   MDEBUG_PRINT1 ("\n  [IM] (shift %s)", MSYMBOL_NAME (state->name));
2337
2338   /* Enter the new state.  */
2339   ic_info->state = state;
2340   ic_info->map = state->map;
2341   ic_info->state_key_head = ic_info->key_head;
2342   if (state == (MIMState *) MPLIST_VAL (im_info->states)
2343       && orig_state)
2344     /* We have shifted to the initial state.  */
2345     preedit_commit (ic);
2346   mtext_cpy (ic_info->preedit_saved, ic->preedit);
2347   ic_info->state_pos = ic->cursor_pos;
2348   if (state != orig_state)
2349     {
2350       if (state == (MIMState *) MPLIST_VAL (im_info->states))
2351         {
2352           /* Shifted to the initial state.  */
2353           ic_info->prev_state = NULL;
2354           M17N_OBJECT_UNREF (ic_info->vars_saved);
2355           ic_info->vars_saved = mplist_copy (ic_info->vars);
2356         }
2357       else
2358         ic_info->prev_state = orig_state;
2359
2360       if (state->title)
2361         ic->status = state->title;
2362       else
2363         ic->status = im_info->title;
2364       ic->status_changed = 1;
2365       if (ic_info->map == ic_info->state->map
2366           && ic_info->map->map_actions)
2367         {
2368           MDEBUG_PRINT (" init-actions:");
2369           take_action_list (ic, ic_info->map->map_actions);
2370         }
2371     }
2372 }
2373
2374 /* Find a candidate group that contains a candidate number INDEX from
2375    PLIST.  Set START_INDEX to the first candidate number of the group,
2376    END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
2377    candidate group number if they are non-NULL.  If INDEX is -1, find
2378    the last candidate group.  */
2379
2380 static MPlist *
2381 find_candidates_group (MPlist *plist, int index,
2382                        int *start_index, int *end_index, int *group_index)
2383 {
2384   int i = 0, gidx = 0, len;
2385
2386   MPLIST_DO (plist, plist)
2387     {
2388       if (MPLIST_MTEXT_P (plist))
2389         len = mtext_nchars (MPLIST_MTEXT (plist));
2390       else
2391         len = mplist_length (MPLIST_PLIST (plist));
2392       if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
2393           : i + len > index)
2394         {
2395           if (start_index)
2396             *start_index = i;
2397           if (end_index)
2398             *end_index = i + len;
2399           if (group_index)
2400             *group_index = gidx;
2401           return plist;
2402         }
2403       i += len;
2404       gidx++;
2405     }
2406   return NULL;
2407 }
2408
2409 /* Adjust markers for the change of preedit text.
2410    If FROM == TO, the change is insertion of INS chars.
2411    If FROM < TO and INS == 0, the change is deletion of the range.
2412    If FROM < TO and INS > 0, the change is replacement.  */
2413
2414 static void
2415 adjust_markers (MInputContext *ic, int from, int to, int ins)
2416 {
2417   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
2418   MPlist *markers;
2419
2420   if (from == to)
2421     {
2422       MPLIST_DO (markers, ic_info->markers)
2423         if (MPLIST_INTEGER (markers) > from)
2424           MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + ins);
2425       if (ic->cursor_pos >= from)
2426         ic->cursor_pos += ins;
2427     }
2428   else
2429     {
2430       MPLIST_DO (markers, ic_info->markers)
2431         {
2432           if (MPLIST_INTEGER (markers) >= to)
2433             MPLIST_VAL (markers)
2434               = (void *) (MPLIST_INTEGER (markers) + ins - (to - from));
2435           else if (MPLIST_INTEGER (markers) > from)
2436             MPLIST_VAL (markers) = (void *) from;
2437         }
2438       if (ic->cursor_pos >= to)
2439         ic->cursor_pos += ins - (to - from);
2440       else if (ic->cursor_pos > from)
2441         ic->cursor_pos = from;
2442     }
2443 }
2444
2445
2446 static void
2447 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
2448 {
2449   int nchars = mt ? mtext_nchars (mt) : 1;
2450
2451   if (mt)
2452     mtext_ins (ic->preedit, pos, mt);
2453   else
2454     mtext_ins_char (ic->preedit, pos, c, 1);
2455   adjust_markers (ic, pos, pos, nchars);
2456   ic->preedit_changed = 1;
2457 }
2458
2459
2460 static void
2461 preedit_delete (MInputContext *ic, int from, int to)
2462 {
2463   mtext_del (ic->preedit, from, to);
2464   adjust_markers (ic, from, to, 0);
2465   ic->preedit_changed = 1;
2466 }
2467
2468 static void
2469 preedit_replace (MInputContext *ic, int from, int to, MText *mt, int c)
2470 {
2471   int ins;
2472
2473   mtext_del (ic->preedit, from, to);
2474   if (mt)
2475     {
2476       mtext_ins (ic->preedit, from, mt);
2477       ins = mtext_nchars (mt);
2478     }
2479   else
2480     {
2481       mtext_ins_char (ic->preedit, from, c, 1);
2482       ins = 1;
2483     }
2484   adjust_markers (ic, from, to, ins);
2485   ic->preedit_changed = 1;
2486 }
2487
2488
2489 static void
2490 preedit_commit (MInputContext *ic)
2491 {
2492   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2493   int preedit_len = mtext_nchars (ic->preedit);
2494
2495   if (preedit_len > 0)
2496     {
2497       MPlist *p;
2498
2499       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
2500                              Mcandidate_list, NULL, 0);
2501       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
2502                              Mcandidate_index, NULL, 0);
2503       mtext_cat (ic->produced, ic->preedit);
2504       if (mdebug__flag & mdebug_mask)
2505         {
2506           int i;
2507
2508           MDEBUG_PRINT (" (commit");
2509           for (i = 0; i < mtext_nchars (ic->preedit); i++)
2510             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i));
2511           MDEBUG_PRINT (")");
2512         }
2513
2514       mtext_reset (ic->preedit);
2515       mtext_reset (ic_info->preedit_saved);
2516       MPLIST_DO (p, ic_info->markers)
2517         MPLIST_VAL (p) = 0;
2518       ic->cursor_pos = ic_info->state_pos = 0;
2519       ic->preedit_changed = 1;
2520       ic_info->commit_key_head = ic_info->key_head;
2521     }
2522   if (ic->candidate_list)
2523     {
2524       M17N_OBJECT_UNREF (ic->candidate_list);
2525       ic->candidate_list = NULL;
2526       ic->candidate_index = 0;
2527       ic->candidate_from = ic->candidate_to = 0;
2528       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
2529       if (ic->candidate_show)
2530         {
2531           ic->candidate_show = 0;
2532           ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
2533         }
2534     }
2535 }
2536
2537 static int
2538 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
2539 {
2540   int code = marker_code (sym, 0);
2541
2542   if (mt && (code == '[' || code == ']'))
2543     {
2544       int pos = current;
2545
2546       if (code == '[' && current > 0)
2547         {
2548           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
2549               && pos > 0)
2550             current = pos;
2551         }
2552       else if (code == ']' && current < mtext_nchars (mt))
2553         {
2554           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
2555             current = pos;
2556         }
2557       return current;
2558     }
2559   if (code >= 0)
2560     return (code == '<' ? 0
2561             : code == '>' ? limit
2562             : code == '-' ? current - 1
2563             : code == '+' ? current + 1
2564             : code == '=' ? current
2565             : code - '0' > limit ? limit
2566             : code - '0');
2567   if (! ic)  
2568     return 0;
2569   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
2570 }
2571
2572 static void
2573 update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
2574 {
2575   int from = mtext_property_start (prop);
2576   int to = mtext_property_end (prop);
2577   int start;
2578   MPlist *candidate_list = mtext_property_value (prop);
2579   MPlist *group = find_candidates_group (candidate_list, idx, &start,
2580                                          NULL, NULL);
2581   int ingroup_index = idx - start;
2582   MText *mt;
2583
2584   if (MPLIST_MTEXT_P (group))
2585     {
2586       mt = MPLIST_MTEXT (group);
2587       preedit_replace (ic, from, to, NULL, mtext_ref_char (mt, ingroup_index));
2588       to = from + 1;
2589     }
2590   else
2591     {
2592       int i;
2593       MPlist *plist;
2594
2595       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
2596            i++, plist = MPLIST_NEXT (plist));
2597       mt = MPLIST_MTEXT (plist);
2598       preedit_replace (ic, from, to, mt, 0);
2599       to = from + mtext_nchars (mt);
2600     }
2601   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
2602   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
2603   ic->cursor_pos = to;
2604 }
2605
2606 static MCharset *
2607 get_select_charset (MInputContextInfo * ic_info)
2608 {
2609   MPlist *plist = resolve_variable (ic_info, Mcandidates_charset);
2610   MSymbol sym;
2611
2612   if (! MPLIST_VAL (plist))
2613     return NULL;
2614   sym = MPLIST_SYMBOL (plist);
2615   if (sym == Mnil)
2616     return NULL;
2617   return MCHARSET (sym);
2618 }
2619
2620 static MPlist *
2621 adjust_candidates (MPlist *plist, MCharset *charset)
2622 {
2623   MPlist *pl;
2624
2625   /* plist ::= MTEXT ... | PLIST ... */
2626   plist = mplist_copy (plist);
2627   if (MPLIST_MTEXT_P (plist))
2628     {
2629       pl = plist;
2630       while (! MPLIST_TAIL_P (pl))
2631         {
2632           /* pl ::= MTEXT ... */
2633           MText *mt = MPLIST_MTEXT (pl);
2634           int mt_copied = 0;
2635           int i, c;
2636
2637           for (i = mtext_nchars (mt) - 1; i >= 0; i--)
2638             {
2639               c = mtext_ref_char (mt, i);
2640               if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
2641                 {
2642                   if (! mt_copied)
2643                     {
2644                       mt = mtext_dup (mt);
2645                       mplist_set (pl, Mtext, mt);
2646                       M17N_OBJECT_UNREF (mt);
2647                       mt_copied = 1;
2648                     }
2649                   mtext_del (mt, i, i + 1);
2650                 }
2651             }
2652           if (mtext_len (mt) > 0)
2653             pl = MPLIST_NEXT (pl);
2654           else
2655             {
2656               mplist_pop (pl);
2657               M17N_OBJECT_UNREF (mt);
2658             }
2659         }
2660     }
2661   else                          /* MPLIST_PLIST_P (plist) */
2662     {
2663       pl = plist;
2664       while (! MPLIST_TAIL_P (pl))
2665         {
2666           /* pl ::= (MTEXT ...) ... */
2667           MPlist *p = MPLIST_PLIST (pl);
2668           int p_copied = 0;
2669           /* p ::= MTEXT ... */
2670           MPlist *p0 = p;
2671           int n = 0;
2672
2673           while (! MPLIST_TAIL_P (p0))
2674             {
2675               MText *mt = MPLIST_MTEXT (p0);
2676               int i, c;
2677
2678               for (i = mtext_nchars (mt) - 1; i >= 0; i--)
2679                 {
2680                   c = mtext_ref_char (mt, i);
2681                   if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
2682                     break;
2683                 }
2684               if (i < 0)
2685                 {
2686                   p0 = MPLIST_NEXT (p0);
2687                   n++;
2688                 }
2689               else
2690                 {
2691                   if (! p_copied)
2692                     {
2693                       p = mplist_copy (p);
2694                       mplist_set (pl, Mplist, p);
2695                       M17N_OBJECT_UNREF (p);
2696                       p_copied = 1;
2697                       p0 = p;
2698                       while (n-- > 0)
2699                         p0 = MPLIST_NEXT (p0);
2700                     }     
2701                   mplist_pop (p0);
2702                   M17N_OBJECT_UNREF (mt);
2703                 }
2704             }
2705           if (! MPLIST_TAIL_P (p))
2706             pl = MPLIST_NEXT (pl);
2707           else
2708             {
2709               mplist_pop (pl);
2710               M17N_OBJECT_UNREF (p);
2711             }
2712         }
2713     }
2714   if (MPLIST_TAIL_P (plist))
2715     {
2716       M17N_OBJECT_UNREF (plist);
2717       return NULL;
2718     }      
2719   return plist;
2720 }
2721
2722 static MPlist *
2723 get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
2724 {
2725   MCharset *charset = get_select_charset (ic_info);
2726   MPlist *plist;
2727   int column;
2728   int i, len;
2729
2730   plist = resolve_variable (ic_info, Mcandidates_group_size);
2731   column = MPLIST_INTEGER (plist);
2732
2733   plist = MPLIST_PLIST (args);
2734   if (charset)
2735     plist = adjust_candidates (plist, charset);
2736
2737   if (plist && column > 0)
2738     {
2739       if (MPLIST_MTEXT_P (plist))
2740         {
2741           MText *mt = MPLIST_MTEXT (plist);
2742           MPlist *next = MPLIST_NEXT (plist);
2743
2744           if (MPLIST_TAIL_P (next))
2745             M17N_OBJECT_REF (mt);
2746           else
2747             {
2748               mt = mtext_dup (mt);
2749               while (! MPLIST_TAIL_P (next))
2750                 {
2751                   mt = mtext_cat (mt, MPLIST_MTEXT (next));
2752                   next = MPLIST_NEXT (next);
2753                 }
2754             }
2755           M17N_OBJECT_UNREF (plist);
2756           plist = mplist ();
2757           len = mtext_nchars (mt);
2758           if (len <= column)
2759             mplist_add (plist, Mtext, mt);
2760           else
2761             {
2762               for (i = 0; i < len; i += column)
2763                 {
2764                   int to = (i + column < len ? i + column : len);
2765                   MText *sub = mtext_copy (mtext (), 0, mt, i, to);
2766                                                        
2767                   mplist_add (plist, Mtext, sub);
2768                   M17N_OBJECT_UNREF (sub);
2769                 }
2770             }
2771           M17N_OBJECT_UNREF (mt);
2772         }
2773       else if (! MPLIST_TAIL_P (plist))
2774         {
2775           MPlist *tail = plist;
2776           MPlist *new = mplist ();
2777           MPlist *this = mplist ();
2778           int count = 0;
2779
2780           MPLIST_DO (tail, tail)
2781             {
2782               MPlist *p = MPLIST_PLIST (tail);
2783
2784               MPLIST_DO (p, p)
2785                 {
2786                   MText *mt = MPLIST_MTEXT (p);
2787
2788                   if (count == column)
2789                     {
2790                       mplist_add (new, Mplist, this);
2791                       M17N_OBJECT_UNREF (this);
2792                       this = mplist ();
2793                       count = 0;
2794                     }
2795                   mplist_add (this, Mtext, mt);
2796                   count++;
2797                 }
2798             }
2799           mplist_add (new, Mplist, this);
2800           M17N_OBJECT_UNREF (this);
2801           mplist_set (plist, Mnil, NULL);
2802           MPLIST_DO (tail, new)
2803             {
2804               MPlist *elt = MPLIST_PLIST (tail);
2805
2806               mplist_add (plist, Mplist, elt);
2807             }
2808           M17N_OBJECT_UNREF (new);
2809         }
2810     }
2811
2812   return plist;
2813 }
2814
2815
2816 static MPlist *
2817 regularize_action (MPlist *action_list, MInputContextInfo *ic_info)
2818 {
2819   MPlist *action = NULL;
2820   MSymbol name;
2821   MPlist *args;
2822
2823   if (MPLIST_SYMBOL_P (action_list))
2824     {
2825       MSymbol var = MPLIST_SYMBOL (action_list);
2826       MPlist *p;
2827
2828       MPLIST_DO (p, ic_info->vars)
2829         if (MPLIST_SYMBOL (MPLIST_PLIST (p)) == var)
2830           break;
2831       if (MPLIST_TAIL_P (p))
2832         return NULL;
2833       action = MPLIST_NEXT (MPLIST_PLIST (p));
2834       mplist_set (action_list, MPLIST_KEY (action), MPLIST_VAL (action));
2835     }
2836
2837   if (MPLIST_PLIST_P (action_list))
2838     {
2839       action = MPLIST_PLIST (action_list);
2840       if (MPLIST_SYMBOL_P (action))
2841         {
2842           name = MPLIST_SYMBOL (action);
2843           args = MPLIST_NEXT (action);
2844           if (name == Minsert
2845               && MPLIST_PLIST_P (args))
2846             mplist_set (action, Msymbol, M_candidates);
2847         }
2848       else if (MPLIST_MTEXT_P (action) || MPLIST_PLIST_P (action))
2849         {
2850           action = mplist ();
2851           mplist_push (action, Mplist, MPLIST_VAL (action_list));
2852           mplist_push (action, Msymbol, M_candidates);
2853           mplist_set (action_list, Mplist, action);
2854           M17N_OBJECT_UNREF (action);
2855         }
2856     }
2857   else if (MPLIST_MTEXT_P (action_list) || MPLIST_INTEGER_P (action_list))
2858     {
2859       action = mplist ();
2860       mplist_push (action, MPLIST_KEY (action_list), MPLIST_VAL (action_list));
2861       mplist_push (action, Msymbol, Minsert);
2862       mplist_set (action_list, Mplist, action);
2863       M17N_OBJECT_UNREF (action);
2864     }
2865   return action;
2866 }
2867
2868 /* Perform list of actions in ACTION_LIST for the current input
2869    context IC.  If unhandle action was not performed, return 0.
2870    Otherwise, return -1.  */
2871
2872 static int
2873 take_action_list (MInputContext *ic, MPlist *action_list)
2874 {
2875   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2876   MPlist *candidate_list = ic->candidate_list;
2877   int candidate_index = ic->candidate_index;
2878   int candidate_show = ic->candidate_show;
2879   MTextProperty *prop;
2880
2881   MPLIST_DO (action_list, action_list)
2882     {
2883       MPlist *action = regularize_action (action_list, ic_info);
2884       MSymbol name;
2885       MPlist *args;
2886
2887       if (! action)
2888         continue;
2889       name = MPLIST_SYMBOL (action);
2890       args = MPLIST_NEXT (action);
2891
2892       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
2893       if (name == Minsert)
2894         {
2895           if (MPLIST_SYMBOL_P (args))
2896             {
2897               args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
2898               if (! MPLIST_MTEXT_P (args) && ! MPLIST_INTEGER_P (args))
2899                 continue;
2900             }
2901           if (MPLIST_MTEXT_P (args))
2902             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
2903           else                  /* MPLIST_INTEGER_P (args)) */
2904             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
2905         }
2906       else if (name == M_candidates)
2907         {
2908           MPlist *plist = get_candidate_list (ic_info, args);
2909           int len;
2910
2911           if (! plist || (MPLIST_PLIST_P (plist) && MPLIST_TAIL_P (plist)))
2912             continue;
2913           if (MPLIST_MTEXT_P (plist))
2914             {
2915               preedit_insert (ic, ic->cursor_pos, NULL,
2916                               mtext_ref_char (MPLIST_MTEXT (plist), 0));
2917               len = 1;
2918             }
2919           else if (MPLIST_TAIL_P (MPLIST_PLIST (plist)))
2920             continue;
2921           else
2922             {
2923               MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
2924
2925               preedit_insert (ic, ic->cursor_pos, mt, 0);
2926               len = mtext_nchars (mt);
2927             }
2928           mtext_put_prop (ic->preedit,
2929                           ic->cursor_pos - len, ic->cursor_pos,
2930                           Mcandidate_list, plist);
2931           mtext_put_prop (ic->preedit,
2932                           ic->cursor_pos - len, ic->cursor_pos,
2933                           Mcandidate_index, (void *) 0);
2934         }
2935       else if (name == Mselect)
2936         {
2937           int start, end;
2938           int code, idx, gindex;
2939           int pos = ic->cursor_pos;
2940           MPlist *group;
2941           int idx_decided = 0;
2942
2943           if (pos == 0
2944               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
2945                                                Mcandidate_list)))
2946             continue;
2947           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
2948           group = find_candidates_group (mtext_property_value (prop), idx,
2949                                          &start, &end, &gindex);
2950           if (MPLIST_SYMBOL_P (args))
2951             {
2952               code = marker_code (MPLIST_SYMBOL (args), 0);
2953               if (code < 0)
2954                 {
2955                   args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
2956                   if (! MPLIST_INTEGER_P (args))
2957                     continue;
2958                   idx = start + MPLIST_INTEGER (args);
2959                   if (idx < start || idx >= end)
2960                     continue;
2961                   idx_decided = 1;
2962                 }                 
2963             }
2964           else
2965             code = -1;
2966
2967           if (code != '[' && code != ']')
2968             {
2969               if (! idx_decided)
2970                 idx = (start
2971                        + (code >= 0
2972                           ? new_index (NULL, ic->candidate_index - start,
2973                                        end - start - 1, MPLIST_SYMBOL (args),
2974                                        NULL)
2975                           : MPLIST_INTEGER (args)));
2976               if (idx < 0)
2977                 {
2978                   find_candidates_group (mtext_property_value (prop), -1,
2979                                          NULL, &end, NULL);
2980                   idx = end - 1;
2981                 }
2982               else if (idx >= end
2983                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
2984                 idx = 0;
2985             }
2986           else
2987             {
2988               int ingroup_index = idx - start;
2989               int len;
2990
2991               group = mtext_property_value (prop);
2992               len = mplist_length (group);
2993               if (code == '[')
2994                 {
2995                   gindex--;
2996                   if (gindex < 0)
2997                     gindex = len - 1;;
2998                 }
2999               else
3000                 {
3001                   gindex++;
3002                   if (gindex >= len)
3003                     gindex = 0;
3004                 }
3005               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
3006                 idx += (MPLIST_MTEXT_P (group)
3007                         ? mtext_nchars (MPLIST_MTEXT (group))
3008                         : mplist_length (MPLIST_PLIST (group)));
3009               len = (MPLIST_MTEXT_P (group)
3010                      ? mtext_nchars (MPLIST_MTEXT (group))
3011                      : mplist_length (MPLIST_PLIST (group)));
3012               if (ingroup_index >= len)
3013                 ingroup_index = len - 1;
3014               idx += ingroup_index;
3015             }
3016           update_candidate (ic, prop, idx);
3017           MDEBUG_PRINT1 ("(%d)", idx);
3018         }
3019       else if (name == Mshow)
3020         ic->candidate_show = 1;
3021       else if (name == Mhide)
3022         ic->candidate_show = 0;
3023       else if (name == Mdelete)
3024         {
3025           int len = mtext_nchars (ic->preedit);
3026           int pos;
3027           int to;
3028
3029           if (MPLIST_SYMBOL_P (args)
3030               && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
3031             {
3032               to = ic->cursor_pos + pos;
3033               if (to < 0)
3034                 {
3035                   delete_surrounding_text (ic, to);
3036                   to = 0;
3037                 }
3038               else if (to > len)
3039                 {
3040                   delete_surrounding_text (ic, to - len);
3041                   to = len;
3042                 }
3043             }
3044           else
3045             {
3046               to = (MPLIST_SYMBOL_P (args)
3047                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
3048                                  ic->preedit)
3049                     : MPLIST_INTEGER (args));
3050               if (to < 0)
3051                 to = 0;
3052               else if (to > len)
3053                 to = len;
3054             }
3055           MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
3056           if (to < ic->cursor_pos)
3057             preedit_delete (ic, to, ic->cursor_pos);
3058           else if (to > ic->cursor_pos)
3059             preedit_delete (ic, ic->cursor_pos, to);
3060         }
3061       else if (name == Mmove)
3062         {
3063           int len = mtext_nchars (ic->preedit);
3064           int pos
3065             = (MPLIST_SYMBOL_P (args)
3066                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
3067                             ic->preedit)
3068                : MPLIST_INTEGER (args));
3069
3070           if (pos < 0)
3071             pos = 0;
3072           else if (pos > len)
3073             pos = len;
3074           if (pos != ic->cursor_pos)
3075             {
3076               ic->cursor_pos = pos;
3077               ic->preedit_changed = 1;
3078             }
3079           MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
3080         }
3081       else if (name == Mmark)
3082         {
3083           int code = marker_code (MPLIST_SYMBOL (args), 0);
3084
3085           if (code < 0)
3086             {
3087               mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
3088                           (void *) ic->cursor_pos);
3089               MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
3090             }
3091         }
3092       else if (name == Mpushback)
3093         {
3094           if (MPLIST_INTEGER_P (args) || MPLIST_SYMBOL_P (args))
3095             {
3096               int num;
3097
3098               if (MPLIST_SYMBOL_P (args))
3099                 {
3100                   args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
3101                   if (MPLIST_INTEGER_P (args))
3102                     num = MPLIST_INTEGER (args);
3103                   else
3104                     num = 0;
3105                 }
3106               else
3107                 num = MPLIST_INTEGER (args);
3108
3109               if (num > 0)
3110                 ic_info->key_head -= num;
3111               else if (num == 0)
3112                 ic_info->key_head = 0;
3113               else
3114                 ic_info->key_head = - num;
3115               if (ic_info->key_head > ic_info->used)
3116                 ic_info->key_head = ic_info->used;
3117             }
3118           else if (MPLIST_MTEXT_P (args))
3119             {
3120               MText *mt = MPLIST_MTEXT (args);
3121               int i, len = mtext_nchars (mt);
3122               MSymbol key;
3123
3124               ic_info->key_head--;
3125               for (i = 0; i < len; i++)
3126                 {
3127                   key = one_char_symbol[MTEXT_DATA (mt)[i]];
3128                   if (ic_info->key_head + i < ic_info->used)
3129                     ic_info->keys[ic_info->key_head + i] = key;
3130                   else
3131                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3132                 }
3133             }
3134           else
3135             {
3136               MPlist *plist = MPLIST_PLIST (args), *pl;
3137               int i = 0;
3138               MSymbol key;
3139
3140               ic_info->key_head--;
3141
3142               MPLIST_DO (pl, plist)
3143                 {
3144                   key = MPLIST_SYMBOL (pl);
3145                   if (ic_info->key_head < ic_info->used)
3146                     ic_info->keys[ic_info->key_head + i] = key;
3147                   else
3148                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3149                   i++;
3150                 }
3151             }
3152         }
3153       else if (name == Mpop)
3154         {
3155           if (ic_info->key_head < ic_info->used)
3156             MLIST_DELETE1 (ic_info, keys, ic_info->key_head, 1);
3157         }
3158       else if (name == Mcall)
3159         {
3160           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3161           MIMExternalFunc func = NULL;
3162           MSymbol module, func_name;
3163           MPlist *func_args, *val;
3164           int ret = 0;
3165
3166           module = MPLIST_SYMBOL (args);
3167           args = MPLIST_NEXT (args);
3168           func_name = MPLIST_SYMBOL (args);
3169
3170           if (im_info->externals)
3171             {
3172               MIMExternalModule *external
3173                 = (MIMExternalModule *) mplist_get (im_info->externals,
3174                                                     module);
3175               if (external)
3176                 func = (MIMExternalFunc) mplist_get (external->func_list,
3177                                                      func_name);
3178             }
3179           if (! func)
3180             continue;
3181           func_args = mplist ();
3182           mplist_add (func_args, Mt, ic);
3183           MPLIST_DO (args, MPLIST_NEXT (args))
3184             {
3185               int code;
3186
3187               if (MPLIST_KEY (args) == Msymbol
3188                   && MPLIST_KEY (args) != Mnil
3189                   && (code = marker_code (MPLIST_SYMBOL (args), 0)) >= 0)
3190                 {
3191                   code = new_index (ic, ic->cursor_pos, 
3192                                     mtext_nchars (ic->preedit),
3193                                     MPLIST_SYMBOL (args), ic->preedit);
3194                   mplist_add (func_args, Minteger, (void *) code);
3195                 }
3196               else
3197                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
3198             }
3199           val = (func) (func_args);
3200           M17N_OBJECT_UNREF (func_args);
3201           if (val && ! MPLIST_TAIL_P (val))
3202             ret = take_action_list (ic, val);
3203           M17N_OBJECT_UNREF (val);
3204           if (ret < 0)
3205             return ret;
3206         }
3207       else if (name == Mshift)
3208         {
3209           shift_state (ic, MPLIST_SYMBOL (args));
3210         }
3211       else if (name == Mundo)
3212         {
3213           int intarg = (MPLIST_TAIL_P (args)
3214                         ? ic_info->used - 2
3215                         : integer_value (ic, args, NULL, 0));
3216
3217           mtext_reset (ic->preedit);
3218           mtext_reset (ic_info->preedit_saved);
3219           mtext_reset (ic->produced);
3220           M17N_OBJECT_UNREF (ic_info->vars);
3221           ic_info->vars = mplist_copy (ic_info->vars_saved);
3222           ic->cursor_pos = ic_info->state_pos = 0;
3223           ic_info->state_key_head = ic_info->key_head
3224             = ic_info->commit_key_head = 0;
3225
3226           shift_state (ic, Mnil);
3227           if (intarg < 0)
3228             {
3229               if (MPLIST_TAIL_P (args))
3230                 {
3231                   ic_info->used = 0;
3232                   return -1;
3233                 }
3234               ic_info->used += intarg;
3235             }
3236           else
3237             ic_info->used = intarg;
3238           break;
3239         }
3240       else if (name == Mset || name == Madd || name == Msub
3241                || name == Mmul || name == Mdiv)
3242         {
3243           MSymbol sym = MPLIST_SYMBOL (args);
3244           int val1, val2;
3245           MPlist *value;
3246           char *op;
3247
3248           val1 = integer_value (ic, args, &value, 0);
3249           args = MPLIST_NEXT (args);
3250           val2 = resolve_expression (ic, args);
3251           if (name == Mset)
3252             val1 = val2, op = "=";
3253           else if (name == Madd)
3254             val1 += val2, op = "+=";
3255           else if (name == Msub)
3256             val1 -= val2, op = "-=";
3257           else if (name == Mmul)
3258             val1 *= val2, op = "*=";
3259           else
3260             val1 /= val2, op = "/=";
3261           MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
3262                          MSYMBOL_NAME (sym), op, val1, val1);
3263           if (value)
3264             mplist_set (value, Minteger, (void *) val1);
3265         }
3266       else if (name == Mequal || name == Mless || name == Mgreater
3267                || name == Mless_equal || name == Mgreater_equal)
3268         {
3269           int val1, val2;
3270           MPlist *actions1, *actions2;
3271           int ret = 0;
3272
3273           val1 = resolve_expression (ic, args);
3274           args = MPLIST_NEXT (args);
3275           val2 = resolve_expression (ic, args);
3276           args = MPLIST_NEXT (args);
3277           actions1 = MPLIST_PLIST (args);
3278           args = MPLIST_NEXT (args);
3279           if (MPLIST_TAIL_P (args))
3280             actions2 = NULL;
3281           else
3282             actions2 = MPLIST_PLIST (args);
3283           MDEBUG_PRINT3 ("(%d %s %d)? ", val1, MSYMBOL_NAME (name), val2);
3284           if (name == Mequal ? val1 == val2
3285               : name == Mless ? val1 < val2
3286               : name == Mgreater ? val1 > val2
3287               : name == Mless_equal ? val1 <= val2
3288               : val1 >= val2)
3289             {
3290               MDEBUG_PRINT ("ok");
3291               ret = take_action_list (ic, actions1);
3292             }
3293           else
3294             {
3295               MDEBUG_PRINT ("no");
3296               if (actions2)
3297                 ret = take_action_list (ic, actions2);
3298             }
3299           if (ret < 0)
3300             return ret;
3301         }
3302       else if (name == Mcond)
3303         {
3304           int idx = 0;
3305
3306           MPLIST_DO (args, args)
3307             {
3308               MPlist *cond;
3309
3310               idx++;
3311               if (! MPLIST_PLIST (args))
3312                 continue;
3313               cond = MPLIST_PLIST (args);
3314               if (resolve_expression (ic, cond) != 0)
3315                 {
3316                   MDEBUG_PRINT1 ("(%dth)", idx);
3317                   if (take_action_list (ic, MPLIST_NEXT (cond)) < 0)
3318                     return -1;;
3319                   break;
3320                 }
3321             }
3322         }
3323       else if (name == Mcommit)
3324         {
3325           preedit_commit (ic);
3326         }
3327       else if (name == Munhandle)
3328         {
3329           preedit_commit (ic);
3330           return -1;
3331         }
3332       else
3333         {
3334           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3335           MPlist *actions;
3336
3337           if (im_info->macros
3338               && (actions = mplist_get (im_info->macros, name)))
3339             {
3340               if (take_action_list (ic, actions) < 0)
3341                 return -1;
3342             };
3343         }
3344     }
3345
3346   if (ic->candidate_list)
3347     {
3348       M17N_OBJECT_UNREF (ic->candidate_list);
3349       ic->candidate_list = NULL;
3350     }
3351   if (ic->cursor_pos > 0
3352       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
3353                                      Mcandidate_list)))
3354     {
3355       ic->candidate_list = mtext_property_value (prop);
3356       M17N_OBJECT_REF (ic->candidate_list);
3357       ic->candidate_index
3358         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
3359                                 Mcandidate_index);
3360       ic->candidate_from = mtext_property_start (prop);
3361       ic->candidate_to = mtext_property_end (prop);
3362     }
3363
3364   if (candidate_list != ic->candidate_list)
3365     ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3366   if (candidate_index != ic->candidate_index)
3367     ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3368   if (candidate_show != ic->candidate_show)
3369     ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
3370   return 0;
3371 }
3372
3373
3374 /* Handle the input key KEY in the current state and map specified in
3375    the input context IC.  If KEY is handled correctly, return 0.
3376    Otherwise, return -1.  */
3377
3378 static int
3379 handle_key (MInputContext *ic)
3380 {
3381   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3382   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3383   MIMMap *map = ic_info->map;
3384   MIMMap *submap = NULL;
3385   MSymbol key = ic_info->keys[ic_info->key_head];
3386   MSymbol alias = Mnil;
3387   int i;
3388
3389   MDEBUG_PRINT2 ("  [IM] handle `%s' in state %s", 
3390                  msymbol_name (key), MSYMBOL_NAME (ic_info->state->name));
3391
3392   if (map->submaps)
3393     {
3394       submap = mplist_get (map->submaps, key);
3395       alias = key;
3396       while (! submap
3397              && (alias = msymbol_get (alias, M_key_alias))
3398              && alias != key)
3399         submap = mplist_get (map->submaps, alias);
3400     }
3401
3402   if (submap)
3403     {
3404       if (! alias || alias == key)
3405         MDEBUG_PRINT (" submap-found");
3406       else
3407         MDEBUG_PRINT1 (" submap-found (by alias `%s')", MSYMBOL_NAME (alias));
3408       mtext_cpy (ic->preedit, ic_info->preedit_saved);
3409       ic->preedit_changed = 1;
3410       ic->cursor_pos = ic_info->state_pos;
3411       ic_info->key_head++;
3412       ic_info->map = map = submap;
3413       if (map->map_actions)
3414         {
3415           MDEBUG_PRINT (" map-actions:");
3416           if (take_action_list (ic, map->map_actions) < 0)
3417             {
3418               MDEBUG_PRINT ("\n");
3419               return -1;
3420             }
3421         }
3422       else if (map->submaps)
3423         {
3424           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
3425             {
3426               MSymbol key = ic_info->keys[i];
3427               char *name = msymbol_name (key);
3428
3429               if (! name[0] || ! name[1])
3430                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
3431             }
3432         }
3433
3434       /* If this is the terminal map or we have shifted to another
3435          state, perform branch actions (if any).  */
3436       if (! map->submaps || map != ic_info->map)
3437         {
3438           if (map->branch_actions)
3439             {
3440               MDEBUG_PRINT (" branch-actions:");
3441               if (take_action_list (ic, map->branch_actions) < 0)
3442                 {
3443                   MDEBUG_PRINT ("\n");
3444                   return -1;
3445                 }
3446             }
3447           /* If MAP is still not the root map, shift to the current
3448              state.  */
3449           if (ic_info->map != ic_info->state->map)
3450             shift_state (ic, ic_info->state->name);
3451         }
3452     }
3453   else
3454     {
3455       /* MAP can not handle KEY.  */
3456
3457       /* Perform branch actions if any.  */
3458       if (map->branch_actions)
3459         {
3460           MDEBUG_PRINT (" branch-actions:");
3461           if (take_action_list (ic, map->branch_actions) < 0)
3462             {
3463               MDEBUG_PRINT ("\n");
3464               return -1;
3465             }
3466         }
3467
3468       if (map == ic_info->map)
3469         {
3470           /* The above branch actions didn't change the state.  */
3471
3472           /* If MAP is the root map of the initial state, and there
3473              still exist an unhandled key, it means that the current
3474              input method can not handle it.  */
3475           if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map
3476               && ic_info->key_head < ic_info->used)
3477             {
3478               MDEBUG_PRINT (" unhandled\n");
3479               return -1;
3480             }
3481
3482           if (map != ic_info->state->map)
3483             {
3484               /* MAP is not the root map.  Shift to the root map of the
3485                  current state. */
3486               shift_state (ic, ic_info->state->name);
3487             }
3488           else if (! map->branch_actions)
3489             {
3490               /* MAP is the root map without any default branch
3491                  actions.  Shift to the initial state.  */
3492               shift_state (ic, Mnil);
3493             }
3494         }
3495     }
3496   MDEBUG_PRINT ("\n");
3497   return 0;
3498 }
3499
3500 /* Initialize IC->ic_info.  */
3501
3502 static void
3503 init_ic_info (MInputContext *ic)
3504 {
3505   MInputMethodInfo *im_info = ic->im->info;
3506   MInputContextInfo *ic_info = ic->info;
3507   MPlist *plist;
3508   
3509   MLIST_INIT1 (ic_info, keys, 8);;
3510
3511   ic_info->markers = mplist ();
3512
3513   ic_info->vars = mplist ();
3514   if (im_info->configured_vars)
3515     MPLIST_DO (plist, im_info->configured_vars)
3516       {
3517         MPlist *pl = MPLIST_PLIST (plist);
3518         MSymbol name = MPLIST_SYMBOL (pl);
3519
3520         pl = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (pl)));
3521         if (MPLIST_KEY (pl) != Mt)
3522           {
3523             MPlist *p = mplist ();
3524
3525             mplist_push (ic_info->vars, Mplist, p);
3526             M17N_OBJECT_UNREF (p);
3527             mplist_add (p, Msymbol, name);
3528             mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
3529           }
3530       }
3531   ic_info->vars_saved = mplist_copy (ic_info->vars);
3532
3533   if (im_info->externals)
3534     {
3535       MPlist *func_args = mplist (), *plist;
3536
3537       mplist_add (func_args, Mt, ic);
3538       MPLIST_DO (plist, im_info->externals)
3539         {
3540           MIMExternalModule *external = MPLIST_VAL (plist);
3541           MIMExternalFunc func
3542             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
3543
3544           if (func)
3545             (func) (func_args);
3546         }
3547       M17N_OBJECT_UNREF (func_args);
3548     }
3549
3550   ic_info->preedit_saved = mtext ();
3551   ic_info->tick = im_info->tick;
3552 }
3553
3554 /* Finalize IC->ic_info.  */
3555
3556 static void
3557 fini_ic_info (MInputContext *ic)
3558 {
3559   MInputMethodInfo *im_info = ic->im->info;
3560   MInputContextInfo *ic_info = ic->info;
3561
3562   if (im_info->externals)
3563     {
3564       MPlist *func_args = mplist (), *plist;
3565
3566       mplist_add (func_args, Mt, ic);
3567       MPLIST_DO (plist, im_info->externals)
3568         {
3569           MIMExternalModule *external = MPLIST_VAL (plist);
3570           MIMExternalFunc func
3571             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
3572
3573           if (func)
3574             (func) (func_args);
3575         }
3576       M17N_OBJECT_UNREF (func_args);
3577     }
3578
3579   MLIST_FREE1 (ic_info, keys);
3580   M17N_OBJECT_UNREF (ic_info->preedit_saved);
3581   M17N_OBJECT_UNREF (ic_info->markers);
3582   M17N_OBJECT_UNREF (ic_info->vars);
3583   M17N_OBJECT_UNREF (ic_info->vars_saved);
3584   M17N_OBJECT_UNREF (ic_info->preceding_text);
3585   M17N_OBJECT_UNREF (ic_info->following_text);
3586
3587   memset (ic_info, 0, sizeof (MInputContextInfo));
3588 }
3589
3590 static void
3591 re_init_ic (MInputContext *ic, int reload)
3592 {
3593   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3594   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3595   int status_changed, preedit_changed, cursor_pos_changed, candidates_changed;
3596
3597   status_changed = ic_info->state != (MIMState *) MPLIST_VAL (im_info->states);
3598   preedit_changed = mtext_nchars (ic->preedit) > 0;
3599   cursor_pos_changed = ic->cursor_pos > 0;
3600   candidates_changed = 0;
3601   if (ic->candidate_list)
3602     {
3603       candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3604       M17N_OBJECT_UNREF (ic->candidate_list);
3605       ic->candidate_list = NULL;
3606     }
3607   if (ic->candidate_show)
3608     {
3609       candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
3610       ic->candidate_show = 0;
3611     }
3612   if (ic->candidate_index > 0)
3613     {
3614       candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3615       ic->candidate_index = 0;
3616       ic->candidate_from = ic->candidate_to = 0;
3617     }
3618   if (mtext_nchars (ic->produced) > 0)
3619     mtext_reset (ic->produced);
3620   if (mtext_nchars (ic->preedit) > 0)
3621     mtext_reset (ic->preedit);
3622   ic->cursor_pos = 0;
3623   M17N_OBJECT_UNREF (ic->plist);
3624   ic->plist = mplist ();
3625
3626   fini_ic_info (ic);
3627   if (reload)
3628     reload_im_info (im_info);
3629   init_ic_info (ic);
3630   shift_state (ic, Mnil);
3631   ic->status_changed = status_changed;
3632   ic->preedit_changed = preedit_changed;
3633   ic->cursor_pos_changed = cursor_pos_changed;
3634   ic->candidates_changed = candidates_changed;
3635 }
3636
3637 static void
3638 reset_ic (MInputContext *ic, MSymbol ignore)
3639 {
3640   MDEBUG_PRINT ("\n  [IM] reset\n");
3641   re_init_ic (ic, 0);
3642 }
3643
3644 static int
3645 open_im (MInputMethod *im)
3646 {
3647   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
3648
3649   if (! im_info)
3650     MERROR (MERROR_IM, -1);
3651   im->info = im_info;
3652
3653   return 0;
3654 }
3655
3656 static void
3657 close_im (MInputMethod *im)
3658 {
3659   im->info = NULL;
3660 }
3661
3662 static int
3663 create_ic (MInputContext *ic)
3664 {
3665   MInputContextInfo *ic_info;
3666
3667   MSTRUCT_CALLOC (ic_info, MERROR_IM);
3668   ic->info = ic_info;
3669   init_ic_info (ic);
3670   shift_state (ic, Mnil);
3671   return 0;
3672 }
3673
3674 static void
3675 destroy_ic (MInputContext *ic)
3676 {
3677   fini_ic_info (ic);
3678   free (ic->info);
3679 }
3680
3681 static int
3682 check_reload (MInputContext *ic, MSymbol key)
3683 {
3684   MInputMethodInfo *im_info = ic->im->info;
3685   MPlist *plist = resolve_command (im_info->configured_cmds, Mat_reload);
3686
3687   if (! plist)
3688     {
3689       plist = resolve_command (global_info->configured_cmds, Mat_reload);
3690       if (! plist)
3691         return 0;
3692     }
3693   MPLIST_DO (plist, plist)
3694     {
3695       MSymbol this_key, alias;
3696
3697       if (MPLIST_MTEXT_P (plist))
3698         {
3699           MText *mt = MPLIST_MTEXT (plist);
3700           int c = mtext_ref_char (mt, 0);
3701
3702           if (c >= 256)
3703             continue;
3704           this_key = one_char_symbol[c];
3705         }
3706       else
3707         {
3708           MPlist *pl = MPLIST_PLIST (plist);
3709       
3710           this_key = MPLIST_SYMBOL (pl);
3711         }
3712       alias = this_key;
3713       while (alias != key 
3714              && (alias = msymbol_get (alias, M_key_alias))
3715              && alias != this_key);
3716       if (alias == key)
3717         break;
3718     }
3719   if (MPLIST_TAIL_P (plist))
3720     return 0;
3721
3722   MDEBUG_PRINT ("\n  [IM] reload");
3723   re_init_ic (ic, 1);
3724   return 1;
3725 }
3726
3727
3728 /** Handle the input key KEY in the current state and map of IC->info.
3729     If KEY is handled but no text is produced, return 0, otherwise
3730     return 1.
3731
3732     Ignore ARG.  */
3733
3734 static int
3735 filter (MInputContext *ic, MSymbol key, void *arg)
3736 {
3737   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3738   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3739   int i = 0;
3740
3741   if (check_reload (ic, key))
3742     return 0;
3743
3744   if (! ic_info->state)
3745     {
3746       ic_info->key_unhandled = 1;
3747       return 0;
3748     }
3749   mtext_reset (ic->produced);
3750   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
3751   M17N_OBJECT_UNREF (ic_info->preceding_text);
3752   M17N_OBJECT_UNREF (ic_info->following_text);
3753   ic_info->preceding_text = ic_info->following_text = NULL;
3754   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3755   ic_info->key_unhandled = 0;
3756
3757   do {
3758     if (handle_key (ic) < 0)
3759       {
3760         /* KEY was not handled.  Delete it from the current key sequence.  */
3761         if (ic_info->used > 0)
3762           {
3763             memmove (ic_info->keys, ic_info->keys + 1,
3764                      sizeof (int) * (ic_info->used - 1));
3765             ic_info->used--;
3766             if (ic_info->state_key_head > 0)
3767               ic_info->state_key_head--;
3768             if (ic_info->commit_key_head > 0)
3769               ic_info->commit_key_head--;             
3770           }
3771         /* This forces returning 1.  */
3772         ic_info->key_unhandled = 1;
3773         break;
3774       }
3775     if (i++ == 100)
3776       {
3777         mdebug_hook ();
3778         reset_ic (ic, Mnil);
3779         ic_info->key_unhandled = 1;
3780         break;
3781       }
3782     /* Break the loop if all keys were handled.  */
3783   } while (ic_info->key_head < ic_info->used);
3784
3785   /* If the current map is the root of the initial state, we should
3786      produce any preedit text in ic->produced.  */
3787   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
3788     preedit_commit (ic);
3789
3790   if (mtext_nchars (ic->produced) > 0)
3791     {
3792       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
3793
3794       if (mdebug__flag & mdebug_mask)
3795         {
3796           MDEBUG_PRINT (" (produced");
3797           for (i = 0; i < mtext_nchars (ic->produced); i++)
3798             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
3799           MDEBUG_PRINT (")");
3800         }
3801
3802       if (lang != Mnil)
3803         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
3804                         Mlanguage, ic->im->language);
3805     }
3806   if (ic_info->commit_key_head > 0)
3807     {
3808       memmove (ic_info->keys, ic_info->keys + ic_info->commit_key_head,
3809                sizeof (int) * (ic_info->used - ic_info->commit_key_head));
3810       ic_info->used -= ic_info->commit_key_head;
3811       ic_info->key_head -= ic_info->commit_key_head;
3812       ic_info->state_key_head -= ic_info->commit_key_head;
3813       ic_info->commit_key_head = 0;
3814     }
3815   if (ic_info->key_unhandled)
3816     {
3817       ic_info->used = 0;
3818       ic_info->key_head = ic_info->state_key_head
3819         = ic_info->commit_key_head = 0;
3820     }
3821
3822   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
3823 }
3824
3825
3826 /** Return 1 if the last event or key was not handled, otherwise
3827     return 0.
3828
3829     There is no need of looking up because ic->produced should already
3830     contain the produced text (if any).
3831
3832     Ignore KEY.  */
3833
3834 static int
3835 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
3836 {
3837   mtext_cat (mt, ic->produced);
3838   mtext_reset (ic->produced);
3839   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
3840 }
3841
3842 \f
3843 /* Input method command handler.  */
3844
3845 /* List of all (global and local) commands. 
3846    (LANG:(IM-NAME:(COMMAND ...) ...) ...) ...
3847    COMMAND is CMD-NAME:(mtext:DESCRIPTION plist:KEYSEQ ...))
3848    Global commands are stored as (t (t COMMAND ...))  */
3849
3850 \f
3851 /* Input method variable handler.  */
3852
3853
3854 /* Support functions for mdebug_dump_im.  */
3855
3856 static void
3857 dump_im_map (MPlist *map_list, int indent)
3858 {
3859   char *prefix;
3860   MSymbol key = MPLIST_KEY (map_list);
3861   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
3862
3863   prefix = (char *) alloca (indent + 1);
3864   memset (prefix, 32, indent);
3865   prefix[indent] = '\0';
3866
3867   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
3868   if (map->map_actions)
3869     mdebug_dump_plist (map->map_actions, indent + 2);
3870   if (map->submaps)
3871     {
3872       MPLIST_DO (map_list, map->submaps)
3873         {
3874           fprintf (stderr, "\n%s  ", prefix);
3875           dump_im_map (map_list, indent + 2);
3876         }
3877     }
3878   if (map->branch_actions)
3879     {
3880       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
3881       mdebug_dump_plist (map->branch_actions, indent + 4);
3882       fprintf (stderr, ")");      
3883     }
3884   fprintf (stderr, ")");
3885 }
3886
3887
3888 static void
3889 dump_im_state (MIMState *state, int indent)
3890 {
3891   char *prefix;
3892   MPlist *map_list;
3893
3894   prefix = (char *) alloca (indent + 1);
3895   memset (prefix, 32, indent);
3896   prefix[indent] = '\0';
3897
3898   fprintf (stderr, "(%s", msymbol_name (state->name));
3899   if (state->map->submaps)
3900     {
3901       MPLIST_DO (map_list, state->map->submaps)
3902         {
3903           fprintf (stderr, "\n%s  ", prefix);
3904           dump_im_map (map_list, indent + 2);
3905         }
3906     }
3907   fprintf (stderr, ")");
3908 }
3909
3910 \f
3911
3912 int
3913 minput__init ()
3914 {
3915   Minput_driver = msymbol ("input-driver");
3916
3917   Minput_preedit_start = msymbol ("input-preedit-start");
3918   Minput_preedit_done = msymbol ("input-preedit-done");
3919   Minput_preedit_draw = msymbol ("input-preedit-draw");
3920   Minput_status_start = msymbol ("input-status-start");
3921   Minput_status_done = msymbol ("input-status-done");
3922   Minput_status_draw = msymbol ("input-status-draw");
3923   Minput_candidates_start = msymbol ("input-candidates-start");
3924   Minput_candidates_done = msymbol ("input-candidates-done");
3925   Minput_candidates_draw = msymbol ("input-candidates-draw");
3926   Minput_set_spot = msymbol ("input-set-spot");
3927   Minput_focus_move = msymbol ("input-focus-move");
3928   Minput_focus_in = msymbol ("input-focus-in");
3929   Minput_focus_out = msymbol ("input-focus-out");
3930   Minput_toggle = msymbol ("input-toggle");
3931   Minput_reset = msymbol ("input-reset");
3932   Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
3933   Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
3934   Mcustomized = msymbol ("customized");
3935   Mconfigured = msymbol ("configured");
3936   Minherited = msymbol ("inherited");
3937
3938   minput_default_driver.open_im = open_im;
3939   minput_default_driver.close_im = close_im;
3940   minput_default_driver.create_ic = create_ic;
3941   minput_default_driver.destroy_ic = destroy_ic;
3942   minput_default_driver.filter = filter;
3943   minput_default_driver.lookup = lookup;
3944   minput_default_driver.callback_list = mplist ();
3945   mplist_put (minput_default_driver.callback_list, Minput_reset,
3946               (void *) reset_ic);
3947   minput_driver = &minput_default_driver;
3948
3949   fully_initialized = 0;
3950   return 0;
3951 }
3952
3953 void
3954 minput__fini ()
3955 {
3956   if (fully_initialized)
3957     {
3958       free_im_list (im_info_list);
3959       if (im_custom_list)
3960         free_im_list (im_custom_list);
3961       if (im_config_list)
3962         free_im_list (im_config_list);
3963       M17N_OBJECT_UNREF (load_im_info_keys);
3964     }
3965
3966   M17N_OBJECT_UNREF (minput_default_driver.callback_list);
3967   M17N_OBJECT_UNREF (minput_driver->callback_list);
3968
3969 }
3970
3971 MSymbol
3972 minput__char_to_key (int c)
3973 {
3974   if (c < 0 || c >= 0x100)
3975     return Mnil;
3976
3977   return one_char_symbol[c];
3978 }
3979
3980 /*** @} */
3981 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
3982
3983 \f
3984 /* External API */
3985
3986 /*** @addtogroup m17nInputMethod */
3987 /*** @{ */
3988 /*=*/
3989
3990 /***en
3991     @name Variables: Predefined symbols for callback commands.
3992
3993     These are the predefined symbols that are used as the @c COMMAND
3994     argument of callback functions of an input method driver (see
3995     #MInputDriver::callback_list).  
3996
3997     Most of them do not require extra argument nor return any value;
3998     exceptions are these:
3999
4000     Minput_get_surrounding_text: When a callback function assigned for
4001     this command is called, the first element of #MInputContext::plist
4002     has key #Minteger and the value specifies which portion of the
4003     surrounding text should be retrieved.  If the value is positive,
4004     it specifies the number of characters following the current cursor
4005     position.  If the value is negative, the absolute value specifies
4006     the number of characters preceding the current cursor position.
4007     If the value is zero, it means that the caller just wants to know
4008     if the surrounding text is currently supported or not.
4009
4010     If the surrounding text is currently supported, the callback
4011     function must set the key of this element to #Mtext and the value
4012     to the retrieved M-text.  The length of the M-text may be shorter
4013     than the requested number of characters, if the available text is
4014     not that long.  The length can be zero in the worst case.  Or, the
4015     length may be longer if an application thinks it is more efficient
4016     to return that length.
4017
4018     If the surrounding text is not currently supported, the callback
4019     function should return without changing the first element of
4020     #MInputContext::plist.
4021
4022     Minput_delete_surrounding_text: When a callback function assigned
4023     for this command is called, the first element of
4024     #MInputContext::plist has key #Minteger and the value specifies
4025     which portion of the surrounding text should be deleted in the
4026     same way as the case of Minput_get_surrounding_text.  The callback
4027     function must delete the specified text.  It should not alter
4028     #MInputContext::plist.  */ 
4029 /***ja
4030     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
4031
4032     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND 
4033     °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
4034
4035     ¤Û¤È¤ó¤É¤ÏÄɲäΰú¿ô¤òɬÍפȤ·¤Ê¤¤¤·ÃͤòÊÖ¤µ¤Ê¤¤¤¬¡¢°Ê²¼¤ÏÎã³°¤Ç¤¢¤ë¡£
4036
4037     Minput_get_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë¥Ð¥Ã
4038     ¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢ #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϥ­¡¼¤È¤·
4039     ¤Æ#Minteger ¤ò¤È¤ê¡¢¤½¤ÎÃͤϥµ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤Î¤¦¤Á¤É¤ÎÉôʬ
4040     ¤ò¼è¤Ã¤ÆÍè¤ë¤«¤ò»ØÄꤹ¤ë¡£Ãͤ¬Àµ¤Ç¤¢¤ì¤Ð¡¢¸½ºß¤Î¥«¡¼¥½¥ë°ÌÃ֤˳¤¯
4041     ÃͤθĿôʬ¤Îʸ»ú¤ò¼è¤ë¡£Éé¤Ç¤¢¤ì¤Ð¡¢¥«¡¼¥½¥ë°ÌÃÖ¤ËÀè¹Ô¤¹¤ëÃͤÎÀäÂÐ
4042     ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£¸½ºß¥µ¥é¥¦¥ó¥É¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦
4043     ¤«¤òÃΤꤿ¤¤¤À¤±¤Ç¤¢¤ì¤Ð¡¢¤³¤ÎÃͤϥ¼¥í¤Ç¤âÎɤ¤¡£
4044
4045     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ï
4046     ¤³¤ÎÍ×ÁǤΥ­¡¼¤ò #Mtext ¤Ë¡¢Ãͤò¼è¤ê¹þ¤ó¤ÀM-text ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê
4047     ¤é¤Ê¤¤¡£¤â¤·¥Æ¥­¥¹¥È¤ÎŤµ¤¬½¼Ê¬¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î M-text ¤ÎŤµ¤ÏÍ×
4048     µá¤µ¤ì¤Æ¤¤¤ëʸ»ú¿ô¤è¤êû¤¯¤ÆÎɤ¤¡£ºÇ°­¤Î¾ì¹ç 0 ¤Ç¤â¤è¤¤¤·¡¢¥¢¥×¥ê¥±¡¼
4049     ¥·¥ç¥ó¦¤ÇɬÍפǸúΨŪ¤À¤È»×¤¨¤ÐŤ¯¤Æ¤âÎɤ¤¡£
4050
4051     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
4052     ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4053
4054     Minput_delete_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë
4055     ¥Ð¥Ã¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢#MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϡ¢¥­¡¼
4056     ¤È¤·¤Æ#Minteger ¤ò¤È¤ê¡¢ÃͤϺï½ü¤¹¤ë¤Ù¤­¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤ò
4057     Minput_get_surrounding_text ¤ÈƱÍͤΤä¤êÊý¤Ç»ØÄꤹ¤ë¡£¥³¡¼¥ë¥Ð¥Ã¥¯
4058     ´Ø¿ô¤Ï»ØÄꤵ¤ì¤¿¥Æ¥­¥¹¥È¤òºï½ü¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤Þ¤¿
4059     #MInputContext::plist ¤òÊѤ¨¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */ 
4060 /*** @{ */ 
4061 /*=*/
4062
4063 MSymbol Minput_preedit_start;
4064 MSymbol Minput_preedit_done;
4065 MSymbol Minput_preedit_draw;
4066 MSymbol Minput_status_start;
4067 MSymbol Minput_status_done;
4068 MSymbol Minput_status_draw;
4069 MSymbol Minput_candidates_start;
4070 MSymbol Minput_candidates_done;
4071 MSymbol Minput_candidates_draw;
4072 MSymbol Minput_set_spot;
4073 MSymbol Minput_toggle;
4074 MSymbol Minput_reset;
4075 MSymbol Minput_get_surrounding_text;
4076 MSymbol Minput_delete_surrounding_text;
4077 /*** @} */
4078
4079 /*=*/
4080
4081 /***en
4082     @name Variables: Predefined symbols for special input events.
4083
4084     These are the predefined symbols that are used as the @c KEY
4085     argument of minput_filter ().  */ 
4086 /***ja
4087     @name ÊÑ¿ô: ÆÃÊ̤ÊÆþÎÏ¥¤¥Ù¥ó¥ÈÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
4088
4089     minput_filter () ¤Î @c KEY °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */ 
4090
4091 /*** @{ */ 
4092 /*=*/
4093
4094 MSymbol Minput_focus_out;
4095 MSymbol Minput_focus_in;
4096 MSymbol Minput_focus_move;
4097
4098 /*** @} */
4099
4100 /*=*/
4101 /***en
4102     @name Variables: Predefined symbols used in input method information.
4103
4104     These are the predefined symbols describing status of input method
4105     command and variable, and are used in a return value of
4106     minput_get_command () and minput_get_variable ().  */
4107 /***ja
4108     @name ÊÑ¿ô: ÆþÎϥ᥽¥Ã¥É¾ðÊóÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
4109
4110     ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤äÊÑ¿ô¤Î¾õÂÖ¤òɽ¤·¡¢minput_get_command () ¤È
4111     minput_get_variable () ¤ÎÌá¤êÃͤȤ·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */
4112 /*** @{ */ 
4113 /*=*/
4114 MSymbol Minherited;
4115 MSymbol Mcustomized;
4116 MSymbol Mconfigured;
4117 /*** @} */ 
4118
4119 /*=*/
4120
4121 /***en
4122     @brief The default driver for internal input methods.
4123
4124     The variable #minput_default_driver is the default driver for
4125     internal input methods.
4126
4127     The member MInputDriver::open_im () searches the m17n database for
4128     an input method that matches the tag \< #Minput_method, $LANGUAGE,
4129     $NAME\> and loads it.
4130
4131     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
4132     programmers responsibility to set it to a plist of proper callback
4133     functions.  Otherwise, no feedback information (e.g. preedit text)
4134     can be shown to users.
4135
4136     The macro M17N_INIT () sets the variable #minput_driver to the
4137     pointer to this driver so that all internal input methods use it.
4138
4139     Therefore, unless @c minput_driver is set differently, the driver
4140     dependent arguments $ARG of the functions whose name begins with
4141     "minput_" are all ignored.  */
4142 /***ja
4143     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
4144
4145     ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£
4146
4147     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
4148     \< #Minput_method, $LANGUAGE, $NAME\> 
4149     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
4150
4151     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢
4152     ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist
4153     ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit 
4154     ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
4155
4156     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver 
4157     ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
4158
4159     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
4160     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
4161
4162 MInputDriver minput_default_driver;
4163 /*=*/
4164
4165 /***en
4166     @brief The driver for internal input methods.
4167
4168     The variable #minput_driver is a pointer to the input method
4169     driver that is used by internal input methods.  The macro
4170     M17N_INIT () initializes it to a pointer to #minput_default_driver
4171     if <m17n<EM></EM>.h> is included.  */ 
4172 /***ja
4173     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
4174
4175     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
4176     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
4177     ¥¿¤ò#minput_default_driver (<m17n<EM></EM>.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë
4178     »þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
4179
4180 MInputDriver *minput_driver;
4181
4182 MSymbol Minput_driver;
4183
4184 /*=*/
4185
4186 /***en
4187     @name Functions
4188 */
4189 /***ja
4190     @name ´Ø¿ô
4191 */
4192 /*** @{ */
4193
4194 /*=*/
4195
4196 /***en
4197     @brief Open an input method.
4198
4199     The minput_open_im () function opens an input method whose
4200     language and name match $LANGUAGE and $NAME, and returns a pointer
4201     to the input method object newly allocated.
4202
4203     This function at first decides a driver for the input method as
4204     described below.
4205
4206     If $LANGUAGE is not #Mnil, the driver pointed by the variable
4207     #minput_driver is used.
4208
4209     If $LANGUAGE is #Mnil and $NAME has the property #Minput_driver, the
4210     driver pointed to by the property value is used to open the input
4211     method.  If $NAME has no such a property, @c NULL is returned.
4212
4213     Then, the member MInputDriver::open_im () of the driver is
4214     called.  
4215
4216     $ARG is set in the member @c arg of the structure MInputMethod so
4217     that the driver can refer to it.  */
4218 /***ja
4219     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
4220
4221     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME 
4222     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
4223     
4224     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
4225
4226     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver 
4227     ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
4228
4229     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver
4230     ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£
4231     $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
4232
4233     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
4234
4235     $ARG ¤Ï¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£
4236
4237     @latexonly \IPAlabel{minput_open} @endlatexonly
4238
4239 */
4240
4241 MInputMethod *
4242 minput_open_im (MSymbol language, MSymbol name, void *arg)
4243 {
4244   MInputMethod *im;
4245   MInputDriver *driver;
4246
4247   MINPUT__INIT ();
4248
4249   MDEBUG_PRINT2 ("  [IM] opening (%s %s) ... ",
4250                  msymbol_name (language), msymbol_name (name));
4251   if (language)
4252     driver = minput_driver;
4253   else
4254     {
4255       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
4256       if (! driver)
4257         MERROR (MERROR_IM, NULL);
4258     }
4259
4260   MSTRUCT_CALLOC (im, MERROR_IM);
4261   im->language = language;
4262   im->name = name;
4263   im->arg = arg;
4264   im->driver = *driver;
4265   if ((*im->driver.open_im) (im) < 0)
4266     {
4267       MDEBUG_PRINT (" failed\n");
4268       free (im);
4269       return NULL;
4270     }
4271   MDEBUG_PRINT (" ok\n");
4272   return im;
4273 }
4274
4275 /*=*/
4276
4277 /***en
4278     @brief Close an input method.
4279
4280     The minput_close_im () function closes the input method $IM, which
4281     must have been created by minput_open_im ().  */
4282
4283 /***ja
4284     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
4285
4286     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£
4287     ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
4288
4289 void
4290 minput_close_im (MInputMethod *im)
4291 {
4292   MDEBUG_PRINT2 ("  [IM] closing (%s %s) ... ",
4293                  msymbol_name (im->name), msymbol_name (im->language));
4294   (*im->driver.close_im) (im);
4295   free (im);
4296   MDEBUG_PRINT (" done\n");
4297 }
4298
4299 /*=*/
4300
4301 /***en
4302     @brief Create an input context.
4303
4304     The minput_create_ic () function creates an input context object
4305     associated with input method $IM, and calls callback functions
4306     corresponding to #Minput_preedit_start, #Minput_status_start, and
4307     #Minput_status_draw in this order.
4308
4309     @return
4310     If an input context is successfully created, minput_create_ic ()
4311     returns a pointer to it.  Otherwise it returns @c NULL.  */
4312
4313 /***ja
4314     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
4315
4316     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
4317     ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
4318     #Minput_preedit_start, #Minput_status_start, #Minput_status_draw
4319     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
4320
4321     @return
4322     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () 
4323     ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
4324       */
4325
4326 MInputContext *
4327 minput_create_ic (MInputMethod *im, void *arg)
4328 {
4329   MInputContext *ic;
4330
4331   MDEBUG_PRINT2 ("  [IM] creating context (%s %s) ... ",
4332                  msymbol_name (im->name), msymbol_name (im->language));
4333   MSTRUCT_CALLOC (ic, MERROR_IM);
4334   ic->im = im;
4335   ic->arg = arg;
4336   ic->preedit = mtext ();
4337   ic->candidate_list = NULL;
4338   ic->produced = mtext ();
4339   ic->spot.x = ic->spot.y = 0;
4340   ic->active = 1;
4341   ic->plist = mplist ();
4342   if ((*im->driver.create_ic) (ic) < 0)
4343     {
4344       MDEBUG_PRINT (" failed\n");
4345       M17N_OBJECT_UNREF (ic->preedit);
4346       M17N_OBJECT_UNREF (ic->produced);
4347       M17N_OBJECT_UNREF (ic->plist);
4348       free (ic);
4349       return NULL;
4350     };
4351
4352   if (im->driver.callback_list)
4353     {
4354       minput_callback (ic, Minput_preedit_start);
4355       minput_callback (ic, Minput_status_start);
4356       minput_callback (ic, Minput_status_draw);
4357     }
4358
4359   MDEBUG_PRINT (" ok\n");
4360   return ic;
4361 }
4362
4363 /*=*/
4364
4365 /***en
4366     @brief Destroy an input context.
4367
4368     The minput_destroy_ic () function destroys the input context $IC,
4369     which must have been created by minput_create_ic ().  It calls
4370     callback functions corresponding to #Minput_preedit_done,
4371     #Minput_status_done, and #Minput_candidates_done in this order.  */
4372
4373 /***ja
4374     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
4375
4376     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
4377     ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () 
4378     ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï 
4379     #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done 
4380     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
4381   */
4382
4383 void
4384 minput_destroy_ic (MInputContext *ic)
4385 {
4386   MDEBUG_PRINT2 ("  [IM] destroying context (%s %s) ... ",
4387                  msymbol_name (ic->im->name), msymbol_name (ic->im->language));
4388   if (ic->im->driver.callback_list)
4389     {
4390       minput_callback (ic, Minput_preedit_done);
4391       minput_callback (ic, Minput_status_done);
4392       minput_callback (ic, Minput_candidates_done);
4393     }
4394   (*ic->im->driver.destroy_ic) (ic);
4395   M17N_OBJECT_UNREF (ic->preedit);
4396   M17N_OBJECT_UNREF (ic->produced);
4397   M17N_OBJECT_UNREF (ic->plist);
4398   MDEBUG_PRINT (" done\n");
4399   free (ic);
4400 }
4401
4402 /*=*/
4403
4404 /***en
4405     @brief Filter an input key.
4406
4407     The minput_filter () function filters input key $KEY according to
4408     input context $IC, and calls callback functions corresponding to
4409     #Minput_preedit_draw, #Minput_status_draw, and
4410     #Minput_candidates_draw if the preedit text, the status, and the
4411     current candidate are changed respectively.
4412
4413     To make the input method commit the current preedit text (if any)
4414     and shift to the initial state, call this function with #Mnil as
4415     $KEY.
4416
4417     To inform the input method about the focus-out event, call this
4418     function with #Minput_focus_out as $KEY.
4419
4420     To inform the input method about the focus-in event, call this
4421     function with #Minput_focus_in as $KEY.
4422
4423     To inform the input method about the focus-move event (i.e. input
4424     spot change within the same input context), call this function
4425     with #Minput_focus_move as $KEY.
4426
4427     @return
4428     If $KEY is filtered out, this function returns 1.  In that case,
4429     the caller should discard the key.  Otherwise, it returns 0, and
4430     the caller should handle the key, for instance, by calling the
4431     function minput_lookup () with the same key.  */
4432
4433 /***ja
4434     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
4435
4436     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4437     ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
4438     #Minput_preedit_draw, #Minput_status_draw,
4439     #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
4440
4441     @return 
4442     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
4443     ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
4444     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup ()
4445     ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
4446
4447     @latexonly \IPAlabel{minput_filter} @endlatexonly
4448 */
4449
4450 int
4451 minput_filter (MInputContext *ic, MSymbol key, void *arg)
4452 {
4453   int ret;
4454
4455   if (! ic
4456       || ! ic->active)
4457     return 0;
4458   if (ic->im->driver.callback_list
4459       && mtext_nchars (ic->preedit) > 0)
4460     minput_callback (ic, Minput_preedit_draw);
4461
4462   ret = (*ic->im->driver.filter) (ic, key, arg);
4463
4464   if (ic->im->driver.callback_list)
4465     {
4466       if (ic->preedit_changed)
4467         minput_callback (ic, Minput_preedit_draw);
4468       if (ic->status_changed)
4469         minput_callback (ic, Minput_status_draw);
4470       if (ic->candidates_changed)
4471         minput_callback (ic, Minput_candidates_draw);
4472     }
4473
4474   return ret;
4475 }
4476
4477 /*=*/
4478
4479 /***en
4480     @brief Look up a text produced in the input context.
4481
4482     The minput_lookup () function looks up a text in the input context
4483     $IC.  $KEY must be identical to the one that was used in the previous call of
4484     minput_filter ().
4485
4486     If a text was produced by the input method, it is concatenated
4487     to M-text $MT.
4488
4489     This function calls #MInputDriver::lookup .
4490
4491     @return
4492     If $KEY was correctly handled by the input method, this function
4493     returns 0.  Otherwise, it returns -1, even though some text
4494     might be produced in $MT.  */
4495
4496 /***ja
4497     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹.
4498
4499     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£
4500     $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4501
4502     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
4503     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
4504
4505     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
4506
4507     @return 
4508     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
4509     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
4510     ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
4511
4512     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
4513
4514 int
4515 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
4516 {
4517   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
4518 }
4519 /*=*/
4520
4521 /***en
4522     @brief Set the spot of the input context.
4523
4524     The minput_set_spot () function sets the spot of input context $IC
4525     to coordinate ($X, $Y ) with the height specified by $ASCENT and $DESCENT .
4526     The semantics of these values depends on the input method driver.
4527
4528     For instance, a driver designed to work in a CUI environment may
4529     use $X and $Y as the column- and row numbers, and may ignore $ASCENT and
4530     $DESCENT .  A driver designed to work in a window system may
4531     interpret $X and $Y as the pixel offsets relative to the origin of the
4532     client window, and may interpret $ASCENT and $DESCENT as the ascent- and
4533     descent pixels of the line at ($X . $Y ).
4534
4535     $FONTSIZE specifies the fontsize of preedit text in 1/10 point.
4536
4537     $MT and $POS are the M-text and the character position at the spot.
4538     $MT may be @c NULL, in which case, the input method cannot get
4539     information about the text around the spot.  */
4540
4541 /***ja
4542     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë.
4543
4544     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y )
4545     ¤Î°ÌÃ֤ˠ¡¢¹â¤µ $ASCENT¡¢ $DESCENT 
4546     ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£
4547
4548     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y 
4549     ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT 
4550     ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï
4551     $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
4552     $ASCENT ¤È $DESCENT ¤ò ($X . $Y )
4553     ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
4554
4555     $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
4556
4557     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
4558     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
4559     */
4560
4561 void
4562 minput_set_spot (MInputContext *ic, int x, int y,
4563                  int ascent, int descent, int fontsize,
4564                  MText *mt, int pos)
4565 {
4566   ic->spot.x = x;
4567   ic->spot.y = y;
4568   ic->spot.ascent = ascent;
4569   ic->spot.descent = descent;
4570   ic->spot.fontsize = fontsize;
4571   ic->spot.mt = mt;
4572   ic->spot.pos = pos;
4573   if (ic->im->driver.callback_list)
4574     minput_callback (ic, Minput_set_spot);
4575 }
4576 /*=*/
4577
4578 /***en
4579     @brief Toggle input method.
4580
4581     The minput_toggle () function toggles the input method associated
4582     with input context $IC.  */
4583 /***ja
4584     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
4585
4586     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4587     ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
4588     */
4589
4590 void
4591 minput_toggle (MInputContext *ic)
4592 {
4593   if (ic->im->driver.callback_list)
4594     minput_callback (ic, Minput_toggle);
4595   ic->active = ! ic->active;
4596 }
4597
4598 /*=*/
4599
4600 /***en
4601     @brief Reset an input context.
4602
4603     The minput_reset_ic () function resets input context $IC by
4604     calling a callback function corresponding to #Minput_reset.  It
4605     resets the status of $IC to its initial one.  As the
4606     current preedit text is deleted without commitment, if necessary,
4607     call minput_filter () with the arg @r key #Mnil to force the input
4608     method to commit the preedit in advance.  */
4609
4610 /***ja
4611     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
4612
4613     ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
4614     ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢
4615     ¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ë¡£¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹
4616     ¥È¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¤³¤È¤Ê¤¯ºï½ü¤µ¤ì¤ë¤Î¤Ç¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
4617     ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @r key #Mnil ¤Ç¸Æ¤ó¤Ç
4618     ¶¯À©Åª¤Ë¥×¥ê¥¨¥Ç¥£¥Ã¥È¥Æ¥­¥¹¥È¤ò¥³¥ß¥Ã¥È¤µ¤»¤ë¤³¤È¡£  */
4619
4620 void
4621 minput_reset_ic (MInputContext *ic)
4622 {
4623   if (ic->im->driver.callback_list)
4624     minput_callback (ic, Minput_reset);
4625 }
4626
4627 /*=*/
4628
4629 /***en
4630     @brief Get title and icon filename of an input method.
4631
4632     The minput_get_title_icon () function returns a plist containing a
4633     title and icon filename (if any) of an input method specified by
4634     $LANGUAGE and $NAME.
4635
4636     The first element of the plist has key #Mtext and the value is an
4637     M-text of the title for identifying the input method.  The second
4638     element (if any) has key #Mtext and the value is an M-text of the
4639     icon image (absolute) filename for the same purpose.
4640
4641     @return
4642     If there exists a specified input method and it defines an title,
4643     a plist is returned.  Otherwise, NULL is returned.  The caller
4644     must free the plist by m17n_object_unref ().  */
4645 /***ja
4646     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë̾¤òÆÀ¤ë.
4647
4648     ´Ø¿ô minput_get_title_icon () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ë
4649     ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¡Ê¤¢¤ì¤Ð¡Ë¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë¤ò´Þ¤à plist ¤ò
4650     ÊÖ¤¹¡£
4651
4652     plist ¤ÎÂè°ìÍ×ÁǤϡ¢#Mtext ¤ò¥­¡¼¤Ë»ý¤Á¡¢ÃͤÏÆþÎϥ᥽¥Ã¥É¤ò¼±Ê̤¹¤ë
4653     ¥¿¥¤¥È¥ë¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£ÂèÆóÍ×ÁǤ¬¤¢¤ì¤Ð¡¢¥­¡¼¤Ï #Mtext ¤Ç¤¢
4654     ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¥Õ¥¡¥¤¥ë¤ÎÀäÂХѥ¹¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
4655
4656     @return
4657     »ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¡¢¥¿¥¤¥È¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð
4658      plist ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð NULL ¤òÊÖ¤¹¡£¸Æ½Ð¦¤Ï
4659      ´Ø¿ô m17n_object_unref () ¤òÍѤ¤¤Æ plist ¤ò²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
4660
4661 MPlist *
4662 minput_get_title_icon (MSymbol language, MSymbol name)
4663 {
4664   MInputMethodInfo *im_info;
4665   MPlist *plist;
4666   char *file = NULL;
4667   MText *mt;
4668
4669   MINPUT__INIT ();
4670
4671   im_info = get_im_info (language, name, Mnil, Mtitle);
4672   if (! im_info || !im_info->title)
4673     return NULL;
4674   mt = mtext_get_prop (im_info->title, 0, Mtext);
4675   if (mt)
4676     file = mdatabase__find_file ((char *) MTEXT_DATA (mt));
4677   else
4678     {
4679       char *buf = alloca (MSYMBOL_NAMELEN (language) + MSYMBOL_NAMELEN (name)
4680                           + 12);
4681
4682       sprintf (buf, "icons/%s-%s.png", (char *) MSYMBOL_NAME (language), 
4683                (char *) MSYMBOL_NAME (name));
4684       file = mdatabase__find_file (buf);
4685       if (! file && language == Mt)
4686         {
4687           sprintf (buf, "icons/%s.png", (char *) MSYMBOL_NAME (name));
4688           file = mdatabase__find_file (buf);
4689         }
4690     }
4691
4692   plist = mplist ();
4693   mplist_add (plist, Mtext, im_info->title);
4694   if (file)
4695     {
4696       mt = mtext__from_data (file, strlen (file), MTEXT_FORMAT_UTF_8, 1);
4697       free (file);
4698       mplist_add (plist, Mtext, mt);
4699       M17N_OBJECT_UNREF (mt);
4700     }
4701   return plist;
4702 }
4703
4704 /*=*/
4705
4706 /***en
4707     @brief Get description text of an input method.
4708
4709     The minput_get_description () function returns an M-text that
4710     describes the input method specified by $LANGUAGE and $NAME.
4711
4712     @return
4713     If the specified input method has a description text, a pointer to
4714     #MText is returned.  The caller has to free it by m17n_object_unref ().
4715     If the input method does not have a description text, @c NULL is
4716     returned.  */
4717 /***ja
4718     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë.
4719
4720     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
4721     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
4722
4723     @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
4724     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
4725     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
4726     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
4727
4728 MText *
4729 minput_get_description (MSymbol language, MSymbol name)
4730 {
4731   MInputMethodInfo *im_info;
4732   MSymbol extra;
4733
4734   MINPUT__INIT ();
4735
4736   if (name != Mnil)
4737     extra = Mnil;
4738   else
4739     extra = language, language = Mt;
4740
4741   im_info = get_im_info (language, name, extra, Mdescription);
4742   if (! im_info || ! im_info->description)
4743     return NULL;
4744   M17N_OBJECT_REF (im_info->description);
4745   return im_info->description;
4746 }
4747
4748 /*=*/
4749
4750 /***en
4751     @brief Get information about input method command(s).
4752
4753     The minput_get_command () function returns information about
4754     the command $COMMAND of the input method specified by $LANGUAGE and
4755     $NAME.  An input method command is a pseudo key event to which one
4756     or more actual input key sequences are assigned.
4757
4758     There are two kinds of commands, global and local.  A global
4759     command has a global definition, and the description and the key
4760     assignment may be inherited by a local command.  Each input method
4761     defines a local command which has a local key assignment.  It may
4762     also declare a local command that inherits the definition of a
4763     global command of the same name.
4764
4765     If $LANGUAGE is #Mt and $NAME is #Mnil, this function returns
4766     information about a global command.  Otherwise information about a
4767     local command is returned.
4768
4769     If $COMMAND is #Mnil, information about all commands is returned.
4770
4771     The return value is a @e well-formed plist (#m17nPlist) of this
4772     format:
4773 @verbatim
4774   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
4775 @endverbatim
4776     @c NAME is a symbol representing the command name.
4777
4778     @c DESCRIPTION is an M-text describing the command, or #Mnil if the
4779     command has no description.
4780
4781     @c STATUS is a symbol representing how the key assignment is decided.
4782     The value is #Mnil (the default key assignment), #Mcustomized (the
4783     key assignment is customized by per-user configuration file), or
4784     #Mconfigured (the key assignment is set by the call of
4785     minput_config_command ()).  For a local command only, it may also
4786     be #Minherited (the key assignment is inherited from the
4787     corresponding global command).
4788
4789     @c KEYSEQ is a plist of one or more symbols representing a key
4790     sequence assigned to the command.  If there's no KEYSEQ, the
4791     command is currently disabled (i.e. no key sequence can trigger
4792     actions of the command).
4793
4794     If $COMMAND is not #Mnil, the first element of the returned plist
4795     contains the information about $COMMAND.
4796
4797     @return
4798
4799     If the requested information was found, a pointer to a non-empty
4800     plist is returned.  As the plist is kept in the library, the
4801     caller must not modify nor free it.
4802
4803     Otherwise (the specified input method or the specified command
4804     does not exist), @c NULL is returned.  */
4805 /***ja
4806     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
4807
4808     ´Ø¿ô minput_get_command () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
4809     ¥á¥½¥Ã¥É¤Î¥³¥Þ¥ó¥É $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ
4810     ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢£±¤Ä°Ê¾å¤Î¼ÂºÝ¤ÎÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨
4811     ¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
4812
4813     ¥³¥Þ¥ó¥É¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É
4814     ¤Ï¥°¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤Ï¤½¤ÎÀâÌÀ¤È¥­¡¼³ä¤êÅö¤Æ
4815     ¤ò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤ò»ý¤Ä¥í¡¼
4816     ¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÄêµÁ¤¹¤ë¡£¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É¤ÎÄêµÁ¤ò·Ñ
4817     ¾µ¤¹¤ë¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÀë¸À¤¹¤ë¤³¤È¤â¤Ç¤­¤ë¡£
4818
4819     $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ë¥³
4820     ¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¤â
4821     ¤Î¤òÊÖ¤¹¡£
4822
4823     $COMMAND ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
4824
4825     Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£
4826
4827 @verbatim
4828   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
4829 @endverbatim
4830     @c NAME ¤Ï¥³¥Þ¥ó¥É̾¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
4831
4832     @c DESCRIPTION ¤Ï¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë
4833     ¤Ï #Mnil ¤Ç¤¢¤ë¡£
4834
4835     @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢
4836     ¤ê¡¢¤½¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶
4837     Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë, #Mconfigured
4838     ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë³ä¤êÅö¤Æ¡Ë¤Î
4839     ¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢#Minherited ¡ÊÂбþ¤¹¤ë
4840     ¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë¤Ç¤â¤è¤¤¡£
4841
4842     @c KEYSEQ ¤Ï£±¤Ä°Ê¾å¤Î¥·¥ó¥Ü¥ë¤«¤é¤Ê¤ë plist ¤Ç¤¢¤ê¡¢³Æ¥·¥ó¥Ü¥ë¤Ï¥³¥Þ
4843     ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òɽ¤¹¡£KEYSEQ ¤¬Ìµ¤¤¾ì¹ç¤Ï¡¢
4844     ¤½¤Î¥³¥Þ¥ó¥É¤Ï¸½¾õ¤Ç»ÈÍÑÉÔǽ¤Ç¤¢¤ë¡£¡Ê¤¹¤Ê¤ï¤Á¥³¥Þ¥ó¥É¤ÎÆ°ºî¤òµ¯
4845     Æ°¤Ç¤­¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Ìµ¤¤¡£¡Ë
4846
4847     $COMMAND ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤϡ¢
4848     $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
4849
4850     @return
4851
4852     µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
4853     ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
4854     ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
4855
4856     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ä¥³¥Þ¥ó¥É¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
4857     @c NULL ¤òÊÖ¤¹¡£  */
4858
4859 #if EXAMPLE_CODE
4860 MText *
4861 get_im_command_description (MSymbol language, MSymbol name, MSymbol command)
4862 {
4863   /* Return a description of the command COMMAND of the input method
4864      specified by LANGUAGE and NAME.  */
4865   MPlist *cmd = minput_get_command (langauge, name, command);
4866   MPlist *plist;
4867
4868   if (! cmds)
4869     return NULL;
4870   plist = mplist_value (cmds);  /* (NAME DESCRIPTION KEY-SEQ ...) */
4871   plist = mplist_next (plist);  /* (DESCRIPTION KEY-SEQ ...) */
4872   return  (mplist_key (plist) == Mtext
4873            ? (MText *) mplist_value (plist)
4874            : NULL);
4875 }
4876 #endif
4877
4878 MPlist *
4879 minput_get_command (MSymbol language, MSymbol name, MSymbol command)
4880 {
4881   MInputMethodInfo *im_info;
4882
4883   MINPUT__INIT ();
4884
4885   im_info = get_im_info (language, name, Mnil, Mcommand);
4886   if (! im_info
4887       || ! im_info->configured_cmds
4888       || MPLIST_TAIL_P (im_info->configured_cmds))
4889     return NULL;
4890   if (command == Mnil)
4891     return im_info->configured_cmds;
4892   return mplist__assq (im_info->configured_cmds, command);
4893 }
4894
4895 /*=*/
4896
4897 /***en
4898     @brief Configure the key sequence of an input method command.
4899
4900     The minput_config_command () function assigns a list of key
4901     sequences $KEYSEQLIST to the command $COMMAND of the input method
4902     specified by $LANGUAGE and $NAME.
4903
4904     If $KEYSEQLIST is a non-empty plist, it must be a list of key
4905     sequences, and each key sequence must be a plist of symbols.
4906
4907     If $KEYSEQLIST is an empty plist, the default key sequences of the
4908     command for the input method is assigned to $COMMAND.
4909
4910     If $KEYSEQLIST is NULL, the configuration of the command for the
4911     input method is canceled, and the default key sequences become
4912     effective.  In such case, if $COMMAND is #Mnil, configurations for
4913     all commands of the input method are canceled.
4914
4915     If $NAME is #Mnil, this function configures the key assignment of a
4916     global command, not that of a specific input method.
4917
4918     The configuration takes effect for input methods opened or
4919     re-opened later in the current session.  In order to make the
4920     configuration take effect for the future session, it must be saved
4921     in a per-user configuration file by the function
4922     minput_save_config ().
4923
4924     @return
4925
4926     If the operation was successful, this function returns 0,
4927     otherwise returns -1.  The operation fails in these cases:
4928     <ul>
4929     <li>$KEYSEQLIST is not in a valid form.
4930     <li>$COMMAND is not available for the input method.
4931     <li>$LANGUAGE and $NAME do not specify an existing input method.
4932     </ul>
4933
4934     @seealso
4935     minput_get_commands (), minput_save_config ().
4936 */
4937 /***ja
4938     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òÀßÄꤹ¤ë.
4939
4940     ´Ø¿ô minput_config_command () ¤Ï¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È
4941     $KEYSEQLIST ¤ò¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤Î
4942     ¥³¥Þ¥ó¥É $COMMAND ¤Ë³ä¤êÅö¤Æ¤ë¡£
4943
4944     $KEYSEQLIST ¤¬¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È¤Ç¤¢¤ê¡¢
4945     ³Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥·¥ó¥Ü¥ë¤Î plist ¤Ç¤¢¤ë¡£
4946
4947     $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¥³¥Þ¥ó¥É¤Ï»ÈÍѤǤ­¤Ê¤¯¤Ê¤ë¡£
4948
4949     $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï
4950     ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£¤³¤Î¾ì¹ç¡¢
4951     $COMMAND ¤¬ #Mnil ¤Ê¤é¤Ð»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥É¤ÎÀßÄ꤬
4952     ¥­¥ã¥ó¥»¥ë¤µ¤ì¤ë¡£
4953
4954     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
4955     ¥ë¤Ê¥³¥Þ¥ó¥É¤Î¥­¡¼³ä¤êÅö¤Æ¤òÀßÄꤹ¤ë¡£
4956
4957     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
4958     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
4959     ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤
4960     ¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4961
4962     @return
4963
4964     ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
4965     <ul>
4966     <li>$KEYSEQLIST ¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£
4967     <li>$COMMAND ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
4968     <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
4969     </ul>
4970
4971     @seealso
4972     minput_get_commands (), minput_save_config ().
4973 */
4974
4975 #if EXAMPLE_CODE
4976 /* Add "C-x u" to the "start" command of Unicode input method.  */
4977 {
4978   MSymbol start_command = msymbol ("start");
4979   MSymbol unicode = msymbol ("unicode");
4980   MPlist *cmd, *plist, *key_seq_list, *key_seq;
4981
4982   /* At first get the current key-sequence assignment.  */
4983   cmd = mplist_get_command (Mt, unicode, start_command);
4984   if (! cmd)
4985     {
4986       /* The input method does not have the command "start".  Here
4987          should come some error handling code.  */
4988     }
4989   /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...).  Extract
4990      the part (KEY-SEQUENCE ...).  */
4991   plist = mplist_next (mplist_next (mplist_value (cmd)));
4992   /* Copy it because we should not modify it directly.  */
4993   key_seq_list = mplist_copy (plist);
4994   m17n_object_unref (cmds);
4995   
4996   key_seq = mplist ();
4997   mplist_add (key_seq, Msymbol, msymbol ("C-x"));
4998   mplist_add (key_seq, Msymbol, msymbol ("u"));
4999   mplist_add (key_seq_list, Mplist, key_seq);
5000   m17n_object_unref (key_seq);
5001
5002   minput_config_command (Mt, unicode, start_command, key_seq_list);
5003   m17n_object_unref (key_seq_list);
5004 }
5005 #endif
5006
5007 int
5008 minput_config_command (MSymbol language, MSymbol name, MSymbol command,
5009                        MPlist *keyseqlist)
5010 {
5011   MInputMethodInfo *im_info, *config;
5012   MPlist *plist;
5013
5014   MINPUT__INIT ();
5015
5016   im_info = get_im_info (language, name, Mnil, Mcommand);
5017   if (! im_info)
5018     MERROR (MERROR_IM, -1);
5019   if (command == Mnil ? (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
5020       : (! im_info->cmds
5021          || ! mplist__assq (im_info->configured_cmds, command)))
5022     MERROR (MERROR_IM, -1);
5023   if (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
5024     {
5025       MPLIST_DO (plist, keyseqlist)
5026         if (! check_command_keyseq (plist))
5027           MERROR (MERROR_IM, -1);
5028     }
5029
5030   config = get_config_info (im_info);
5031   if (! config)
5032     {
5033       if (! im_config_list)
5034         im_config_list = mplist ();
5035       config = new_im_info (NULL, language, name, Mnil, im_config_list);
5036       config->cmds = mplist ();
5037       config->vars = mplist ();
5038     }
5039
5040   if (! keyseqlist && MPLIST_TAIL_P (config->cmds))
5041     /* Nothing to do.  */
5042     return 0;
5043
5044   if (command == Mnil)
5045     {
5046       if (! keyseqlist)
5047         {
5048           /* Cancal the configuration. */
5049           if (MPLIST_TAIL_P (config->cmds))
5050             return 0;
5051           mplist_set (config->cmds, Mnil, NULL);
5052         }
5053       else
5054         {
5055           /* Cancal the customization. */
5056           MInputMethodInfo *custom = get_custom_info (im_info);
5057
5058           if (MPLIST_TAIL_P (config->cmds)
5059               && (! custom || ! custom->cmds || MPLIST_TAIL_P (custom->cmds)))
5060             /* Nothing to do.  */
5061             return 0;
5062           mplist_set (config->cmds, Mnil, NULL);
5063           MPLIST_DO (plist, custom->cmds)
5064             {
5065               command = MPLIST_SYMBOL (MPLIST_PLIST (plist));
5066               plist = mplist ();
5067               mplist_add (plist, Msymbol, command);
5068               mplist_push (config->cmds, Mplist, plist);
5069               M17N_OBJECT_UNREF (plist);
5070             }
5071         }
5072     }
5073   else
5074     {
5075       plist = mplist__assq (config->cmds, command);
5076       if (! keyseqlist)
5077         {
5078           /* Cancel the configuration.  */
5079           if (! plist)
5080             return 0;
5081           mplist__pop_unref (plist);
5082         }
5083       else if (MPLIST_TAIL_P (keyseqlist))
5084         {
5085           /* Cancel the customization.  */
5086           MInputMethodInfo *custom = get_custom_info (im_info);
5087           int no_custom = (! custom || ! custom->cmds
5088                            || ! mplist__assq (custom->cmds, command));
5089           if (! plist)
5090             {
5091               if (no_custom)
5092                 return 0;
5093               plist = mplist ();
5094               mplist_add (config->cmds, Mplist, plist);
5095               M17N_OBJECT_UNREF (plist);
5096               plist = mplist_add (plist, Msymbol, command);
5097             }
5098           else
5099             {
5100               plist = MPLIST_PLIST (plist); /* (NAME nil KEYSEQ ...) */
5101               plist = MPLIST_NEXT (plist);
5102               if (MPLIST_TAIL_P (plist))
5103                 return 0;
5104               mplist_set (plist, Mnil, NULL);
5105             }
5106         }
5107       else
5108         {
5109           MPlist *pl;
5110
5111           if (plist)
5112             {
5113               plist = MPLIST_NEXT (MPLIST_PLIST (plist));
5114               if (! MPLIST_TAIL_P (plist))
5115                 mplist_set (plist, Mnil, NULL);
5116             }
5117           else
5118             {
5119               plist = mplist ();
5120               mplist_add (config->cmds, Mplist, plist);
5121               M17N_OBJECT_UNREF (plist);
5122               plist = mplist_add (plist, Msymbol, command);
5123               plist = MPLIST_NEXT (plist);
5124             }
5125           MPLIST_DO (keyseqlist, keyseqlist)
5126             {
5127               pl = mplist_copy (MPLIST_VAL (keyseqlist));
5128               plist = mplist_add (plist, Mplist, pl);
5129               M17N_OBJECT_UNREF (pl);
5130             }
5131         }
5132     }
5133   config_all_commands (im_info);
5134   im_info->tick = time (NULL);
5135   return 0;
5136 }
5137
5138 /*=*/
5139
5140 /***en
5141     @brief Get information about input method variable(s).
5142
5143     The minput_get_variable () function returns information about
5144     the variable $VARIABLE of the input method specified by $LANGUAGE and $NAME.
5145     An input method variable controls behavior of an input method.
5146
5147     There are two kinds of variables, global and local.  A global
5148     variable has a global definition, and the description and the value
5149     may be inherited by a local variable.  Each input method defines a
5150     local variable which has local value.  It may also declare a
5151     local variable that inherits definition of a global variable of
5152     the same name.
5153
5154     If $LANGUAGE is #Mt and $NAME is #Mnil, information about a global
5155     variable is returned.  Otherwise information about a local variable
5156     is returned.
5157
5158     If $VARIABLE is #Mnil, information about all variables is
5159     returned.
5160
5161     The return value is a @e well-formed plist (#m17nPlist) of this
5162     format:
5163 @verbatim
5164   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
5165 @endverbatim
5166     @c NAME is a symbol representing the variable name.
5167
5168     @c DESCRIPTION is an M-text describing the variable, or #Mnil if the
5169     variable has no description.
5170
5171     @c STATUS is a symbol representing how the value is decided.  The
5172     value is #Mnil (the default value), #Mcustomized (the value is
5173     customized by per-user configuration file), or #Mconfigured (the
5174     value is set by the call of minput_config_variable ()).  For a
5175     local variable only, it may also be #Minherited (the value is
5176     inherited from the corresponding global variable).
5177
5178     @c VALUE is the initial value of the variable.  If the key of this
5179     element is #Mt, the variable has no initial value.  Otherwise, the
5180     key is #Minteger, #Msymbol, or #Mtext and the value is of the
5181     corresponding type.
5182
5183     @c VALID-VALUEs (if any) specify which values the variable can have.
5184     They have the same type (i.e. having the same key) as @c VALUE except
5185     for the case that VALUE is an integer.  In that case, @c VALID-VALUE
5186     may be a plist of two integers specifying the range of possible
5187     values.
5188
5189     If there no @c VALID-VALUE, the variable can have any value as long
5190     as the type is the same as @c VALUE.
5191
5192     If $VARIABLE is not #Mnil, the first element of the returned plist
5193     contains the information about $VARIABLE.
5194
5195     @return
5196
5197     If the requested information was found, a pointer to a non-empty
5198     plist is returned.  As the plist is kept in the library, the
5199     caller must not modify nor free it.
5200
5201     Otherwise (the specified input method or the specified variable
5202     does not exist), @c NULL is returned.  */
5203 /***ja
5204     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
5205
5206     ´Ø¿ô minput_get_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
5207     ¥á¥½¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤È¤Ï¡¢
5208     ÆþÎϥ᥽¥Ã¥É¤Î¿¶Éñ¤òÀ©¸æ¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£
5209
5210     ÊÑ¿ô¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤Ï¥°
5211     ¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤Ï¤½¤ÎÀâÌÀ¤ÈÃͤò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç
5212     ¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤ÊÃͤò»ý¤Ä¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÄêµÁ¤¹¤ë¡£
5213     ¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤ÎÄêµÁ¤ò·Ñ¾µ¤¹¤ë¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÀë¸À¤¹¤ë
5214     ¤³¤È¤â¤Ç¤­¤ë¡£
5215
5216     $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ëÊÑ
5217     ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ëÊÑ¿ô¤Ë´Ø¤¹¤ë¤â¤Î¤òÊÖ¤¹¡£
5218
5219     $VARIABLE ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
5220
5221     Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£
5222 @verbatim
5223   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
5224 @endverbatim
5225
5226     @c NAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
5227
5228     @c DESCRIPTION ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë¤Ï
5229     #Mnil ¤Ç¤¢¤ë¡£
5230
5231     @c STATUS ¤ÏÃͤ¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢
5232     @c STATUS ¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤ÎÀß
5233     Äê¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, #Mconfigured
5234     ¡Êminput_config_variable ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ëÃ͡ˤΤ¤¤º¤ì
5235     ¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ëÊÑ¿ô¤Î¾ì¹ç¤Ë¤Ï¡¢#Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë
5236     ÊÑ¿ô¤«¤é·Ñ¾µ¤·¤¿Ã͡ˤǤâ¤è¤¤¡£
5237
5238     @c VALUE ¤ÏÊÑ¿ô¤Î½é´üÃͤǤ¢¤ë¡£¤³¤ÎÍ×ÁǤΥ­¡¼¤¬#Mt ¤Ç¤¢¤ì¤Ð½é´üÃͤò»ý
5239     ¤¿¤Ê¤¤¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤Ï #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì
5240     ¤«¤Ç¤¢¤ê¡¢ÃͤϤ½¤ì¤¾¤ìÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
5241
5242     @c VALID-VALUE ¤Ï¤â¤·¤¢¤ì¤Ð¡¢ÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò»ØÄꤹ¤ë¡£¤³¤ì¤Ï @c VALUE
5243     ¤ÈƱ¤¸·¿(¤¹¤Ê¤ï¤ÁƱ¤¸¥­¡¼¤ò»ý¤Ä) ¤Ç¤¢¤ë¤¬¡¢Îã³°¤È¤·¤Æ @c VALUE ¤¬
5244     integer ¤Î¾ì¹ç¤Ï @c VALID-VALUE ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹Æó¤Ä¤ÎÀ°¿ô¤«¤é
5245     ¤Ê¤ë plist ¤È¤Ê¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
5246
5247     @c VALID-VALUE ¤¬¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô¤Ï @c VALUE ¤ÈƱ¤¸·¿¤Ç¤¢¤ë¸Â¤ê¤¤¤«¤Ê¤ëÃͤâ
5248     ¤È¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
5249
5250     $VARIABLE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤÏ
5251     $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
5252
5253     @return
5254
5255     µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
5256     ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
5257     ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5258
5259     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤äÊÑ¿ô¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
5260     @c NULL ¤òÊÖ¤¹¡£ */
5261
5262 MPlist *
5263 minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
5264 {
5265   MInputMethodInfo *im_info;
5266
5267   MINPUT__INIT ();
5268
5269   im_info = get_im_info (language, name, Mnil, Mvariable);
5270   if (! im_info || ! im_info->configured_vars)
5271     return NULL;
5272   if (variable == Mnil)
5273     return im_info->configured_vars;
5274   return mplist__assq (im_info->configured_vars, variable);
5275 }
5276
5277 /*=*/
5278
5279 /***en
5280     @brief Configure the value of an input method variable.
5281
5282     The minput_config_variable () function assigns $VALUE to the
5283     variable $VARIABLE of the input method specified by $LANGUAGE and
5284     $NAME.
5285
5286     If $VALUE is not NULL, it must be a plist of one element whose key
5287     is #Minteger, #Msymbol, or #Mtext, or an empty plist.  In the
5288     former case, the value must be of the corresponding type, and it
5289     is assinged to $VARIABLE.  In the latter case, the default value
5290     for the input method is assigned to $VARIABLE.
5291
5292     If $VALUE is NULL, a configuration for the variable for the input
5293     method is canceled, and the variable is initialized to the
5294     original value (it may be what saved in per-user configuration
5295     file, or the default value of the input method).
5296
5297     If $VALUE is an empty plist or NULL, $VARIABLE can be #Mnil.  In
5298     that case, it is applied to all the variables of the input method
5299     are canceled.
5300
5301     If $NAME is #Mnil, this function configure the value of global
5302     variable, not that of a specific input method.
5303
5304     The configuration takes effect for input methods opened or
5305     re-opened later in the current session.  To make the configuration
5306     take effect for the future session, it must be saved in a per-user
5307     configuration file by the function minput_save_config ().
5308
5309     @return
5310
5311     If the operation was successful, this function returns 0,
5312     otherwise returns -1.  The operation fails in these cases:
5313     <ul>
5314     <li>$VALUE is not in a valid form, the type does not match the
5315     definition, or the value is our of range.
5316     <li>$VARIABLE is not available for the input method.
5317     <li>$LANGUAGE and $NAME do not specify an existing input method.  
5318     </ul>
5319
5320     @seealso
5321     minput_get_variable (), minput_save_config ().  */
5322 /***ja
5323     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë.
5324
5325     ´Ø¿ô minput_config_variable () ¤ÏÃÍ $VALUE ¤ò¡¢$LANGUAGE ¤È $NAME
5326     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤ë¡£
5327
5328     $VALUE ¤¬ NULL¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï
5329     #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì¤«¡¢ÃͤÏÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
5330
5331     $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë
5332     ¤µ¤ì¡¢ÊÑ¿ô¤Ï¥Ç¥Õ¥©¥ë¥ÈÃͤ˽é´ü²½¤µ¤ì¤ë¡£¤³¤Î¾ì¹ç¡¢$VARIABLE ¤¬
5333     #Mnil ¤Ê¤é¤Ð»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ô¤ÎÀßÄ꤬¥­¥ã¥ó¥»¥ë¤µ¤ì¤ë¡£
5334
5335     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
5336     ¥ë¤ÊÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë¡£
5337
5338     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
5339     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
5340     ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤
5341     ¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
5342
5343     @return
5344
5345     ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
5346     <ul>
5347     <li>$VALUE¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£·¿¤¬ÄêµÁ¤Ë¹ç¤ï¤Ê¤¤¡¢¤Þ¤¿¤ÏÃͤ¬Èϰϳ°¤Ç¤¢¤ë¡£
5348     <li>$VARIABLE ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
5349     <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
5350     </ul>
5351
5352     @seealso
5353     minput_get_commands (), minput_save_config ().
5354 */
5355 int
5356 minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
5357                         MPlist *value)
5358 {
5359   MInputMethodInfo *im_info, *config;
5360   MPlist *plist;
5361
5362   MINPUT__INIT ();
5363
5364   im_info = get_im_info (language, name, Mnil, Mvariable);
5365   if (! im_info)
5366     MERROR (MERROR_IM, -1);
5367   if (variable == Mnil ? (value && ! MPLIST_TAIL_P (value))
5368       : (! im_info->vars
5369          || ! (plist = mplist__assq (im_info->configured_vars, variable))))
5370     MERROR (MERROR_IM, -1);
5371
5372   if (value && ! MPLIST_TAIL_P (value))
5373     {
5374       plist = MPLIST_PLIST (plist);
5375       plist = MPLIST_NEXT (plist); /* (DESC STATUS VALUE VALIDS ...) */
5376       plist = MPLIST_NEXT (plist); /* (STATUS VALUE VALIDS ...) */
5377       plist = MPLIST_NEXT (plist); /* (VALUE VALIDS ...) */
5378       if (MPLIST_KEY (plist) != Mt
5379           && ! check_variable_value (value, plist))
5380         MERROR (MERROR_IM, -1);
5381     }
5382
5383   config = get_config_info (im_info);
5384   if (! config)
5385     {
5386       if (! im_config_list)
5387         im_config_list = mplist ();
5388       config = new_im_info (NULL, language, name, Mnil, im_config_list);
5389       config->cmds = mplist ();
5390       config->vars = mplist ();
5391     }
5392
5393   if (! value && MPLIST_TAIL_P (config->vars))
5394     /* Nothing to do.  */
5395     return 0;
5396
5397   if (variable == Mnil)
5398     {
5399       if (! value)
5400         {
5401           /* Cancel the configuration.  */
5402           if (MPLIST_TAIL_P (config->vars))
5403             return 0;
5404           mplist_set (config->vars, Mnil, NULL);
5405         }
5406       else
5407         {
5408           /* Cancel the customization.  */
5409           MInputMethodInfo *custom = get_custom_info (im_info);
5410
5411           if (MPLIST_TAIL_P (config->vars)
5412               && (! custom || ! custom->vars || MPLIST_TAIL_P (custom->vars)))
5413             /* Nothing to do.  */
5414             return 0;
5415           mplist_set (config->vars, Mnil, NULL);
5416           MPLIST_DO (plist, custom->vars)
5417             {
5418               variable = MPLIST_SYMBOL (MPLIST_PLIST (plist));
5419               plist = mplist ();
5420               mplist_add (plist, Msymbol, variable);
5421               mplist_push (config->vars, Mplist, plist);
5422               M17N_OBJECT_UNREF (plist);
5423             }
5424         }
5425     }
5426   else
5427     {
5428       plist = mplist__assq (config->vars, variable);
5429       if (! value)
5430         {
5431           /* Cancel the configuration.  */
5432           if (! plist)
5433             return 0;
5434           mplist__pop_unref (plist);
5435         }
5436       else if (MPLIST_TAIL_P (value))
5437         {
5438           /* Cancel the customization.  */
5439           MInputMethodInfo *custom = get_custom_info (im_info);
5440           int no_custom = (! custom || ! custom->vars
5441                            || ! mplist__assq (custom->vars, variable));
5442           if (! plist)
5443             {
5444               if (no_custom)
5445                 return 0;
5446               plist = mplist ();
5447               mplist_add (config->vars, Mplist, plist);
5448               M17N_OBJECT_UNREF (plist);
5449               plist = mplist_add (plist, Msymbol, variable);
5450             }
5451           else
5452             {
5453               plist = MPLIST_PLIST (plist); /* (NAME nil VALUE) */
5454               plist = MPLIST_NEXT (plist);      /* ([nil VALUE]) */
5455               if (! MPLIST_TAIL_P (plist))
5456                 return 0;
5457               mplist_set (plist, Mnil ,NULL);
5458             }
5459         }
5460       else
5461         {
5462           if (plist)
5463             {
5464               plist = MPLIST_NEXT (MPLIST_PLIST (plist));
5465               if (! MPLIST_TAIL_P (plist))
5466                 mplist_set (plist, Mnil, NULL);
5467             }
5468           else
5469             {
5470               plist = mplist ();
5471               mplist_add (config->vars, Mplist, plist);
5472               M17N_OBJECT_UNREF (plist);
5473               plist = mplist_add (plist, Msymbol, variable);
5474               plist = MPLIST_NEXT (plist);
5475             }
5476           mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value));
5477         }
5478     }
5479   config_all_variables (im_info);
5480   im_info->tick = time (NULL);
5481   return 0;
5482 }
5483
5484 /*=*/
5485
5486 /***en
5487     @brief Get the name of per-user configuration file.
5488     
5489     The minput_config_file () function returns the absolute path name
5490     of per-user configuration file into which minput_save_config ()
5491     save configurations.  It is usually @c "config.mic" under the
5492     directory @c ".m17n.d" of user's home directory.  It is not assured
5493     that the file of the returned name exists nor is
5494     readable/writable.  If minput_save_config () fails and returns -1,
5495     an application program might check the file, make it
5496     writable (if possible), and try minput_save_config () again.
5497
5498     @return
5499
5500     This function returns a string.  As the string is kept in the
5501     library, the caller must not modify nor free it.
5502
5503     @seealso
5504     minput_save_config ()
5505 */
5506 /***ja
5507     @brief ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÆÀ¤ë.
5508     
5509     ´Ø¿ô minput_config_file () ¤Ï¡¢´Ø¿ô minput_save_config () ¤¬ÀßÄê¤ò
5510     Êݸ¤¹¤ë¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Ø¤ÎÀäÂХѥ¹Ì¾¤òÊÖ¤¹¡£Ä̾ï¤Ï¡¢¥æ¡¼¥¶
5511     ¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î²¼¤Î¥Ç¥£¥ì¥¯¥È¥ê @c ".m17n.d" ¤Ë¤¢¤ë@c
5512     "config.mic" ¤È¤Ê¤ë¡£ÊÖ¤µ¤ì¤¿Ì¾Á°¤Î¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¡¢Æɤ߽ñ¤­¤Ç
5513     ¤­¤ë¤«¤ÏÊݾڤµ¤ì¤Ê¤¤¡£´Ø¿ôminput_save_config () ¤¬¼ºÇÔ¤·¤Æ -1 ¤òÊÖ
5514     ¤·¤¿¾ì¹ç¤Ë¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò³Îǧ¤·¡¢
5515     ¡Ê¤Ç¤­¤ì¤Ð¡Ë½ñ¤­¹þ¤ß²Äǽ¤Ë¤·ºÆÅÙminput_save_config () ¤ò»î¤¹¤³¤È¤¬
5516     ¤Ç¤­¤ë¡£
5517
5518     @return
5519
5520     ¤³¤Î´Ø¿ô¤Ïʸ»úÎó¤òÊÖ¤¹¡£Ê¸»úÎó¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð
5521     Â¦¤¬½¤Àµ¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5522
5523     @seealso
5524     minput_save_config ()
5525 */
5526
5527 char *
5528 minput_config_file ()
5529 {
5530   MINPUT__INIT ();
5531
5532   return mdatabase__file (im_custom_mdb);
5533 }
5534
5535 /*=*/
5536
5537 /***en
5538     @brief Save configurations in per-user configuration file.
5539
5540     The minput_save_config () function saves the configurations done
5541     so far in the current session into the per-user configuration
5542     file.
5543
5544     @return
5545
5546     If the operation was successful, 1 is returned.  If the per-user
5547     configuration file is currently locked, 0 is returned.  In that
5548     case, the caller may wait for a while and try again.  If the
5549     configuration file is not writable, -1 is returned.  In that case,
5550     the caller may check the name of the file by calling
5551     minput_config_file (), make it writable if possible, and try
5552     again.
5553
5554     @seealso
5555     minput_config_file ()  */
5556 /***ja
5557     @brief ÀßÄê¤ò¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë.
5558
5559     ´Ø¿ô minput_save_config () ¤Ï¸½¹Ô¤Î¥»¥Ã¥·¥ç¥ó¤Ç¤³¤ì¤Þ¤Ç¤Ë¹Ô¤Ã¤¿ÀßÄê
5560     ¤ò¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë¡£
5561
5562     @return
5563
5564     À®¸ù¤¹¤ì¤Ð 1 ¤òÊÖ¤¹¡£¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤ì¤Ð 0
5565     ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢¸Æ½Ð¦¤Ï¤·¤Ð¤é¤¯ÂԤäƺƻî¹Ô¤Ç¤­¤ë¡£ÀßÄê¥Õ¥¡¥¤¥ë
5566     ¤¬½ñ¤­¹þ¤ßÉԲĤξì¹ç¡¢-1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢minput_config_file () ¤ò
5567     ¸Æ¤ó¤Ç¥Õ¥¡¥¤¥ë̾¤ò¥Á¥§¥Ã¥¯¤·¡¢¤Ç¤­¤ì¤Ð½ñ¤­¹þ¤ß²Äǽ¤Ë¤·¡¢ºÆ»î¹Ô¤Ç¤­
5568     ¤ë¡£
5569
5570     @seealso
5571     minput_config_file ()  */
5572
5573 int
5574 minput_save_config (void)
5575 {
5576   MPlist *data, *tail, *plist, *p, *elt;
5577   int ret;
5578
5579   MINPUT__INIT ();
5580   ret = mdatabase__lock (im_custom_mdb);
5581   if (ret <= 0)
5582     return ret;
5583   if (! im_config_list)
5584     return 1;
5585   update_custom_info ();
5586   if (! im_custom_list)
5587     im_custom_list = mplist ();
5588
5589   /* At first, reflect configuration in customization.  */
5590   MPLIST_DO (plist, im_config_list)
5591     {
5592       MPlist *pl = MPLIST_PLIST (plist);
5593       MSymbol language, name, extra, command, variable;
5594       MInputMethodInfo *custom, *config;
5595
5596       language = MPLIST_SYMBOL (pl);
5597       pl = MPLIST_NEXT (pl);
5598       name = MPLIST_SYMBOL (pl);
5599       pl = MPLIST_NEXT (pl);
5600       extra = MPLIST_SYMBOL (pl);
5601       pl = MPLIST_NEXT (pl);
5602       config = MPLIST_VAL (pl);
5603       custom = get_custom_info (config);
5604       if (! custom)
5605         custom = new_im_info (NULL, language, name, extra, im_custom_list);
5606       if (config->cmds)
5607         MPLIST_DO (pl, config->cmds)
5608           {
5609             elt = MPLIST_PLIST (pl);
5610             command = MPLIST_SYMBOL (elt);
5611             if (custom->cmds)
5612               p = mplist__assq (custom->cmds, command);
5613             else
5614               custom->cmds = mplist (), p = NULL;
5615             elt = MPLIST_NEXT (elt);
5616             if (MPLIST_TAIL_P (elt))
5617               {
5618                 if (p)
5619                   {
5620                     /* Make customization ignored.  */
5621                     p = MPLIST_NEXT (MPLIST_PLIST (p));
5622                     mplist_set (p, Mnil, NULL);
5623                   }
5624               }
5625             else
5626               {
5627                 elt = MPLIST_NEXT (elt);
5628                 if (p)
5629                   {
5630                     p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5631                     mplist_set (p, Mnil, NULL);
5632                     mplist__conc (p, elt);
5633                   }
5634                 else
5635                   {
5636                     p = MPLIST_PLIST (pl);
5637                     mplist_add (custom->cmds, Mplist, p);
5638                   }
5639               }
5640           }
5641       if (config->vars)
5642         MPLIST_DO (pl, config->vars)
5643           {
5644             elt = MPLIST_PLIST (pl);
5645             variable = MPLIST_SYMBOL (elt);
5646             if (custom->vars)
5647               p = mplist__assq (custom->vars, variable);
5648             else
5649               custom->vars = mplist (), p = NULL;
5650             elt = MPLIST_NEXT (elt);
5651             if (MPLIST_TAIL_P (elt))
5652               {
5653                 if (p)
5654                   mplist__pop_unref (p);
5655               }
5656             else
5657               {
5658                 elt = MPLIST_NEXT (elt);
5659                 if (p)
5660                   {
5661                     p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5662                     mplist_set (p, Mnil, NULL);
5663                     mplist__conc (p, elt);
5664                   }
5665                 else
5666                   {
5667                     p = MPLIST_PLIST (pl);
5668                     mplist_add (custom->vars, Mplist, p);
5669                   }
5670               }
5671           }
5672     }
5673   M17N_OBJECT_UNREF (im_config_list);
5674
5675   /* Next, reflect customization to the actual plist to be written.  */
5676   data = tail = mplist ();
5677   MPLIST_DO (plist, im_custom_list)
5678     {
5679       MPlist *pl = MPLIST_PLIST (plist);
5680       MSymbol language, name, extra;
5681       MInputMethodInfo *custom, *im_info;
5682
5683       language = MPLIST_SYMBOL (pl);
5684       pl  = MPLIST_NEXT (pl);
5685       name = MPLIST_SYMBOL (pl);
5686       pl = MPLIST_NEXT (pl);
5687       extra = MPLIST_SYMBOL (pl);
5688       pl = MPLIST_NEXT (pl);
5689       custom = MPLIST_VAL (pl);
5690       if ((! custom->cmds || MPLIST_TAIL_P (custom->cmds))
5691           && (! custom->vars || MPLIST_TAIL_P (custom->vars)))
5692         continue;
5693       im_info = lookup_im_info (im_info_list, language, name, extra);
5694       if (im_info)
5695         {
5696           if (im_info->cmds)
5697             config_all_commands (im_info);
5698           if (im_info->vars)
5699             config_all_variables (im_info);
5700         }
5701       
5702       elt = NULL;
5703       if (custom->cmds && ! MPLIST_TAIL_P (custom->cmds))
5704         {
5705           MPLIST_DO (p, custom->cmds)
5706             if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5707               break;
5708           if (! MPLIST_TAIL_P (p))
5709             {
5710               elt = mplist ();
5711               pl = mplist ();
5712               mplist_add (elt, Mplist, pl);
5713               M17N_OBJECT_UNREF (pl);
5714               pl = mplist_add (pl, Msymbol, Mcommand);
5715               MPLIST_DO (p, custom->cmds)
5716                 if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5717                   pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5718             }
5719         }
5720       if (custom->vars && ! MPLIST_TAIL_P (custom->vars))
5721         {
5722           MPLIST_DO (p, custom->vars)
5723             if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5724               break;
5725           if (! MPLIST_TAIL_P (p))
5726             {
5727               if (! elt)
5728                 elt = mplist ();
5729               pl = mplist ();
5730               mplist_add (elt, Mplist, pl);
5731               M17N_OBJECT_UNREF (pl);
5732               pl = mplist_add (pl, Msymbol, Mvariable);
5733               MPLIST_DO (p, custom->vars)
5734                 if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5735                   pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5736             }
5737         }
5738       if (elt)
5739         {
5740           pl = mplist ();
5741           mplist_push (elt, Mplist, pl);
5742           M17N_OBJECT_UNREF (pl);
5743           pl = mplist_add (pl, Msymbol, Minput_method);
5744           pl = mplist_add (pl, Msymbol, language);
5745           pl = mplist_add (pl, Msymbol, name);
5746           if (extra != Mnil)
5747             pl = mplist_add (pl, Msymbol, extra);
5748           tail = mplist_add (tail, Mplist, elt);
5749           M17N_OBJECT_UNREF (elt);
5750         }
5751     }
5752
5753   mplist_push (data, Mstring, ";; -*- mode:lisp; coding:utf-8 -*-");
5754   ret = mdatabase__save (im_custom_mdb, data);
5755   mdatabase__unlock (im_custom_mdb);
5756   M17N_OBJECT_UNREF (data);
5757   return (ret < 0 ? -1 : 1);
5758 }
5759
5760 /*=*/
5761 /*** @} */
5762 /*=*/
5763 /***en
5764     @name Obsolete functions
5765 */
5766 /***ja
5767     @name Obsolete ¤Ê´Ø¿ô
5768 */
5769 /*** @{ */
5770
5771 /*=*/
5772 /***en
5773     @brief Get a list of variables of an input method (obsolete).
5774
5775     This function is obsolete.  Use minput_get_variable () instead.
5776
5777     The minput_get_variables () function returns a plist (#MPlist) of
5778     variables used to control the behavior of the input method
5779     specified by $LANGUAGE and $NAME.  The plist is @e well-formed
5780     (#m17nPlist) of the following format:
5781
5782 @verbatim
5783     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5784      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5785      ...)
5786 @endverbatim
5787
5788     @c VARNAME is a symbol representing the variable name.
5789
5790     @c DOC-MTEXT is an M-text describing the variable.
5791
5792     @c DEFAULT-VALUE is the default value of the variable.  It is a
5793     symbol, integer, or M-text.
5794
5795     @c VALUEs (if any) specifies the possible values of the variable.
5796     If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
5797     @c TO), where @c FROM and @c TO specifies a range of possible
5798     values.
5799
5800     For instance, suppose an input method has the variables:
5801
5802     @li name:intvar, description:"value is an integer",
5803          initial value:0, value-range:0..3,10,20
5804
5805     @li name:symvar, description:"value is a symbol",
5806          initial value:nil, value-range:a, b, c, nil
5807
5808     @li name:txtvar, description:"value is an M-text",
5809          initial value:empty text, no value-range (i.e. any text)
5810
5811     Then, the returned plist is as follows.
5812
5813 @verbatim
5814     (intvar ("value is an integer" 0 (0 3) 10 20)
5815      symvar ("value is a symbol" nil a b c nil)
5816      txtvar ("value is an M-text" ""))
5817 @endverbatim
5818
5819     @return
5820     If the input method uses any variables, a pointer to #MPlist is
5821     returned.  As the plist is kept in the library, the caller must not
5822     modify nor free it.  If the input method does not use any
5823     variable, @c NULL is returned.  */
5824 /***ja
5825     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
5826
5827     ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
5828     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
5829     (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
5830     ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
5831
5832 @verbatim
5833     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5834      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5835      ...)
5836 @endverbatim
5837
5838     @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
5839
5840     @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
5841
5842     @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
5843     M-text ¤Ç¤¢¤ë¡£
5844
5845     @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
5846     @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
5847     ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
5848
5849     Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
5850
5851     @li name:intvar, ÀâÌÀ:"value is an integer",
5852         ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
5853
5854     @li name:symvar, ÀâÌÀ:"value is a symbol",
5855          ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
5856
5857     @li name:txtvar, ÀâÌÀ:"value is an M-text",
5858         ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
5859
5860     ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
5861
5862 @verbatim
5863     (intvar ("value is an integer" 0 (0 3) 10 20)
5864      symvar ("value is a symbol" nil a b c nil)
5865      txtvar ("value is an M-text" ""))
5866 @endverbatim
5867
5868     @return 
5869     ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
5870     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
5871     ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
5872
5873 MPlist *
5874 minput_get_variables (MSymbol language, MSymbol name)
5875 {
5876   MInputMethodInfo *im_info;
5877   MPlist *vars;
5878
5879   MINPUT__INIT ();
5880
5881   im_info = get_im_info (language, name, Mnil, Mvariable);
5882   if (! im_info || ! im_info->configured_vars)
5883     return NULL;
5884
5885   M17N_OBJECT_UNREF (im_info->bc_vars);
5886   im_info->bc_vars = mplist ();
5887   MPLIST_DO (vars, im_info->configured_vars)
5888     {
5889       MPlist *plist = MPLIST_PLIST (vars);
5890       MPlist *elt = mplist ();
5891
5892       mplist_push (im_info->bc_vars, Mplist, elt);
5893       mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
5894       elt = MPLIST_NEXT (elt);
5895       mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
5896       M17N_OBJECT_UNREF (elt);
5897     }
5898   return im_info->bc_vars;
5899 }
5900
5901 /*=*/
5902
5903 /***en
5904     @brief Set the initial value of an input method variable.
5905
5906     The minput_set_variable () function sets the initial value of
5907     input method variable $VARIABLE to $VALUE for the input method
5908     specified by $LANGUAGE and $NAME.
5909
5910     By default, the initial value is 0.
5911
5912     This setting gets effective in a newly opened input method.
5913
5914     @return
5915     If the operation was successful, 0 is returned.  Otherwise -1 is
5916     returned, and #merror_code is set to #MERROR_IM.  */
5917 /***ja
5918     @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
5919
5920     ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
5921     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
5922     ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
5923
5924     ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
5925
5926     ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
5927
5928     @return
5929     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
5930     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
5931
5932 int
5933 minput_set_variable (MSymbol language, MSymbol name,
5934                      MSymbol variable, void *value)
5935 {
5936   MPlist *plist, *pl;
5937   MInputMethodInfo *im_info;
5938   int ret;
5939
5940   MINPUT__INIT ();
5941
5942   if (variable == Mnil)
5943     MERROR (MERROR_IM, -1);
5944   plist = minput_get_variable (language, name, variable);
5945   plist = MPLIST_PLIST (plist);
5946   plist = MPLIST_NEXT (plist);
5947   pl = mplist ();
5948   mplist_add (pl, MPLIST_KEY (plist), value);
5949   ret = minput_config_variable (language, name, variable, pl);
5950   M17N_OBJECT_UNREF (pl);
5951   if (ret == 0)
5952     {
5953       im_info = get_im_info (language, name, Mnil, Mvariable);
5954       im_info->tick = 0;
5955     }
5956   return ret;
5957 }
5958
5959 /*=*/
5960
5961 /***en
5962     @brief Get information about input method commands.
5963
5964     The minput_get_commands () function returns information about
5965     input method commands of the input method specified by $LANGUAGE
5966     and $NAME.  An input method command is a pseudo key event to which
5967     one or more actual input key sequences are assigned.
5968
5969     There are two kinds of commands, global and local.  Global
5970     commands are used by multiple input methods for the same purpose,
5971     and have global key assignments.  Local commands are used only by
5972     a specific input method, and have only local key assignments.
5973
5974     Each input method may locally change key assignments for global
5975     commands.  The global key assignment for a global command is
5976     effective only when the current input method does not have local
5977     key assignments for that command.
5978
5979     If $NAME is #Mnil, information about global commands is returned.
5980     In this case $LANGUAGE is ignored.
5981
5982     If $NAME is not #Mnil, information about those commands that have
5983     local key assignments in the input method specified by $LANGUAGE
5984     and $NAME is returned.
5985
5986     @return
5987     If no input method commands are found, this function returns @c NULL.
5988
5989     Otherwise, a pointer to a plist is returned.  The key of each
5990     element in the plist is a symbol representing a command, and the
5991     value is a plist of the form COMMAND-INFO described below.
5992
5993     The first element of COMMAND-INFO has the key #Mtext, and the
5994     value is an M-text describing the command.
5995
5996     If there are no more elements, that means no key sequences are
5997     assigned to the command.  Otherwise, each of the remaining
5998     elements has the key #Mplist, and the value is a plist whose keys are
5999     #Msymbol and values are symbols representing input keys, which are
6000     currently assigned to the command.
6001
6002     As the returned plist is kept in the library, the caller must not
6003     modify nor free it.  */
6004 /***ja
6005     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
6006
6007     ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
6008     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
6009     ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
6010     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
6011
6012     ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
6013     ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
6014     ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
6015     ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
6016
6017     ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
6018     ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
6019     ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
6020     ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
6021
6022     $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
6023     ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
6024
6025     $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
6026     Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
6027     ¤òÊÖ¤¹¡£
6028
6029     @return
6030     ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
6031
6032     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
6033     ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
6034     ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
6035
6036     COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
6037     ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
6038     #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
6039     ¤¤¤³¤È¤Ë¤Ê¤ë¡£
6040
6041     ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
6042     ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
6043     ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
6044     ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
6045     ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
6046
6047     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
6048     ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
6049
6050 MPlist *
6051 minput_get_commands (MSymbol language, MSymbol name)
6052 {
6053   MInputMethodInfo *im_info;
6054   MPlist *cmds;
6055
6056   MINPUT__INIT ();
6057
6058   im_info = get_im_info (language, name, Mnil, Mcommand);
6059   if (! im_info || ! im_info->configured_vars)
6060     return NULL;
6061   M17N_OBJECT_UNREF (im_info->bc_cmds);
6062   im_info->bc_cmds = mplist ();
6063   MPLIST_DO (cmds, im_info->configured_cmds)
6064     {
6065       MPlist *plist = MPLIST_PLIST (cmds);
6066       MPlist *elt = mplist ();
6067
6068       mplist_push (im_info->bc_cmds, Mplist, elt);
6069       mplist_add (elt, MPLIST_SYMBOL (plist),
6070                   mplist_copy (MPLIST_NEXT (plist)));
6071       M17N_OBJECT_UNREF (elt);
6072     }
6073   return im_info->bc_cmds;
6074 }
6075
6076 /*=*/
6077
6078 /***en
6079     @brief Assign a key sequence to an input method command (obsolete).
6080
6081     This function is obsolete.  Use minput_config_command () instead.
6082
6083     The minput_assign_command_keys () function assigns input key
6084     sequence $KEYSEQ to input method command $COMMAND for the input
6085     method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
6086     key sequence is assigned globally no matter what $LANGUAGE is.
6087     Otherwise the key sequence is assigned locally.
6088
6089     Each element of $KEYSEQ must have the key $Msymbol and the value
6090     must be a symbol representing an input key.
6091
6092     $KEYSEQ may be @c NULL, in which case, all assignments are deleted
6093     globally or locally.
6094
6095     This assignment gets effective in a newly opened input method.
6096
6097     @return
6098     If the operation was successful, 0 is returned.  Otherwise -1 is
6099     returned, and #merror_code is set to #MERROR_IM.  */
6100 /***ja
6101     @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
6102
6103     ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
6104     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
6105     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
6106     $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
6107     ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
6108
6109     $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
6110     ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
6111
6112     $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
6113     ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
6114
6115     ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
6116     ¸ú¤Ë¤Ê¤ë¡£
6117
6118     @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
6119     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
6120
6121 int
6122 minput_assign_command_keys (MSymbol language, MSymbol name,
6123                             MSymbol command, MPlist *keyseq)
6124 {
6125   int ret;
6126
6127   MINPUT__INIT ();
6128
6129   if (command == Mnil)
6130     MERROR (MERROR_IM, -1);
6131   if (keyseq)
6132     {
6133       MPlist *plist;
6134
6135       if  (! check_command_keyseq (keyseq))
6136         MERROR (MERROR_IM, -1);
6137       plist = mplist ();
6138       mplist_add (plist, Mplist, keyseq);
6139       keyseq = plist;
6140     }  
6141   else
6142     keyseq = mplist ();
6143   ret = minput_config_command (language, name, command, keyseq);
6144   M17N_OBJECT_UNREF (keyseq);
6145   return ret;
6146 }
6147
6148 /*=*/
6149
6150 /***en
6151     @brief Call a callback function
6152
6153     The minput_callback () functions calls a callback function
6154     $COMMAND assigned for the input context $IC.  The caller must set
6155     specific elements in $IC->plist if the callback function requires.
6156
6157     @return
6158     If there exists a specified callback function, 0 is returned.
6159     Otherwise -1 is returned.  By side effects, $IC->plist may be
6160     modified.  */
6161
6162 int
6163 minput_callback (MInputContext *ic, MSymbol command)
6164 {
6165   MInputCallbackFunc func;
6166
6167   if (! ic->im->driver.callback_list)
6168     return -1;
6169   func = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
6170                                           command);
6171   if (! func)
6172     return -1;
6173   (func) (ic, command);
6174   return 0;
6175 }
6176
6177 /*** @} */ 
6178 /*** @} */
6179 /*=*/
6180 /*** @addtogroup m17nDebug */
6181 /*=*/
6182 /*** @{  */
6183 /*=*/
6184
6185 /***en
6186     @brief Dump an input method.
6187
6188     The mdebug_dump_im () function prints the input method $IM in a
6189     human readable way to the stderr.  $INDENT specifies how many
6190     columns to indent the lines but the first one.
6191
6192     @return
6193     This function returns $IM.  */
6194 /***ja
6195     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
6196
6197     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
6198     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
6199
6200     @return
6201     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
6202
6203 MInputMethod *
6204 mdebug_dump_im (MInputMethod *im, int indent)
6205 {
6206   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
6207   char *prefix;
6208
6209   prefix = (char *) alloca (indent + 1);
6210   memset (prefix, 32, indent);
6211   prefix[indent] = '\0';
6212
6213   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
6214            msymbol_name (im->name));
6215   mdebug_dump_mtext (im_info->title, 0, 0);
6216   if (im->name != Mnil)
6217     {
6218       MPlist *state;
6219
6220       MPLIST_DO (state, im_info->states)
6221         {
6222           fprintf (stderr, "\n%s  ", prefix);
6223           dump_im_state (MPLIST_VAL (state), indent + 2);
6224         }
6225     }
6226   fprintf (stderr, ")");
6227   return im;
6228 }
6229
6230 /*** @} */ 
6231
6232 /*
6233   Local Variables:
6234   coding: euc-japan
6235   End:
6236 */