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