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