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