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