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