(run_otf_category): Fix previous change.
[m17n/m17n-lib.git] / src / input.c
1 /* input.c -- input method module.
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
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 @anchor 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 #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 #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> ³°ÉôÆþÎϥ᥽¥Ã¥É @anchor foreign-input-method
110
111     ³°ÉôÆþÎϥ᥽¥Ã¥É¤È¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂΤϳ°
112     Éô¤Î¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê
113     ¤É¡£) ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï #Minput_driver ¤ò
114     ¥­¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
115     ¥¿¤Ç¤¢¤ë¡£¤³¤Î¤³¤È¤Ë¤è¤ê¡¢Å¬Àڤʥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢¤¤
116     ¤«¤Ê¤ë¼ïÎà¤ÎÆþÎϥ᥽¥Ã¥É¤â@c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÎÏÈÁȤÎÃæ¤Ç°·¤¦»ö
117     ¤¬¤Ç¤­¤ë¡£
118
119     ÍøÊØÀ­¤Î´ÑÅÀ¤«¤é¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤Ï XIM ¤Î OverTheSpot ¤ÎÆþÎÏ¥¹¥¿
120     ¥¤¥ë¤ò¼Â¸½¤¹¤ëÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤òÄ󶡤·¡¢¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î
121     #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 /** Symbols to load an input method data.  */
171 static MSymbol Mtitle, Mmacro, Mmodule, Mstate, Minclude;
172
173 /** Symbols for actions.  */
174 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
175 static MSymbol Mselect, Mshow, Mhide, Mcommit, Munhandle, Mpop;
176 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
177 static MSymbol Mless_equal, Mgreater_equal;
178 static MSymbol Mcond;
179 static MSymbol Mplus, Mminus, Mstar, Mslash, Mand, Mor, Mnot;
180
181 /** Special action symbol.  */
182 static MSymbol Mat_reload;
183
184 static MSymbol M_candidates;
185
186 static MSymbol Mcandidate_list, Mcandidate_index;
187
188 static MSymbol Minit, Mfini;
189
190 /** Symbols for variables.  */
191 static MSymbol Mcandidates_group_size, Mcandidates_charset;
192
193 /** Symbols for key events.  */
194 static MSymbol one_char_symbol[256];
195
196 static MSymbol M_key_alias;
197
198 static MSymbol Mdescription, Mcommand, Mvariable, Mglobal, Mconfig;
199
200 static MSymbol M_gettext;
201
202 /** Structure to hold a map.  */
203
204 struct MIMMap
205 {
206   /** List of actions to take when we reach the map.  In a root map,
207       the actions are executed only when there is no more key.  */
208   MPlist *map_actions;
209
210   /** List of deeper maps.  If NULL, this is a terminal map.  */
211   MPlist *submaps;
212
213   /** List of actions to take when we leave the map successfully.  In
214       a root map, the actions are executed only when none of submaps
215       handle the current key.  */
216   MPlist *branch_actions;
217 };
218
219 typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
220
221 typedef struct
222 {
223   void *handle;
224   MPlist *func_list;            /* function name vs (MIMExternalFunc *) */
225 } MIMExternalModule;
226
227 struct MIMState
228 {
229   M17NObject control;
230
231   /** Name of the state.  */
232   MSymbol name;
233
234   /** Title of the state, or NULL.  */
235   MText *title;
236
237   /** Key translation map of the state.  Built by merging all maps of
238       branches.  */
239   MIMMap *map;
240 };
241
242 #define CUSTOM_FILE "config.mic"
243
244 static MPlist *load_im_info_keys;
245
246 /* List of input method information.  The format is:
247      (LANGUAGE NAME t:IM_INFO ... ... ...)  */
248 static MPlist *im_info_list;
249
250 /* Database for user's customization file.  */
251 static MDatabase *im_custom_mdb;
252
253 /* List of input method information loaded from im_custom_mdb.  The
254    format is the same as im_info_list.  */
255 static MPlist *im_custom_list;
256
257 /* List of input method information configured by
258    minput_config_command and minput_config_variable.  The format is
259    the same as im_info_list.  */
260 static MPlist *im_config_list;
261
262 /* Global input method information.  It points into the element of
263    im_info_list corresponding to LANGUAGE == `nil' and NAME ==
264    `global'.  */
265 static MInputMethodInfo *global_info;
266
267 static int update_global_info (void);
268 static int update_custom_info (void);
269 static MInputMethodInfo *get_im_info (MSymbol, MSymbol, MSymbol, MSymbol);
270
271 \f
272 void
273 fully_initialize ()
274 {
275   char *key_names[32]
276     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
277         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
278         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
279         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
280   char buf[6], buf2[32], buf3[2];
281   int i, j;
282   /* Maximum case: '\215', C-M-m, C-M-M, M-Return, C-A-m, C-A-M, A-Return
283      plus one for cyclic alias.  */
284   MSymbol alias[8];
285
286   M_key_alias = msymbol ("  key-alias");
287
288   buf3[1] = '\0';
289
290   /* Aliases for 0x00-0x1F */
291   buf[0] = 'C';
292   buf[1] = '-';
293   buf[3] = '\0';
294   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
295     {
296       j = 0;
297       buf3[0] = i;
298       alias[j++] = msymbol (buf3);
299       alias[j++] = one_char_symbol[i] = msymbol (buf);
300       if (key_names[i] || (buf[2] >= 'A' && buf[2] <= 'Z'))
301         {
302           if (key_names[i])
303             {
304               /* Ex: `Escape' == `C-['  */
305               alias[j++] = msymbol (key_names[i]);
306             }
307           if (buf[2] >= 'A' && buf[2] <= 'Z')
308             {
309               /* Ex: `C-a' == `C-A'  */
310               buf[2] += 32;
311               alias[j++] = msymbol (buf);
312               buf[2] -= 32;
313             }
314         }
315       /* Establish cyclic alias chain.  */
316       alias[j] = alias[0];
317       while (--j >= 0)
318         msymbol_put (alias[j], M_key_alias, alias[j + 1]);
319     }
320
321   /* Aliases for 0x20-0x7E */
322   buf[0] = 'S';
323   for (i = buf[2] = ' '; i < 127; i++, buf[2]++)
324     {
325       one_char_symbol[i] = msymbol (buf + 2);
326       if (i >= 'A' && i <= 'Z')
327         {
328           /* Ex: `A' == `S-A' == `S-a'.  */
329           alias[0] = alias[3] = one_char_symbol[i];
330           alias[1] = msymbol (buf);
331           buf[2] += 32;
332           alias[2] = msymbol (buf);
333           buf[2] -= 32;
334           for (j = 0; j < 3; j++)
335             msymbol_put (alias[j], M_key_alias, alias[j + 1]);
336         }
337     }
338
339   /* Aliases for 0x7F */
340   buf3[0] = 0x7F;
341   alias[0] = alias[3] = msymbol (buf3);
342   alias[1] = one_char_symbol[127] = msymbol ("Delete");
343   alias[2] = msymbol ("C-?");
344   for (j = 0; j < 3; j++)
345     msymbol_put (alias[j], M_key_alias, alias[j + 1]);
346
347   /* Aliases for 0x80-0x9F */
348   buf[0] = 'C';
349   /* buf[1] = '-'; -- already done */
350   buf[3] = '-';
351   buf[5] = '\0';
352   buf2[1] = '-';
353   for (i = 128, buf[4] = '@'; i < 160; i++, buf[4]++)
354     {
355       j = 0;
356       buf3[0] = i;
357       alias[j++] = msymbol (buf3);
358       /* `C-M-a' == `C-A-a' */
359       buf[2] = 'M';
360       alias[j++] = one_char_symbol[i] = msymbol (buf);
361       buf[2] = 'A';
362       alias[j++] = msymbol (buf);
363       if (key_names[i - 128])
364         {
365           /* Ex: `M-Escape' == `A-Escape' == `C-M-['.  */
366           buf2[0] = 'M';
367           strcpy (buf2 + 2, key_names[i - 128]);
368           alias[j++] = msymbol (buf2);
369           buf2[0] = 'A';
370           alias[j++] = msymbol (buf2);
371         }
372       if (buf[4] >= 'A' && buf[4] <= 'Z')
373         {
374           /* Ex: `C-M-a' == `C-M-A'.  */
375           buf[4] += 32;
376           buf[2] = 'M';
377           alias[j++] = msymbol (buf);
378           buf[2] = 'A';
379           alias[j++] = msymbol (buf);
380           buf[4] -= 32;
381         }
382
383       /* Establish cyclic alias chain.  */
384       alias[j] = alias[0];
385       while (--j >= 0)
386         msymbol_put (alias[j], M_key_alias, alias[j + 1]);
387     }
388
389   /* Aliases for 0xA0-0xFF */
390   for (i = 160, buf[4] = ' '; i < 255; i++, buf[4]++)
391     {
392       j = 0;
393       buf3[0] = i;
394       alias[j++] = msymbol (buf3);
395       buf[2] = 'M';
396       alias[j++] = one_char_symbol[i] = msymbol (buf + 2);
397       buf[2] = 'A';
398       alias[j++] = msymbol (buf + 2);
399       alias[j]= alias[0];
400       while (--j >= 0)
401         msymbol_put (alias[j], M_key_alias, alias[j + 1]);
402     }
403
404   buf3[0] = 255;
405   alias[0] = alias[3] = msymbol (buf3);
406   alias[1] = one_char_symbol[255] = msymbol ("M-Delete");
407   alias[2] = msymbol ("A-Delete");
408   for (j = 0; j < 3; j++)
409     msymbol_put (alias[j], M_key_alias, alias[j + 1]);
410
411   /* Aliases for keys that can't be mapped to one-char-symbol
412      (e.g. C-A-1) */
413   /* buf is already set to "C-?-".  */
414   for (i = ' '; i <= '~'; i++)
415     {
416       if (i == '@')
417         {
418           i = '_';
419           continue;
420         }
421       if (i == 'a')
422         {
423           i = 'z';
424           continue;
425         }
426       buf[2] = 'M';
427       buf[4] = i;
428       alias[0] = alias[2] = msymbol (buf);
429       buf[2] = 'A';
430       alias[1] = msymbol (buf);
431       for (j = 0; j < 2; j++)
432         msymbol_put (alias[j], M_key_alias, alias[j + 1]);
433     }
434
435   Minput_method = msymbol ("input-method");
436   Mtitle = msymbol ("title");
437   Mmacro = msymbol ("macro");
438   Mmodule = msymbol ("module");
439   Mmap = msymbol ("map");
440   Mstate = msymbol ("state");
441   Minclude = msymbol ("include");
442   Minsert = msymbol ("insert");
443   M_candidates = msymbol ("  candidates");
444   Mdelete = msymbol ("delete");
445   Mmove = msymbol ("move");
446   Mmark = msymbol ("mark");
447   Mpushback = msymbol ("pushback");
448   Mpop = msymbol ("pop");
449   Mundo = msymbol ("undo");
450   Mcall = msymbol ("call");
451   Mshift = msymbol ("shift");
452   Mselect = msymbol ("select");
453   Mshow = msymbol ("show");
454   Mhide = msymbol ("hide");
455   Mcommit = msymbol ("commit");
456   Munhandle = msymbol ("unhandle");
457   Mset = msymbol ("set");
458   Madd = msymbol ("add");
459   Msub = msymbol ("sub");
460   Mmul = msymbol ("mul");
461   Mdiv = msymbol ("div");
462   Mequal = msymbol ("=");
463   Mless = msymbol ("<");
464   Mgreater = msymbol (">");
465   Mless_equal = msymbol ("<=");
466   Mgreater_equal = msymbol (">=");
467   Mcond = msymbol ("cond");
468   Mplus = msymbol ("+");
469   Mminus = msymbol ("-");
470   Mstar = msymbol ("*");
471   Mslash = msymbol ("/");
472   Mand = msymbol ("&");
473   Mor = msymbol ("|");
474   Mnot = msymbol ("!");
475
476   Mat_reload = msymbol ("-reload");
477
478   Mcandidates_group_size = msymbol ("candidates-group-size");
479   Mcandidates_charset = msymbol ("candidates-charset");
480
481   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
482   Mcandidate_index = msymbol ("  candidate-index");
483
484   Minit = msymbol ("init");
485   Mfini = msymbol ("fini");
486
487   Mdescription = msymbol ("description");
488   Mcommand = msymbol ("command");
489   Mvariable = msymbol ("variable");
490   Mglobal = msymbol ("global");
491   Mconfig = msymbol ("config");
492   M_gettext = msymbol ("_");
493
494   load_im_info_keys = mplist ();
495   mplist_add (load_im_info_keys, Mstate, Mnil);
496   mplist_push (load_im_info_keys, Mmap, Mnil);
497
498   im_info_list = mplist ();
499   im_config_list = im_custom_list = NULL;
500   im_custom_mdb = NULL;
501   update_custom_info ();
502   global_info = NULL;
503   update_global_info ();
504
505   fully_initialized = 1;
506 }
507
508 #define MINPUT__INIT()          \
509   do {                          \
510     if (! fully_initialized)    \
511       fully_initialize ();      \
512   } while (0)
513
514 \f
515 static int
516 marker_code (MSymbol sym, int surrounding)
517 {
518   char *name;
519
520   if (sym == Mnil)
521     return -1;
522   name = MSYMBOL_NAME (sym);
523   return (name[0] != '@' ? -1
524           : (((name[1] >= '0' && name[1] <= '9')
525               || name[1] == '<' || name[1] == '>' || name[1] == '='
526               || name[1] == '[' || name[1] == ']'
527               || name[1] == '@')
528              && name[2] == '\0') ? name[1]
529           : (name[1] != '+' && name[1] != '-') ? -1
530           : (name[2] == '\0' || surrounding) ? name[1]
531           : -1);
532 }
533
534
535 /* Return a plist containing an integer value of VAR.  The plist must
536    not be UNREFed. */
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, int *pos)
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[2] >= '1' && name[2] <= '9')
668           : name[1] == '+' ? (name[2] >= '0' && name[2] <= '9')
669           : 0))
670     {
671       *pos = name[1] == '-' ? - atoi (name + 2) : atoi (name + 2);
672       return 1;
673     }
674   return 0;
675 }
676
677 static int
678 integer_value (MInputContext *ic, MPlist *arg, int surrounding)
679 {
680   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
681   int code, pos;
682   MText *preedit = ic->preedit;
683   int len = mtext_nchars (preedit);
684
685   if (MPLIST_INTEGER_P (arg))
686     return MPLIST_INTEGER (arg);
687
688   code = marker_code (MPLIST_SYMBOL (arg), surrounding);
689   if (code < 0)
690     {
691       MPlist *val = resolve_variable (ic_info, MPLIST_SYMBOL (arg));
692
693       return (MPLIST_INTEGER_P (val) ? MPLIST_INTEGER (val) : 0);
694     }
695   if (code == '@')
696     return ic_info->key_head;
697   if ((code == '-' || code == '+'))
698     {
699       char *name = MSYMBOL_NAME (MPLIST_SYMBOL (arg));
700
701       if (name[2])
702         {
703           pos = atoi (name + 1);
704           if (pos == 0 && code == '-')
705             return get_preceding_char (ic, 0);
706           pos = ic->cursor_pos + pos;
707           if (pos < 0)
708             {
709               if (ic->produced && mtext_len (ic->produced) + pos >= 0)
710                 return mtext_ref_char (ic->produced,
711                                        mtext_len (ic->produced) + pos);
712               return get_preceding_char (ic, - pos);
713             }
714           else if (pos >= len)
715             return get_following_char (ic, pos - len);
716         }
717       else
718         pos = ic->cursor_pos + (code == '+' ? 1 : -1);
719     }
720   else if (code >= '0' && code <= '9')
721     pos = code - '0';
722   else if (code == '=')
723     pos = ic->cursor_pos;
724   else if (code == '[')
725     pos = ic->cursor_pos - 1;
726   else if (code == ']')
727     pos = ic->cursor_pos + 1;
728   else if (code == '<')
729     pos = 0;
730   else if (code == '>')
731     pos = len - 1;
732   return (pos >= 0 && pos < len ? mtext_ref_char (preedit, pos) : -1);
733 }
734
735 static int
736 parse_expression (MPlist *plist)
737 {
738   MSymbol op;
739
740   if (MPLIST_INTEGER_P (plist) || MPLIST_SYMBOL_P (plist))
741     return 0;
742   if (! MPLIST_PLIST_P (plist))
743     return -1;
744   plist = MPLIST_PLIST (plist);
745   op = MPLIST_SYMBOL (plist);
746   if (op != Mplus && op != Mminus && op != Mstar && op != Mslash
747       && op != Mand && op != Mor && op != Mnot
748       && op != Mless && op != Mgreater && op != Mequal
749       && op != Mless_equal && op != Mgreater_equal)
750     MERROR (MERROR_IM, -1);
751   MPLIST_DO (plist, MPLIST_NEXT (plist))
752     if (parse_expression (plist) < 0)
753       return -1;
754   return 0;
755 }
756
757 static int
758 resolve_expression (MInputContext *ic, MPlist *plist)
759 {
760   int val;
761   MSymbol op;
762   
763   if (MPLIST_INTEGER_P (plist))
764     return MPLIST_INTEGER (plist);
765   if (MPLIST_SYMBOL_P (plist))
766     return integer_value (ic, plist, 1);
767   if (! MPLIST_PLIST_P (plist))
768     return 0;
769   plist = MPLIST_PLIST (plist);
770   if (! MPLIST_SYMBOL_P (plist))
771     return 0;
772   op = MPLIST_SYMBOL (plist);
773   plist = MPLIST_NEXT (plist);
774   val = resolve_expression (ic, plist);
775   if (op == Mplus)
776     MPLIST_DO (plist, MPLIST_NEXT (plist))
777       val += resolve_expression (ic, plist);
778   else if (op == Mminus)
779     MPLIST_DO (plist, MPLIST_NEXT (plist))
780       val -= resolve_expression (ic, plist);
781   else if (op == Mstar)
782     MPLIST_DO (plist, MPLIST_NEXT (plist))
783       val *= resolve_expression (ic, plist);
784   else if (op == Mslash)
785     MPLIST_DO (plist, MPLIST_NEXT (plist))
786       val /= resolve_expression (ic, plist);
787   else if (op == Mand)
788     MPLIST_DO (plist, MPLIST_NEXT (plist))
789       val &= resolve_expression (ic, plist);
790   else if (op == Mor)
791     MPLIST_DO (plist, MPLIST_NEXT (plist))
792       val |= resolve_expression (ic, plist);
793   else if (op == Mnot)
794     val = ! val;
795   else if (op == Mless)
796     val = val < resolve_expression (ic, MPLIST_NEXT (plist));
797   else if (op == Mequal)
798     val = val == resolve_expression (ic, MPLIST_NEXT (plist));
799   else if (op == Mgreater)
800     val = val > resolve_expression (ic, MPLIST_NEXT (plist));
801   else if (op == Mless_equal)
802     val = val <= resolve_expression (ic, MPLIST_NEXT (plist));
803   else if (op == Mgreater_equal)
804     val = val >= resolve_expression (ic, MPLIST_NEXT (plist));
805   return val;
806 }
807
808 /* Parse PLIST as an action list.  PLIST should have this form:
809       PLIST ::= ( (ACTION-NAME ACTION-ARG *) *).
810    Return 0 if successfully parsed, otherwise return -1.  */
811
812 static int
813 parse_action_list (MPlist *plist, MPlist *macros)
814 {
815   MPLIST_DO (plist, plist)
816     {
817       if (MPLIST_MTEXT_P (plist))
818         {
819           /* This is a short form of (insert MTEXT).  */
820           /* if (mtext_nchars (MPLIST_MTEXT (plist)) == 0)
821              MERROR (MERROR_IM, -1); */
822         }
823       else if (MPLIST_PLIST_P (plist)
824                && (MPLIST_MTEXT_P (MPLIST_PLIST (plist))
825                    || MPLIST_PLIST_P (MPLIST_PLIST (plist))))
826         {
827           MPlist *pl;
828
829           /* This is a short form of (insert (GROUPS *)).  */
830           MPLIST_DO (pl, MPLIST_PLIST (plist))
831             {
832               if (MPLIST_PLIST_P (pl))
833                 {
834                   MPlist *elt;
835
836                   MPLIST_DO (elt, MPLIST_PLIST (pl))
837                     if (! MPLIST_MTEXT_P (elt)
838                         || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
839                       MERROR (MERROR_IM, -1);
840                 }
841               else
842                 {
843                   if (! MPLIST_MTEXT_P (pl)
844                       || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
845                     MERROR (MERROR_IM, -1);
846                 }
847             }
848         }
849       else if (MPLIST_INTEGER_P (plist))
850         {
851           int c = MPLIST_INTEGER (plist);
852
853           if (c < 0 || c > MCHAR_MAX)
854             MERROR (MERROR_IM, -1);
855         }
856       else if (MPLIST_PLIST_P (plist)
857                && MPLIST_SYMBOL_P (MPLIST_PLIST (plist)))
858         {
859           MPlist *pl = MPLIST_PLIST (plist);
860           MSymbol action_name = MPLIST_SYMBOL (pl);
861
862           pl = MPLIST_NEXT (pl);
863
864           if (action_name == M_candidates)
865             {
866               /* This is an already regularised action.  */
867               continue;
868             }
869           if (action_name == Minsert)
870             {
871               if (MPLIST_MTEXT_P (pl))
872                 {
873                   if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
874                     MERROR (MERROR_IM, -1);
875                 }
876               else if (MPLIST_INTEGER_P (pl))
877                 {
878                   int c = MPLIST_INTEGER (pl);
879
880                   if (c < 0 || c > MCHAR_MAX)
881                     MERROR (MERROR_IM, -1);
882                 }
883               else if (MPLIST_PLIST_P (pl))
884                 {
885                   MPLIST_DO (pl, MPLIST_PLIST (pl))
886                     {
887                       if (MPLIST_PLIST_P (pl))
888                         {
889                           MPlist *elt;
890
891                           MPLIST_DO (elt, MPLIST_PLIST (pl))
892                             if (! MPLIST_MTEXT_P (elt)
893                                 || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
894                               MERROR (MERROR_IM, -1);
895                         }
896                       else
897                         {
898                           if (! MPLIST_MTEXT_P (pl)
899                               || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
900                             MERROR (MERROR_IM, -1);
901                         }
902                     }
903                 }
904               else if (! MPLIST_SYMBOL_P (pl))
905                 MERROR (MERROR_IM, -1); 
906             }
907           else if (action_name == Mselect
908                    || action_name == Mdelete
909                    || action_name == Mmove)
910             {
911               if (parse_expression (pl) < 0)
912                 return -1;
913             }
914           else if (action_name == Mmark
915                    || action_name == Mcall
916                    || action_name == Mshift)
917             {
918               if (! MPLIST_SYMBOL_P (pl))
919                 MERROR (MERROR_IM, -1);
920             }
921           else if (action_name == Mundo)
922             {
923               if (! MPLIST_TAIL_P (pl))
924                 {
925                   if (! MPLIST_SYMBOL_P (pl)
926                       && ! MPLIST_INTEGER_P (pl))
927                     MERROR (MERROR_IM, -1);                 
928                 }
929             }
930           else if (action_name == Mpushback)
931             {
932               if (MPLIST_MTEXT_P (pl))
933                 {
934                   MText *mt = MPLIST_MTEXT (pl);
935
936                   if (mtext_nchars (mt) != mtext_nbytes (mt))
937                     MERROR (MERROR_IM, -1);                 
938                 }
939               else if (MPLIST_PLIST_P (pl))
940                 {
941                   MPlist *p;
942
943                   MPLIST_DO (p, MPLIST_PLIST (pl))
944                     if (! MPLIST_SYMBOL_P (p))
945                       MERROR (MERROR_IM, -1);
946                 }
947               else if (! MPLIST_INTEGER_P (pl))
948                 MERROR (MERROR_IM, -1);
949             }
950           else if (action_name == Mset || action_name == Madd
951                    || action_name == Msub || action_name == Mmul
952                    || action_name == Mdiv)
953             {
954               if (! MPLIST_SYMBOL_P (pl))
955                 MERROR (MERROR_IM, -1);
956               if (parse_expression (MPLIST_NEXT (pl)) < 0)
957                 return -1;
958             }
959           else if (action_name == Mequal || action_name == Mless
960                    || action_name == Mgreater || action_name == Mless_equal
961                    || action_name == Mgreater_equal)
962             {
963               if (parse_expression (pl) < 0
964                   || parse_expression (MPLIST_NEXT (pl)) < 0)
965                 return -1;
966               pl = MPLIST_NEXT (MPLIST_NEXT (pl));
967               if (! MPLIST_PLIST_P (pl))
968                 MERROR (MERROR_IM, -1);
969               if (parse_action_list (MPLIST_PLIST (pl), macros) < 0)
970                 MERROR (MERROR_IM, -1);
971               pl = MPLIST_NEXT (pl);
972               if (MPLIST_PLIST_P (pl)
973                   && parse_action_list (MPLIST_PLIST (pl), macros) < 0)
974                 MERROR (MERROR_IM, -1);
975             }
976           else if (action_name == Mshow || action_name == Mhide
977                    || action_name == Mcommit || action_name == Munhandle
978                    || action_name == Mpop)
979             ;
980           else if (action_name == Mcond)
981             {
982               MPLIST_DO (pl, pl)
983                 if (! MPLIST_PLIST_P (pl))
984                   MERROR (MERROR_IM, -1);
985             }
986           else if (! macros || ! mplist_get (macros, action_name))
987             MERROR (MERROR_IM, -1);
988         }
989       else if (! MPLIST_SYMBOL_P (plist))
990         MERROR (MERROR_IM, -1);
991     }
992
993   return 0;
994 }
995
996 static MPlist *
997 resolve_command (MPlist *cmds, MSymbol command)
998 {
999   MPlist *plist;
1000
1001   if (! cmds || ! (plist = mplist__assq (cmds, command)))
1002     return NULL;
1003   plist = MPLIST_PLIST (plist); /* (NAME DESC STATUS [KEYSEQ ...]) */
1004   plist = MPLIST_NEXT (plist);
1005   plist = MPLIST_NEXT (plist);
1006   plist = MPLIST_NEXT (plist);
1007   return plist;
1008 }
1009
1010 /* Load a translation into MAP from PLIST.
1011    PLIST has this form:
1012       PLIST ::= ( KEYSEQ MAP-ACTION * )  */
1013
1014 static int
1015 load_translation (MIMMap *map, MPlist *keylist, MPlist *map_actions,
1016                   MPlist *branch_actions, MPlist *macros)
1017 {
1018   MSymbol *keyseq;
1019   int len, i;
1020
1021   if (MPLIST_MTEXT_P (keylist))
1022     {
1023       MText *mt = MPLIST_MTEXT (keylist);
1024
1025       len = mtext_nchars (mt);
1026       if (MFAILP (len > 0 && len == mtext_nbytes (mt)))
1027         return -1;
1028       keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len);
1029       for (i = 0; i < len; i++)
1030         keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]];
1031     }
1032   else
1033     {
1034       MPlist *elt;
1035           
1036       if (MFAILP (MPLIST_PLIST_P (keylist)))
1037         return -1;
1038       elt = MPLIST_PLIST (keylist);
1039       len = MPLIST_LENGTH (elt);
1040       if (MFAILP (len > 0))
1041         return -1;
1042       keyseq = (MSymbol *) alloca (sizeof (int) * len);
1043       for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
1044         {
1045           if (MPLIST_INTEGER_P (elt))
1046             {
1047               int c = MPLIST_INTEGER (elt);
1048
1049               if (MFAILP (c >= 0 && c < 0x100))
1050                 return -1;
1051               keyseq[i] = one_char_symbol[c];
1052             }
1053           else
1054             {
1055               if (MFAILP (MPLIST_SYMBOL_P (elt)))
1056                 return -1;
1057               keyseq[i] = MPLIST_SYMBOL (elt);
1058             }
1059         }
1060     }
1061
1062   for (i = 0; i < len; i++)
1063     {
1064       MIMMap *deeper = NULL;
1065
1066       if (map->submaps)
1067         deeper = mplist_get (map->submaps, keyseq[i]);
1068       else
1069         map->submaps = mplist ();
1070       if (! deeper)
1071         {
1072           /* Fixme: It is better to make all deeper maps at once.  */
1073           MSTRUCT_CALLOC (deeper, MERROR_IM);
1074           mplist_put (map->submaps, keyseq[i], deeper);
1075         }
1076       map = deeper;
1077     }
1078
1079   /* We reach a terminal map.  */
1080   if (map->map_actions
1081       || map->branch_actions)
1082     /* This map is already defined.  We avoid overriding it.  */
1083     return 0;
1084
1085   if (! MPLIST_TAIL_P (map_actions))
1086     {
1087       if (parse_action_list (map_actions, macros) < 0)
1088         MERROR (MERROR_IM, -1);
1089       map->map_actions = map_actions;
1090     }
1091   if (branch_actions)
1092     {
1093       map->branch_actions = branch_actions;
1094       M17N_OBJECT_REF (branch_actions);
1095     }
1096
1097   return 0;
1098 }
1099
1100 /* Load a branch from PLIST into MAP.  PLIST has this form:
1101       PLIST ::= ( MAP-NAME BRANCH-ACTION * )  */
1102
1103 static int
1104 load_branch (MInputMethodInfo *im_info, MPlist *plist, MIMMap *map)
1105 {
1106   MSymbol map_name;
1107   MPlist *branch_actions;
1108
1109   if (MFAILP (MPLIST_SYMBOL_P (plist)))
1110     return -1;
1111   map_name = MPLIST_SYMBOL (plist);
1112   plist = MPLIST_NEXT (plist);
1113   if (MPLIST_TAIL_P (plist))
1114     branch_actions = NULL;
1115   else if (MFAILP (parse_action_list (plist, im_info->macros) >= 0))
1116     return -1;
1117   else
1118     branch_actions = plist;
1119   if (map_name == Mnil)
1120     {
1121       map->branch_actions = branch_actions;
1122       if (branch_actions)
1123         M17N_OBJECT_REF (branch_actions);
1124     }
1125   else if (map_name == Mt)
1126     {
1127       map->map_actions = branch_actions;
1128       if (branch_actions)
1129         M17N_OBJECT_REF (branch_actions);
1130     }
1131   else if (im_info->maps) 
1132     {
1133       plist = (MPlist *) mplist_get (im_info->maps, map_name);
1134       if (! plist && im_info->configured_vars)
1135         {
1136           MPlist *p = mplist__assq (im_info->configured_vars, map_name);
1137
1138           if (p && MPLIST_PLIST_P (p))
1139             {
1140               p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p))));
1141               if (MPLIST_SYMBOL_P (p))
1142                 plist = mplist_get (im_info->maps, MPLIST_SYMBOL (p));
1143             }
1144         }
1145       if (plist)
1146         {
1147           MPLIST_DO (plist, plist)
1148             {
1149               MPlist *keylist, *map_actions;
1150
1151               if (! MPLIST_PLIST_P (plist))
1152                 MERROR (MERROR_IM, -1);
1153               keylist = MPLIST_PLIST (plist);
1154               map_actions = MPLIST_NEXT (keylist);
1155               if (MPLIST_SYMBOL_P (keylist))
1156                 {
1157                   MSymbol command = MPLIST_SYMBOL (keylist);
1158                   MPlist *pl;
1159
1160                   if (MFAILP (command != Mat_reload))
1161                     continue;
1162                   pl = resolve_command (im_info->configured_cmds, command);
1163                   if (MFAILP (pl))
1164                     continue;
1165                   MPLIST_DO (pl, pl)
1166                     load_translation (map, pl, map_actions, branch_actions,
1167                                       im_info->macros);
1168                 }
1169               else
1170                 load_translation (map, keylist, map_actions, branch_actions,
1171                                   im_info->macros);
1172             }
1173         }
1174     }
1175
1176   return 0;
1177 }
1178
1179 /* Load a macro from PLIST into IM_INFO->macros.
1180    PLIST has this form:
1181       PLIST ::= ( MACRO-NAME ACTION * )
1182    IM_INFO->macros is a plist of macro names vs action list.  */
1183
1184 static int
1185 load_macros (MInputMethodInfo *im_info, MPlist *plist)
1186 {
1187   MSymbol name; 
1188   MPlist *pl;
1189
1190   if (! MPLIST_SYMBOL_P (plist))
1191     MERROR (MERROR_IM, -1);
1192   name = MPLIST_SYMBOL (plist);
1193   plist = MPLIST_NEXT (plist);
1194   if (MFAILP (! MPLIST_TAIL_P (plist)))
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   if (im_info->macros)
2383     {
2384       MPLIST_DO (pl, im_info->macros)
2385         parse_action_list (MPLIST_PLIST (pl), im_info->macros);
2386     }
2387
2388   im_info->tick = time (NULL);
2389 }
2390
2391 \f
2392
2393 static int take_action_list (MInputContext *ic, MPlist *action_list);
2394 static void preedit_commit (MInputContext *ic, int need_prefix);
2395
2396 static void
2397 shift_state (MInputContext *ic, MSymbol state_name)
2398 {
2399   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2400   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2401   MIMState *orig_state = ic_info->state, *state;
2402
2403   /* Find a state to shift to.  If not found, shift to the initial
2404      state.  */
2405   if (state_name == Mt)
2406     {
2407       if (! ic_info->prev_state)
2408         return;
2409       state = ic_info->prev_state;
2410     }
2411   else if (state_name == Mnil)
2412     {
2413       state = (MIMState *) MPLIST_VAL (im_info->states);
2414     }
2415   else
2416     {
2417       state = (MIMState *) mplist_get (im_info->states, state_name);
2418       if (! state)
2419         state = (MIMState *) MPLIST_VAL (im_info->states);
2420     }
2421
2422   if (MDEBUG_FLAG ())
2423     {
2424       if (orig_state)
2425         MDEBUG_PRINT2 ("\n  [IM] [%s] (shift %s)\n",
2426                        MSYMBOL_NAME (orig_state->name),
2427                        MSYMBOL_NAME (state->name));
2428       else
2429         MDEBUG_PRINT1 (" (shift %s)\n", MSYMBOL_NAME (state->name));
2430     }
2431
2432   /* Enter the new state.  */
2433   ic_info->state = state;
2434   ic_info->map = state->map;
2435   ic_info->state_key_head = ic_info->key_head;
2436   if (state == (MIMState *) MPLIST_VAL (im_info->states)
2437       && orig_state)
2438     /* We have shifted to the initial state.  */
2439     preedit_commit (ic, 0);
2440   mtext_cpy (ic_info->preedit_saved, ic->preedit);
2441   ic_info->state_pos = ic->cursor_pos;
2442   if (state != orig_state)
2443     {
2444       if (state == (MIMState *) MPLIST_VAL (im_info->states))
2445         {
2446           /* Shifted to the initial state.  */
2447           ic_info->prev_state = NULL;
2448           M17N_OBJECT_UNREF (ic_info->vars_saved);
2449           ic_info->vars_saved = mplist_copy (ic_info->vars);
2450         }
2451       else
2452         ic_info->prev_state = orig_state;
2453
2454       if (state->title)
2455         ic->status = state->title;
2456       else
2457         ic->status = im_info->title;
2458       ic->status_changed = 1;
2459       if (ic_info->map == ic_info->state->map
2460           && ic_info->map->map_actions)
2461         {
2462           MDEBUG_PRINT1 ("  [IM] [%s] init-actions:",
2463                          MSYMBOL_NAME (state->name));
2464           take_action_list (ic, ic_info->map->map_actions);
2465         }
2466     }
2467 }
2468
2469 /* Find a candidate group that contains a candidate number INDEX from
2470    PLIST.  Set START_INDEX to the first candidate number of the group,
2471    END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
2472    candidate group number if they are non-NULL.  If INDEX is -1, find
2473    the last candidate group.  */
2474
2475 static MPlist *
2476 find_candidates_group (MPlist *plist, int index,
2477                        int *start_index, int *end_index, int *group_index)
2478 {
2479   int i = 0, gidx = 0, len;
2480
2481   MPLIST_DO (plist, plist)
2482     {
2483       if (MPLIST_MTEXT_P (plist))
2484         len = mtext_nchars (MPLIST_MTEXT (plist));
2485       else
2486         len = mplist_length (MPLIST_PLIST (plist));
2487       if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
2488           : i + len > index)
2489         {
2490           if (start_index)
2491             *start_index = i;
2492           if (end_index)
2493             *end_index = i + len;
2494           if (group_index)
2495             *group_index = gidx;
2496           return plist;
2497         }
2498       i += len;
2499       gidx++;
2500     }
2501   return NULL;
2502 }
2503
2504 /* Adjust markers for the change of preedit text.
2505    If FROM == TO, the change is insertion of INS chars.
2506    If FROM < TO and INS == 0, the change is deletion of the range.
2507    If FROM < TO and INS > 0, the change is replacement.  */
2508
2509 static void
2510 adjust_markers (MInputContext *ic, int from, int to, int ins)
2511 {
2512   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
2513   MPlist *markers;
2514
2515   if (from == to)
2516     {
2517       MPLIST_DO (markers, ic_info->markers)
2518         if (MPLIST_INTEGER (markers) > from)
2519           MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + ins);
2520       if (ic->cursor_pos >= from)
2521         ic->cursor_pos += ins;
2522     }
2523   else
2524     {
2525       MPLIST_DO (markers, ic_info->markers)
2526         {
2527           if (MPLIST_INTEGER (markers) >= to)
2528             MPLIST_VAL (markers)
2529               = (void *) (MPLIST_INTEGER (markers) + ins - (to - from));
2530           else if (MPLIST_INTEGER (markers) > from)
2531             MPLIST_VAL (markers) = (void *) from;
2532         }
2533       if (ic->cursor_pos >= to)
2534         ic->cursor_pos += ins - (to - from);
2535       else if (ic->cursor_pos > from)
2536         ic->cursor_pos = from;
2537     }
2538 }
2539
2540
2541 static void
2542 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
2543 {
2544   int nchars = mt ? mtext_nchars (mt) : 1;
2545
2546   if (mt)
2547     {
2548       mtext_ins (ic->preedit, pos, mt);
2549       MDEBUG_PRINT1 ("(\"%s\")", MTEXT_DATA (mt));
2550     }
2551   else
2552     {
2553       mtext_ins_char (ic->preedit, pos, c, 1);
2554       if (c < 0x7F)
2555         MDEBUG_PRINT1 ("('%c')", c);
2556       else
2557         MDEBUG_PRINT1 ("(U+%04X)", c);
2558     }
2559   adjust_markers (ic, pos, pos, nchars);
2560   ic->preedit_changed = 1;
2561 }
2562
2563
2564 static void
2565 preedit_delete (MInputContext *ic, int from, int to)
2566 {
2567   mtext_del (ic->preedit, from, to);
2568   adjust_markers (ic, from, to, 0);
2569   ic->preedit_changed = 1;
2570 }
2571
2572 static void
2573 preedit_replace (MInputContext *ic, int from, int to, MText *mt, int c)
2574 {
2575   int ins;
2576
2577   mtext_del (ic->preedit, from, to);
2578   if (mt)
2579     {
2580       mtext_ins (ic->preedit, from, mt);
2581       ins = mtext_nchars (mt);
2582     }
2583   else
2584     {
2585       mtext_ins_char (ic->preedit, from, c, 1);
2586       ins = 1;
2587     }
2588   adjust_markers (ic, from, to, ins);
2589   ic->preedit_changed = 1;
2590 }
2591
2592
2593 static void
2594 preedit_commit (MInputContext *ic, int need_prefix)
2595 {
2596   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2597   int preedit_len = mtext_nchars (ic->preedit);
2598
2599   if (preedit_len > 0)
2600     {
2601       MPlist *p;
2602
2603       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
2604                              Mcandidate_list, NULL, 0);
2605       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
2606                              Mcandidate_index, NULL, 0);
2607       mtext_cat (ic->produced, ic->preedit);
2608       if (MDEBUG_FLAG ())
2609         {
2610           int i;
2611
2612           if (need_prefix)
2613             MDEBUG_PRINT1 ("\n  [IM] [%s]",
2614                            MSYMBOL_NAME (ic_info->state->name));
2615           MDEBUG_PRINT (" (commit");
2616           for (i = 0; i < mtext_nchars (ic->preedit); i++)
2617             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i));
2618           MDEBUG_PRINT (")");
2619         }
2620
2621       mtext_reset (ic->preedit);
2622       mtext_reset (ic_info->preedit_saved);
2623       MPLIST_DO (p, ic_info->markers)
2624         MPLIST_VAL (p) = 0;
2625       ic->cursor_pos = ic_info->state_pos = 0;
2626       ic->preedit_changed = 1;
2627       ic_info->commit_key_head = ic_info->key_head;
2628     }
2629   if (ic->candidate_list)
2630     {
2631       M17N_OBJECT_UNREF (ic->candidate_list);
2632       ic->candidate_list = NULL;
2633       ic->candidate_index = 0;
2634       ic->candidate_from = ic->candidate_to = 0;
2635       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
2636       if (ic->candidate_show)
2637         {
2638           ic->candidate_show = 0;
2639           ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
2640         }
2641     }
2642 }
2643
2644 static int
2645 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
2646 {
2647   int code = marker_code (sym, 0);
2648
2649   if (mt && (code == '[' || code == ']'))
2650     {
2651       int pos = current;
2652
2653       if (code == '[' && current > 0)
2654         {
2655           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
2656               && pos > 0)
2657             current = pos;
2658         }
2659       else if (code == ']' && current < mtext_nchars (mt))
2660         {
2661           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
2662             current = pos;
2663         }
2664       return current;
2665     }
2666   if (code >= 0)
2667     return (code == '<' ? 0
2668             : code == '>' ? limit
2669             : code == '-' ? current - 1
2670             : code == '+' ? current + 1
2671             : code == '=' ? current
2672             : code - '0' > limit ? limit
2673             : code - '0');
2674   if (! ic)  
2675     return 0;
2676   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
2677 }
2678
2679 static void
2680 update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
2681 {
2682   int from = mtext_property_start (prop);
2683   int to = mtext_property_end (prop);
2684   int start;
2685   MPlist *candidate_list = mtext_property_value (prop);
2686   MPlist *group = find_candidates_group (candidate_list, idx, &start,
2687                                          NULL, NULL);
2688   int ingroup_index = idx - start;
2689   MText *mt;
2690
2691   candidate_list = mplist_copy (candidate_list);
2692   if (MPLIST_MTEXT_P (group))
2693     {
2694       mt = MPLIST_MTEXT (group);
2695       preedit_replace (ic, from, to, NULL, mtext_ref_char (mt, ingroup_index));
2696       to = from + 1;
2697     }
2698   else
2699     {
2700       int i;
2701       MPlist *plist;
2702
2703       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
2704            i++, plist = MPLIST_NEXT (plist));
2705       mt = MPLIST_MTEXT (plist);
2706       preedit_replace (ic, from, to, mt, 0);
2707       to = from + mtext_nchars (mt);
2708     }
2709   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
2710   M17N_OBJECT_UNREF (candidate_list);
2711   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
2712   ic->cursor_pos = to;
2713 }
2714
2715 static MCharset *
2716 get_select_charset (MInputContextInfo * ic_info)
2717 {
2718   MPlist *plist = resolve_variable (ic_info, Mcandidates_charset);
2719   MSymbol sym;
2720
2721   if (! MPLIST_VAL (plist))
2722     return NULL;
2723   sym = MPLIST_SYMBOL (plist);
2724   if (sym == Mnil)
2725     return NULL;
2726   return MCHARSET (sym);
2727 }
2728
2729 /* The returned plist must be UNREFed.  */
2730
2731 static MPlist *
2732 adjust_candidates (MPlist *plist, MCharset *charset)
2733 {
2734   MPlist *pl;
2735
2736   /* plist ::= MTEXT ... | PLIST ... */
2737   plist = mplist_copy (plist);
2738   if (MPLIST_MTEXT_P (plist))
2739     {
2740       pl = plist;
2741       while (! MPLIST_TAIL_P (pl))
2742         {
2743           /* pl ::= MTEXT ... */
2744           MText *mt = MPLIST_MTEXT (pl);
2745           int mt_copied = 0;
2746           int i, c;
2747
2748           for (i = mtext_nchars (mt) - 1; i >= 0; i--)
2749             {
2750               c = mtext_ref_char (mt, i);
2751               if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
2752                 {
2753                   if (! mt_copied)
2754                     {
2755                       mt = mtext_dup (mt);
2756                       mplist_set (pl, Mtext, mt);
2757                       M17N_OBJECT_UNREF (mt);
2758                       mt_copied = 1;
2759                     }
2760                   mtext_del (mt, i, i + 1);
2761                 }
2762             }
2763           if (mtext_len (mt) > 0)
2764             pl = MPLIST_NEXT (pl);
2765           else
2766             {
2767               mplist_pop (pl);
2768               M17N_OBJECT_UNREF (mt);
2769             }
2770         }
2771     }
2772   else                          /* MPLIST_PLIST_P (plist) */
2773     {
2774       pl = plist;
2775       while (! MPLIST_TAIL_P (pl))
2776         {
2777           /* pl ::= (MTEXT ...) ... */
2778           MPlist *p = MPLIST_PLIST (pl);
2779           int p_copied = 0;
2780           /* p ::= MTEXT ... */
2781           MPlist *p0 = p;
2782           int n = 0;
2783
2784           while (! MPLIST_TAIL_P (p0))
2785             {
2786               MText *mt = MPLIST_MTEXT (p0);
2787               int i, c;
2788
2789               for (i = mtext_nchars (mt) - 1; i >= 0; i--)
2790                 {
2791                   c = mtext_ref_char (mt, i);
2792                   if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
2793                     break;
2794                 }
2795               if (i < 0)
2796                 {
2797                   p0 = MPLIST_NEXT (p0);
2798                   n++;
2799                 }
2800               else
2801                 {
2802                   if (! p_copied)
2803                     {
2804                       p = mplist_copy (p);
2805                       mplist_set (pl, Mplist, p);
2806                       M17N_OBJECT_UNREF (p);
2807                       p_copied = 1;
2808                       p0 = p;
2809                       while (n-- > 0)
2810                         p0 = MPLIST_NEXT (p0);
2811                     }     
2812                   mplist_pop (p0);
2813                   M17N_OBJECT_UNREF (mt);
2814                 }
2815             }
2816           if (! MPLIST_TAIL_P (p))
2817             pl = MPLIST_NEXT (pl);
2818           else
2819             {
2820               mplist_pop (pl);
2821               M17N_OBJECT_UNREF (p);
2822             }
2823         }
2824     }
2825   if (MPLIST_TAIL_P (plist))
2826     {
2827       M17N_OBJECT_UNREF (plist);
2828       return NULL;
2829     }      
2830   return plist;
2831 }
2832
2833 /* The returned Plist must be UNREFed.  */
2834
2835 static MPlist *
2836 get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
2837 {
2838   MCharset *charset = get_select_charset (ic_info);
2839   MPlist *plist;
2840   int column;
2841   int i, len;
2842
2843   plist = resolve_variable (ic_info, Mcandidates_group_size);
2844   column = MPLIST_INTEGER (plist);
2845
2846   plist = MPLIST_PLIST (args);
2847   if (! plist)
2848     return NULL;
2849   if (charset)
2850     {
2851       plist = adjust_candidates (plist, charset);
2852       if (! plist)
2853         return NULL;
2854     }
2855   else
2856     M17N_OBJECT_REF (plist);
2857
2858   if (column == 0)
2859     return plist;
2860
2861   if (MPLIST_MTEXT_P (plist))
2862     {
2863       MText *mt = MPLIST_MTEXT (plist);
2864       MPlist *next = MPLIST_NEXT (plist);
2865
2866       if (MPLIST_TAIL_P (next))
2867         M17N_OBJECT_REF (mt);
2868       else
2869         {
2870           mt = mtext_dup (mt);
2871           while (! MPLIST_TAIL_P (next))
2872             {
2873               mt = mtext_cat (mt, MPLIST_MTEXT (next));
2874               next = MPLIST_NEXT (next);
2875             }
2876         }
2877       M17N_OBJECT_UNREF (plist);
2878       plist = mplist ();
2879       len = mtext_nchars (mt);
2880       if (len <= column)
2881         mplist_add (plist, Mtext, mt);
2882       else
2883         {
2884           for (i = 0; i < len; i += column)
2885             {
2886               int to = (i + column < len ? i + column : len);
2887               MText *sub = mtext_copy (mtext (), 0, mt, i, to);
2888                                                        
2889               mplist_add (plist, Mtext, sub);
2890               M17N_OBJECT_UNREF (sub);
2891             }
2892         }
2893       M17N_OBJECT_UNREF (mt);
2894     }
2895   else if (MPLIST_PLIST_P (plist))
2896     {
2897       MPlist *tail = plist;
2898       MPlist *new = mplist ();
2899       MPlist *this = mplist ();
2900       int count = 0;
2901
2902       MPLIST_DO (tail, tail)
2903         {
2904           MPlist *p = MPLIST_PLIST (tail);
2905
2906           MPLIST_DO (p, p)
2907             {
2908               MText *mt = MPLIST_MTEXT (p);
2909
2910               if (count == column)
2911                 {
2912                   mplist_add (new, Mplist, this);
2913                   M17N_OBJECT_UNREF (this);
2914                   this = mplist ();
2915                   count = 0;
2916                 }
2917               mplist_add (this, Mtext, mt);
2918               count++;
2919             }
2920         }
2921       mplist_add (new, Mplist, this);
2922       M17N_OBJECT_UNREF (this);
2923       mplist_set (plist, Mnil, NULL);
2924       MPLIST_DO (tail, new)
2925         {
2926           MPlist *elt = MPLIST_PLIST (tail);
2927
2928           mplist_add (plist, Mplist, elt);
2929         }
2930       M17N_OBJECT_UNREF (new);
2931     }
2932
2933   return plist;
2934 }
2935
2936
2937 static MPlist *
2938 regularize_action (MPlist *action_list, MInputContextInfo *ic_info)
2939 {
2940   MPlist *action = NULL;
2941   MSymbol name;
2942   MPlist *args;
2943
2944   if (MPLIST_SYMBOL_P (action_list))
2945     {
2946       MSymbol var = MPLIST_SYMBOL (action_list);
2947       MPlist *p;
2948
2949       MPLIST_DO (p, ic_info->vars)
2950         if (MPLIST_SYMBOL (MPLIST_PLIST (p)) == var)
2951           break;
2952       if (MPLIST_TAIL_P (p))
2953         return NULL;
2954       action = MPLIST_NEXT (MPLIST_PLIST (p));
2955       mplist_set (action_list, MPLIST_KEY (action), MPLIST_VAL (action));
2956     }
2957
2958   if (MPLIST_PLIST_P (action_list))
2959     {
2960       action = MPLIST_PLIST (action_list);
2961       if (MPLIST_SYMBOL_P (action))
2962         {
2963           name = MPLIST_SYMBOL (action);
2964           args = MPLIST_NEXT (action);
2965           if (name == Minsert
2966               && MPLIST_PLIST_P (args))
2967             mplist_set (action, Msymbol, M_candidates);
2968         }
2969       else if (MPLIST_MTEXT_P (action) || MPLIST_PLIST_P (action))
2970         {
2971           action = mplist ();
2972           mplist_push (action, Mplist, MPLIST_VAL (action_list));
2973           mplist_push (action, Msymbol, M_candidates);
2974           mplist_set (action_list, Mplist, action);
2975           M17N_OBJECT_UNREF (action);
2976         }
2977     }
2978   else if (MPLIST_MTEXT_P (action_list) || MPLIST_INTEGER_P (action_list))
2979     {
2980       action = mplist ();
2981       mplist_push (action, MPLIST_KEY (action_list), MPLIST_VAL (action_list));
2982       mplist_push (action, Msymbol, Minsert);
2983       mplist_set (action_list, Mplist, action);
2984       M17N_OBJECT_UNREF (action);
2985     }
2986   return action;
2987 }
2988
2989 /* Perform list of actions in ACTION_LIST for the current input
2990    context IC.  If unhandle action was not performed, return 0.
2991    Otherwise, return -1.  */
2992
2993 static int
2994 take_action_list (MInputContext *ic, MPlist *action_list)
2995 {
2996   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2997   MPlist *candidate_list = ic->candidate_list;
2998   int candidate_index = ic->candidate_index;
2999   int candidate_show = ic->candidate_show;
3000   MTextProperty *prop;
3001
3002   MPLIST_DO (action_list, action_list)
3003     {
3004       MPlist *action = regularize_action (action_list, ic_info);
3005       MSymbol name;
3006       MPlist *args;
3007
3008       if (! action)
3009         continue;
3010       name = MPLIST_SYMBOL (action);
3011       args = MPLIST_NEXT (action);
3012
3013       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
3014       if (name == Minsert)
3015         {
3016           if (MPLIST_SYMBOL_P (args))
3017             {
3018               args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
3019               if (! MPLIST_MTEXT_P (args) && ! MPLIST_INTEGER_P (args))
3020                 continue;
3021             }
3022           if (MPLIST_MTEXT_P (args))
3023             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
3024           else                  /* MPLIST_INTEGER_P (args)) */
3025             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
3026         }
3027       else if (name == M_candidates)
3028         {
3029           MPlist *plist = get_candidate_list (ic_info, args);
3030           MPlist *pl;
3031           int len;
3032
3033           if (! plist)
3034             continue;
3035           if (MPLIST_PLIST_P (plist) && MPLIST_TAIL_P (plist))
3036             {
3037               M17N_OBJECT_UNREF (plist);
3038               continue;
3039             }
3040           if (MPLIST_MTEXT_P (plist))
3041             {
3042               preedit_insert (ic, ic->cursor_pos, NULL,
3043                               mtext_ref_char (MPLIST_MTEXT (plist), 0));
3044               len = 1;
3045             }
3046           else
3047             {
3048               MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
3049
3050               preedit_insert (ic, ic->cursor_pos, mt, 0);
3051               len = mtext_nchars (mt);
3052             }
3053           pl = mplist_copy (plist);
3054           M17N_OBJECT_UNREF (plist);
3055           mtext_put_prop (ic->preedit,
3056                           ic->cursor_pos - len, ic->cursor_pos,
3057                           Mcandidate_list, pl);
3058           M17N_OBJECT_UNREF (pl);
3059           mtext_put_prop (ic->preedit,
3060                           ic->cursor_pos - len, ic->cursor_pos,
3061                           Mcandidate_index, (void *) 0);
3062         }
3063       else if (name == Mselect)
3064         {
3065           int start, end;
3066           int code, idx, gindex;
3067           int pos = ic->cursor_pos;
3068           MPlist *group;
3069           int idx_decided = 0;
3070
3071           if (pos == 0
3072               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
3073                                                Mcandidate_list)))
3074             continue;
3075           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
3076           group = find_candidates_group (mtext_property_value (prop), idx,
3077                                          &start, &end, &gindex);
3078           if (MPLIST_SYMBOL_P (args))
3079             {
3080               code = marker_code (MPLIST_SYMBOL (args), 0);
3081               if (code < 0)
3082                 {
3083                   args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
3084                   if (! MPLIST_INTEGER_P (args))
3085                     continue;
3086                   idx = start + MPLIST_INTEGER (args);
3087                   if (idx < start || idx >= end)
3088                     continue;
3089                   idx_decided = 1;
3090                 }                 
3091             }
3092           else
3093             code = -1;
3094
3095           if (code != '[' && code != ']')
3096             {
3097               if (! idx_decided)
3098                 idx = (start
3099                        + (code >= 0
3100                           ? new_index (NULL, ic->candidate_index - start,
3101                                        end - start - 1, MPLIST_SYMBOL (args),
3102                                        NULL)
3103                           : MPLIST_INTEGER (args)));
3104               if (idx < 0)
3105                 {
3106                   find_candidates_group (mtext_property_value (prop), -1,
3107                                          NULL, &end, NULL);
3108                   idx = end - 1;
3109                 }
3110               else if (idx >= end
3111                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
3112                 idx = 0;
3113             }
3114           else
3115             {
3116               int ingroup_index = idx - start;
3117               int len;
3118
3119               group = mtext_property_value (prop);
3120               len = mplist_length (group);
3121               if (code == '[')
3122                 {
3123                   gindex--;
3124                   if (gindex < 0)
3125                     gindex = len - 1;;
3126                 }
3127               else
3128                 {
3129                   gindex++;
3130                   if (gindex >= len)
3131                     gindex = 0;
3132                 }
3133               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
3134                 idx += (MPLIST_MTEXT_P (group)
3135                         ? mtext_nchars (MPLIST_MTEXT (group))
3136                         : mplist_length (MPLIST_PLIST (group)));
3137               len = (MPLIST_MTEXT_P (group)
3138                      ? mtext_nchars (MPLIST_MTEXT (group))
3139                      : mplist_length (MPLIST_PLIST (group)));
3140               if (ingroup_index >= len)
3141                 ingroup_index = len - 1;
3142               idx += ingroup_index;
3143             }
3144           update_candidate (ic, prop, idx);
3145           MDEBUG_PRINT1 ("(%d)", idx);
3146         }
3147       else if (name == Mshow)
3148         ic->candidate_show = 1;
3149       else if (name == Mhide)
3150         ic->candidate_show = 0;
3151       else if (name == Mdelete)
3152         {
3153           int len = mtext_nchars (ic->preedit);
3154           int pos;
3155           int to;
3156
3157           if (MPLIST_SYMBOL_P (args)
3158               && surrounding_pos (MPLIST_SYMBOL (args), &pos))
3159             {
3160               to = ic->cursor_pos + pos;
3161               if (to < 0)
3162                 {
3163                   delete_surrounding_text (ic, to);
3164                   to = 0;
3165                 }
3166               else if (to > len)
3167                 {
3168                   delete_surrounding_text (ic, to - len);
3169                   to = len;
3170                 }
3171             }
3172           else
3173             {
3174               to = (MPLIST_SYMBOL_P (args)
3175                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
3176                                  ic->preedit)
3177                     : MPLIST_INTEGER (args));
3178               if (to < 0)
3179                 to = 0;
3180               else if (to > len)
3181                 to = len;
3182               pos = to - ic->cursor_pos;
3183             }
3184           MDEBUG_PRINT1 ("(%d)", pos);
3185           if (to < ic->cursor_pos)
3186             preedit_delete (ic, to, ic->cursor_pos);
3187           else if (to > ic->cursor_pos)
3188             preedit_delete (ic, ic->cursor_pos, to);
3189         }
3190       else if (name == Mmove)
3191         {
3192           int len = mtext_nchars (ic->preedit);
3193           int pos
3194             = (MPLIST_SYMBOL_P (args)
3195                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
3196                             ic->preedit)
3197                : MPLIST_INTEGER (args));
3198
3199           if (pos < 0)
3200             pos = 0;
3201           else if (pos > len)
3202             pos = len;
3203           if (pos != ic->cursor_pos)
3204             {
3205               ic->cursor_pos = pos;
3206               ic->preedit_changed = 1;
3207             }
3208           MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
3209         }
3210       else if (name == Mmark)
3211         {
3212           int code = marker_code (MPLIST_SYMBOL (args), 0);
3213
3214           if (code < 0)
3215             {
3216               mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
3217                           (void *) ic->cursor_pos);
3218               MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
3219             }
3220         }
3221       else if (name == Mpushback)
3222         {
3223           if (MPLIST_INTEGER_P (args) || MPLIST_SYMBOL_P (args))
3224             {
3225               int num;
3226
3227               if (MPLIST_SYMBOL_P (args))
3228                 {
3229                   args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
3230                   if (MPLIST_INTEGER_P (args))
3231                     num = MPLIST_INTEGER (args);
3232                   else
3233                     num = 0;
3234                 }
3235               else
3236                 num = MPLIST_INTEGER (args);
3237
3238               if (num > 0)
3239                 ic_info->key_head -= num;
3240               else if (num == 0)
3241                 ic_info->key_head = 0;
3242               else
3243                 ic_info->key_head = - num;
3244               if (ic_info->key_head > ic_info->used)
3245                 ic_info->key_head = ic_info->used;
3246             }
3247           else if (MPLIST_MTEXT_P (args))
3248             {
3249               MText *mt = MPLIST_MTEXT (args);
3250               int i, len = mtext_nchars (mt);
3251               MSymbol key;
3252
3253               ic_info->key_head--;
3254               for (i = 0; i < len; i++)
3255                 {
3256                   key = one_char_symbol[MTEXT_DATA (mt)[i]];
3257                   if (ic_info->key_head + i < ic_info->used)
3258                     ic_info->keys[ic_info->key_head + i] = key;
3259                   else
3260                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3261                 }
3262             }
3263           else
3264             {
3265               MPlist *plist = MPLIST_PLIST (args), *pl;
3266               int i = 0;
3267               MSymbol key;
3268
3269               ic_info->key_head--;
3270
3271               MPLIST_DO (pl, plist)
3272                 {
3273                   key = MPLIST_SYMBOL (pl);
3274                   if (ic_info->key_head < ic_info->used)
3275                     ic_info->keys[ic_info->key_head + i] = key;
3276                   else
3277                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3278                   i++;
3279                 }
3280             }
3281         }
3282       else if (name == Mpop)
3283         {
3284           if (ic_info->key_head < ic_info->used)
3285             MLIST_DELETE1 (ic_info, keys, ic_info->key_head, 1);
3286         }
3287       else if (name == Mcall)
3288         {
3289           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3290           MIMExternalFunc func = NULL;
3291           MSymbol module, func_name;
3292           MPlist *func_args, *val;
3293           int ret = 0;
3294
3295           module = MPLIST_SYMBOL (args);
3296           args = MPLIST_NEXT (args);
3297           func_name = MPLIST_SYMBOL (args);
3298
3299           if (im_info->externals)
3300             {
3301               MIMExternalModule *external
3302                 = (MIMExternalModule *) mplist_get (im_info->externals,
3303                                                     module);
3304               if (external)
3305                 func = ((MIMExternalFunc)
3306                         mplist_get_func (external->func_list, func_name));
3307             }
3308           if (! func)
3309             continue;
3310           func_args = mplist ();
3311           mplist_add (func_args, Mt, ic);
3312           MPLIST_DO (args, MPLIST_NEXT (args))
3313             {
3314               int code;
3315
3316               if (MPLIST_KEY (args) == Msymbol
3317                   && MPLIST_KEY (args) != Mnil
3318                   && (code = marker_code (MPLIST_SYMBOL (args), 0)) >= 0)
3319                 {
3320                   code = new_index (ic, ic->cursor_pos, 
3321                                     mtext_nchars (ic->preedit),
3322                                     MPLIST_SYMBOL (args), ic->preedit);
3323                   mplist_add (func_args, Minteger, (void *) code);
3324                 }
3325               else
3326                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
3327             }
3328           val = (func) (func_args);
3329           M17N_OBJECT_UNREF (func_args);
3330           if (val && ! MPLIST_TAIL_P (val))
3331             ret = take_action_list (ic, val);
3332           M17N_OBJECT_UNREF (val);
3333           if (ret < 0)
3334             return ret;
3335         }
3336       else if (name == Mshift)
3337         {
3338           shift_state (ic, MPLIST_SYMBOL (args));
3339         }
3340       else if (name == Mundo)
3341         {
3342           int intarg = (MPLIST_TAIL_P (args)
3343                         ? ic_info->used - 2
3344                         : integer_value (ic, args, 0));
3345
3346           mtext_reset (ic->preedit);
3347           mtext_reset (ic_info->preedit_saved);
3348           mtext_reset (ic->produced);
3349           M17N_OBJECT_UNREF (ic_info->vars);
3350           ic_info->vars = mplist_copy (ic_info->vars_saved);
3351           ic->cursor_pos = ic_info->state_pos = 0;
3352           ic_info->state_key_head = ic_info->key_head
3353             = ic_info->commit_key_head = 0;
3354
3355           shift_state (ic, Mnil);
3356           if (intarg < 0)
3357             {
3358               if (MPLIST_TAIL_P (args))
3359                 {
3360                   ic_info->used = 0;
3361                   return -1;
3362                 }
3363               ic_info->used += intarg;
3364             }
3365           else
3366             ic_info->used = intarg;
3367           break;
3368         }
3369       else if (name == Mset || name == Madd || name == Msub
3370                || name == Mmul || name == Mdiv)
3371         {
3372           MSymbol sym = MPLIST_SYMBOL (args);
3373           MPlist *value = resolve_variable (ic_info, sym);
3374           int val1, val2;
3375           char *op;
3376
3377           val1 = MPLIST_INTEGER (value);
3378           args = MPLIST_NEXT (args);
3379           val2 = resolve_expression (ic, args);
3380           if (name == Mset)
3381             val1 = val2, op = "=";
3382           else if (name == Madd)
3383             val1 += val2, op = "+=";
3384           else if (name == Msub)
3385             val1 -= val2, op = "-=";
3386           else if (name == Mmul)
3387             val1 *= val2, op = "*=";
3388           else
3389             val1 /= val2, op = "/=";
3390           MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
3391                          MSYMBOL_NAME (sym), op, val1, val1);
3392           mplist_set (value, Minteger, (void *) val1);
3393         }
3394       else if (name == Mequal || name == Mless || name == Mgreater
3395                || name == Mless_equal || name == Mgreater_equal)
3396         {
3397           int val1, val2;
3398           MPlist *actions1, *actions2;
3399           int ret = 0;
3400
3401           val1 = resolve_expression (ic, args);
3402           args = MPLIST_NEXT (args);
3403           val2 = resolve_expression (ic, args);
3404           args = MPLIST_NEXT (args);
3405           actions1 = MPLIST_PLIST (args);
3406           args = MPLIST_NEXT (args);
3407           if (MPLIST_TAIL_P (args))
3408             actions2 = NULL;
3409           else
3410             actions2 = MPLIST_PLIST (args);
3411           MDEBUG_PRINT3 ("(%d %s %d)? ", val1, MSYMBOL_NAME (name), val2);
3412           if (name == Mequal ? val1 == val2
3413               : name == Mless ? val1 < val2
3414               : name == Mgreater ? val1 > val2
3415               : name == Mless_equal ? val1 <= val2
3416               : val1 >= val2)
3417             {
3418               MDEBUG_PRINT ("ok");
3419               ret = take_action_list (ic, actions1);
3420             }
3421           else
3422             {
3423               MDEBUG_PRINT ("no");
3424               if (actions2)
3425                 ret = take_action_list (ic, actions2);
3426             }
3427           if (ret < 0)
3428             return ret;
3429         }
3430       else if (name == Mcond)
3431         {
3432           int idx = 0;
3433
3434           MPLIST_DO (args, args)
3435             {
3436               MPlist *cond;
3437
3438               idx++;
3439               if (! MPLIST_PLIST (args))
3440                 continue;
3441               cond = MPLIST_PLIST (args);
3442               if (resolve_expression (ic, cond) != 0)
3443                 {
3444                   MDEBUG_PRINT1 ("(%dth)", idx);
3445                   if (take_action_list (ic, MPLIST_NEXT (cond)) < 0)
3446                     return -1;;
3447                   break;
3448                 }
3449             }
3450         }
3451       else if (name == Mcommit)
3452         {
3453           preedit_commit (ic, 0);
3454         }
3455       else if (name == Munhandle)
3456         {
3457           preedit_commit (ic, 0);
3458           return -1;
3459         }
3460       else
3461         {
3462           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3463           MPlist *actions;
3464
3465           if (im_info->macros
3466               && (actions = mplist_get (im_info->macros, name)))
3467             {
3468               if (take_action_list (ic, actions) < 0)
3469                 return -1;
3470             };
3471         }
3472     }
3473
3474   if (ic->candidate_list)
3475     {
3476       M17N_OBJECT_UNREF (ic->candidate_list);
3477       ic->candidate_list = NULL;
3478     }
3479   if (ic->cursor_pos > 0
3480       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
3481                                      Mcandidate_list)))
3482     {
3483       ic->candidate_list = mtext_property_value (prop);
3484       M17N_OBJECT_REF (ic->candidate_list);
3485       ic->candidate_index
3486         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
3487                                 Mcandidate_index);
3488       ic->candidate_from = mtext_property_start (prop);
3489       ic->candidate_to = mtext_property_end (prop);
3490     }
3491
3492   if (candidate_list != ic->candidate_list)
3493     ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3494   if (candidate_index != ic->candidate_index)
3495     ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3496   if (candidate_show != ic->candidate_show)
3497     ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
3498   return 0;
3499 }
3500
3501
3502 /* Handle the input key KEY in the current state and map specified in
3503    the input context IC.  If KEY is handled correctly, return 0.
3504    Otherwise, return -1.  */
3505
3506 static int
3507 handle_key (MInputContext *ic)
3508 {
3509   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3510   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3511   MIMMap *map = ic_info->map;
3512   MIMMap *submap = NULL;
3513   MSymbol key = ic_info->keys[ic_info->key_head];
3514   MSymbol alias = Mnil;
3515   int i;
3516
3517   MDEBUG_PRINT2 ("  [IM] [%s] handle `%s'", 
3518                  MSYMBOL_NAME (ic_info->state->name), msymbol_name (key));
3519
3520   if (map->submaps)
3521     {
3522       submap = mplist_get (map->submaps, key);
3523       alias = key;
3524       while (! submap
3525              && (alias = msymbol_get (alias, M_key_alias))
3526              && alias != key)
3527         submap = mplist_get (map->submaps, alias);
3528     }
3529
3530   if (submap)
3531     {
3532       if (! alias || alias == key)
3533         MDEBUG_PRINT (" submap-found");
3534       else
3535         MDEBUG_PRINT1 (" submap-found (by alias `%s')", MSYMBOL_NAME (alias));
3536       mtext_cpy (ic->preedit, ic_info->preedit_saved);
3537       ic->preedit_changed = 1;
3538       ic->cursor_pos = ic_info->state_pos;
3539       ic_info->key_head++;
3540       ic_info->map = map = submap;
3541       if (map->map_actions)
3542         {
3543           MDEBUG_PRINT (" map-actions:");
3544           if (take_action_list (ic, map->map_actions) < 0)
3545             {
3546               MDEBUG_PRINT ("\n");
3547               return -1;
3548             }
3549         }
3550       else if (map->submaps)
3551         {
3552           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
3553             {
3554               MSymbol key = ic_info->keys[i];
3555               char *name = msymbol_name (key);
3556
3557               if (! name[0] || ! name[1])
3558                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
3559             }
3560         }
3561
3562       /* If this is the terminal map or we have shifted to another
3563          state, perform branch actions (if any).  */
3564       if (! map->submaps || map != ic_info->map)
3565         {
3566           if (map->branch_actions)
3567             {
3568               MDEBUG_PRINT (" branch-actions:");
3569               if (take_action_list (ic, map->branch_actions) < 0)
3570                 {
3571                   MDEBUG_PRINT ("\n");
3572                   return -1;
3573                 }
3574             }
3575           /* If MAP is still not the root map, shift to the current
3576              state.  */
3577           if (ic_info->map != ic_info->state->map)
3578             shift_state (ic, ic_info->state->name);
3579         }
3580     }
3581   else
3582     {
3583       /* MAP can not handle KEY.  */
3584
3585       /* Perform branch actions if any.  */
3586       if (map->branch_actions)
3587         {
3588           MDEBUG_PRINT (" branch-actions:");
3589           if (take_action_list (ic, map->branch_actions) < 0)
3590             {
3591               MDEBUG_PRINT ("\n");
3592               return -1;
3593             }
3594         }
3595
3596       if (map == ic_info->map)
3597         {
3598           /* The above branch actions didn't change the state.  */
3599
3600           /* If MAP is the root map of the initial state, and there
3601              still exist an unhandled key, it means that the current
3602              input method can not handle it.  */
3603           if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map
3604               && ic_info->key_head < ic_info->used)
3605             {
3606               MDEBUG_PRINT (" unhandled\n");
3607               return -1;
3608             }
3609
3610           if (map != ic_info->state->map)
3611             {
3612               /* MAP is not the root map.  Shift to the root map of the
3613                  current state. */
3614               shift_state (ic, ic_info->state->name);
3615             }
3616           else if (! map->branch_actions)
3617             {
3618               /* MAP is the root map without any default branch
3619                  actions.  Shift to the initial state.  */
3620               shift_state (ic, Mnil);
3621             }
3622         }
3623     }
3624   MDEBUG_PRINT ("\n");
3625   return 0;
3626 }
3627
3628 /* Initialize IC->ic_info.  */
3629
3630 static void
3631 init_ic_info (MInputContext *ic)
3632 {
3633   MInputMethodInfo *im_info = ic->im->info;
3634   MInputContextInfo *ic_info = ic->info;
3635   MPlist *plist;
3636   
3637   MLIST_INIT1 (ic_info, keys, 8);;
3638
3639   ic_info->markers = mplist ();
3640
3641   ic_info->vars = mplist ();
3642   if (im_info->configured_vars)
3643     MPLIST_DO (plist, im_info->configured_vars)
3644       {
3645         MPlist *pl = MPLIST_PLIST (plist);
3646         MSymbol name = MPLIST_SYMBOL (pl);
3647
3648         pl = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (pl)));
3649         if (MPLIST_KEY (pl) != Mt)
3650           {
3651             MPlist *p = mplist ();
3652
3653             mplist_push (ic_info->vars, Mplist, p);
3654             M17N_OBJECT_UNREF (p);
3655             mplist_add (p, Msymbol, name);
3656             mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
3657           }
3658       }
3659   ic_info->vars_saved = mplist_copy (ic_info->vars);
3660
3661   if (im_info->externals)
3662     {
3663       MPlist *func_args = mplist (), *plist;
3664
3665       mplist_add (func_args, Mt, ic);
3666       MPLIST_DO (plist, im_info->externals)
3667         {
3668           MIMExternalModule *external = MPLIST_VAL (plist);
3669           MIMExternalFunc func
3670             = (MIMExternalFunc) mplist_get_func (external->func_list, Minit);
3671
3672           if (func)
3673             (func) (func_args);
3674         }
3675       M17N_OBJECT_UNREF (func_args);
3676     }
3677
3678   ic_info->preedit_saved = mtext ();
3679   ic_info->tick = im_info->tick;
3680 }
3681
3682 /* Finalize IC->ic_info.  */
3683
3684 static void
3685 fini_ic_info (MInputContext *ic)
3686 {
3687   MInputMethodInfo *im_info = ic->im->info;
3688   MInputContextInfo *ic_info = ic->info;
3689
3690   if (im_info->externals)
3691     {
3692       MPlist *func_args = mplist (), *plist;
3693
3694       mplist_add (func_args, Mt, ic);
3695       MPLIST_DO (plist, im_info->externals)
3696         {
3697           MIMExternalModule *external = MPLIST_VAL (plist);
3698           MIMExternalFunc func
3699             = (MIMExternalFunc) mplist_get_func (external->func_list, Mfini);
3700
3701           if (func)
3702             (func) (func_args);
3703         }
3704       M17N_OBJECT_UNREF (func_args);
3705     }
3706
3707   MLIST_FREE1 (ic_info, keys);
3708   M17N_OBJECT_UNREF (ic_info->preedit_saved);
3709   M17N_OBJECT_UNREF (ic_info->markers);
3710   M17N_OBJECT_UNREF (ic_info->vars);
3711   M17N_OBJECT_UNREF (ic_info->vars_saved);
3712   M17N_OBJECT_UNREF (ic_info->preceding_text);
3713   M17N_OBJECT_UNREF (ic_info->following_text);
3714
3715   memset (ic_info, 0, sizeof (MInputContextInfo));
3716 }
3717
3718 static void
3719 re_init_ic (MInputContext *ic, int reload)
3720 {
3721   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3722   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3723   int status_changed, preedit_changed, cursor_pos_changed, candidates_changed;
3724
3725   status_changed = ic_info->state != (MIMState *) MPLIST_VAL (im_info->states);
3726   preedit_changed = mtext_nchars (ic->preedit) > 0;
3727   cursor_pos_changed = ic->cursor_pos > 0;
3728   candidates_changed = 0;
3729   if (ic->candidate_list)
3730     {
3731       candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3732       M17N_OBJECT_UNREF (ic->candidate_list);
3733       ic->candidate_list = NULL;
3734     }
3735   if (ic->candidate_show)
3736     {
3737       candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
3738       ic->candidate_show = 0;
3739     }
3740   if (ic->candidate_index > 0)
3741     {
3742       candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3743       ic->candidate_index = 0;
3744       ic->candidate_from = ic->candidate_to = 0;
3745     }
3746   if (mtext_nchars (ic->produced) > 0)
3747     mtext_reset (ic->produced);
3748   if (mtext_nchars (ic->preedit) > 0)
3749     mtext_reset (ic->preedit);
3750   ic->cursor_pos = 0;
3751   M17N_OBJECT_UNREF (ic->plist);
3752   ic->plist = mplist ();
3753
3754   fini_ic_info (ic);
3755   if (reload)
3756     reload_im_info (im_info);
3757   if (! im_info->states)
3758     {
3759       struct MIMState *state;
3760
3761       M17N_OBJECT (state, free_state, MERROR_IM);
3762       state->name = msymbol ("init");
3763       state->title = mtext__from_data ("ERROR!", 6, MTEXT_FORMAT_US_ASCII, 0);
3764       MSTRUCT_CALLOC (state->map, MERROR_IM);
3765       im_info->states = mplist ();
3766       mplist_add (im_info->states, state->name, state);
3767     }
3768   init_ic_info (ic);
3769   shift_state (ic, Mnil);
3770
3771   ic->status_changed = status_changed;
3772   ic->preedit_changed = preedit_changed;
3773   ic->cursor_pos_changed = cursor_pos_changed;
3774   ic->candidates_changed = candidates_changed;
3775 }
3776
3777 static void
3778 reset_ic (MInputContext *ic, MSymbol ignore)
3779 {
3780   MDEBUG_PRINT ("\n  [IM] reset\n");
3781   re_init_ic (ic, 0);
3782 }
3783
3784 static int
3785 open_im (MInputMethod *im)
3786 {
3787   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
3788
3789   if (! im_info || ! im_info->states)
3790     MERROR (MERROR_IM, -1);
3791   im->info = im_info;
3792
3793   return 0;
3794 }
3795
3796 static void
3797 close_im (MInputMethod *im)
3798 {
3799   im->info = NULL;
3800 }
3801
3802 static int
3803 create_ic (MInputContext *ic)
3804 {
3805   MInputContextInfo *ic_info;
3806
3807   MSTRUCT_CALLOC (ic_info, MERROR_IM);
3808   ic->info = ic_info;
3809   init_ic_info (ic);
3810   shift_state (ic, Mnil);
3811   return 0;
3812 }
3813
3814 static void
3815 destroy_ic (MInputContext *ic)
3816 {
3817   fini_ic_info (ic);
3818   free (ic->info);
3819 }
3820
3821 static int
3822 check_reload (MInputContext *ic, MSymbol key)
3823 {
3824   MInputMethodInfo *im_info = ic->im->info;
3825   MPlist *plist = resolve_command (im_info->configured_cmds, Mat_reload);
3826
3827   if (! plist)
3828     {
3829       plist = resolve_command (global_info->configured_cmds, Mat_reload);
3830       if (! plist)
3831         return 0;
3832     }
3833   MPLIST_DO (plist, plist)
3834     {
3835       MSymbol this_key, alias;
3836
3837       if (MPLIST_MTEXT_P (plist))
3838         {
3839           MText *mt = MPLIST_MTEXT (plist);
3840           int c = mtext_ref_char (mt, 0);
3841
3842           if (c >= 256)
3843             continue;
3844           this_key = one_char_symbol[c];
3845         }
3846       else
3847         {
3848           MPlist *pl = MPLIST_PLIST (plist);
3849       
3850           this_key = MPLIST_SYMBOL (pl);
3851         }
3852       alias = this_key;
3853       while (alias != key 
3854              && (alias = msymbol_get (alias, M_key_alias))
3855              && alias != this_key);
3856       if (alias == key)
3857         break;
3858     }
3859   if (MPLIST_TAIL_P (plist))
3860     return 0;
3861
3862   MDEBUG_PRINT ("\n  [IM] reload");
3863   re_init_ic (ic, 1);
3864   return 1;
3865 }
3866
3867
3868 /** Handle the input key KEY in the current state and map of IC->info.
3869     If KEY is handled but no text is produced, return 0, otherwise
3870     return 1.
3871
3872     Ignore ARG.  */
3873
3874 static int
3875 filter (MInputContext *ic, MSymbol key, void *arg)
3876 {
3877   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3878   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3879   int i = 0;
3880
3881   if (check_reload (ic, key))
3882     return 0;
3883
3884   if (! ic_info->state)
3885     {
3886       ic_info->key_unhandled = 1;
3887       return 0;
3888     }
3889   mtext_reset (ic->produced);
3890   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
3891   M17N_OBJECT_UNREF (ic_info->preceding_text);
3892   M17N_OBJECT_UNREF (ic_info->following_text);
3893   ic_info->preceding_text = ic_info->following_text = NULL;
3894   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3895   ic_info->key_unhandled = 0;
3896
3897   do {
3898     if (handle_key (ic) < 0)
3899       {
3900         /* KEY was not handled.  Delete it from the current key sequence.  */
3901         if (ic_info->used > 0)
3902           {
3903             memmove (ic_info->keys, ic_info->keys + 1,
3904                      sizeof (int) * (ic_info->used - 1));
3905             ic_info->used--;
3906             if (ic_info->state_key_head > 0)
3907               ic_info->state_key_head--;
3908             if (ic_info->commit_key_head > 0)
3909               ic_info->commit_key_head--;             
3910           }
3911         /* This forces returning 1.  */
3912         ic_info->key_unhandled = 1;
3913         break;
3914       }
3915     if (i++ == 100)
3916       {
3917         mdebug_hook ();
3918         reset_ic (ic, Mnil);
3919         ic_info->key_unhandled = 1;
3920         break;
3921       }
3922     /* Break the loop if all keys were handled.  */
3923   } while (ic_info->key_head < ic_info->used);
3924
3925   /* If the current map is the root of the initial state, we should
3926      produce any preedit text in ic->produced.  */
3927   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
3928     preedit_commit (ic, 1);
3929
3930   if (mtext_nchars (ic->produced) > 0)
3931     {
3932       if (MDEBUG_FLAG ())
3933         {
3934           MDEBUG_PRINT1 ("\n  [IM] [%s] (produced",
3935                          MSYMBOL_NAME (ic_info->state->name));
3936           for (i = 0; i < mtext_nchars (ic->produced); i++)
3937             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
3938           MDEBUG_PRINT (")");
3939         }
3940
3941       mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
3942                       Mlanguage, ic->im->language);
3943     }
3944   if (ic_info->commit_key_head > 0)
3945     {
3946       memmove (ic_info->keys, ic_info->keys + ic_info->commit_key_head,
3947                sizeof (int) * (ic_info->used - ic_info->commit_key_head));
3948       ic_info->used -= ic_info->commit_key_head;
3949       ic_info->key_head -= ic_info->commit_key_head;
3950       ic_info->state_key_head -= ic_info->commit_key_head;
3951       ic_info->commit_key_head = 0;
3952     }
3953   if (ic_info->key_unhandled)
3954     {
3955       ic_info->used = 0;
3956       ic_info->key_head = ic_info->state_key_head
3957         = ic_info->commit_key_head = 0;
3958     }
3959
3960   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
3961 }
3962
3963
3964 /** Return 1 if the last event or key was not handled, otherwise
3965     return 0.
3966
3967     There is no need of looking up because ic->produced should already
3968     contain the produced text (if any).
3969
3970     Ignore KEY.  */
3971
3972 static int
3973 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
3974 {
3975   mtext_cat (mt, ic->produced);
3976   mtext_reset (ic->produced);
3977   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
3978 }
3979
3980 \f
3981 /* Input method command handler.  */
3982
3983 /* List of all (global and local) commands. 
3984    (LANG:(IM-NAME:(COMMAND ...) ...) ...) ...
3985    COMMAND is CMD-NAME:(mtext:DESCRIPTION plist:KEYSEQ ...))
3986    Global commands are stored as (t (t COMMAND ...))  */
3987
3988 \f
3989 /* Input method variable handler.  */
3990
3991
3992 /* Support functions for mdebug_dump_im.  */
3993
3994 static void
3995 dump_im_map (MPlist *map_list, int indent)
3996 {
3997   char *prefix;
3998   MSymbol key = MPLIST_KEY (map_list);
3999   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
4000
4001   prefix = (char *) alloca (indent + 1);
4002   memset (prefix, 32, indent);
4003   prefix[indent] = '\0';
4004
4005   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
4006   if (map->map_actions)
4007     mdebug_dump_plist (map->map_actions, indent + 2);
4008   if (map->submaps)
4009     {
4010       MPLIST_DO (map_list, map->submaps)
4011         {
4012           fprintf (stderr, "\n%s  ", prefix);
4013           dump_im_map (map_list, indent + 2);
4014         }
4015     }
4016   if (map->branch_actions)
4017     {
4018       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
4019       mdebug_dump_plist (map->branch_actions, indent + 4);
4020       fprintf (stderr, ")");      
4021     }
4022   fprintf (stderr, ")");
4023 }
4024
4025
4026 static void
4027 dump_im_state (MIMState *state, int indent)
4028 {
4029   char *prefix;
4030   MPlist *map_list;
4031
4032   prefix = (char *) alloca (indent + 1);
4033   memset (prefix, 32, indent);
4034   prefix[indent] = '\0';
4035
4036   fprintf (stderr, "(%s", msymbol_name (state->name));
4037   if (state->map->submaps)
4038     {
4039       MPLIST_DO (map_list, state->map->submaps)
4040         {
4041           fprintf (stderr, "\n%s  ", prefix);
4042           dump_im_map (map_list, indent + 2);
4043         }
4044     }
4045   fprintf (stderr, ")");
4046 }
4047
4048 \f
4049
4050 int
4051 minput__init ()
4052 {
4053   Minput_driver = msymbol ("input-driver");
4054
4055   Minput_preedit_start = msymbol ("input-preedit-start");
4056   Minput_preedit_done = msymbol ("input-preedit-done");
4057   Minput_preedit_draw = msymbol ("input-preedit-draw");
4058   Minput_status_start = msymbol ("input-status-start");
4059   Minput_status_done = msymbol ("input-status-done");
4060   Minput_status_draw = msymbol ("input-status-draw");
4061   Minput_candidates_start = msymbol ("input-candidates-start");
4062   Minput_candidates_done = msymbol ("input-candidates-done");
4063   Minput_candidates_draw = msymbol ("input-candidates-draw");
4064   Minput_set_spot = msymbol ("input-set-spot");
4065   Minput_focus_move = msymbol ("input-focus-move");
4066   Minput_focus_in = msymbol ("input-focus-in");
4067   Minput_focus_out = msymbol ("input-focus-out");
4068   Minput_toggle = msymbol ("input-toggle");
4069   Minput_reset = msymbol ("input-reset");
4070   Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
4071   Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
4072   Mcustomized = msymbol ("customized");
4073   Mconfigured = msymbol ("configured");
4074   Minherited = msymbol ("inherited");
4075
4076   minput_default_driver.open_im = open_im;
4077   minput_default_driver.close_im = close_im;
4078   minput_default_driver.create_ic = create_ic;
4079   minput_default_driver.destroy_ic = destroy_ic;
4080   minput_default_driver.filter = filter;
4081   minput_default_driver.lookup = lookup;
4082   minput_default_driver.callback_list = mplist ();
4083   mplist_put_func (minput_default_driver.callback_list, Minput_reset,
4084                    M17N_FUNC (reset_ic));
4085   minput_driver = &minput_default_driver;
4086
4087   fully_initialized = 0;
4088   return 0;
4089 }
4090
4091 void
4092 minput__fini ()
4093 {
4094   if (fully_initialized)
4095     {
4096       free_im_list (im_info_list);
4097       if (im_custom_list)
4098         free_im_list (im_custom_list);
4099       if (im_config_list)
4100         free_im_list (im_config_list);
4101       M17N_OBJECT_UNREF (load_im_info_keys);
4102     }
4103
4104   M17N_OBJECT_UNREF (minput_default_driver.callback_list);
4105   M17N_OBJECT_UNREF (minput_driver->callback_list);
4106
4107 }
4108
4109 MSymbol
4110 minput__char_to_key (int c)
4111 {
4112   if (c < 0 || c >= 0x100)
4113     return Mnil;
4114
4115   return one_char_symbol[c];
4116 }
4117
4118 /*** @} */
4119 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
4120
4121 \f
4122 /* External API */
4123
4124 /*** @addtogroup m17nInputMethod */
4125 /*** @{ */
4126 /*=*/
4127
4128 /***en
4129     @brief Symbol whose name is "input-method".
4130  */
4131 /***ja
4132     @brief "input-method" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
4133  */
4134 MSymbol Minput_method;
4135
4136 /***en
4137     @name Variables: Predefined symbols for callback commands.  */
4138 /***ja
4139     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.  */
4140 /*** @{ */ 
4141 /***en
4142     These are the predefined symbols that are used as the @c COMMAND
4143     argument of callback functions of an input method driver (see
4144     #MInputDriver::callback_list).  
4145
4146     Most of them do not require extra argument nor return any value;
4147     exceptions are these:
4148
4149     @b Minput_get_surrounding_text: When a callback function assigned for
4150     this command is called, the first element of #MInputContext::plist
4151     has key #Minteger and the value specifies which portion of the
4152     surrounding text should be retrieved.  If the value is positive,
4153     it specifies the number of characters following the current cursor
4154     position.  If the value is negative, the absolute value specifies
4155     the number of characters preceding the current cursor position.
4156     If the value is zero, it means that the caller just wants to know
4157     if the surrounding text is currently supported or not.
4158
4159     If the surrounding text is currently supported, the callback
4160     function must set the key of this element to #Mtext and the value
4161     to the retrieved M-text.  The length of the M-text may be shorter
4162     than the requested number of characters, if the available text is
4163     not that long.  The length can be zero in the worst case.  Or, the
4164     length may be longer if an application thinks it is more efficient
4165     to return that length.
4166
4167     If the surrounding text is not currently supported, the callback
4168     function should return without changing the first element of
4169     #MInputContext::plist.
4170
4171     @b Minput_delete_surrounding_text: When a callback function assigned
4172     for this command is called, the first element of
4173     #MInputContext::plist has key #Minteger and the value specifies
4174     which portion of the surrounding text should be deleted in the
4175     same way as the case of Minput_get_surrounding_text.  The callback
4176     function must delete the specified text.  It should not alter
4177     #MInputContext::plist.  */ 
4178 /***ja
4179     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND 
4180     °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
4181
4182     ¤Û¤È¤ó¤É¤ÏÄɲäΰú¿ô¤òɬÍפȤ·¤Ê¤¤¤·ÃͤòÊÖ¤µ¤Ê¤¤¤¬¡¢°Ê²¼¤ÏÎã³°¤Ç¤¢¤ë¡£
4183
4184     Minput_get_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë¥Ð¥Ã
4185     ¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢ #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϥ­¡¼¤È¤·
4186     ¤Æ#Minteger ¤ò¤È¤ê¡¢¤½¤ÎÃͤϥµ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤Î¤¦¤Á¤É¤ÎÉôʬ
4187     ¤ò¼è¤Ã¤ÆÍè¤ë¤«¤ò»ØÄꤹ¤ë¡£Ãͤ¬Àµ¤Ç¤¢¤ì¤Ð¡¢¸½ºß¤Î¥«¡¼¥½¥ë°ÌÃ֤˳¤¯
4188     ÃͤθĿôʬ¤Îʸ»ú¤ò¼è¤ë¡£Éé¤Ç¤¢¤ì¤Ð¡¢¥«¡¼¥½¥ë°ÌÃÖ¤ËÀè¹Ô¤¹¤ëÃͤÎÀäÂÐ
4189     ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£¸½ºß¥µ¥é¥¦¥ó¥É¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦
4190     ¤«¤òÃΤꤿ¤¤¤À¤±¤Ç¤¢¤ì¤Ð¡¢¤³¤ÎÃͤϥ¼¥í¤Ç¤âÎɤ¤¡£
4191
4192     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ï
4193     ¤³¤ÎÍ×ÁǤΥ­¡¼¤ò #Mtext ¤Ë¡¢Ãͤò¼è¤ê¹þ¤ó¤ÀM-text ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê
4194     ¤é¤Ê¤¤¡£¤â¤·¥Æ¥­¥¹¥È¤ÎŤµ¤¬½¼Ê¬¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î M-text ¤ÎŤµ¤ÏÍ×
4195     µá¤µ¤ì¤Æ¤¤¤ëʸ»ú¿ô¤è¤êû¤¯¤ÆÎɤ¤¡£ºÇ°­¤Î¾ì¹ç 0 ¤Ç¤â¤è¤¤¤·¡¢¥¢¥×¥ê¥±¡¼
4196     ¥·¥ç¥ó¦¤ÇɬÍפǸúΨŪ¤À¤È»×¤¨¤ÐŤ¯¤Æ¤âÎɤ¤¡£
4197
4198     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
4199     ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4200
4201     Minput_delete_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë
4202     ¥Ð¥Ã¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢#MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϡ¢¥­¡¼
4203     ¤È¤·¤Æ#Minteger ¤ò¤È¤ê¡¢ÃͤϺï½ü¤¹¤ë¤Ù¤­¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤ò
4204     Minput_get_surrounding_text ¤ÈƱÍͤΤä¤êÊý¤Ç»ØÄꤹ¤ë¡£¥³¡¼¥ë¥Ð¥Ã¥¯
4205     ´Ø¿ô¤Ï»ØÄꤵ¤ì¤¿¥Æ¥­¥¹¥È¤òºï½ü¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤Þ¤¿
4206     #MInputContext::plist ¤òÊѤ¨¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */ 
4207 MSymbol Minput_preedit_start;
4208 MSymbol Minput_preedit_done;
4209 MSymbol Minput_preedit_draw;
4210 MSymbol Minput_status_start;
4211 MSymbol Minput_status_done;
4212 MSymbol Minput_status_draw;
4213 MSymbol Minput_candidates_start;
4214 MSymbol Minput_candidates_done;
4215 MSymbol Minput_candidates_draw;
4216 MSymbol Minput_set_spot;
4217 MSymbol Minput_toggle;
4218 MSymbol Minput_reset;
4219 MSymbol Minput_get_surrounding_text;
4220 MSymbol Minput_delete_surrounding_text;
4221 /*** @} */
4222
4223 /*=*/
4224
4225 /***en
4226     @name Variables: Predefined symbols for special input events.
4227
4228     These are the predefined symbols that are used as the @c KEY
4229     argument of minput_filter ().  */ 
4230 /***ja
4231     @name ÊÑ¿ô: ÆÃÊ̤ÊÆþÎÏ¥¤¥Ù¥ó¥ÈÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
4232
4233     minput_filter () ¤Î @c KEY °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */ 
4234
4235 /*** @{ */ 
4236 /*=*/
4237
4238 MSymbol Minput_focus_out;
4239 MSymbol Minput_focus_in;
4240 MSymbol Minput_focus_move;
4241
4242 /*** @} */
4243
4244 /*=*/
4245 /***en
4246     @name Variables: Predefined symbols used in input method information.  */
4247 /***ja
4248     @name ÊÑ¿ô: ÆþÎϥ᥽¥Ã¥É¾ðÊóÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.  */
4249 /*** @{ */ 
4250 /*=*/
4251 /***en
4252     These are the predefined symbols describing status of input method
4253     command and variable, and are used in a return value of
4254     minput_get_command () and minput_get_variable ().  */
4255 /***ja
4256     ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤äÊÑ¿ô¤Î¾õÂÖ¤òɽ¤·¡¢minput_get_command () ¤È
4257     minput_get_variable () ¤ÎÌá¤êÃͤȤ·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */
4258 MSymbol Minherited;
4259 MSymbol Mcustomized;
4260 MSymbol Mconfigured;
4261 /*** @} */ 
4262
4263 /*=*/
4264
4265 /***en
4266     @brief The default driver for internal input methods.
4267
4268     The variable #minput_default_driver is the default driver for
4269     internal input methods.
4270
4271     The member MInputDriver::open_im () searches the m17n database for
4272     an input method that matches the tag \< #Minput_method, $LANGUAGE,
4273     $NAME\> and loads it.
4274
4275     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
4276     programmers responsibility to set it to a plist of proper callback
4277     functions.  Otherwise, no feedback information (e.g. preedit text)
4278     can be shown to users.
4279
4280     The macro M17N_INIT () sets the variable #minput_driver to the
4281     pointer to this driver so that all internal input methods use it.
4282
4283     Therefore, unless @c minput_driver is set differently, the driver
4284     dependent arguments $ARG of the functions whose name begins with
4285     "minput_" are all ignored.  */
4286 /***ja
4287     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
4288
4289     ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£
4290
4291     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
4292     \< #Minput_method, $LANGUAGE, $NAME\> 
4293     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
4294
4295     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢
4296     ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist
4297     ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit 
4298     ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
4299
4300     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver 
4301     ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
4302
4303     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
4304     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
4305
4306 MInputDriver minput_default_driver;
4307 /*=*/
4308
4309 /***en
4310     @brief The driver for internal input methods.
4311
4312     The variable #minput_driver is a pointer to the input method
4313     driver that is used by internal input methods.  The macro
4314     M17N_INIT () initializes it to a pointer to #minput_default_driver
4315     if <m17n<EM></EM>.h> is included.  */ 
4316 /***ja
4317     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
4318
4319     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
4320     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
4321     ¥¿¤ò#minput_default_driver (<m17n<EM></EM>.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë
4322     »þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
4323
4324 MInputDriver *minput_driver;
4325
4326 /*=*/
4327 /***
4328     The variable #Minput_driver is a symbol for a foreign input method.
4329     See @ref foreign-input-method "foreign input method" for the detail.  */
4330 MSymbol Minput_driver;
4331
4332 /*=*/
4333
4334 /***en
4335     @name Functions
4336 */
4337 /***ja
4338     @name ´Ø¿ô
4339 */
4340 /*** @{ */
4341
4342 /*=*/
4343
4344 /***en
4345     @brief Open an input method.
4346
4347     The minput_open_im () function opens an input method whose
4348     language and name match $LANGUAGE and $NAME, and returns a pointer
4349     to the input method object newly allocated.
4350
4351     This function at first decides a driver for the input method as
4352     described below.
4353
4354     If $LANGUAGE is not #Mnil, the driver pointed by the variable
4355     #minput_driver is used.
4356
4357     If $LANGUAGE is #Mnil and $NAME has the property #Minput_driver, the
4358     driver pointed to by the property value is used to open the input
4359     method.  If $NAME has no such a property, @c NULL is returned.
4360
4361     Then, the member MInputDriver::open_im () of the driver is
4362     called.  
4363
4364     $ARG is set in the member @c arg of the structure MInputMethod so
4365     that the driver can refer to it.  */
4366 /***ja
4367     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
4368
4369     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME 
4370     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
4371     
4372     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
4373
4374     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver 
4375     ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
4376
4377     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver
4378     ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£
4379     $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
4380
4381     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
4382
4383     $ARG ¤Ï¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£
4384
4385     @latexonly \IPAlabel{minput_open} @endlatexonly
4386
4387 */
4388
4389 MInputMethod *
4390 minput_open_im (MSymbol language, MSymbol name, void *arg)
4391 {
4392   MInputMethod *im;
4393   MInputDriver *driver;
4394
4395   MINPUT__INIT ();
4396
4397   MDEBUG_PRINT2 ("  [IM] opening (%s %s) ... ",
4398                  msymbol_name (language), msymbol_name (name));
4399   if (language)
4400     {
4401       if (name == Mnil)
4402         MERROR (MERROR_IM, NULL);
4403       driver = minput_driver;
4404     }
4405   else
4406     {
4407       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
4408       if (! driver)
4409         MERROR (MERROR_IM, NULL);
4410     }
4411
4412   MSTRUCT_CALLOC (im, MERROR_IM);
4413   im->language = language;
4414   im->name = name;
4415   im->arg = arg;
4416   im->driver = *driver;
4417   if ((*im->driver.open_im) (im) < 0)
4418     {
4419       MDEBUG_PRINT (" failed\n");
4420       free (im);
4421       return NULL;
4422     }
4423   MDEBUG_PRINT (" ok\n");
4424   return im;
4425 }
4426
4427 /*=*/
4428
4429 /***en
4430     @brief Close an input method.
4431
4432     The minput_close_im () function closes the input method $IM, which
4433     must have been created by minput_open_im ().  */
4434
4435 /***ja
4436     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
4437
4438     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£
4439     ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
4440
4441 void
4442 minput_close_im (MInputMethod *im)
4443 {
4444   MDEBUG_PRINT2 ("  [IM] closing (%s %s) ... ",
4445                  msymbol_name (im->name), msymbol_name (im->language));
4446   (*im->driver.close_im) (im);
4447   free (im);
4448   MDEBUG_PRINT (" done\n");
4449 }
4450
4451 /*=*/
4452
4453 /***en
4454     @brief Create an input context.
4455
4456     The minput_create_ic () function creates an input context object
4457     associated with input method $IM, and calls callback functions
4458     corresponding to @b Minput_preedit_start, @b Minput_status_start, and
4459     @b Minput_status_draw in this order.
4460
4461     @return
4462     If an input context is successfully created, minput_create_ic ()
4463     returns a pointer to it.  Otherwise it returns @c NULL.  */
4464
4465 /***ja
4466     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
4467
4468     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
4469     ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
4470     @b Minput_preedit_start, @b Minput_status_start, @b Minput_status_draw
4471     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
4472
4473     @return
4474     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () 
4475     ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
4476       */
4477
4478 MInputContext *
4479 minput_create_ic (MInputMethod *im, void *arg)
4480 {
4481   MInputContext *ic;
4482
4483   MDEBUG_PRINT2 ("  [IM] creating context (%s %s) ... ",
4484                  msymbol_name (im->name), msymbol_name (im->language));
4485   MSTRUCT_CALLOC (ic, MERROR_IM);
4486   ic->im = im;
4487   ic->arg = arg;
4488   ic->preedit = mtext ();
4489   ic->candidate_list = NULL;
4490   ic->produced = mtext ();
4491   ic->spot.x = ic->spot.y = 0;
4492   ic->active = 1;
4493   ic->plist = mplist ();
4494   if ((*im->driver.create_ic) (ic) < 0)
4495     {
4496       MDEBUG_PRINT (" failed\n");
4497       M17N_OBJECT_UNREF (ic->preedit);
4498       M17N_OBJECT_UNREF (ic->produced);
4499       M17N_OBJECT_UNREF (ic->plist);
4500       free (ic);
4501       return NULL;
4502     };
4503
4504   if (im->driver.callback_list)
4505     {
4506       minput_callback (ic, Minput_preedit_start);
4507       minput_callback (ic, Minput_status_start);
4508       minput_callback (ic, Minput_status_draw);
4509     }
4510
4511   MDEBUG_PRINT (" ok\n");
4512   return ic;
4513 }
4514
4515 /*=*/
4516
4517 /***en
4518     @brief Destroy an input context.
4519
4520     The minput_destroy_ic () function destroys the input context $IC,
4521     which must have been created by minput_create_ic ().  It calls
4522     callback functions corresponding to @b Minput_preedit_done,
4523     @b Minput_status_done, and @b Minput_candidates_done in this order.  */
4524
4525 /***ja
4526     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
4527
4528     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
4529     ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () 
4530     ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï 
4531     @b Minput_preedit_done, @b Minput_status_done, @b Minput_candidates_done 
4532     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
4533   */
4534
4535 void
4536 minput_destroy_ic (MInputContext *ic)
4537 {
4538   MDEBUG_PRINT2 ("  [IM] destroying context (%s %s) ... ",
4539                  msymbol_name (ic->im->name), msymbol_name (ic->im->language));
4540   if (ic->im->driver.callback_list)
4541     {
4542       minput_callback (ic, Minput_preedit_done);
4543       minput_callback (ic, Minput_status_done);
4544       minput_callback (ic, Minput_candidates_done);
4545     }
4546   (*ic->im->driver.destroy_ic) (ic);
4547   M17N_OBJECT_UNREF (ic->preedit);
4548   M17N_OBJECT_UNREF (ic->produced);
4549   M17N_OBJECT_UNREF (ic->plist);
4550   MDEBUG_PRINT (" done\n");
4551   free (ic);
4552 }
4553
4554 /*=*/
4555
4556 /***en
4557     @brief Filter an input key.
4558
4559     The minput_filter () function filters input key $KEY according to
4560     input context $IC, and calls callback functions corresponding to
4561     @b Minput_preedit_draw, @b Minput_status_draw, and
4562     @b Minput_candidates_draw if the preedit text, the status, and the
4563     current candidate are changed respectively.
4564
4565     To make the input method commit the current preedit text (if any)
4566     and shift to the initial state, call this function with #Mnil as
4567     $KEY.
4568
4569     To inform the input method about the focus-out event, call this
4570     function with @b Minput_focus_out as $KEY.
4571
4572     To inform the input method about the focus-in event, call this
4573     function with @b Minput_focus_in as $KEY.
4574
4575     To inform the input method about the focus-move event (i.e. input
4576     spot change within the same input context), call this function
4577     with @b Minput_focus_move as $KEY.
4578
4579     @return
4580     If $KEY is filtered out, this function returns 1.  In that case,
4581     the caller should discard the key.  Otherwise, it returns 0, and
4582     the caller should handle the key, for instance, by calling the
4583     function minput_lookup () with the same key.  */
4584
4585 /***ja
4586     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
4587
4588     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4589     ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
4590     @b Minput_preedit_draw, @b Minput_status_draw,
4591     @b Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
4592
4593     @return 
4594     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
4595     ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
4596     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup ()
4597     ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
4598
4599     @latexonly \IPAlabel{minput_filter} @endlatexonly
4600 */
4601
4602 int
4603 minput_filter (MInputContext *ic, MSymbol key, void *arg)
4604 {
4605   int ret;
4606
4607   if (! ic
4608       || ! ic->active)
4609     return 0;
4610   if (ic->im->driver.callback_list
4611       && mtext_nchars (ic->preedit) > 0)
4612     minput_callback (ic, Minput_preedit_draw);
4613
4614   ret = (*ic->im->driver.filter) (ic, key, arg);
4615
4616   if (ic->im->driver.callback_list)
4617     {
4618       if (ic->preedit_changed)
4619         minput_callback (ic, Minput_preedit_draw);
4620       if (ic->status_changed)
4621         minput_callback (ic, Minput_status_draw);
4622       if (ic->candidates_changed)
4623         minput_callback (ic, Minput_candidates_draw);
4624     }
4625
4626   return ret;
4627 }
4628
4629 /*=*/
4630
4631 /***en
4632     @brief Look up a text produced in the input context.
4633
4634     The minput_lookup () function looks up a text in the input context
4635     $IC.  $KEY must be identical to the one that was used in the previous call of
4636     minput_filter ().
4637
4638     If a text was produced by the input method, it is concatenated
4639     to M-text $MT.
4640
4641     This function calls #MInputDriver::lookup .
4642
4643     @return
4644     If $KEY was correctly handled by the input method, this function
4645     returns 0.  Otherwise, it returns -1, even though some text
4646     might be produced in $MT.  */
4647
4648 /***ja
4649     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹.
4650
4651     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£
4652     $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4653
4654     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
4655     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
4656
4657     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
4658
4659     @return 
4660     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
4661     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
4662     ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
4663
4664     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
4665
4666 int
4667 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
4668 {
4669   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
4670 }
4671 /*=*/
4672
4673 /***en
4674     @brief Set the spot of the input context.
4675
4676     The minput_set_spot () function sets the spot of input context $IC
4677     to coordinate ($X, $Y ) with the height specified by $ASCENT and $DESCENT .
4678     The semantics of these values depends on the input method driver.
4679
4680     For instance, a driver designed to work in a CUI environment may
4681     use $X and $Y as the column- and row numbers, and may ignore $ASCENT and
4682     $DESCENT .  A driver designed to work in a window system may
4683     interpret $X and $Y as the pixel offsets relative to the origin of the
4684     client window, and may interpret $ASCENT and $DESCENT as the ascent- and
4685     descent pixels of the line at ($X . $Y ).
4686
4687     $FONTSIZE specifies the fontsize of preedit text in 1/10 point.
4688
4689     $MT and $POS are the M-text and the character position at the spot.
4690     $MT may be @c NULL, in which case, the input method cannot get
4691     information about the text around the spot.  */
4692
4693 /***ja
4694     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë.
4695
4696     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y )
4697     ¤Î°ÌÃ֤ˠ¡¢¹â¤µ $ASCENT¡¢ $DESCENT 
4698     ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£
4699
4700     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y 
4701     ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT 
4702     ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï
4703     $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
4704     $ASCENT ¤È $DESCENT ¤ò ($X . $Y )
4705     ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
4706
4707     $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
4708
4709     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
4710     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
4711     */
4712
4713 void
4714 minput_set_spot (MInputContext *ic, int x, int y,
4715                  int ascent, int descent, int fontsize,
4716                  MText *mt, int pos)
4717 {
4718   ic->spot.x = x;
4719   ic->spot.y = y;
4720   ic->spot.ascent = ascent;
4721   ic->spot.descent = descent;
4722   ic->spot.fontsize = fontsize;
4723   ic->spot.mt = mt;
4724   ic->spot.pos = pos;
4725   if (ic->im->driver.callback_list)
4726     minput_callback (ic, Minput_set_spot);
4727 }
4728 /*=*/
4729
4730 /***en
4731     @brief Toggle input method.
4732
4733     The minput_toggle () function toggles the input method associated
4734     with input context $IC.  */
4735 /***ja
4736     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
4737
4738     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4739     ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
4740     */
4741
4742 void
4743 minput_toggle (MInputContext *ic)
4744 {
4745   if (ic->im->driver.callback_list)
4746     minput_callback (ic, Minput_toggle);
4747   ic->active = ! ic->active;
4748 }
4749
4750 /*=*/
4751
4752 /***en
4753     @brief Reset an input context.
4754
4755     The minput_reset_ic () function resets input context $IC by
4756     calling a callback function corresponding to @b Minput_reset.  It
4757     resets the status of $IC to its initial one.  As the
4758     current preedit text is deleted without commitment, if necessary,
4759     call minput_filter () with the arg @b key #Mnil to force the input
4760     method to commit the preedit in advance.  */
4761
4762 /***ja
4763     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
4764
4765     ´Ø¿ô minput_reset_ic () ¤Ï @b Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
4766     ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢
4767     ¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ë¡£¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹
4768     ¥È¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¤³¤È¤Ê¤¯ºï½ü¤µ¤ì¤ë¤Î¤Ç¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
4769     ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @b key #Mnil ¤Ç¸Æ¤ó¤Ç
4770     ¶¯À©Åª¤Ë¥×¥ê¥¨¥Ç¥£¥Ã¥È¥Æ¥­¥¹¥È¤ò¥³¥ß¥Ã¥È¤µ¤»¤ë¤³¤È¡£  */
4771
4772 void
4773 minput_reset_ic (MInputContext *ic)
4774 {
4775   if (ic->im->driver.callback_list)
4776     minput_callback (ic, Minput_reset);
4777 }
4778
4779 /*=*/
4780
4781 /***en
4782     @brief Get title and icon filename of an input method.
4783
4784     The minput_get_title_icon () function returns a plist containing a
4785     title and icon filename (if any) of an input method specified by
4786     $LANGUAGE and $NAME.
4787
4788     The first element of the plist has key #Mtext and the value is an
4789     M-text of the title for identifying the input method.  The second
4790     element (if any) has key #Mtext and the value is an M-text of the
4791     icon image (absolute) filename for the same purpose.
4792
4793     @return
4794     If there exists a specified input method and it defines an title,
4795     a plist is returned.  Otherwise, NULL is returned.  The caller
4796     must free the plist by m17n_object_unref ().  */
4797 /***ja
4798     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë̾¤òÆÀ¤ë.
4799
4800     ´Ø¿ô minput_get_title_icon () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ë
4801     ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¡Ê¤¢¤ì¤Ð¡Ë¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë¤ò´Þ¤à plist ¤ò
4802     ÊÖ¤¹¡£
4803
4804     plist ¤ÎÂè°ìÍ×ÁǤϡ¢#Mtext ¤ò¥­¡¼¤Ë»ý¤Á¡¢ÃͤÏÆþÎϥ᥽¥Ã¥É¤ò¼±Ê̤¹¤ë
4805     ¥¿¥¤¥È¥ë¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£ÂèÆóÍ×ÁǤ¬¤¢¤ì¤Ð¡¢¥­¡¼¤Ï #Mtext ¤Ç¤¢
4806     ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¥Õ¥¡¥¤¥ë¤ÎÀäÂХѥ¹¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
4807
4808     @return
4809     »ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¡¢¥¿¥¤¥È¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð
4810      plist ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð NULL ¤òÊÖ¤¹¡£¸Æ½Ð¦¤Ï
4811      ´Ø¿ô m17n_object_unref () ¤òÍѤ¤¤Æ plist ¤ò²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
4812
4813 MPlist *
4814 minput_get_title_icon (MSymbol language, MSymbol name)
4815 {
4816   MInputMethodInfo *im_info;
4817   MPlist *plist;
4818   char *file = NULL;
4819   MText *mt;
4820
4821   MINPUT__INIT ();
4822
4823   im_info = get_im_info (language, name, Mnil, Mtitle);
4824   if (! im_info || !im_info->title)
4825     return NULL;
4826   mt = mtext_get_prop (im_info->title, 0, Mtext);
4827   if (mt)
4828     file = mdatabase__find_file ((char *) MTEXT_DATA (mt));
4829   else
4830     {
4831       char *buf = alloca (MSYMBOL_NAMELEN (language) + MSYMBOL_NAMELEN (name)
4832                           + 12);
4833
4834       sprintf (buf, "icons/%s-%s.png", (char *) MSYMBOL_NAME (language), 
4835                (char *) MSYMBOL_NAME (name));
4836       file = mdatabase__find_file (buf);
4837       if (! file && language == Mt)
4838         {
4839           sprintf (buf, "icons/%s.png", (char *) MSYMBOL_NAME (name));
4840           file = mdatabase__find_file (buf);
4841         }
4842     }
4843
4844   plist = mplist ();
4845   mplist_add (plist, Mtext, im_info->title);
4846   if (file)
4847     {
4848       mt = mtext__from_data (file, strlen (file), MTEXT_FORMAT_UTF_8, 1);
4849       free (file);
4850       mplist_add (plist, Mtext, mt);
4851       M17N_OBJECT_UNREF (mt);
4852     }
4853   return plist;
4854 }
4855
4856 /*=*/
4857
4858 /***en
4859     @brief Get description text of an input method.
4860
4861     The minput_get_description () function returns an M-text that
4862     describes the input method specified by $LANGUAGE and $NAME.
4863
4864     @return
4865     If the specified input method has a description text, a pointer to
4866     #MText is returned.  The caller has to free it by m17n_object_unref ().
4867     If the input method does not have a description text, @c NULL is
4868     returned.  */
4869 /***ja
4870     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë.
4871
4872     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
4873     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
4874
4875     @return
4876     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
4877     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
4878     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
4879     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
4880
4881 MText *
4882 minput_get_description (MSymbol language, MSymbol name)
4883 {
4884   MInputMethodInfo *im_info;
4885   MSymbol extra;
4886
4887   MINPUT__INIT ();
4888
4889   if (name != Mnil)
4890     extra = Mnil;
4891   else
4892     extra = language, language = Mt;
4893
4894   im_info = get_im_info (language, name, extra, Mdescription);
4895   if (! im_info || ! im_info->description)
4896     return NULL;
4897   M17N_OBJECT_REF (im_info->description);
4898   return im_info->description;
4899 }
4900
4901 /*=*/
4902
4903 /***en
4904     @brief Get information about input method command(s).
4905
4906     The minput_get_command () function returns information about
4907     the command $COMMAND of the input method specified by $LANGUAGE and
4908     $NAME.  An input method command is a pseudo key event to which one
4909     or more actual input key sequences are assigned.
4910
4911     There are two kinds of commands, global and local.  A global
4912     command has a global definition, and the description and the key
4913     assignment may be inherited by a local command.  Each input method
4914     defines a local command which has a local key assignment.  It may
4915     also declare a local command that inherits the definition of a
4916     global command of the same name.
4917
4918     If $LANGUAGE is #Mt and $NAME is #Mnil, this function returns
4919     information about a global command.  Otherwise information about a
4920     local command is returned.
4921
4922     If $COMMAND is #Mnil, information about all commands is returned.
4923
4924     The return value is a @e well-formed plist (@ref m17nPlist) of this
4925     format:
4926 @verbatim
4927   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
4928 @endverbatim
4929     @c NAME is a symbol representing the command name.
4930
4931     @c DESCRIPTION is an M-text describing the command, or #Mnil if the
4932     command has no description.
4933
4934     @c STATUS is a symbol representing how the key assignment is decided.
4935     The value is #Mnil (the default key assignment), @b Mcustomized (the
4936     key assignment is customized by per-user customization file), or
4937     @b Mconfigured (the key assignment is set by the call of
4938     minput_config_command ()).  For a local command only, it may also
4939     be @b Minherited (the key assignment is inherited from the
4940     corresponding global command).
4941
4942     @c KEYSEQ is a plist of one or more symbols representing a key
4943     sequence assigned to the command.  If there's no KEYSEQ, the
4944     command is currently disabled (i.e. no key sequence can trigger
4945     actions of the command).
4946
4947     If $COMMAND is not #Mnil, the first element of the returned plist
4948     contains the information about $COMMAND.
4949
4950     @return
4951
4952     If the requested information was found, a pointer to a non-empty
4953     plist is returned.  As the plist is kept in the library, the
4954     caller must not modify nor free it.
4955
4956     Otherwise (the specified input method or the specified command
4957     does not exist), @c NULL is returned.  */
4958 /***ja
4959     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
4960
4961     ´Ø¿ô minput_get_command () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
4962     ¥á¥½¥Ã¥É¤Î¥³¥Þ¥ó¥É $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ
4963     ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢£±¤Ä°Ê¾å¤Î¼ÂºÝ¤ÎÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨
4964     ¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
4965
4966     ¥³¥Þ¥ó¥É¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É
4967     ¤Ï¥°¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤Ï¤½¤ÎÀâÌÀ¤È¥­¡¼³ä¤êÅö¤Æ
4968     ¤ò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤ò»ý¤Ä¥í¡¼
4969     ¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÄêµÁ¤¹¤ë¡£¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É¤ÎÄêµÁ¤ò·Ñ
4970     ¾µ¤¹¤ë¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÀë¸À¤¹¤ë¤³¤È¤â¤Ç¤­¤ë¡£
4971
4972     $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ë¥³
4973     ¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¤â
4974     ¤Î¤òÊÖ¤¹¡£
4975
4976     $COMMAND ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
4977
4978     Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
4979
4980 @verbatim
4981   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
4982 @endverbatim
4983     @c NAME ¤Ï¥³¥Þ¥ó¥É̾¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
4984
4985     @c DESCRIPTION ¤Ï¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë
4986     ¤Ï #Mnil ¤Ç¤¢¤ë¡£
4987
4988     @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë
4989     ¤Ç¤¢¤ê¡¢¤½¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, @b Mcustomized ¡Ê¥æ¡¼
4990     ¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë,
4991     @b Mconfigured ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë
4992     ³ä¤êÅö¤Æ¡Ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢
4993     @b Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë
4994     ¤Ç¤â¤è¤¤¡£
4995
4996     @c KEYSEQ ¤Ï£±¤Ä°Ê¾å¤Î¥·¥ó¥Ü¥ë¤«¤é¤Ê¤ë plist ¤Ç¤¢¤ê¡¢³Æ¥·¥ó¥Ü¥ë¤Ï¥³¥Þ
4997     ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òɽ¤¹¡£KEYSEQ ¤¬Ìµ¤¤¾ì¹ç¤Ï¡¢
4998     ¤½¤Î¥³¥Þ¥ó¥É¤Ï¸½¾õ¤Ç»ÈÍÑÉÔǽ¤Ç¤¢¤ë¡£¡Ê¤¹¤Ê¤ï¤Á¥³¥Þ¥ó¥É¤ÎÆ°ºî¤òµ¯
4999     Æ°¤Ç¤­¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Ìµ¤¤¡£¡Ë
5000
5001     $COMMAND ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤϡ¢
5002     $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
5003
5004     @return
5005
5006     µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
5007     ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
5008     ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5009
5010     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ä¥³¥Þ¥ó¥É¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
5011     @c NULL ¤òÊÖ¤¹¡£  */
5012
5013 #if EXAMPLE_CODE
5014 MText *
5015 get_im_command_description (MSymbol language, MSymbol name, MSymbol command)
5016 {
5017   /* Return a description of the command COMMAND of the input method
5018      specified by LANGUAGE and NAME.  */
5019   MPlist *cmd = minput_get_command (langauge, name, command);
5020   MPlist *plist;
5021
5022   if (! cmds)
5023     return NULL;
5024   plist = mplist_value (cmds);  /* (NAME DESCRIPTION STATUS KEY-SEQ ...) */
5025   plist = mplist_next (plist);  /* (DESCRIPTION STATUS KEY-SEQ ...) */
5026   return  (mplist_key (plist) == Mtext
5027            ? (MText *) mplist_value (plist)
5028            : NULL);
5029 }
5030 #endif
5031
5032 MPlist *
5033 minput_get_command (MSymbol language, MSymbol name, MSymbol command)
5034 {
5035   MInputMethodInfo *im_info;
5036
5037   MINPUT__INIT ();
5038
5039   im_info = get_im_info (language, name, Mnil, Mcommand);
5040   if (! im_info
5041       || ! im_info->configured_cmds
5042       || MPLIST_TAIL_P (im_info->configured_cmds))
5043     return NULL;
5044   if (command == Mnil)
5045     return im_info->configured_cmds;
5046   return mplist__assq (im_info->configured_cmds, command);
5047 }
5048
5049 /*=*/
5050
5051 /***en
5052     @brief Configure the key sequence of an input method command.
5053
5054     The minput_config_command () function assigns a list of key
5055     sequences $KEYSEQLIST to the command $COMMAND of the input method
5056     specified by $LANGUAGE and $NAME.
5057
5058     If $KEYSEQLIST is a non-empty plist, it must be a list of key
5059     sequences, and each key sequence must be a plist of symbols.
5060
5061     If $KEYSEQLIST is an empty plist, any configuration and
5062     customization of the command are cancelled, and default key
5063     sequences become effective.
5064
5065     If $KEYSEQLIST is NULL, the configuration of the command is
5066     canceled, and the original key sequences (what saved in per-user
5067     customization file, or the default one) become effective.
5068
5069     In the latter two cases, $COMMAND can be #Mnil to make all the
5070     commands of the input method the target of the operation.
5071
5072     If $NAME is #Mnil, this function configures the key assignment of a
5073     global command, not that of a specific input method.
5074
5075     The configuration takes effect for input methods opened or
5076     re-opened later in the current session.  In order to make the
5077     configuration take effect for the future session, it must be saved
5078     in a per-user customization file by the function
5079     minput_save_config ().
5080
5081     @return
5082     If the operation was successful, this function returns 0,
5083     otherwise returns -1.  The operation fails in these cases:
5084     <ul>
5085     <li>$KEYSEQLIST is not in a valid form.
5086     <li>$COMMAND is not available for the input method.
5087     <li>$LANGUAGE and $NAME do not specify an existing input method.
5088     </ul>
5089
5090     @seealso
5091     minput_get_commands (), minput_save_config ().
5092 */
5093 /***ja
5094     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òÀßÄꤹ¤ë.
5095
5096     ´Ø¿ô minput_config_command () ¤Ï¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È
5097     $KEYSEQLIST ¤ò¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤Î
5098     ¥³¥Þ¥ó¥É $COMMAND ¤Ë³ä¤êÅö¤Æ¤ë¡£
5099
5100     $KEYSEQLIST ¤¬¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È¤Ç¤¢¤ê¡¢
5101     ³Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥·¥ó¥Ü¥ë¤Î plist ¤Ç¤¢¤ë¡£
5102
5103     $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤ä¥«¥¹¥¿¥Þ¥¤¥º¤Ï
5104     ¤¹¤Ù¤Æ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£
5105
5106     $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢
5107     ¸µ¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¡Ê¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤µ¤ì¤Æ¤¤
5108     ¤ë¤â¤Î¡¢¤¢¤ë¤¤¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¤â¤Î¡Ë¤¬Í­¸ú¤Ë¤Ê¤ë¡£
5109
5110     ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$COMMAND ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄê¤ÎÆþ
5111     Îϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥ÉÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
5112
5113     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
5114     ¥ë¤Ê¥³¥Þ¥ó¥É¤Î¥­¡¼³ä¤êÅö¤Æ¤òÀßÄꤹ¤ë¡£
5115
5116     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
5117     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
5118     ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
5119     ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
5120
5121     @return
5122
5123     ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
5124     <ul>
5125     <li>$KEYSEQLIST ¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£
5126     <li>$COMMAND ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
5127     <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
5128     </ul>
5129
5130     @seealso
5131     minput_get_commands (), minput_save_config ().
5132 */
5133
5134 #if EXAMPLE_CODE
5135 /* Add "C-x u" to the "start" command of Unicode input method.  */
5136 {
5137   MSymbol start_command = msymbol ("start");
5138   MSymbol unicode = msymbol ("unicode");
5139   MPlist *cmd, *plist, *key_seq_list, *key_seq;
5140
5141   /* At first get the current key-sequence assignment.  */
5142   cmd = minput_get_command (Mt, unicode, start_command);
5143   if (! cmd)
5144     {
5145       /* The input method does not have the command "start".  Here
5146          should come some error handling code.  */
5147     }
5148   /* Now CMD == ((start DESCRIPTION STATUS KEY-SEQUENCE ...) ...).
5149      Extract the part (KEY-SEQUENCE ...).  */
5150   plist = mplist_next (mplist_next (mplist_next (mplist_value (cmd))));
5151   /* Copy it because we should not modify it directly.  */
5152   key_seq_list = mplist_copy (plist);
5153   
5154   key_seq = mplist ();
5155   mplist_add (key_seq, Msymbol, msymbol ("C-x"));
5156   mplist_add (key_seq, Msymbol, msymbol ("u"));
5157   mplist_add (key_seq_list, Mplist, key_seq);
5158   m17n_object_unref (key_seq);
5159
5160   minput_config_command (Mt, unicode, start_command, key_seq_list);
5161   m17n_object_unref (key_seq_list);
5162 }
5163 #endif
5164
5165 int
5166 minput_config_command (MSymbol language, MSymbol name, MSymbol command,
5167                        MPlist *keyseqlist)
5168 {
5169   MInputMethodInfo *im_info, *config;
5170   MPlist *plist;
5171
5172   MINPUT__INIT ();
5173
5174   im_info = get_im_info (language, name, Mnil, Mcommand);
5175   if (! im_info)
5176     MERROR (MERROR_IM, -1);
5177   if (command == Mnil ? (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
5178       : (! im_info->cmds
5179          || ! mplist__assq (im_info->configured_cmds, command)))
5180     MERROR (MERROR_IM, -1);
5181   if (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
5182     {
5183       MPLIST_DO (plist, keyseqlist)
5184         if (! check_command_keyseq (plist))
5185           MERROR (MERROR_IM, -1);
5186     }
5187
5188   config = get_config_info (im_info);
5189   if (! config)
5190     {
5191       if (! im_config_list)
5192         im_config_list = mplist ();
5193       config = new_im_info (NULL, language, name, Mnil, im_config_list);
5194       config->cmds = mplist ();
5195       config->vars = mplist ();
5196     }
5197
5198   if (! keyseqlist && MPLIST_TAIL_P (config->cmds))
5199     /* Nothing to do.  */
5200     return 0;
5201
5202   if (command == Mnil)
5203     {
5204       if (! keyseqlist)
5205         {
5206           /* Cancal the configuration. */
5207           if (MPLIST_TAIL_P (config->cmds))
5208             return 0;
5209           mplist_set (config->cmds, Mnil, NULL);
5210         }
5211       else
5212         {
5213           /* Cancal the customization. */
5214           MInputMethodInfo *custom = get_custom_info (im_info);
5215
5216           if (MPLIST_TAIL_P (config->cmds)
5217               && (! custom || ! custom->cmds || MPLIST_TAIL_P (custom->cmds)))
5218             /* Nothing to do.  */
5219             return 0;
5220           mplist_set (config->cmds, Mnil, NULL);
5221           MPLIST_DO (plist, custom->cmds)
5222             {
5223               command = MPLIST_SYMBOL (MPLIST_PLIST (plist));
5224               plist = mplist ();
5225               mplist_add (plist, Msymbol, command);
5226               mplist_push (config->cmds, Mplist, plist);
5227               M17N_OBJECT_UNREF (plist);
5228             }
5229         }
5230     }
5231   else
5232     {
5233       plist = mplist__assq (config->cmds, command);
5234       if (! keyseqlist)
5235         {
5236           /* Cancel the configuration.  */
5237           if (! plist)
5238             return 0;
5239           mplist__pop_unref (plist);
5240         }
5241       else if (MPLIST_TAIL_P (keyseqlist))
5242         {
5243           /* Cancel the customization.  */
5244           MInputMethodInfo *custom = get_custom_info (im_info);
5245           int no_custom = (! custom || ! custom->cmds
5246                            || ! mplist__assq (custom->cmds, command));
5247           if (! plist)
5248             {
5249               if (no_custom)
5250                 return 0;
5251               plist = mplist ();
5252               mplist_add (config->cmds, Mplist, plist);
5253               M17N_OBJECT_UNREF (plist);
5254               plist = mplist_add (plist, Msymbol, command);
5255             }
5256           else
5257             {
5258               if (no_custom)
5259                 mplist__pop_unref (plist);
5260               else
5261                 {
5262                   plist = MPLIST_PLIST (plist); /* (NAME nil KEYSEQ ...) */
5263                   plist = MPLIST_NEXT (plist);
5264                   mplist_set (plist, Mnil, NULL);
5265                 }
5266             }
5267         }
5268       else
5269         {
5270           MPlist *pl;
5271
5272           if (plist)
5273             {
5274               plist = MPLIST_NEXT (MPLIST_PLIST (plist));
5275               if (! MPLIST_TAIL_P (plist))
5276                 mplist_set (plist, Mnil, NULL);
5277             }
5278           else
5279             {
5280               plist = mplist ();
5281               mplist_add (config->cmds, Mplist, plist);
5282               M17N_OBJECT_UNREF (plist);
5283               plist = mplist_add (plist, Msymbol, command);
5284               plist = MPLIST_NEXT (plist);
5285             }
5286           MPLIST_DO (keyseqlist, keyseqlist)
5287             {
5288               pl = mplist_copy (MPLIST_VAL (keyseqlist));
5289               plist = mplist_add (plist, Mplist, pl);
5290               M17N_OBJECT_UNREF (pl);
5291             }
5292         }
5293     }
5294   config_all_commands (im_info);
5295   im_info->tick = time (NULL);
5296   return 0;
5297 }
5298
5299 /*=*/
5300
5301 /***en
5302     @brief Get information about input method variable(s).
5303
5304     The minput_get_variable () function returns information about
5305     variable $VARIABLE of the input method specified by $LANGUAGE and $NAME.
5306     An input method variable controls behavior of an input method.
5307
5308     There are two kinds of variables, global and local.  A global
5309     variable has a global definition, and the description and the value
5310     may be inherited by a local variable.  Each input method defines a
5311     local variable which has local value.  It may also declare a
5312     local variable that inherits definition of a global variable of
5313     the same name.
5314
5315     If $LANGUAGE is #Mt and $NAME is #Mnil, information about a global
5316     variable is returned.  Otherwise information about a local variable
5317     is returned.
5318
5319     If $VARIABLE is #Mnil, information about all variables is
5320     returned.
5321
5322     The return value is a @e well-formed plist (@ref m17nPlist) of this
5323     format:
5324 @verbatim
5325   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
5326 @endverbatim
5327     @c NAME is a symbol representing the variable name.
5328
5329     @c DESCRIPTION is an M-text describing the variable, or #Mnil if the
5330     variable has no description.
5331
5332     @c STATUS is a symbol representing how the value is decided.  The
5333     value is #Mnil (the default value), @b Mcustomized (the value is
5334     customized by per-user customization file), or @b Mconfigured (the
5335     value is set by the call of minput_config_variable ()).  For a
5336     local variable only, it may also be @b Minherited (the value is
5337     inherited from the corresponding global variable).
5338
5339     @c VALUE is the initial value of the variable.  If the key of this
5340     element is #Mt, the variable has no initial value.  Otherwise, the
5341     key is #Minteger, #Msymbol, or #Mtext and the value is of the
5342     corresponding type.
5343
5344     @c VALID-VALUEs (if any) specify which values the variable can have.
5345     They have the same type (i.e. having the same key) as @c VALUE except
5346     for the case that VALUE is an integer.  In that case, @c VALID-VALUE
5347     may be a plist of two integers specifying the range of possible
5348     values.
5349
5350     If there no @c VALID-VALUE, the variable can have any value as long
5351     as the type is the same as @c VALUE.
5352
5353     If $VARIABLE is not #Mnil, the first element of the returned plist
5354     contains the information about $VARIABLE.
5355
5356     @return
5357
5358     If the requested information was found, a pointer to a non-empty
5359     plist is returned.  As the plist is kept in the library, the
5360     caller must not modify nor free it.
5361
5362     Otherwise (the specified input method or the specified variable
5363     does not exist), @c NULL is returned.  */
5364 /***ja
5365     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
5366
5367     ´Ø¿ô minput_get_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
5368     ¥á¥½¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤È¤Ï¡¢
5369     ÆþÎϥ᥽¥Ã¥É¤Î¿¶Éñ¤òÀ©¸æ¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£
5370
5371     ÊÑ¿ô¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤Ï¥°
5372     ¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤Ï¤½¤ÎÀâÌÀ¤ÈÃͤò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç
5373     ¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤ÊÃͤò»ý¤Ä¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÄêµÁ¤¹¤ë¡£
5374     ¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤ÎÄêµÁ¤ò·Ñ¾µ¤¹¤ë¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÀë¸À¤¹¤ë
5375     ¤³¤È¤â¤Ç¤­¤ë¡£
5376
5377     $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ëÊÑ
5378     ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ëÊÑ¿ô¤Ë´Ø¤¹¤ë¤â¤Î¤òÊÖ¤¹¡£
5379
5380     $VARIABLE ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
5381
5382     Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
5383 @verbatim
5384   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
5385 @endverbatim
5386
5387     @c NAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
5388
5389     @c DESCRIPTION ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë¤Ï
5390     #Mnil ¤Ç¤¢¤ë¡£
5391
5392     @c STATUS ¤ÏÃͤ¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢
5393     @c STATUS ¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, @b Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤Î
5394     ¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, @b Mconfigured
5395     ¡Êminput_config_variable ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ëÃ͡ˤΤ¤¤º¤ì
5396     ¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ëÊÑ¿ô¤Î¾ì¹ç¤Ë¤Ï¡¢@b Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë
5397     ÊÑ¿ô¤«¤é·Ñ¾µ¤·¤¿Ã͡ˤǤâ¤è¤¤¡£
5398
5399     @c VALUE ¤ÏÊÑ¿ô¤Î½é´üÃͤǤ¢¤ë¡£¤³¤ÎÍ×ÁǤΥ­¡¼¤¬#Mt ¤Ç¤¢¤ì¤Ð½é´üÃͤò»ý
5400     ¤¿¤Ê¤¤¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤Ï #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì
5401     ¤«¤Ç¤¢¤ê¡¢ÃͤϤ½¤ì¤¾¤ìÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
5402
5403     @c VALID-VALUE ¤Ï¤â¤·¤¢¤ì¤Ð¡¢ÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò»ØÄꤹ¤ë¡£¤³¤ì¤Ï @c VALUE
5404     ¤ÈƱ¤¸·¿(¤¹¤Ê¤ï¤ÁƱ¤¸¥­¡¼¤ò»ý¤Ä) ¤Ç¤¢¤ë¤¬¡¢Îã³°¤È¤·¤Æ @c VALUE ¤¬
5405     integer ¤Î¾ì¹ç¤Ï @c VALID-VALUE ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹Æó¤Ä¤ÎÀ°¿ô¤«¤é
5406     ¤Ê¤ë plist ¤È¤Ê¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
5407
5408     @c VALID-VALUE ¤¬¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô¤Ï @c VALUE ¤ÈƱ¤¸·¿¤Ç¤¢¤ë¸Â¤ê¤¤¤«¤Ê¤ëÃͤâ
5409     ¤È¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
5410
5411     $VARIABLE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤÏ
5412     $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
5413
5414     @return
5415
5416     µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
5417     ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
5418     ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5419
5420     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤äÊÑ¿ô¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
5421     @c NULL ¤òÊÖ¤¹¡£ */
5422
5423 MPlist *
5424 minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
5425 {
5426   MInputMethodInfo *im_info;
5427
5428   MINPUT__INIT ();
5429
5430   im_info = get_im_info (language, name, Mnil, Mvariable);
5431   if (! im_info || ! im_info->configured_vars)
5432     return NULL;
5433   if (variable == Mnil)
5434     return im_info->configured_vars;
5435   return mplist__assq (im_info->configured_vars, variable);
5436 }
5437
5438 /*=*/
5439
5440 /***en
5441     @brief Configure the value of an input method variable.
5442
5443     The minput_config_variable () function assigns $VALUE to the
5444     variable $VARIABLE of the input method specified by $LANGUAGE and
5445     $NAME.
5446
5447     If $VALUE is a non-empty plist, it must be a plist of one element
5448     whose key is #Minteger, #Msymbol, or #Mtext, and the value is of
5449     the corresponding type.  That value is assigned to the variable.
5450
5451     If $VALUE is an empty plist, any configuration and customization
5452     of the variable are canceled, and the default value is assigned to
5453     the variable.
5454
5455     If $VALUE is NULL, the configuration of the variable is canceled,
5456     and the original value (what saved in per-user customization file,
5457     or the default value) is assigned to the variable.
5458
5459     In the latter two cases, $VARIABLE can be #Mnil to make all the
5460     variables of the input method the target of the operation.
5461
5462     If $NAME is #Mnil, this function configures the value of global
5463     variable, not that of a specific input method.
5464
5465     The configuration takes effect for input methods opened or
5466     re-opened later in the current session.  To make the configuration
5467     take effect for the future session, it must be saved in a per-user
5468     customization file by the function minput_save_config ().
5469
5470     @return
5471
5472     If the operation was successful, this function returns 0,
5473     otherwise returns -1.  The operation fails in these cases:
5474     <ul>
5475     <li>$VALUE is not in a valid form, the type does not match the
5476     definition, or the value is our of range.
5477     <li>$VARIABLE is not available for the input method.
5478     <li>$LANGUAGE and $NAME do not specify an existing input method.  
5479     </ul>
5480
5481     @seealso
5482     minput_get_variable (), minput_save_config ().  */
5483 /***ja
5484     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë.
5485
5486     ´Ø¿ô minput_config_variable () ¤ÏÃÍ $VALUE ¤ò¡¢$LANGUAGE ¤È $NAME
5487     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤ë¡£
5488
5489     $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï
5490     #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì¤«¡¢ÃͤÏÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
5491     ¤³¤ÎÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
5492
5493     $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤È¥«¥¹¥¿¥Þ¥¤¥º¤¬¥­¥ã¥ó¥»¥ë¤µ
5494     ¤ì¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
5495
5496     $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¸µ¤ÎÃ͡ʥ桼¥¶
5497     Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ëÃæ¤ÎÃÍ¡¢¤Þ¤¿¤Ï¥Ç¥Õ¥©¥ë¥È¤ÎÃ͡ˤ¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
5498
5499     ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$VARIABLE ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄꤵ¤ì
5500     ¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ôÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
5501
5502     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
5503     ¥ë¤ÊÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë¡£
5504
5505     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
5506     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
5507     ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
5508     ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
5509
5510     @return
5511
5512     ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
5513     <ul>
5514     <li>$VALUE¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£·¿¤¬ÄêµÁ¤Ë¹ç¤ï¤Ê¤¤¡¢¤Þ¤¿¤ÏÃͤ¬Èϰϳ°¤Ç¤¢¤ë¡£
5515     <li>$VARIABLE ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
5516     <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
5517     </ul>
5518
5519     @seealso
5520     minput_get_commands (), minput_save_config ().
5521 */
5522 int
5523 minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
5524                         MPlist *value)
5525 {
5526   MInputMethodInfo *im_info, *config;
5527   MPlist *plist;
5528
5529   MINPUT__INIT ();
5530
5531   im_info = get_im_info (language, name, Mnil, Mvariable);
5532   if (! im_info)
5533     MERROR (MERROR_IM, -1);
5534   if (variable == Mnil ? (value && ! MPLIST_TAIL_P (value))
5535       : (! im_info->vars
5536          || ! (plist = mplist__assq (im_info->configured_vars, variable))))
5537     MERROR (MERROR_IM, -1);
5538
5539   if (value && ! MPLIST_TAIL_P (value))
5540     {
5541       plist = MPLIST_PLIST (plist);
5542       plist = MPLIST_NEXT (plist); /* (DESC STATUS VALUE VALIDS ...) */
5543       plist = MPLIST_NEXT (plist); /* (STATUS VALUE VALIDS ...) */
5544       plist = MPLIST_NEXT (plist); /* (VALUE VALIDS ...) */
5545       if (MPLIST_KEY (plist) != Mt
5546           && ! check_variable_value (value, plist))
5547         MERROR (MERROR_IM, -1);
5548     }
5549
5550   config = get_config_info (im_info);
5551   if (! config)
5552     {
5553       if (! im_config_list)
5554         im_config_list = mplist ();
5555       config = new_im_info (NULL, language, name, Mnil, im_config_list);
5556       config->cmds = mplist ();
5557       config->vars = mplist ();
5558     }
5559
5560   if (! value && MPLIST_TAIL_P (config->vars))
5561     /* Nothing to do.  */
5562     return 0;
5563
5564   if (variable == Mnil)
5565     {
5566       if (! value)
5567         {
5568           /* Cancel the configuration.  */
5569           if (MPLIST_TAIL_P (config->vars))
5570             return 0;
5571           mplist_set (config->vars, Mnil, NULL);
5572         }
5573       else
5574         {
5575           /* Cancel the customization.  */
5576           MInputMethodInfo *custom = get_custom_info (im_info);
5577
5578           if (MPLIST_TAIL_P (config->vars)
5579               && (! custom || ! custom->vars || MPLIST_TAIL_P (custom->vars)))
5580             /* Nothing to do.  */
5581             return 0;
5582           mplist_set (config->vars, Mnil, NULL);
5583           MPLIST_DO (plist, custom->vars)
5584             {
5585               variable = MPLIST_SYMBOL (MPLIST_PLIST (plist));
5586               plist = mplist ();
5587               mplist_add (plist, Msymbol, variable);
5588               mplist_push (config->vars, Mplist, plist);
5589               M17N_OBJECT_UNREF (plist);
5590             }
5591         }
5592     }
5593   else
5594     {
5595       plist = mplist__assq (config->vars, variable);
5596       if (! value)
5597         {
5598           /* Cancel the configuration.  */
5599           if (! plist)
5600             return 0;
5601           mplist__pop_unref (plist);
5602         }
5603       else if (MPLIST_TAIL_P (value))
5604         {
5605           /* Cancel the customization.  */
5606           MInputMethodInfo *custom = get_custom_info (im_info);
5607           int no_custom = (! custom || ! custom->vars
5608                            || ! mplist__assq (custom->vars, variable));
5609           if (! plist)
5610             {
5611               if (no_custom)
5612                 return 0;
5613               plist = mplist ();
5614               mplist_add (config->vars, Mplist, plist);
5615               M17N_OBJECT_UNREF (plist);
5616               plist = mplist_add (plist, Msymbol, variable);
5617             }
5618           else
5619             {
5620               if (no_custom)
5621                 mplist__pop_unref (plist);
5622               else
5623                 {
5624                   plist = MPLIST_PLIST (plist); /* (NAME nil VALUE) */
5625                   plist = MPLIST_NEXT (plist);  /* ([nil VALUE]) */
5626                   mplist_set (plist, Mnil ,NULL);
5627                 }
5628             }
5629         }
5630       else
5631         {
5632           if (plist)
5633             {
5634               plist = MPLIST_NEXT (MPLIST_PLIST (plist));
5635               if (! MPLIST_TAIL_P (plist))
5636                 mplist_set (plist, Mnil, NULL);
5637             }
5638           else
5639             {
5640               plist = mplist ();
5641               mplist_add (config->vars, Mplist, plist);
5642               M17N_OBJECT_UNREF (plist);
5643               plist = mplist_add (plist, Msymbol, variable);
5644               plist = MPLIST_NEXT (plist);
5645             }
5646           mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value));
5647         }
5648     }
5649   config_all_variables (im_info);
5650   im_info->tick = time (NULL);
5651   return 0;
5652 }
5653
5654 /*=*/
5655
5656 /***en
5657     @brief Get the name of per-user customization file.
5658     
5659     The minput_config_file () function returns the absolute path name
5660     of per-user customization file into which minput_save_config ()
5661     save configurations.  It is usually @c config.mic under the
5662     directory <tt>${HOME}/.m17n.d</tt> (${HOME} is user's home
5663     directory).  It is not assured that the file of the returned name
5664     exists nor is readable/writable.  If minput_save_config () fails
5665     and returns -1, an application program might check the file, make
5666     it writable (if possible), and try minput_save_config () again.
5667
5668     @return
5669
5670     This function returns a string.  As the string is kept in the
5671     library, the caller must not modify nor free it.
5672
5673     @seealso
5674     minput_save_config ()
5675 */
5676 /***ja
5677     @brief ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÆÀ¤ë.
5678     
5679     ´Ø¿ô minput_config_file () ¤Ï¡¢´Ø¿ô minput_save_config () ¤¬ÀßÄê¤ò
5680     Êݸ¤¹¤ë¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ø¤ÎÀäÂХѥ¹Ì¾¤òÊÖ¤¹¡£Ä̾ï¤Ï¡¢¥æ¡¼¥¶
5681     ¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î²¼¤Î¥Ç¥£¥ì¥¯¥È¥ê @c ".m17n.d" ¤Ë¤¢¤ë@c
5682     "config.mic" ¤È¤Ê¤ë¡£ÊÖ¤µ¤ì¤¿Ì¾Á°¤Î¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¡¢Æɤ߽ñ¤­¤Ç
5683     ¤­¤ë¤«¤ÏÊݾڤµ¤ì¤Ê¤¤¡£´Ø¿ôminput_save_config () ¤¬¼ºÇÔ¤·¤Æ -1 ¤òÊÖ
5684     ¤·¤¿¾ì¹ç¤Ë¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò³Îǧ¤·¡¢
5685     ¡Ê¤Ç¤­¤ì¤Ð¡Ë½ñ¤­¹þ¤ß²Äǽ¤Ë¤·ºÆÅÙminput_save_config () ¤ò»î¤¹¤³¤È¤¬
5686     ¤Ç¤­¤ë¡£
5687
5688     @return
5689
5690     ¤³¤Î´Ø¿ô¤Ïʸ»úÎó¤òÊÖ¤¹¡£Ê¸»úÎó¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð
5691     Â¦¤¬½¤Àµ¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5692
5693     @seealso
5694     minput_save_config ()
5695 */
5696
5697 char *
5698 minput_config_file ()
5699 {
5700   MINPUT__INIT ();
5701
5702   return mdatabase__file (im_custom_mdb);
5703 }
5704
5705 /*=*/
5706
5707 /***en
5708     @brief Save configurations in per-user customization file.
5709
5710     The minput_save_config () function saves the configurations done
5711     so far in the current session into the per-user customization
5712     file.
5713
5714     @return
5715
5716     If the operation was successful, 1 is returned.  If the per-user
5717     customization file is currently locked, 0 is returned.  In that
5718     case, the caller may wait for a while and try again.  If the
5719     configuration file is not writable, -1 is returned.  In that case,
5720     the caller may check the name of the file by calling
5721     minput_config_file (), make it writable if possible, and try
5722     again.
5723
5724     @seealso
5725     minput_config_file ()  */
5726 /***ja
5727     @brief ÀßÄê¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë.
5728
5729     ´Ø¿ô minput_save_config () ¤Ï¸½¹Ô¤Î¥»¥Ã¥·¥ç¥ó¤Ç¤³¤ì¤Þ¤Ç¤Ë¹Ô¤Ã¤¿ÀßÄê
5730     ¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë¡£
5731
5732     @return
5733
5734     À®¸ù¤¹¤ì¤Ð 1 ¤òÊÖ¤¹¡£¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤
5735     ¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢¸Æ½Ð¦¤Ï¤·¤Ð¤é¤¯ÂԤäƺƻî¹Ô¤Ç¤­¤ë¡£ÀßÄê¥Õ¥¡
5736     ¥¤¥ë¤¬½ñ¤­¹þ¤ßÉԲĤξì¹ç¡¢-1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢minput_config_file
5737     () ¤ò¸Æ¤ó¤Ç¥Õ¥¡¥¤¥ë̾¤ò¥Á¥§¥Ã¥¯¤·¡¢¤Ç¤­¤ì¤Ð½ñ¤­¹þ¤ß²Äǽ¤Ë¤·¡¢ºÆ»î¹Ô
5738     ¤Ç¤­¤ë¡£
5739
5740     @seealso
5741     minput_config_file ()  */
5742
5743 int
5744 minput_save_config (void)
5745 {
5746   MPlist *data, *tail, *plist, *p, *elt;
5747   int ret;
5748
5749   MINPUT__INIT ();
5750   ret = mdatabase__lock (im_custom_mdb);
5751   if (ret <= 0)
5752     return ret;
5753   if (! im_config_list)
5754     return 1;
5755   update_custom_info ();
5756   if (! im_custom_list)
5757     im_custom_list = mplist ();
5758
5759   /* At first, reflect configuration in customization.  */
5760   MPLIST_DO (plist, im_config_list)
5761     {
5762       MPlist *pl = MPLIST_PLIST (plist);
5763       MSymbol language, name, extra, command, variable;
5764       MInputMethodInfo *custom, *config;
5765
5766       language = MPLIST_SYMBOL (pl);
5767       pl = MPLIST_NEXT (pl);
5768       name = MPLIST_SYMBOL (pl);
5769       pl = MPLIST_NEXT (pl);
5770       extra = MPLIST_SYMBOL (pl);
5771       pl = MPLIST_NEXT (pl);
5772       config = MPLIST_VAL (pl);
5773       custom = get_custom_info (config);
5774       if (! custom)
5775         custom = new_im_info (NULL, language, name, extra, im_custom_list);
5776       if (config->cmds)
5777         MPLIST_DO (pl, config->cmds)
5778           {
5779             elt = MPLIST_PLIST (pl);
5780             command = MPLIST_SYMBOL (elt);
5781             if (custom->cmds)
5782               p = mplist__assq (custom->cmds, command);
5783             else
5784               custom->cmds = mplist (), p = NULL;
5785             elt = MPLIST_NEXT (elt);
5786             if (p)
5787               {
5788                 p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5789                 mplist_set (p, Mnil, NULL);
5790               }
5791             else
5792               {
5793                 p = mplist ();
5794                 mplist_add (custom->cmds, Mplist, p);
5795                 M17N_OBJECT_UNREF (p);
5796                 mplist_add (p, Msymbol, command);
5797                 p = mplist_add (p, Msymbol, Mnil);
5798                 p = MPLIST_NEXT (p);
5799               }
5800             mplist__conc (p, elt);
5801           }
5802       if (config->vars)
5803         MPLIST_DO (pl, config->vars)
5804           {
5805             elt = MPLIST_PLIST (pl);
5806             variable = MPLIST_SYMBOL (elt);
5807             if (custom->vars)
5808               p = mplist__assq (custom->vars, variable);
5809             else
5810               custom->vars = mplist (), p = NULL;
5811             elt = MPLIST_NEXT (elt);
5812             if (p)
5813               {
5814                 p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5815                 mplist_set (p, Mnil, NULL);
5816               }
5817             else
5818               {
5819                 p = mplist ();
5820                 mplist_add (custom->vars, Mplist, p);
5821                 M17N_OBJECT_UNREF (p);
5822                 mplist_add (p, Msymbol, variable);
5823                 p = mplist_add (p, Msymbol, Mnil);
5824                 p = MPLIST_NEXT (p);
5825               }
5826             mplist__conc (p, elt);
5827           }
5828     }
5829   free_im_list (im_config_list);
5830   im_config_list = NULL;
5831
5832   /* Next, reflect customization to the actual plist to be written.  */
5833   data = tail = mplist ();
5834   MPLIST_DO (plist, im_custom_list)
5835     {
5836       MPlist *pl = MPLIST_PLIST (plist);
5837       MSymbol language, name, extra;
5838       MInputMethodInfo *custom, *im_info;
5839
5840       language = MPLIST_SYMBOL (pl);
5841       pl  = MPLIST_NEXT (pl);
5842       name = MPLIST_SYMBOL (pl);
5843       pl = MPLIST_NEXT (pl);
5844       extra = MPLIST_SYMBOL (pl);
5845       pl = MPLIST_NEXT (pl);
5846       custom = MPLIST_VAL (pl);
5847       if ((! custom->cmds || MPLIST_TAIL_P (custom->cmds))
5848           && (! custom->vars || MPLIST_TAIL_P (custom->vars)))
5849         continue;
5850       im_info = lookup_im_info (im_info_list, language, name, extra);
5851       if (im_info)
5852         {
5853           if (im_info->cmds)
5854             config_all_commands (im_info);
5855           if (im_info->vars)
5856             config_all_variables (im_info);
5857         }
5858       
5859       elt = NULL;
5860       if (custom->cmds && ! MPLIST_TAIL_P (custom->cmds))
5861         {
5862           MPLIST_DO (p, custom->cmds)
5863             if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5864               break;
5865           if (! MPLIST_TAIL_P (p))
5866             {
5867               elt = mplist ();
5868               pl = mplist ();
5869               mplist_add (elt, Mplist, pl);
5870               M17N_OBJECT_UNREF (pl);
5871               pl = mplist_add (pl, Msymbol, Mcommand);
5872               MPLIST_DO (p, custom->cmds)
5873                 if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5874                   pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5875             }
5876         }
5877       if (custom->vars && ! MPLIST_TAIL_P (custom->vars))
5878         {
5879           MPLIST_DO (p, custom->vars)
5880             if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5881               break;
5882           if (! MPLIST_TAIL_P (p))
5883             {
5884               if (! elt)
5885                 elt = mplist ();
5886               pl = mplist ();
5887               mplist_add (elt, Mplist, pl);
5888               M17N_OBJECT_UNREF (pl);
5889               pl = mplist_add (pl, Msymbol, Mvariable);
5890               MPLIST_DO (p, custom->vars)
5891                 if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5892                   pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5893             }
5894         }
5895       if (elt)
5896         {
5897           pl = mplist ();
5898           mplist_push (elt, Mplist, pl);
5899           M17N_OBJECT_UNREF (pl);
5900           pl = mplist_add (pl, Msymbol, Minput_method);
5901           pl = mplist_add (pl, Msymbol, language);
5902           pl = mplist_add (pl, Msymbol, name);
5903           if (extra != Mnil)
5904             pl = mplist_add (pl, Msymbol, extra);
5905           tail = mplist_add (tail, Mplist, elt);
5906           M17N_OBJECT_UNREF (elt);
5907         }
5908     }
5909
5910   mplist_push (data, Mstring, ";; -*- mode:lisp; coding:utf-8 -*-");
5911   ret = mdatabase__save (im_custom_mdb, data);
5912   mdatabase__unlock (im_custom_mdb);
5913   M17N_OBJECT_UNREF (data);
5914   return (ret < 0 ? -1 : 1);
5915 }
5916
5917 /*=*/
5918 /*** @} */
5919 /*=*/
5920 /***en
5921     @name Obsolete functions
5922 */
5923 /***ja
5924     @name Obsolete ¤Ê´Ø¿ô
5925 */
5926 /*** @{ */
5927
5928 /*=*/
5929 /***en
5930     @brief Get a list of variables of an input method (obsolete).
5931
5932     This function is obsolete.  Use minput_get_variable () instead.
5933
5934     The minput_get_variables () function returns a plist (#MPlist) of
5935     variables used to control the behavior of the input method
5936     specified by $LANGUAGE and $NAME.  The plist is @e well-formed
5937     (@ref m17nPlist) of the following format:
5938
5939 @verbatim
5940     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5941      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5942      ...)
5943 @endverbatim
5944
5945     @c VARNAME is a symbol representing the variable name.
5946
5947     @c DOC-MTEXT is an M-text describing the variable.
5948
5949     @c DEFAULT-VALUE is the default value of the variable.  It is a
5950     symbol, integer, or M-text.
5951
5952     @c VALUEs (if any) specifies the possible values of the variable.
5953     If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
5954     @c TO), where @c FROM and @c TO specifies a range of possible
5955     values.
5956
5957     For instance, suppose an input method has the variables:
5958
5959     @li name:intvar, description:"value is an integer",
5960          initial value:0, value-range:0..3,10,20
5961
5962     @li name:symvar, description:"value is a symbol",
5963          initial value:nil, value-range:a, b, c, nil
5964
5965     @li name:txtvar, description:"value is an M-text",
5966          initial value:empty text, no value-range (i.e. any text)
5967
5968     Then, the returned plist is as follows.
5969
5970 @verbatim
5971     (intvar ("value is an integer" 0 (0 3) 10 20)
5972      symvar ("value is a symbol" nil a b c nil)
5973      txtvar ("value is an M-text" ""))
5974 @endverbatim
5975
5976     @return
5977     If the input method uses any variables, a pointer to #MPlist is
5978     returned.  As the plist is kept in the library, the caller must not
5979     modify nor free it.  If the input method does not use any
5980     variable, @c NULL is returned.  */
5981 /***ja
5982     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
5983
5984     ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
5985     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
5986     (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(@ref m17nPlist) °Ê
5987     ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
5988
5989 @verbatim
5990     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5991      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
5992      ...)
5993 @endverbatim
5994
5995     @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
5996
5997     @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
5998
5999     @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
6000     M-text ¤Ç¤¢¤ë¡£
6001
6002     @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
6003     @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
6004     ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
6005
6006     Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
6007
6008     @li name:intvar, ÀâÌÀ:"value is an integer",
6009         ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
6010
6011     @li name:symvar, ÀâÌÀ:"value is a symbol",
6012          ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
6013
6014     @li name:txtvar, ÀâÌÀ:"value is an M-text",
6015         ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
6016
6017     ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
6018
6019 @verbatim
6020     (intvar ("value is an integer" 0 (0 3) 10 20)
6021      symvar ("value is a symbol" nil a b c nil)
6022      txtvar ("value is an M-text" ""))
6023 @endverbatim
6024
6025     @return 
6026     ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
6027     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
6028     ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
6029
6030 MPlist *
6031 minput_get_variables (MSymbol language, MSymbol name)
6032 {
6033   MInputMethodInfo *im_info;
6034   MPlist *vars;
6035
6036   MINPUT__INIT ();
6037
6038   im_info = get_im_info (language, name, Mnil, Mvariable);
6039   if (! im_info || ! im_info->configured_vars)
6040     return NULL;
6041
6042   M17N_OBJECT_UNREF (im_info->bc_vars);
6043   im_info->bc_vars = mplist ();
6044   MPLIST_DO (vars, im_info->configured_vars)
6045     {
6046       MPlist *plist = MPLIST_PLIST (vars);
6047       MPlist *elt = mplist ();
6048
6049       mplist_push (im_info->bc_vars, Mplist, elt);
6050       mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
6051       elt = MPLIST_NEXT (elt);
6052       mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
6053       M17N_OBJECT_UNREF (elt);
6054     }
6055   return im_info->bc_vars;
6056 }
6057
6058 /*=*/
6059
6060 /***en
6061     @brief Set the initial value of an input method variable.
6062
6063     The minput_set_variable () function sets the initial value of
6064     input method variable $VARIABLE to $VALUE for the input method
6065     specified by $LANGUAGE and $NAME.
6066
6067     By default, the initial value is 0.
6068
6069     This setting gets effective in a newly opened input method.
6070
6071     @return
6072     If the operation was successful, 0 is returned.  Otherwise -1 is
6073     returned, and #merror_code is set to @c MERROR_IM.  */
6074 /***ja
6075     @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
6076
6077     ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
6078     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
6079     ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
6080
6081     ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
6082
6083     ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
6084
6085     @return
6086     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
6087     #merror_code ¤ò @c MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
6088
6089 int
6090 minput_set_variable (MSymbol language, MSymbol name,
6091                      MSymbol variable, void *value)
6092 {
6093   MPlist *plist, *pl;
6094   MInputMethodInfo *im_info;
6095   int ret;
6096
6097   MINPUT__INIT ();
6098
6099   if (variable == Mnil)
6100     MERROR (MERROR_IM, -1);
6101   plist = minput_get_variable (language, name, variable);
6102   plist = MPLIST_PLIST (plist);
6103   plist = MPLIST_NEXT (plist);
6104   pl = mplist ();
6105   mplist_add (pl, MPLIST_KEY (plist), value);
6106   ret = minput_config_variable (language, name, variable, pl);
6107   M17N_OBJECT_UNREF (pl);
6108   if (ret == 0)
6109     {
6110       im_info = get_im_info (language, name, Mnil, Mvariable);
6111       im_info->tick = 0;
6112     }
6113   return ret;
6114 }
6115
6116 /*=*/
6117
6118 /***en
6119     @brief Get information about input method commands.
6120
6121     The minput_get_commands () function returns information about
6122     input method commands of the input method specified by $LANGUAGE
6123     and $NAME.  An input method command is a pseudo key event to which
6124     one or more actual input key sequences are assigned.
6125
6126     There are two kinds of commands, global and local.  Global
6127     commands are used by multiple input methods for the same purpose,
6128     and have global key assignments.  Local commands are used only by
6129     a specific input method, and have only local key assignments.
6130
6131     Each input method may locally change key assignments for global
6132     commands.  The global key assignment for a global command is
6133     effective only when the current input method does not have local
6134     key assignments for that command.
6135
6136     If $NAME is #Mnil, information about global commands is returned.
6137     In this case $LANGUAGE is ignored.
6138
6139     If $NAME is not #Mnil, information about those commands that have
6140     local key assignments in the input method specified by $LANGUAGE
6141     and $NAME is returned.
6142
6143     @return
6144     If no input method commands are found, this function returns @c NULL.
6145
6146     Otherwise, a pointer to a plist is returned.  The key of each
6147     element in the plist is a symbol representing a command, and the
6148     value is a plist of the form COMMAND-INFO described below.
6149
6150     The first element of COMMAND-INFO has the key #Mtext, and the
6151     value is an M-text describing the command.
6152
6153     If there are no more elements, that means no key sequences are
6154     assigned to the command.  Otherwise, each of the remaining
6155     elements has the key #Mplist, and the value is a plist whose keys are
6156     #Msymbol and values are symbols representing input keys, which are
6157     currently assigned to the command.
6158
6159     As the returned plist is kept in the library, the caller must not
6160     modify nor free it.  */
6161 /***ja
6162     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
6163
6164     ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
6165     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
6166     ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
6167     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
6168
6169     ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
6170     ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
6171     ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
6172     ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
6173
6174     ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
6175     ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
6176     ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
6177     ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
6178
6179     $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
6180     ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
6181
6182     $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
6183     Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
6184     ¤òÊÖ¤¹¡£
6185
6186     @return
6187     ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
6188
6189     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
6190     ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
6191     ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
6192
6193     COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
6194     ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
6195     #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
6196     ¤¤¤³¤È¤Ë¤Ê¤ë¡£
6197
6198     ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
6199     ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
6200     ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
6201     ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
6202     ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
6203
6204     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
6205     ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
6206
6207 MPlist *
6208 minput_get_commands (MSymbol language, MSymbol name)
6209 {
6210   MInputMethodInfo *im_info;
6211   MPlist *cmds;
6212
6213   MINPUT__INIT ();
6214
6215   im_info = get_im_info (language, name, Mnil, Mcommand);
6216   if (! im_info || ! im_info->configured_vars)
6217     return NULL;
6218   M17N_OBJECT_UNREF (im_info->bc_cmds);
6219   im_info->bc_cmds = mplist ();
6220   MPLIST_DO (cmds, im_info->configured_cmds)
6221     {
6222       MPlist *plist = MPLIST_PLIST (cmds);
6223       MPlist *elt = mplist ();
6224
6225       mplist_push (im_info->bc_cmds, Mplist, elt);
6226       mplist_add (elt, MPLIST_SYMBOL (plist),
6227                   mplist_copy (MPLIST_NEXT (plist)));
6228       M17N_OBJECT_UNREF (elt);
6229     }
6230   return im_info->bc_cmds;
6231 }
6232
6233 /*=*/
6234
6235 /***en
6236     @brief Assign a key sequence to an input method command (obsolete).
6237
6238     This function is obsolete.  Use minput_config_command () instead.
6239
6240     The minput_assign_command_keys () function assigns input key
6241     sequence $KEYSEQ to input method command $COMMAND for the input
6242     method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
6243     key sequence is assigned globally no matter what $LANGUAGE is.
6244     Otherwise the key sequence is assigned locally.
6245
6246     Each element of $KEYSEQ must have the key $Msymbol and the value
6247     must be a symbol representing an input key.
6248
6249     $KEYSEQ may be @c NULL, in which case, all assignments are deleted
6250     globally or locally.
6251
6252     This assignment gets effective in a newly opened input method.
6253
6254     @return
6255     If the operation was successful, 0 is returned.  Otherwise -1 is
6256     returned, and #merror_code is set to @c MERROR_IM.  */
6257 /***ja
6258     @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
6259
6260     ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
6261     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
6262     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
6263     $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
6264     ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
6265
6266     $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
6267     ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
6268
6269     $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
6270     ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
6271
6272     ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
6273     ¸ú¤Ë¤Ê¤ë¡£
6274
6275     @return 
6276     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
6277     #merror_code ¤ò @c MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
6278
6279 int
6280 minput_assign_command_keys (MSymbol language, MSymbol name,
6281                             MSymbol command, MPlist *keyseq)
6282 {
6283   int ret;
6284
6285   MINPUT__INIT ();
6286
6287   if (command == Mnil)
6288     MERROR (MERROR_IM, -1);
6289   if (keyseq)
6290     {
6291       MPlist *plist;
6292
6293       if  (! check_command_keyseq (keyseq))
6294         MERROR (MERROR_IM, -1);
6295       plist = mplist ();
6296       mplist_add (plist, Mplist, keyseq);
6297       keyseq = plist;
6298     }  
6299   else
6300     keyseq = mplist ();
6301   ret = minput_config_command (language, name, command, keyseq);
6302   M17N_OBJECT_UNREF (keyseq);
6303   return ret;
6304 }
6305
6306 /*=*/
6307
6308 /***en
6309     @brief Call a callback function
6310
6311     The minput_callback () functions calls a callback function
6312     $COMMAND assigned for the input context $IC.  The caller must set
6313     specific elements in $IC->plist if the callback function requires.
6314
6315     @return
6316     If there exists a specified callback function, 0 is returned.
6317     Otherwise -1 is returned.  By side effects, $IC->plist may be
6318     modified.  */
6319
6320 int
6321 minput_callback (MInputContext *ic, MSymbol command)
6322 {
6323   MInputCallbackFunc func;
6324
6325   if (! ic->im->driver.callback_list)
6326     return -1;
6327   func = ((MInputCallbackFunc)
6328           mplist_get_func (ic->im->driver.callback_list, command));
6329   if (! func)
6330     return -1;
6331   (func) (ic, command);
6332   return 0;
6333 }
6334
6335 /*** @} */ 
6336 /*** @} */
6337 /*=*/
6338 /*** @addtogroup m17nDebug */
6339 /*=*/
6340 /*** @{  */
6341 /*=*/
6342
6343 /***en
6344     @brief Dump an input method.
6345
6346     The mdebug_dump_im () function prints the input method $IM in a
6347     human readable way to the stderr.  $INDENT specifies how many
6348     columns to indent the lines but the first one.
6349
6350     @return
6351     This function returns $IM.  */
6352 /***ja
6353     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
6354
6355     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
6356     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
6357
6358     @return
6359     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
6360
6361 MInputMethod *
6362 mdebug_dump_im (MInputMethod *im, int indent)
6363 {
6364   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
6365   char *prefix;
6366
6367   prefix = (char *) alloca (indent + 1);
6368   memset (prefix, 32, indent);
6369   prefix[indent] = '\0';
6370
6371   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
6372            msymbol_name (im->name));
6373   mdebug_dump_mtext (im_info->title, 0, 0);
6374   if (im->name != Mnil)
6375     {
6376       MPlist *state;
6377
6378       MPLIST_DO (state, im_info->states)
6379         {
6380           fprintf (stderr, "\n%s  ", prefix);
6381           dump_im_state (MPLIST_VAL (state), indent + 2);
6382         }
6383     }
6384   fprintf (stderr, ")");
6385   return im;
6386 }
6387
6388 /*** @} */ 
6389
6390 /*
6391   Local Variables:
6392   coding: euc-japan
6393   End:
6394 */