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