(moduledir): Use ${libdir} instead of ${exec_prefix}/lib.
[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
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   MPlist *candidate_list = ic->candidate_list;
3008   int candidate_index = ic->candidate_index;
3009   int candidate_show = ic->candidate_show;
3010   MTextProperty *prop;
3011
3012   MPLIST_DO (action_list, action_list)
3013     {
3014       MPlist *action = regularize_action (action_list, ic_info);
3015       MSymbol name;
3016       MPlist *args;
3017
3018       if (! action)
3019         continue;
3020       name = MPLIST_SYMBOL (action);
3021       args = MPLIST_NEXT (action);
3022
3023       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
3024       if (name == Minsert)
3025         {
3026           if (MPLIST_SYMBOL_P (args))
3027             {
3028               args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
3029               if (! MPLIST_MTEXT_P (args) && ! MPLIST_INTEGER_P (args))
3030                 continue;
3031             }
3032           if (MPLIST_MTEXT_P (args))
3033             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
3034           else                  /* MPLIST_INTEGER_P (args)) */
3035             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
3036         }
3037       else if (name == M_candidates)
3038         {
3039           MPlist *plist = get_candidate_list (ic_info, args);
3040           MPlist *pl;
3041           int len;
3042
3043           if (! plist)
3044             continue;
3045           if (MPLIST_PLIST_P (plist) && MPLIST_TAIL_P (plist))
3046             {
3047               M17N_OBJECT_UNREF (plist);
3048               continue;
3049             }
3050           if (MPLIST_MTEXT_P (plist))
3051             {
3052               preedit_insert (ic, ic->cursor_pos, NULL,
3053                               mtext_ref_char (MPLIST_MTEXT (plist), 0));
3054               len = 1;
3055             }
3056           else
3057             {
3058               MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
3059
3060               preedit_insert (ic, ic->cursor_pos, mt, 0);
3061               len = mtext_nchars (mt);
3062             }
3063           pl = mplist_copy (plist);
3064           M17N_OBJECT_UNREF (plist);
3065           mtext_put_prop (ic->preedit,
3066                           ic->cursor_pos - len, ic->cursor_pos,
3067                           Mcandidate_list, pl);
3068           M17N_OBJECT_UNREF (pl);
3069           mtext_put_prop (ic->preedit,
3070                           ic->cursor_pos - len, ic->cursor_pos,
3071                           Mcandidate_index, (void *) 0);
3072         }
3073       else if (name == Mselect)
3074         {
3075           int start, end;
3076           int code, idx, gindex;
3077           int pos = ic->cursor_pos;
3078           MPlist *group;
3079           int idx_decided = 0;
3080
3081           if (pos == 0
3082               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
3083                                                Mcandidate_list)))
3084             continue;
3085           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
3086           group = find_candidates_group (mtext_property_value (prop), idx,
3087                                          &start, &end, &gindex);
3088           if (MPLIST_SYMBOL_P (args))
3089             {
3090               code = marker_code (MPLIST_SYMBOL (args), 0);
3091               if (code < 0)
3092                 {
3093                   args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
3094                   if (! MPLIST_INTEGER_P (args))
3095                     continue;
3096                   idx = start + MPLIST_INTEGER (args);
3097                   if (idx < start || idx >= end)
3098                     continue;
3099                   idx_decided = 1;
3100                 }                 
3101             }
3102           else
3103             code = -1;
3104
3105           if (code != '[' && code != ']')
3106             {
3107               if (! idx_decided)
3108                 idx = (start
3109                        + (code >= 0
3110                           ? new_index (NULL, ic->candidate_index - start,
3111                                        end - start - 1, MPLIST_SYMBOL (args),
3112                                        NULL)
3113                           : MPLIST_INTEGER (args)));
3114               if (idx < 0)
3115                 {
3116                   find_candidates_group (mtext_property_value (prop), -1,
3117                                          NULL, &end, NULL);
3118                   idx = end - 1;
3119                 }
3120               else if (idx >= end
3121                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
3122                 idx = 0;
3123             }
3124           else
3125             {
3126               int ingroup_index = idx - start;
3127               int len;
3128
3129               group = mtext_property_value (prop);
3130               len = mplist_length (group);
3131               if (code == '[')
3132                 {
3133                   gindex--;
3134                   if (gindex < 0)
3135                     gindex = len - 1;;
3136                 }
3137               else
3138                 {
3139                   gindex++;
3140                   if (gindex >= len)
3141                     gindex = 0;
3142                 }
3143               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
3144                 idx += (MPLIST_MTEXT_P (group)
3145                         ? mtext_nchars (MPLIST_MTEXT (group))
3146                         : mplist_length (MPLIST_PLIST (group)));
3147               len = (MPLIST_MTEXT_P (group)
3148                      ? mtext_nchars (MPLIST_MTEXT (group))
3149                      : mplist_length (MPLIST_PLIST (group)));
3150               if (ingroup_index >= len)
3151                 ingroup_index = len - 1;
3152               idx += ingroup_index;
3153             }
3154           update_candidate (ic, prop, idx);
3155           MDEBUG_PRINT1 ("(%d)", idx);
3156         }
3157       else if (name == Mshow)
3158         ic->candidate_show = 1;
3159       else if (name == Mhide)
3160         ic->candidate_show = 0;
3161       else if (name == Mdelete)
3162         {
3163           int len = mtext_nchars (ic->preedit);
3164           int pos;
3165           int to;
3166
3167           if (MPLIST_SYMBOL_P (args)
3168               && surrounding_pos (MPLIST_SYMBOL (args), &pos))
3169             {
3170               to = ic->cursor_pos + pos;
3171               if (to < 0)
3172                 {
3173                   delete_surrounding_text (ic, to);
3174                   to = 0;
3175                 }
3176               else if (to > len)
3177                 {
3178                   delete_surrounding_text (ic, to - len);
3179                   to = len;
3180                 }
3181             }
3182           else
3183             {
3184               to = (MPLIST_SYMBOL_P (args)
3185                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
3186                                  ic->preedit)
3187                     : MPLIST_INTEGER (args));
3188               if (to < 0)
3189                 to = 0;
3190               else if (to > len)
3191                 to = len;
3192               pos = to - ic->cursor_pos;
3193             }
3194           MDEBUG_PRINT1 ("(%d)", pos);
3195           if (to < ic->cursor_pos)
3196             preedit_delete (ic, to, ic->cursor_pos);
3197           else if (to > ic->cursor_pos)
3198             preedit_delete (ic, ic->cursor_pos, to);
3199         }
3200       else if (name == Mmove)
3201         {
3202           int len = mtext_nchars (ic->preedit);
3203           int pos
3204             = (MPLIST_SYMBOL_P (args)
3205                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
3206                             ic->preedit)
3207                : MPLIST_INTEGER (args));
3208
3209           if (pos < 0)
3210             pos = 0;
3211           else if (pos > len)
3212             pos = len;
3213           if (pos != ic->cursor_pos)
3214             {
3215               ic->cursor_pos = pos;
3216               ic->preedit_changed = 1;
3217             }
3218           MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
3219         }
3220       else if (name == Mmark)
3221         {
3222           int code = marker_code (MPLIST_SYMBOL (args), 0);
3223
3224           if (code < 0)
3225             {
3226               mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
3227                           (void *) ic->cursor_pos);
3228               MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
3229             }
3230         }
3231       else if (name == Mpushback)
3232         {
3233           if (MPLIST_INTEGER_P (args) || MPLIST_SYMBOL_P (args))
3234             {
3235               int num;
3236
3237               if (MPLIST_SYMBOL_P (args))
3238                 {
3239                   args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
3240                   if (MPLIST_INTEGER_P (args))
3241                     num = MPLIST_INTEGER (args);
3242                   else
3243                     num = 0;
3244                 }
3245               else
3246                 num = MPLIST_INTEGER (args);
3247
3248               if (num > 0)
3249                 ic_info->key_head -= num;
3250               else if (num == 0)
3251                 ic_info->key_head = 0;
3252               else
3253                 ic_info->key_head = - num;
3254               if (ic_info->key_head > ic_info->used)
3255                 ic_info->key_head = ic_info->used;
3256             }
3257           else if (MPLIST_MTEXT_P (args))
3258             {
3259               MText *mt = MPLIST_MTEXT (args);
3260               int i, len = mtext_nchars (mt);
3261               MSymbol key;
3262
3263               ic_info->key_head--;
3264               for (i = 0; i < len; i++)
3265                 {
3266                   key = one_char_symbol[MTEXT_DATA (mt)[i]];
3267                   if (ic_info->key_head + i < ic_info->used)
3268                     ic_info->keys[ic_info->key_head + i] = key;
3269                   else
3270                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3271                 }
3272             }
3273           else
3274             {
3275               MPlist *plist = MPLIST_PLIST (args), *pl;
3276               int i = 0;
3277               MSymbol key;
3278
3279               ic_info->key_head--;
3280
3281               MPLIST_DO (pl, plist)
3282                 {
3283                   key = MPLIST_SYMBOL (pl);
3284                   if (ic_info->key_head < ic_info->used)
3285                     ic_info->keys[ic_info->key_head + i] = key;
3286                   else
3287                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3288                   i++;
3289                 }
3290             }
3291         }
3292       else if (name == Mpop)
3293         {
3294           if (ic_info->key_head < ic_info->used)
3295             MLIST_DELETE1 (ic_info, keys, ic_info->key_head, 1);
3296         }
3297       else if (name == Mcall)
3298         {
3299           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3300           MIMExternalFunc func = NULL;
3301           MSymbol module, func_name;
3302           MPlist *func_args, *val;
3303           int ret = 0;
3304
3305           module = MPLIST_SYMBOL (args);
3306           args = MPLIST_NEXT (args);
3307           func_name = MPLIST_SYMBOL (args);
3308
3309           if (im_info->externals)
3310             {
3311               MIMExternalModule *external
3312                 = (MIMExternalModule *) mplist_get (im_info->externals,
3313                                                     module);
3314               if (external)
3315                 func = ((MIMExternalFunc)
3316                         mplist_get_func (external->func_list, func_name));
3317             }
3318           if (! func)
3319             continue;
3320           func_args = mplist ();
3321           mplist_add (func_args, Mt, ic);
3322           MPLIST_DO (args, MPLIST_NEXT (args))
3323             {
3324               int code;
3325
3326               if (MPLIST_KEY (args) == Msymbol
3327                   && MPLIST_KEY (args) != Mnil
3328                   && (code = marker_code (MPLIST_SYMBOL (args), 0)) >= 0)
3329                 {
3330                   code = new_index (ic, ic->cursor_pos, 
3331                                     mtext_nchars (ic->preedit),
3332                                     MPLIST_SYMBOL (args), ic->preedit);
3333                   mplist_add (func_args, Minteger, (void *) code);
3334                 }
3335               else
3336                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
3337             }
3338           val = (func) (func_args);
3339           M17N_OBJECT_UNREF (func_args);
3340           if (val && ! MPLIST_TAIL_P (val))
3341             ret = take_action_list (ic, val);
3342           M17N_OBJECT_UNREF (val);
3343           if (ret < 0)
3344             return ret;
3345         }
3346       else if (name == Mshift)
3347         {
3348           shift_state (ic, MPLIST_SYMBOL (args));
3349         }
3350       else if (name == Mundo)
3351         {
3352           int intarg = (MPLIST_TAIL_P (args)
3353                         ? ic_info->used - 2
3354                         : integer_value (ic, args, 0));
3355
3356           mtext_reset (ic->preedit);
3357           mtext_reset (ic_info->preedit_saved);
3358           mtext_reset (ic->produced);
3359           M17N_OBJECT_UNREF (ic_info->vars);
3360           ic_info->vars = mplist_copy (ic_info->vars_saved);
3361           ic->cursor_pos = ic_info->state_pos = 0;
3362           ic_info->state_key_head = ic_info->key_head
3363             = ic_info->commit_key_head = 0;
3364
3365           shift_state (ic, Mnil);
3366           if (intarg < 0)
3367             {
3368               if (MPLIST_TAIL_P (args))
3369                 {
3370                   ic_info->used = 0;
3371                   return -1;
3372                 }
3373               ic_info->used += intarg;
3374             }
3375           else
3376             ic_info->used = intarg;
3377           break;
3378         }
3379       else if (name == Mset || name == Madd || name == Msub
3380                || name == Mmul || name == Mdiv)
3381         {
3382           MSymbol sym = MPLIST_SYMBOL (args);
3383           MPlist *value = resolve_variable (ic_info, sym);
3384           int val1, val2;
3385           char *op;
3386
3387           val1 = MPLIST_INTEGER (value);
3388           args = MPLIST_NEXT (args);
3389           val2 = resolve_expression (ic, args);
3390           if (name == Mset)
3391             val1 = val2, op = "=";
3392           else if (name == Madd)
3393             val1 += val2, op = "+=";
3394           else if (name == Msub)
3395             val1 -= val2, op = "-=";
3396           else if (name == Mmul)
3397             val1 *= val2, op = "*=";
3398           else
3399             val1 /= val2, op = "/=";
3400           MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
3401                          MSYMBOL_NAME (sym), op, val1, val1);
3402           mplist_set (value, Minteger, (void *) val1);
3403         }
3404       else if (name == Mequal || name == Mless || name == Mgreater
3405                || name == Mless_equal || name == Mgreater_equal)
3406         {
3407           int val1, val2;
3408           MPlist *actions1, *actions2;
3409           int ret = 0;
3410
3411           val1 = resolve_expression (ic, args);
3412           args = MPLIST_NEXT (args);
3413           val2 = resolve_expression (ic, args);
3414           args = MPLIST_NEXT (args);
3415           actions1 = MPLIST_PLIST (args);
3416           args = MPLIST_NEXT (args);
3417           if (MPLIST_TAIL_P (args))
3418             actions2 = NULL;
3419           else
3420             actions2 = MPLIST_PLIST (args);
3421           MDEBUG_PRINT3 ("(%d %s %d)? ", val1, MSYMBOL_NAME (name), val2);
3422           if (name == Mequal ? val1 == val2
3423               : name == Mless ? val1 < val2
3424               : name == Mgreater ? val1 > val2
3425               : name == Mless_equal ? val1 <= val2
3426               : val1 >= val2)
3427             {
3428               MDEBUG_PRINT ("ok");
3429               ret = take_action_list (ic, actions1);
3430             }
3431           else
3432             {
3433               MDEBUG_PRINT ("no");
3434               if (actions2)
3435                 ret = take_action_list (ic, actions2);
3436             }
3437           if (ret < 0)
3438             return ret;
3439         }
3440       else if (name == Mcond)
3441         {
3442           int idx = 0;
3443
3444           MPLIST_DO (args, args)
3445             {
3446               MPlist *cond;
3447
3448               idx++;
3449               if (! MPLIST_PLIST (args))
3450                 continue;
3451               cond = MPLIST_PLIST (args);
3452               if (resolve_expression (ic, cond) != 0)
3453                 {
3454                   MDEBUG_PRINT1 ("(%dth)", idx);
3455                   if (take_action_list (ic, MPLIST_NEXT (cond)) < 0)
3456                     return -1;;
3457                   break;
3458                 }
3459             }
3460         }
3461       else if (name == Mcommit)
3462         {
3463           preedit_commit (ic, 0);
3464         }
3465       else if (name == Munhandle)
3466         {
3467           preedit_commit (ic, 0);
3468           return -1;
3469         }
3470       else
3471         {
3472           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3473           MPlist *actions;
3474
3475           if (im_info->macros
3476               && (actions = mplist_get (im_info->macros, name)))
3477             {
3478               if (take_action_list (ic, actions) < 0)
3479                 return -1;
3480             };
3481         }
3482     }
3483
3484   if (ic->candidate_list)
3485     {
3486       M17N_OBJECT_UNREF (ic->candidate_list);
3487       ic->candidate_list = NULL;
3488     }
3489   if (ic->cursor_pos > 0
3490       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
3491                                      Mcandidate_list)))
3492     {
3493       ic->candidate_list = mtext_property_value (prop);
3494       M17N_OBJECT_REF (ic->candidate_list);
3495       ic->candidate_index
3496         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
3497                                 Mcandidate_index);
3498       ic->candidate_from = mtext_property_start (prop);
3499       ic->candidate_to = mtext_property_end (prop);
3500     }
3501
3502   if (candidate_list != ic->candidate_list)
3503     ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3504   if (candidate_index != ic->candidate_index)
3505     ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3506   if (candidate_show != ic->candidate_show)
3507     ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
3508   return 0;
3509 }
3510
3511
3512 /* Handle the input key KEY in the current state and map specified in
3513    the input context IC.  If KEY is handled correctly, return 0.
3514    Otherwise, return -1.  */
3515
3516 static int
3517 handle_key (MInputContext *ic)
3518 {
3519   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3520   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3521   MIMMap *map = ic_info->map;
3522   MIMMap *submap = NULL;
3523   MSymbol key = ic_info->keys[ic_info->key_head];
3524   MSymbol alias = Mnil;
3525   int i;
3526
3527   if (ic_info->state_hook)
3528     {
3529       MDEBUG_PRINT1 ("  [IM] [%s] init-actions:",
3530                      MSYMBOL_NAME (ic_info->state->name));
3531       take_action_list (ic, ic_info->state_hook);
3532       ic_info->state_hook = NULL;
3533     }
3534
3535   MDEBUG_PRINT2 ("  [IM] [%s] handle `%s'", 
3536                  MSYMBOL_NAME (ic_info->state->name), msymbol_name (key));
3537
3538   if (map->submaps)
3539     {
3540       submap = mplist_get (map->submaps, key);
3541       alias = key;
3542       while (! submap
3543              && (alias = msymbol_get (alias, M_key_alias))
3544              && alias != key)
3545         submap = mplist_get (map->submaps, alias);
3546     }
3547
3548   if (submap)
3549     {
3550       if (! alias || alias == key)
3551         MDEBUG_PRINT (" submap-found");
3552       else
3553         MDEBUG_PRINT1 (" submap-found (by alias `%s')", MSYMBOL_NAME (alias));
3554       mtext_cpy (ic->preedit, ic_info->preedit_saved);
3555       ic->preedit_changed = 1;
3556       ic->cursor_pos = ic_info->state_pos;
3557       ic_info->key_head++;
3558       ic_info->map = map = submap;
3559       if (map->map_actions)
3560         {
3561           MDEBUG_PRINT (" map-actions:");
3562           if (take_action_list (ic, map->map_actions) < 0)
3563             {
3564               MDEBUG_PRINT ("\n");
3565               return -1;
3566             }
3567         }
3568       else if (map->submaps)
3569         {
3570           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
3571             {
3572               MSymbol key = ic_info->keys[i];
3573               char *name = msymbol_name (key);
3574
3575               if (! name[0] || ! name[1])
3576                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
3577             }
3578         }
3579
3580       /* If this is the terminal map or we have shifted to another
3581          state, perform branch actions (if any).  */
3582       if (! map->submaps || map != ic_info->map)
3583         {
3584           if (map->branch_actions)
3585             {
3586               MDEBUG_PRINT (" branch-actions:");
3587               if (take_action_list (ic, map->branch_actions) < 0)
3588                 {
3589                   MDEBUG_PRINT ("\n");
3590                   return -1;
3591                 }
3592             }
3593           /* If MAP is still not the root map, shift to the current
3594              state.  */
3595           if (ic_info->map != ic_info->state->map)
3596             shift_state (ic, ic_info->state->name);
3597         }
3598     }
3599   else
3600     {
3601       /* MAP can not handle KEY.  */
3602
3603       /* Perform branch actions if any.  */
3604       if (map->branch_actions)
3605         {
3606           MDEBUG_PRINT (" branch-actions:");
3607           if (take_action_list (ic, map->branch_actions) < 0)
3608             {
3609               MDEBUG_PRINT ("\n");
3610               return -1;
3611             }
3612         }
3613
3614       if (map == ic_info->map)
3615         {
3616           /* The above branch actions didn't change the state.  */
3617
3618           /* If MAP is the root map of the initial state, and there
3619              still exist an unhandled key, it means that the current
3620              input method can not handle it.  */
3621           if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map
3622               && ic_info->key_head < ic_info->used)
3623             {
3624               MDEBUG_PRINT (" unhandled\n");
3625               ic_info->state_hook = map->map_actions;
3626               return -1;
3627             }
3628
3629           if (map != ic_info->state->map)
3630             {
3631               /* MAP is not the root map.  Shift to the root map of the
3632                  current state. */
3633               shift_state (ic, ic_info->state->name);
3634             }
3635           else if (! map->branch_actions)
3636             {
3637               /* MAP is the root map without any default branch
3638                  actions.  Shift to the initial state.  */
3639               shift_state (ic, Mnil);
3640             }
3641         }
3642     }
3643   MDEBUG_PRINT ("\n");
3644   return 0;
3645 }
3646
3647 /* Initialize IC->ic_info.  */
3648
3649 static void
3650 init_ic_info (MInputContext *ic)
3651 {
3652   MInputMethodInfo *im_info = ic->im->info;
3653   MInputContextInfo *ic_info = ic->info;
3654   MPlist *plist;
3655   
3656   MLIST_INIT1 (ic_info, keys, 8);;
3657
3658   ic_info->markers = mplist ();
3659
3660   ic_info->vars = mplist ();
3661   if (im_info->configured_vars)
3662     MPLIST_DO (plist, im_info->configured_vars)
3663       {
3664         MPlist *pl = MPLIST_PLIST (plist);
3665         MSymbol name = MPLIST_SYMBOL (pl);
3666
3667         pl = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (pl)));
3668         if (MPLIST_KEY (pl) != Mt)
3669           {
3670             MPlist *p = mplist ();
3671
3672             mplist_push (ic_info->vars, Mplist, p);
3673             M17N_OBJECT_UNREF (p);
3674             mplist_add (p, Msymbol, name);
3675             mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
3676           }
3677       }
3678   ic_info->vars_saved = mplist_copy (ic_info->vars);
3679
3680   if (im_info->externals)
3681     {
3682       MPlist *func_args = mplist (), *plist;
3683
3684       mplist_add (func_args, Mt, ic);
3685       MPLIST_DO (plist, im_info->externals)
3686         {
3687           MIMExternalModule *external = MPLIST_VAL (plist);
3688           MIMExternalFunc func
3689             = (MIMExternalFunc) mplist_get_func (external->func_list, Minit);
3690
3691           if (func)
3692             (func) (func_args);
3693         }
3694       M17N_OBJECT_UNREF (func_args);
3695     }
3696
3697   ic_info->preedit_saved = mtext ();
3698   ic_info->tick = im_info->tick;
3699 }
3700
3701 /* Finalize IC->ic_info.  */
3702
3703 static void
3704 fini_ic_info (MInputContext *ic)
3705 {
3706   MInputMethodInfo *im_info = ic->im->info;
3707   MInputContextInfo *ic_info = ic->info;
3708
3709   if (im_info->externals)
3710     {
3711       MPlist *func_args = mplist (), *plist;
3712
3713       mplist_add (func_args, Mt, ic);
3714       MPLIST_DO (plist, im_info->externals)
3715         {
3716           MIMExternalModule *external = MPLIST_VAL (plist);
3717           MIMExternalFunc func
3718             = (MIMExternalFunc) mplist_get_func (external->func_list, Mfini);
3719
3720           if (func)
3721             (func) (func_args);
3722         }
3723       M17N_OBJECT_UNREF (func_args);
3724     }
3725
3726   MLIST_FREE1 (ic_info, keys);
3727   M17N_OBJECT_UNREF (ic_info->preedit_saved);
3728   M17N_OBJECT_UNREF (ic_info->markers);
3729   M17N_OBJECT_UNREF (ic_info->vars);
3730   M17N_OBJECT_UNREF (ic_info->vars_saved);
3731   M17N_OBJECT_UNREF (ic_info->preceding_text);
3732   M17N_OBJECT_UNREF (ic_info->following_text);
3733
3734   memset (ic_info, 0, sizeof (MInputContextInfo));
3735 }
3736
3737 static void
3738 re_init_ic (MInputContext *ic, int reload)
3739 {
3740   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3741   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3742   int status_changed, preedit_changed, cursor_pos_changed, candidates_changed;
3743
3744   status_changed = ic_info->state != (MIMState *) MPLIST_VAL (im_info->states);
3745   preedit_changed = mtext_nchars (ic->preedit) > 0;
3746   cursor_pos_changed = ic->cursor_pos > 0;
3747   candidates_changed = 0;
3748   if (ic->candidate_list)
3749     {
3750       candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
3751       M17N_OBJECT_UNREF (ic->candidate_list);
3752       ic->candidate_list = NULL;
3753     }
3754   if (ic->candidate_show)
3755     {
3756       candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
3757       ic->candidate_show = 0;
3758     }
3759   if (ic->candidate_index > 0)
3760     {
3761       candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
3762       ic->candidate_index = 0;
3763       ic->candidate_from = ic->candidate_to = 0;
3764     }
3765   if (mtext_nchars (ic->produced) > 0)
3766     mtext_reset (ic->produced);
3767   if (mtext_nchars (ic->preedit) > 0)
3768     mtext_reset (ic->preedit);
3769   ic->cursor_pos = 0;
3770   M17N_OBJECT_UNREF (ic->plist);
3771   ic->plist = mplist ();
3772
3773   fini_ic_info (ic);
3774   if (reload)
3775     reload_im_info (im_info);
3776   if (! im_info->states)
3777     {
3778       struct MIMState *state;
3779
3780       M17N_OBJECT (state, free_state, MERROR_IM);
3781       state->name = msymbol ("init");
3782       state->title = mtext__from_data ("ERROR!", 6, MTEXT_FORMAT_US_ASCII, 0);
3783       MSTRUCT_CALLOC (state->map, MERROR_IM);
3784       im_info->states = mplist ();
3785       mplist_add (im_info->states, state->name, state);
3786     }
3787   init_ic_info (ic);
3788   shift_state (ic, Mnil);
3789
3790   ic->status_changed = status_changed;
3791   ic->preedit_changed = preedit_changed;
3792   ic->cursor_pos_changed = cursor_pos_changed;
3793   ic->candidates_changed = candidates_changed;
3794 }
3795
3796 static void
3797 reset_ic (MInputContext *ic, MSymbol ignore)
3798 {
3799   MDEBUG_PRINT ("\n  [IM] reset\n");
3800   re_init_ic (ic, 0);
3801 }
3802
3803 static int
3804 open_im (MInputMethod *im)
3805 {
3806   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
3807
3808   if (! im_info || ! im_info->states || MPLIST_LENGTH (im_info->states) == 0)
3809     MERROR (MERROR_IM, -1);
3810   im->info = im_info;
3811
3812   return 0;
3813 }
3814
3815 static void
3816 close_im (MInputMethod *im)
3817 {
3818   im->info = NULL;
3819 }
3820
3821 static int
3822 create_ic (MInputContext *ic)
3823 {
3824   MInputContextInfo *ic_info;
3825
3826   MSTRUCT_CALLOC (ic_info, MERROR_IM);
3827   ic->info = ic_info;
3828   init_ic_info (ic);
3829   shift_state (ic, Mnil);
3830   return 0;
3831 }
3832
3833 static void
3834 destroy_ic (MInputContext *ic)
3835 {
3836   fini_ic_info (ic);
3837   free (ic->info);
3838 }
3839
3840 static int
3841 check_reload (MInputContext *ic, MSymbol key)
3842 {
3843   MInputMethodInfo *im_info = ic->im->info;
3844   MPlist *plist = resolve_command (im_info->configured_cmds, Mat_reload);
3845
3846   if (! plist)
3847     {
3848       plist = resolve_command (global_info->configured_cmds, Mat_reload);
3849       if (! plist)
3850         return 0;
3851     }
3852   MPLIST_DO (plist, plist)
3853     {
3854       MSymbol this_key, alias;
3855
3856       if (MPLIST_MTEXT_P (plist))
3857         {
3858           MText *mt = MPLIST_MTEXT (plist);
3859           int c = mtext_ref_char (mt, 0);
3860
3861           if (c >= 256)
3862             continue;
3863           this_key = one_char_symbol[c];
3864         }
3865       else
3866         {
3867           MPlist *pl = MPLIST_PLIST (plist);
3868       
3869           this_key = MPLIST_SYMBOL (pl);
3870         }
3871       alias = this_key;
3872       while (alias != key 
3873              && (alias = msymbol_get (alias, M_key_alias))
3874              && alias != this_key);
3875       if (alias == key)
3876         break;
3877     }
3878   if (MPLIST_TAIL_P (plist))
3879     return 0;
3880
3881   MDEBUG_PRINT ("\n  [IM] reload");
3882   re_init_ic (ic, 1);
3883   return 1;
3884 }
3885
3886
3887 /** Handle the input key KEY in the current state and map of IC->info.
3888     If KEY is handled but no text is produced, return 0, otherwise
3889     return 1.
3890
3891     Ignore ARG.  */
3892
3893 static int
3894 filter (MInputContext *ic, MSymbol key, void *arg)
3895 {
3896   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
3897   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
3898   int i = 0;
3899
3900   if (check_reload (ic, key))
3901     return 0;
3902
3903   if (! ic_info->state)
3904     {
3905       ic_info->key_unhandled = 1;
3906       return 0;
3907     }
3908   mtext_reset (ic->produced);
3909   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
3910   M17N_OBJECT_UNREF (ic_info->preceding_text);
3911   M17N_OBJECT_UNREF (ic_info->following_text);
3912   ic_info->preceding_text = ic_info->following_text = NULL;
3913   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
3914   ic_info->key_unhandled = 0;
3915
3916   do {
3917     if (handle_key (ic) < 0)
3918       {
3919         /* KEY was not handled.  Delete it from the current key sequence.  */
3920         if (ic_info->used > 0)
3921           {
3922             memmove (ic_info->keys, ic_info->keys + 1,
3923                      sizeof (int) * (ic_info->used - 1));
3924             ic_info->used--;
3925             if (ic_info->state_key_head > 0)
3926               ic_info->state_key_head--;
3927             if (ic_info->commit_key_head > 0)
3928               ic_info->commit_key_head--;             
3929           }
3930         /* This forces returning 1.  */
3931         ic_info->key_unhandled = 1;
3932         break;
3933       }
3934     if (i++ == 100)
3935       {
3936         mdebug_hook ();
3937         reset_ic (ic, Mnil);
3938         ic_info->key_unhandled = 1;
3939         break;
3940       }
3941     /* Break the loop if all keys were handled.  */
3942   } while (ic_info->key_head < ic_info->used);
3943
3944   /* If the current map is the root of the initial state, we should
3945      produce any preedit text in ic->produced.  */
3946   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
3947     preedit_commit (ic, 1);
3948
3949   if (mtext_nchars (ic->produced) > 0)
3950     {
3951       if (MDEBUG_FLAG ())
3952         {
3953           MDEBUG_PRINT1 ("\n  [IM] [%s] (produced",
3954                          MSYMBOL_NAME (ic_info->state->name));
3955           for (i = 0; i < mtext_nchars (ic->produced); i++)
3956             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
3957           MDEBUG_PRINT (")");
3958         }
3959
3960       mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
3961                       Mlanguage, ic->im->language);
3962     }
3963   if (ic_info->commit_key_head > 0)
3964     {
3965       memmove (ic_info->keys, ic_info->keys + ic_info->commit_key_head,
3966                sizeof (int) * (ic_info->used - ic_info->commit_key_head));
3967       ic_info->used -= ic_info->commit_key_head;
3968       ic_info->key_head -= ic_info->commit_key_head;
3969       ic_info->state_key_head -= ic_info->commit_key_head;
3970       ic_info->commit_key_head = 0;
3971     }
3972   if (ic_info->key_unhandled)
3973     {
3974       ic_info->used = 0;
3975       ic_info->key_head = ic_info->state_key_head
3976         = ic_info->commit_key_head = 0;
3977     }
3978
3979   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
3980 }
3981
3982
3983 /** Return 1 if the last event or key was not handled, otherwise
3984     return 0.
3985
3986     There is no need of looking up because ic->produced should already
3987     contain the produced text (if any).
3988
3989     Ignore KEY.  */
3990
3991 static int
3992 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
3993 {
3994   mtext_cat (mt, ic->produced);
3995   mtext_reset (ic->produced);
3996   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
3997 }
3998
3999 \f
4000 /* Input method command handler.  */
4001
4002 /* List of all (global and local) commands. 
4003    (LANG:(IM-NAME:(COMMAND ...) ...) ...) ...
4004    COMMAND is CMD-NAME:(mtext:DESCRIPTION plist:KEYSEQ ...))
4005    Global commands are stored as (t (t COMMAND ...))  */
4006
4007 \f
4008 /* Input method variable handler.  */
4009
4010
4011 /* Support functions for mdebug_dump_im.  */
4012
4013 static void
4014 dump_im_map (MPlist *map_list, int indent)
4015 {
4016   char *prefix;
4017   MSymbol key = MPLIST_KEY (map_list);
4018   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
4019
4020   prefix = (char *) alloca (indent + 1);
4021   memset (prefix, 32, indent);
4022   prefix[indent] = '\0';
4023
4024   fprintf (mdebug__output, "(\"%s\" ", msymbol_name (key));
4025   if (map->map_actions)
4026     mdebug_dump_plist (map->map_actions, indent + 2);
4027   if (map->submaps)
4028     {
4029       MPLIST_DO (map_list, map->submaps)
4030         {
4031           fprintf (mdebug__output, "\n%s  ", prefix);
4032           dump_im_map (map_list, indent + 2);
4033         }
4034     }
4035   if (map->branch_actions)
4036     {
4037       fprintf (mdebug__output, "\n%s  (branch\n%s    ", prefix, prefix);
4038       mdebug_dump_plist (map->branch_actions, indent + 4);
4039       fprintf (mdebug__output, ")");      
4040     }
4041   fprintf (mdebug__output, ")");
4042 }
4043
4044
4045 static void
4046 dump_im_state (MIMState *state, int indent)
4047 {
4048   char *prefix;
4049   MPlist *map_list;
4050
4051   prefix = (char *) alloca (indent + 1);
4052   memset (prefix, 32, indent);
4053   prefix[indent] = '\0';
4054
4055   fprintf (mdebug__output, "(%s", msymbol_name (state->name));
4056   if (state->map->submaps)
4057     {
4058       MPLIST_DO (map_list, state->map->submaps)
4059         {
4060           fprintf (mdebug__output, "\n%s  ", prefix);
4061           dump_im_map (map_list, indent + 2);
4062         }
4063     }
4064   fprintf (mdebug__output, ")");
4065 }
4066
4067 \f
4068
4069 int
4070 minput__init ()
4071 {
4072   Minput_driver = msymbol ("input-driver");
4073
4074   Minput_preedit_start = msymbol ("input-preedit-start");
4075   Minput_preedit_done = msymbol ("input-preedit-done");
4076   Minput_preedit_draw = msymbol ("input-preedit-draw");
4077   Minput_status_start = msymbol ("input-status-start");
4078   Minput_status_done = msymbol ("input-status-done");
4079   Minput_status_draw = msymbol ("input-status-draw");
4080   Minput_candidates_start = msymbol ("input-candidates-start");
4081   Minput_candidates_done = msymbol ("input-candidates-done");
4082   Minput_candidates_draw = msymbol ("input-candidates-draw");
4083   Minput_set_spot = msymbol ("input-set-spot");
4084   Minput_focus_move = msymbol ("input-focus-move");
4085   Minput_focus_in = msymbol ("input-focus-in");
4086   Minput_focus_out = msymbol ("input-focus-out");
4087   Minput_toggle = msymbol ("input-toggle");
4088   Minput_reset = msymbol ("input-reset");
4089   Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
4090   Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
4091   Mcustomized = msymbol ("customized");
4092   Mconfigured = msymbol ("configured");
4093   Minherited = msymbol ("inherited");
4094
4095   minput_default_driver.open_im = open_im;
4096   minput_default_driver.close_im = close_im;
4097   minput_default_driver.create_ic = create_ic;
4098   minput_default_driver.destroy_ic = destroy_ic;
4099   minput_default_driver.filter = filter;
4100   minput_default_driver.lookup = lookup;
4101   minput_default_driver.callback_list = mplist ();
4102   mplist_put_func (minput_default_driver.callback_list, Minput_reset,
4103                    M17N_FUNC (reset_ic));
4104   minput_driver = &minput_default_driver;
4105
4106   fully_initialized = 0;
4107   return 0;
4108 }
4109
4110 void
4111 minput__fini ()
4112 {
4113   if (fully_initialized)
4114     {
4115       free_im_list (im_info_list);
4116       if (im_custom_list)
4117         free_im_list (im_custom_list);
4118       if (im_config_list)
4119         free_im_list (im_config_list);
4120       M17N_OBJECT_UNREF (load_im_info_keys);
4121     }
4122
4123   M17N_OBJECT_UNREF (minput_default_driver.callback_list);
4124   M17N_OBJECT_UNREF (minput_driver->callback_list);
4125
4126 }
4127
4128 MSymbol
4129 minput__char_to_key (int c)
4130 {
4131   if (c < 0 || c >= 0x100)
4132     return Mnil;
4133
4134   return one_char_symbol[c];
4135 }
4136
4137 /*** @} */
4138 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
4139
4140 \f
4141 /* External API */
4142
4143 /*** @addtogroup m17nInputMethod */
4144 /*** @{ */
4145 /*=*/
4146
4147 /***en
4148     @brief Symbol whose name is "input-method".
4149  */
4150 /***ja
4151     @brief "input-method" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
4152  */
4153 MSymbol Minput_method;
4154
4155 /***en
4156     @name Variables: Predefined symbols for callback commands.  */
4157 /***ja
4158     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.  */
4159 /*** @{ */ 
4160 /***en
4161     These are the predefined symbols that are used as the @c COMMAND
4162     argument of callback functions of an input method driver (see
4163     #MInputDriver::callback_list).  
4164
4165     Most of them do not require extra argument nor return any value;
4166     exceptions are these:
4167
4168     @b Minput_get_surrounding_text: When a callback function assigned for
4169     this command is called, the first element of #MInputContext::plist
4170     has key #Minteger and the value specifies which portion of the
4171     surrounding text should be retrieved.  If the value is positive,
4172     it specifies the number of characters following the current cursor
4173     position.  If the value is negative, the absolute value specifies
4174     the number of characters preceding the current cursor position.
4175     If the value is zero, it means that the caller just wants to know
4176     if the surrounding text is currently supported or not.
4177
4178     If the surrounding text is currently supported, the callback
4179     function must set the key of this element to #Mtext and the value
4180     to the retrieved M-text.  The length of the M-text may be shorter
4181     than the requested number of characters, if the available text is
4182     not that long.  The length can be zero in the worst case.  Or, the
4183     length may be longer if an application thinks it is more efficient
4184     to return that length.
4185
4186     If the surrounding text is not currently supported, the callback
4187     function should return without changing the first element of
4188     #MInputContext::plist.
4189
4190     @b Minput_delete_surrounding_text: When a callback function assigned
4191     for this command is called, the first element of
4192     #MInputContext::plist has key #Minteger and the value specifies
4193     which portion of the surrounding text should be deleted in the
4194     same way as the case of Minput_get_surrounding_text.  The callback
4195     function must delete the specified text.  It should not alter
4196     #MInputContext::plist.  */ 
4197 /***ja
4198     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND 
4199     °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
4200
4201     ¤Û¤È¤ó¤É¤ÏÄɲäΰú¿ô¤òɬÍפȤ·¤Ê¤¤¤·ÃͤòÊÖ¤µ¤Ê¤¤¤¬¡¢°Ê²¼¤ÏÎã³°¤Ç¤¢¤ë¡£
4202
4203     Minput_get_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë¥Ð¥Ã
4204     ¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢ #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϥ­¡¼¤È¤·
4205     ¤Æ#Minteger ¤ò¤È¤ê¡¢¤½¤ÎÃͤϥµ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤Î¤¦¤Á¤É¤ÎÉôʬ
4206     ¤ò¼è¤Ã¤ÆÍè¤ë¤«¤ò»ØÄꤹ¤ë¡£Ãͤ¬Àµ¤Ç¤¢¤ì¤Ð¡¢¸½ºß¤Î¥«¡¼¥½¥ë°ÌÃ֤˳¤¯
4207     ÃͤθĿôʬ¤Îʸ»ú¤ò¼è¤ë¡£Éé¤Ç¤¢¤ì¤Ð¡¢¥«¡¼¥½¥ë°ÌÃÖ¤ËÀè¹Ô¤¹¤ëÃͤÎÀäÂÐ
4208     ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£¸½ºß¥µ¥é¥¦¥ó¥É¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦
4209     ¤«¤òÃΤꤿ¤¤¤À¤±¤Ç¤¢¤ì¤Ð¡¢¤³¤ÎÃͤϥ¼¥í¤Ç¤âÎɤ¤¡£
4210
4211     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ï
4212     ¤³¤ÎÍ×ÁǤΥ­¡¼¤ò #Mtext ¤Ë¡¢Ãͤò¼è¤ê¹þ¤ó¤ÀM-text ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê
4213     ¤é¤Ê¤¤¡£¤â¤·¥Æ¥­¥¹¥È¤ÎŤµ¤¬½¼Ê¬¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î M-text ¤ÎŤµ¤ÏÍ×
4214     µá¤µ¤ì¤Æ¤¤¤ëʸ»ú¿ô¤è¤êû¤¯¤ÆÎɤ¤¡£ºÇ°­¤Î¾ì¹ç 0 ¤Ç¤â¤è¤¤¤·¡¢¥¢¥×¥ê¥±¡¼
4215     ¥·¥ç¥ó¦¤ÇɬÍפǸúΨŪ¤À¤È»×¤¨¤ÐŤ¯¤Æ¤âÎɤ¤¡£
4216
4217     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
4218     ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4219
4220     Minput_delete_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë
4221     ¥Ð¥Ã¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢#MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϡ¢¥­¡¼
4222     ¤È¤·¤Æ#Minteger ¤ò¤È¤ê¡¢ÃͤϺï½ü¤¹¤ë¤Ù¤­¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤ò
4223     Minput_get_surrounding_text ¤ÈƱÍͤΤä¤êÊý¤Ç»ØÄꤹ¤ë¡£¥³¡¼¥ë¥Ð¥Ã¥¯
4224     ´Ø¿ô¤Ï»ØÄꤵ¤ì¤¿¥Æ¥­¥¹¥È¤òºï½ü¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤Þ¤¿
4225     #MInputContext::plist ¤òÊѤ¨¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */ 
4226 MSymbol Minput_preedit_start;
4227 MSymbol Minput_preedit_done;
4228 MSymbol Minput_preedit_draw;
4229 MSymbol Minput_status_start;
4230 MSymbol Minput_status_done;
4231 MSymbol Minput_status_draw;
4232 MSymbol Minput_candidates_start;
4233 MSymbol Minput_candidates_done;
4234 MSymbol Minput_candidates_draw;
4235 MSymbol Minput_set_spot;
4236 MSymbol Minput_toggle;
4237 MSymbol Minput_reset;
4238 MSymbol Minput_get_surrounding_text;
4239 MSymbol Minput_delete_surrounding_text;
4240 /*** @} */
4241
4242 /*=*/
4243
4244 /***en
4245     @name Variables: Predefined symbols for special input events.
4246
4247     These are the predefined symbols that are used as the @c KEY
4248     argument of minput_filter ().  */ 
4249 /***ja
4250     @name ÊÑ¿ô: ÆÃÊ̤ÊÆþÎÏ¥¤¥Ù¥ó¥ÈÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
4251
4252     minput_filter () ¤Î @c KEY °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */ 
4253
4254 /*** @{ */ 
4255 /*=*/
4256
4257 MSymbol Minput_focus_out;
4258 MSymbol Minput_focus_in;
4259 MSymbol Minput_focus_move;
4260
4261 /*** @} */
4262
4263 /*=*/
4264 /***en
4265     @name Variables: Predefined symbols used in input method information.  */
4266 /***ja
4267     @name ÊÑ¿ô: ÆþÎϥ᥽¥Ã¥É¾ðÊóÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.  */
4268 /*** @{ */ 
4269 /*=*/
4270 /***en
4271     These are the predefined symbols describing status of input method
4272     command and variable, and are used in a return value of
4273     minput_get_command () and minput_get_variable ().  */
4274 /***ja
4275     ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤äÊÑ¿ô¤Î¾õÂÖ¤òɽ¤·¡¢minput_get_command () ¤È
4276     minput_get_variable () ¤ÎÌá¤êÃͤȤ·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */
4277 MSymbol Minherited;
4278 MSymbol Mcustomized;
4279 MSymbol Mconfigured;
4280 /*** @} */ 
4281
4282 /*=*/
4283
4284 /***en
4285     @brief The default driver for internal input methods.
4286
4287     The variable #minput_default_driver is the default driver for
4288     internal input methods.
4289
4290     The member MInputDriver::open_im () searches the m17n database for
4291     an input method that matches the tag \< #Minput_method, $LANGUAGE,
4292     $NAME\> and loads it.
4293
4294     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
4295     programmers responsibility to set it to a plist of proper callback
4296     functions.  Otherwise, no feedback information (e.g. preedit text)
4297     can be shown to users.
4298
4299     The macro M17N_INIT () sets the variable #minput_driver to the
4300     pointer to this driver so that all internal input methods use it.
4301
4302     Therefore, unless @c minput_driver is set differently, the driver
4303     dependent arguments $ARG of the functions whose name begins with
4304     "minput_" are all ignored.  */
4305 /***ja
4306     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
4307
4308     ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£
4309
4310     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
4311     \< #Minput_method, $LANGUAGE, $NAME\> 
4312     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
4313
4314     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢
4315     ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist
4316     ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit 
4317     ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
4318
4319     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver 
4320     ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
4321
4322     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
4323     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
4324
4325 MInputDriver minput_default_driver;
4326 /*=*/
4327
4328 /***en
4329     @brief The driver for internal input methods.
4330
4331     The variable #minput_driver is a pointer to the input method
4332     driver that is used by internal input methods.  The macro
4333     M17N_INIT () initializes it to a pointer to #minput_default_driver
4334     if <m17n<EM></EM>.h> is included.  */ 
4335 /***ja
4336     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
4337
4338     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
4339     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
4340     ¥¿¤ò#minput_default_driver (<m17n<EM></EM>.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë
4341     »þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
4342
4343 MInputDriver *minput_driver;
4344
4345 /*=*/
4346 /***
4347     The variable #Minput_driver is a symbol for a foreign input method.
4348     See @ref foreign-input-method "foreign input method" for the detail.  */
4349 MSymbol Minput_driver;
4350
4351 /*=*/
4352
4353 /***en
4354     @name Functions
4355 */
4356 /***ja
4357     @name ´Ø¿ô
4358 */
4359 /*** @{ */
4360
4361 /*=*/
4362
4363 /***en
4364     @brief Open an input method.
4365
4366     The minput_open_im () function opens an input method whose
4367     language and name match $LANGUAGE and $NAME, and returns a pointer
4368     to the input method object newly allocated.
4369
4370     This function at first decides a driver for the input method as
4371     described below.
4372
4373     If $LANGUAGE is not #Mnil, the driver pointed by the variable
4374     #minput_driver is used.
4375
4376     If $LANGUAGE is #Mnil and $NAME has the property #Minput_driver, the
4377     driver pointed to by the property value is used to open the input
4378     method.  If $NAME has no such a property, @c NULL is returned.
4379
4380     Then, the member MInputDriver::open_im () of the driver is
4381     called.  
4382
4383     $ARG is set in the member @c arg of the structure MInputMethod so
4384     that the driver can refer to it.  */
4385 /***ja
4386     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
4387
4388     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME 
4389     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
4390     
4391     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
4392
4393     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver 
4394     ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
4395
4396     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver
4397     ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£
4398     $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
4399
4400     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
4401
4402     $ARG ¤Ï¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£
4403
4404     @latexonly \IPAlabel{minput_open} @endlatexonly
4405
4406 */
4407
4408 MInputMethod *
4409 minput_open_im (MSymbol language, MSymbol name, void *arg)
4410 {
4411   MInputMethod *im;
4412   MInputDriver *driver;
4413
4414   MINPUT__INIT ();
4415
4416   MDEBUG_PRINT2 ("  [IM] opening (%s %s) ... ",
4417                  msymbol_name (language), msymbol_name (name));
4418   if (language)
4419     {
4420       if (name == Mnil)
4421         MERROR (MERROR_IM, NULL);
4422       driver = minput_driver;
4423     }
4424   else
4425     {
4426       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
4427       if (! driver)
4428         MERROR (MERROR_IM, NULL);
4429     }
4430
4431   MSTRUCT_CALLOC (im, MERROR_IM);
4432   im->language = language;
4433   im->name = name;
4434   im->arg = arg;
4435   im->driver = *driver;
4436   if ((*im->driver.open_im) (im) < 0)
4437     {
4438       MDEBUG_PRINT (" failed\n");
4439       free (im);
4440       return NULL;
4441     }
4442   MDEBUG_PRINT (" ok\n");
4443   return im;
4444 }
4445
4446 /*=*/
4447
4448 /***en
4449     @brief Close an input method.
4450
4451     The minput_close_im () function closes the input method $IM, which
4452     must have been created by minput_open_im ().  */
4453
4454 /***ja
4455     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
4456
4457     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£
4458     ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
4459
4460 void
4461 minput_close_im (MInputMethod *im)
4462 {
4463   MDEBUG_PRINT2 ("  [IM] closing (%s %s) ... ",
4464                  msymbol_name (im->name), msymbol_name (im->language));
4465   (*im->driver.close_im) (im);
4466   free (im);
4467   MDEBUG_PRINT (" done\n");
4468 }
4469
4470 /*=*/
4471
4472 /***en
4473     @brief Create an input context.
4474
4475     The minput_create_ic () function creates an input context object
4476     associated with input method $IM, and calls callback functions
4477     corresponding to @b Minput_preedit_start, @b Minput_status_start, and
4478     @b Minput_status_draw in this order.
4479
4480     @return
4481     If an input context is successfully created, minput_create_ic ()
4482     returns a pointer to it.  Otherwise it returns @c NULL.  */
4483
4484 /***ja
4485     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
4486
4487     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
4488     ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
4489     @b Minput_preedit_start, @b Minput_status_start, @b Minput_status_draw
4490     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
4491
4492     @return
4493     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () 
4494     ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
4495       */
4496
4497 MInputContext *
4498 minput_create_ic (MInputMethod *im, void *arg)
4499 {
4500   MInputContext *ic;
4501
4502   MDEBUG_PRINT2 ("  [IM] creating context (%s %s) ... ",
4503                  msymbol_name (im->name), msymbol_name (im->language));
4504   MSTRUCT_CALLOC (ic, MERROR_IM);
4505   ic->im = im;
4506   ic->arg = arg;
4507   ic->preedit = mtext ();
4508   ic->candidate_list = NULL;
4509   ic->produced = mtext ();
4510   ic->spot.x = ic->spot.y = 0;
4511   ic->active = 1;
4512   ic->plist = mplist ();
4513   if ((*im->driver.create_ic) (ic) < 0)
4514     {
4515       MDEBUG_PRINT (" failed\n");
4516       M17N_OBJECT_UNREF (ic->preedit);
4517       M17N_OBJECT_UNREF (ic->produced);
4518       M17N_OBJECT_UNREF (ic->plist);
4519       free (ic);
4520       return NULL;
4521     };
4522
4523   if (im->driver.callback_list)
4524     {
4525       minput_callback (ic, Minput_preedit_start);
4526       minput_callback (ic, Minput_status_start);
4527       minput_callback (ic, Minput_status_draw);
4528     }
4529
4530   MDEBUG_PRINT (" ok\n");
4531   return ic;
4532 }
4533
4534 /*=*/
4535
4536 /***en
4537     @brief Destroy an input context.
4538
4539     The minput_destroy_ic () function destroys the input context $IC,
4540     which must have been created by minput_create_ic ().  It calls
4541     callback functions corresponding to @b Minput_preedit_done,
4542     @b Minput_status_done, and @b Minput_candidates_done in this order.  */
4543
4544 /***ja
4545     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
4546
4547     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
4548     ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () 
4549     ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï 
4550     @b Minput_preedit_done, @b Minput_status_done, @b Minput_candidates_done 
4551     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
4552   */
4553
4554 void
4555 minput_destroy_ic (MInputContext *ic)
4556 {
4557   MDEBUG_PRINT2 ("  [IM] destroying context (%s %s) ... ",
4558                  msymbol_name (ic->im->name), msymbol_name (ic->im->language));
4559   if (ic->im->driver.callback_list)
4560     {
4561       minput_callback (ic, Minput_preedit_done);
4562       minput_callback (ic, Minput_status_done);
4563       minput_callback (ic, Minput_candidates_done);
4564     }
4565   (*ic->im->driver.destroy_ic) (ic);
4566   M17N_OBJECT_UNREF (ic->preedit);
4567   M17N_OBJECT_UNREF (ic->produced);
4568   M17N_OBJECT_UNREF (ic->plist);
4569   MDEBUG_PRINT (" done\n");
4570   free (ic);
4571 }
4572
4573 /*=*/
4574
4575 /***en
4576     @brief Filter an input key.
4577
4578     The minput_filter () function filters input key $KEY according to
4579     input context $IC, and calls callback functions corresponding to
4580     @b Minput_preedit_draw, @b Minput_status_draw, and
4581     @b Minput_candidates_draw if the preedit text, the status, and the
4582     current candidate are changed respectively.
4583
4584     To make the input method commit the current preedit text (if any)
4585     and shift to the initial state, call this function with #Mnil as
4586     $KEY.
4587
4588     To inform the input method about the focus-out event, call this
4589     function with @b Minput_focus_out as $KEY.
4590
4591     To inform the input method about the focus-in event, call this
4592     function with @b Minput_focus_in as $KEY.
4593
4594     To inform the input method about the focus-move event (i.e. input
4595     spot change within the same input context), call this function
4596     with @b Minput_focus_move as $KEY.
4597
4598     @return
4599     If $KEY is filtered out, this function returns 1.  In that case,
4600     the caller should discard the key.  Otherwise, it returns 0, and
4601     the caller should handle the key, for instance, by calling the
4602     function minput_lookup () with the same key.  */
4603
4604 /***ja
4605     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
4606
4607     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4608     ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
4609     @b Minput_preedit_draw, @b Minput_status_draw,
4610     @b Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
4611
4612     @return 
4613     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
4614     ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
4615     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup ()
4616     ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
4617
4618     @latexonly \IPAlabel{minput_filter} @endlatexonly
4619 */
4620
4621 int
4622 minput_filter (MInputContext *ic, MSymbol key, void *arg)
4623 {
4624   int ret;
4625
4626   if (! ic
4627       || ! ic->active)
4628     return 0;
4629   if (ic->im->driver.callback_list
4630       && mtext_nchars (ic->preedit) > 0)
4631     minput_callback (ic, Minput_preedit_draw);
4632
4633   ret = (*ic->im->driver.filter) (ic, key, arg);
4634
4635   if (ic->im->driver.callback_list)
4636     {
4637       if (ic->preedit_changed)
4638         minput_callback (ic, Minput_preedit_draw);
4639       if (ic->status_changed)
4640         minput_callback (ic, Minput_status_draw);
4641       if (ic->candidates_changed)
4642         minput_callback (ic, Minput_candidates_draw);
4643     }
4644
4645   return ret;
4646 }
4647
4648 /*=*/
4649
4650 /***en
4651     @brief Look up a text produced in the input context.
4652
4653     The minput_lookup () function looks up a text in the input context
4654     $IC.  $KEY must be identical to the one that was used in the previous call of
4655     minput_filter ().
4656
4657     If a text was produced by the input method, it is concatenated
4658     to M-text $MT.
4659
4660     This function calls #MInputDriver::lookup .
4661
4662     @return
4663     If $KEY was correctly handled by the input method, this function
4664     returns 0.  Otherwise, it returns -1, even though some text
4665     might be produced in $MT.  */
4666
4667 /***ja
4668     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹.
4669
4670     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£
4671     $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4672
4673     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
4674     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
4675
4676     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
4677
4678     @return 
4679     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
4680     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
4681     ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
4682
4683     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
4684
4685 int
4686 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
4687 {
4688   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
4689 }
4690 /*=*/
4691
4692 /***en
4693     @brief Set the spot of the input context.
4694
4695     The minput_set_spot () function sets the spot of input context $IC
4696     to coordinate ($X, $Y ) with the height specified by $ASCENT and $DESCENT .
4697     The semantics of these values depends on the input method driver.
4698
4699     For instance, a driver designed to work in a CUI environment may
4700     use $X and $Y as the column- and row numbers, and may ignore $ASCENT and
4701     $DESCENT .  A driver designed to work in a window system may
4702     interpret $X and $Y as the pixel offsets relative to the origin of the
4703     client window, and may interpret $ASCENT and $DESCENT as the ascent- and
4704     descent pixels of the line at ($X . $Y ).
4705
4706     $FONTSIZE specifies the fontsize of preedit text in 1/10 point.
4707
4708     $MT and $POS are the M-text and the character position at the spot.
4709     $MT may be @c NULL, in which case, the input method cannot get
4710     information about the text around the spot.  */
4711
4712 /***ja
4713     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë.
4714
4715     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y )
4716     ¤Î°ÌÃ֤ˠ¡¢¹â¤µ $ASCENT¡¢ $DESCENT 
4717     ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£
4718
4719     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y 
4720     ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT 
4721     ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï
4722     $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
4723     $ASCENT ¤È $DESCENT ¤ò ($X . $Y )
4724     ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
4725
4726     $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
4727
4728     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
4729     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
4730     */
4731
4732 void
4733 minput_set_spot (MInputContext *ic, int x, int y,
4734                  int ascent, int descent, int fontsize,
4735                  MText *mt, int pos)
4736 {
4737   ic->spot.x = x;
4738   ic->spot.y = y;
4739   ic->spot.ascent = ascent;
4740   ic->spot.descent = descent;
4741   ic->spot.fontsize = fontsize;
4742   ic->spot.mt = mt;
4743   ic->spot.pos = pos;
4744   if (ic->im->driver.callback_list)
4745     minput_callback (ic, Minput_set_spot);
4746 }
4747 /*=*/
4748
4749 /***en
4750     @brief Toggle input method.
4751
4752     The minput_toggle () function toggles the input method associated
4753     with input context $IC.  */
4754 /***ja
4755     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
4756
4757     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
4758     ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
4759     */
4760
4761 void
4762 minput_toggle (MInputContext *ic)
4763 {
4764   if (ic->im->driver.callback_list)
4765     minput_callback (ic, Minput_toggle);
4766   ic->active = ! ic->active;
4767 }
4768
4769 /*=*/
4770
4771 /***en
4772     @brief Reset an input context.
4773
4774     The minput_reset_ic () function resets input context $IC by
4775     calling a callback function corresponding to @b Minput_reset.  It
4776     resets the status of $IC to its initial one.  As the
4777     current preedit text is deleted without commitment, if necessary,
4778     call minput_filter () with the arg @b key #Mnil to force the input
4779     method to commit the preedit in advance.  */
4780
4781 /***ja
4782     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
4783
4784     ´Ø¿ô minput_reset_ic () ¤Ï @b Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
4785     ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢
4786     ¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ë¡£¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹
4787     ¥È¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¤³¤È¤Ê¤¯ºï½ü¤µ¤ì¤ë¤Î¤Ç¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
4788     ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @b key #Mnil ¤Ç¸Æ¤ó¤Ç
4789     ¶¯À©Åª¤Ë¥×¥ê¥¨¥Ç¥£¥Ã¥È¥Æ¥­¥¹¥È¤ò¥³¥ß¥Ã¥È¤µ¤»¤ë¤³¤È¡£  */
4790
4791 void
4792 minput_reset_ic (MInputContext *ic)
4793 {
4794   if (ic->im->driver.callback_list)
4795     minput_callback (ic, Minput_reset);
4796 }
4797
4798 /*=*/
4799
4800 /***en
4801     @brief Get title and icon filename of an input method.
4802
4803     The minput_get_title_icon () function returns a plist containing a
4804     title and icon filename (if any) of an input method specified by
4805     $LANGUAGE and $NAME.
4806
4807     The first element of the plist has key #Mtext and the value is an
4808     M-text of the title for identifying the input method.  The second
4809     element (if any) has key #Mtext and the value is an M-text of the
4810     icon image (absolute) filename for the same purpose.
4811
4812     @return
4813     If there exists a specified input method and it defines an title,
4814     a plist is returned.  Otherwise, NULL is returned.  The caller
4815     must free the plist by m17n_object_unref ().  */
4816 /***ja
4817     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë̾¤òÆÀ¤ë.
4818
4819     ´Ø¿ô minput_get_title_icon () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ë
4820     ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¡Ê¤¢¤ì¤Ð¡Ë¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë¤ò´Þ¤à plist ¤ò
4821     ÊÖ¤¹¡£
4822
4823     plist ¤ÎÂè°ìÍ×ÁǤϡ¢#Mtext ¤ò¥­¡¼¤Ë»ý¤Á¡¢ÃͤÏÆþÎϥ᥽¥Ã¥É¤ò¼±Ê̤¹¤ë
4824     ¥¿¥¤¥È¥ë¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£ÂèÆóÍ×ÁǤ¬¤¢¤ì¤Ð¡¢¥­¡¼¤Ï #Mtext ¤Ç¤¢
4825     ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¥Õ¥¡¥¤¥ë¤ÎÀäÂХѥ¹¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
4826
4827     @return
4828     »ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¡¢¥¿¥¤¥È¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð
4829      plist ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð NULL ¤òÊÖ¤¹¡£¸Æ½Ð¦¤Ï
4830      ´Ø¿ô m17n_object_unref () ¤òÍѤ¤¤Æ plist ¤ò²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
4831
4832 MPlist *
4833 minput_get_title_icon (MSymbol language, MSymbol name)
4834 {
4835   MInputMethodInfo *im_info;
4836   MPlist *plist;
4837   char *file = NULL;
4838   MText *mt;
4839
4840   MINPUT__INIT ();
4841
4842   im_info = get_im_info (language, name, Mnil, Mtitle);
4843   if (! im_info || !im_info->title)
4844     return NULL;
4845   mt = mtext_get_prop (im_info->title, 0, Mtext);
4846   if (mt)
4847     file = mdatabase__find_file ((char *) MTEXT_DATA (mt));
4848   else
4849     {
4850       char *buf = alloca (MSYMBOL_NAMELEN (language) + MSYMBOL_NAMELEN (name)
4851                           + 12);
4852
4853       sprintf (buf, "icons/%s-%s.png", (char *) MSYMBOL_NAME (language), 
4854                (char *) MSYMBOL_NAME (name));
4855       file = mdatabase__find_file (buf);
4856       if (! file && language == Mt)
4857         {
4858           sprintf (buf, "icons/%s.png", (char *) MSYMBOL_NAME (name));
4859           file = mdatabase__find_file (buf);
4860         }
4861     }
4862
4863   plist = mplist ();
4864   mplist_add (plist, Mtext, im_info->title);
4865   if (file)
4866     {
4867       mt = mtext__from_data (file, strlen (file), MTEXT_FORMAT_UTF_8, 1);
4868       free (file);
4869       mplist_add (plist, Mtext, mt);
4870       M17N_OBJECT_UNREF (mt);
4871     }
4872   return plist;
4873 }
4874
4875 /*=*/
4876
4877 /***en
4878     @brief Get description text of an input method.
4879
4880     The minput_get_description () function returns an M-text that
4881     describes the input method specified by $LANGUAGE and $NAME.
4882
4883     @return
4884     If the specified input method has a description text, a pointer to
4885     #MText is returned.  The caller has to free it by m17n_object_unref ().
4886     If the input method does not have a description text, @c NULL is
4887     returned.  */
4888 /***ja
4889     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë.
4890
4891     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
4892     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
4893
4894     @return
4895     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
4896     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
4897     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
4898     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
4899
4900 MText *
4901 minput_get_description (MSymbol language, MSymbol name)
4902 {
4903   MInputMethodInfo *im_info;
4904   MSymbol extra;
4905
4906   MINPUT__INIT ();
4907
4908   if (name != Mnil)
4909     extra = Mnil;
4910   else
4911     extra = language, language = Mt;
4912
4913   im_info = get_im_info (language, name, extra, Mdescription);
4914   if (! im_info || ! im_info->description)
4915     return NULL;
4916   M17N_OBJECT_REF (im_info->description);
4917   return im_info->description;
4918 }
4919
4920 /*=*/
4921
4922 /***en
4923     @brief Get information about input method command(s).
4924
4925     The minput_get_command () function returns information about
4926     the command $COMMAND of the input method specified by $LANGUAGE and
4927     $NAME.  An input method command is a pseudo key event to which one
4928     or more actual input key sequences are assigned.
4929
4930     There are two kinds of commands, global and local.  A global
4931     command has a global definition, and the description and the key
4932     assignment may be inherited by a local command.  Each input method
4933     defines a local command which has a local key assignment.  It may
4934     also declare a local command that inherits the definition of a
4935     global command of the same name.
4936
4937     If $LANGUAGE is #Mt and $NAME is #Mnil, this function returns
4938     information about a global command.  Otherwise information about a
4939     local command is returned.
4940
4941     If $COMMAND is #Mnil, information about all commands is returned.
4942
4943     The return value is a @e well-formed plist (@ref m17nPlist) of this
4944     format:
4945 @verbatim
4946   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
4947 @endverbatim
4948     @c NAME is a symbol representing the command name.
4949
4950     @c DESCRIPTION is an M-text describing the command, or #Mnil if the
4951     command has no description.
4952
4953     @c STATUS is a symbol representing how the key assignment is decided.
4954     The value is #Mnil (the default key assignment), @b Mcustomized (the
4955     key assignment is customized by per-user customization file), or
4956     @b Mconfigured (the key assignment is set by the call of
4957     minput_config_command ()).  For a local command only, it may also
4958     be @b Minherited (the key assignment is inherited from the
4959     corresponding global command).
4960
4961     @c KEYSEQ is a plist of one or more symbols representing a key
4962     sequence assigned to the command.  If there's no KEYSEQ, the
4963     command is currently disabled (i.e. no key sequence can trigger
4964     actions of the command).
4965
4966     If $COMMAND is not #Mnil, the first element of the returned plist
4967     contains the information about $COMMAND.
4968
4969     @return
4970
4971     If the requested information was found, a pointer to a non-empty
4972     plist is returned.  As the plist is kept in the library, the
4973     caller must not modify nor free it.
4974
4975     Otherwise (the specified input method or the specified command
4976     does not exist), @c NULL is returned.  */
4977 /***ja
4978     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
4979
4980     ´Ø¿ô minput_get_command () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
4981     ¥á¥½¥Ã¥É¤Î¥³¥Þ¥ó¥É $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ
4982     ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢£±¤Ä°Ê¾å¤Î¼ÂºÝ¤ÎÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨
4983     ¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
4984
4985     ¥³¥Þ¥ó¥É¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É
4986     ¤Ï¥°¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤Ï¤½¤ÎÀâÌÀ¤È¥­¡¼³ä¤êÅö¤Æ
4987     ¤ò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤ò»ý¤Ä¥í¡¼
4988     ¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÄêµÁ¤¹¤ë¡£¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É¤ÎÄêµÁ¤ò·Ñ
4989     ¾µ¤¹¤ë¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÀë¸À¤¹¤ë¤³¤È¤â¤Ç¤­¤ë¡£
4990
4991     $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ë¥³
4992     ¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¤â
4993     ¤Î¤òÊÖ¤¹¡£
4994
4995     $COMMAND ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
4996
4997     Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
4998
4999 @verbatim
5000   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
5001 @endverbatim
5002     @c NAME ¤Ï¥³¥Þ¥ó¥É̾¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
5003
5004     @c DESCRIPTION ¤Ï¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë
5005     ¤Ï #Mnil ¤Ç¤¢¤ë¡£
5006
5007     @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë
5008     ¤Ç¤¢¤ê¡¢¤½¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, @b Mcustomized ¡Ê¥æ¡¼
5009     ¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë,
5010     @b Mconfigured ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë
5011     ³ä¤êÅö¤Æ¡Ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢
5012     @b Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë
5013     ¤Ç¤â¤è¤¤¡£
5014
5015     @c KEYSEQ ¤Ï£±¤Ä°Ê¾å¤Î¥·¥ó¥Ü¥ë¤«¤é¤Ê¤ë plist ¤Ç¤¢¤ê¡¢³Æ¥·¥ó¥Ü¥ë¤Ï¥³¥Þ
5016     ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òɽ¤¹¡£KEYSEQ ¤¬Ìµ¤¤¾ì¹ç¤Ï¡¢
5017     ¤½¤Î¥³¥Þ¥ó¥É¤Ï¸½¾õ¤Ç»ÈÍÑÉÔǽ¤Ç¤¢¤ë¡£¡Ê¤¹¤Ê¤ï¤Á¥³¥Þ¥ó¥É¤ÎÆ°ºî¤òµ¯
5018     Æ°¤Ç¤­¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Ìµ¤¤¡£¡Ë
5019
5020     $COMMAND ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤϡ¢
5021     $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
5022
5023     @return
5024
5025     µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
5026     ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
5027     ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5028
5029     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ä¥³¥Þ¥ó¥É¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
5030     @c NULL ¤òÊÖ¤¹¡£  */
5031
5032 #if EXAMPLE_CODE
5033 MText *
5034 get_im_command_description (MSymbol language, MSymbol name, MSymbol command)
5035 {
5036   /* Return a description of the command COMMAND of the input method
5037      specified by LANGUAGE and NAME.  */
5038   MPlist *cmd = minput_get_command (langauge, name, command);
5039   MPlist *plist;
5040
5041   if (! cmds)
5042     return NULL;
5043   plist = mplist_value (cmds);  /* (NAME DESCRIPTION STATUS KEY-SEQ ...) */
5044   plist = mplist_next (plist);  /* (DESCRIPTION STATUS KEY-SEQ ...) */
5045   return  (mplist_key (plist) == Mtext
5046            ? (MText *) mplist_value (plist)
5047            : NULL);
5048 }
5049 #endif
5050
5051 MPlist *
5052 minput_get_command (MSymbol language, MSymbol name, MSymbol command)
5053 {
5054   MInputMethodInfo *im_info;
5055
5056   MINPUT__INIT ();
5057
5058   im_info = get_im_info (language, name, Mnil, Mcommand);
5059   if (! im_info
5060       || ! im_info->configured_cmds
5061       || MPLIST_TAIL_P (im_info->configured_cmds))
5062     return NULL;
5063   if (command == Mnil)
5064     return im_info->configured_cmds;
5065   return mplist__assq (im_info->configured_cmds, command);
5066 }
5067
5068 /*=*/
5069
5070 /***en
5071     @brief Configure the key sequence of an input method command.
5072
5073     The minput_config_command () function assigns a list of key
5074     sequences $KEYSEQLIST to the command $COMMAND of the input method
5075     specified by $LANGUAGE and $NAME.
5076
5077     If $KEYSEQLIST is a non-empty plist, it must be a list of key
5078     sequences, and each key sequence must be a plist of symbols.
5079
5080     If $KEYSEQLIST is an empty plist, any configuration and
5081     customization of the command are cancelled, and default key
5082     sequences become effective.
5083
5084     If $KEYSEQLIST is NULL, the configuration of the command is
5085     canceled, and the original key sequences (what saved in per-user
5086     customization file, or the default one) become effective.
5087
5088     In the latter two cases, $COMMAND can be #Mnil to make all the
5089     commands of the input method the target of the operation.
5090
5091     If $NAME is #Mnil, this function configures the key assignment of a
5092     global command, not that of a specific input method.
5093
5094     The configuration takes effect for input methods opened or
5095     re-opened later in the current session.  In order to make the
5096     configuration take effect for the future session, it must be saved
5097     in a per-user customization file by the function
5098     minput_save_config ().
5099
5100     @return
5101     If the operation was successful, this function returns 0,
5102     otherwise returns -1.  The operation fails in these cases:
5103     <ul>
5104     <li>$KEYSEQLIST is not in a valid form.
5105     <li>$COMMAND is not available for the input method.
5106     <li>$LANGUAGE and $NAME do not specify an existing input method.
5107     </ul>
5108
5109     @seealso
5110     minput_get_commands (), minput_save_config ().
5111 */
5112 /***ja
5113     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òÀßÄꤹ¤ë.
5114
5115     ´Ø¿ô minput_config_command () ¤Ï¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È
5116     $KEYSEQLIST ¤ò¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤Î
5117     ¥³¥Þ¥ó¥É $COMMAND ¤Ë³ä¤êÅö¤Æ¤ë¡£
5118
5119     $KEYSEQLIST ¤¬¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È¤Ç¤¢¤ê¡¢
5120     ³Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥·¥ó¥Ü¥ë¤Î plist ¤Ç¤¢¤ë¡£
5121
5122     $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤ä¥«¥¹¥¿¥Þ¥¤¥º¤Ï
5123     ¤¹¤Ù¤Æ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£
5124
5125     $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢
5126     ¸µ¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¡Ê¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤µ¤ì¤Æ¤¤
5127     ¤ë¤â¤Î¡¢¤¢¤ë¤¤¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¤â¤Î¡Ë¤¬Í­¸ú¤Ë¤Ê¤ë¡£
5128
5129     ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$COMMAND ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄê¤ÎÆþ
5130     Îϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥ÉÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
5131
5132     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
5133     ¥ë¤Ê¥³¥Þ¥ó¥É¤Î¥­¡¼³ä¤êÅö¤Æ¤òÀßÄꤹ¤ë¡£
5134
5135     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
5136     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
5137     ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
5138     ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
5139
5140     @return
5141
5142     ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
5143     <ul>
5144     <li>$KEYSEQLIST ¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£
5145     <li>$COMMAND ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
5146     <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
5147     </ul>
5148
5149     @seealso
5150     minput_get_commands (), minput_save_config ().
5151 */
5152
5153 #if EXAMPLE_CODE
5154 /* Add "C-x u" to the "start" command of Unicode input method.  */
5155 {
5156   MSymbol start_command = msymbol ("start");
5157   MSymbol unicode = msymbol ("unicode");
5158   MPlist *cmd, *plist, *key_seq_list, *key_seq;
5159
5160   /* At first get the current key-sequence assignment.  */
5161   cmd = minput_get_command (Mt, unicode, start_command);
5162   if (! cmd)
5163     {
5164       /* The input method does not have the command "start".  Here
5165          should come some error handling code.  */
5166     }
5167   /* Now CMD == ((start DESCRIPTION STATUS KEY-SEQUENCE ...) ...).
5168      Extract the part (KEY-SEQUENCE ...).  */
5169   plist = mplist_next (mplist_next (mplist_next (mplist_value (cmd))));
5170   /* Copy it because we should not modify it directly.  */
5171   key_seq_list = mplist_copy (plist);
5172   
5173   key_seq = mplist ();
5174   mplist_add (key_seq, Msymbol, msymbol ("C-x"));
5175   mplist_add (key_seq, Msymbol, msymbol ("u"));
5176   mplist_add (key_seq_list, Mplist, key_seq);
5177   m17n_object_unref (key_seq);
5178
5179   minput_config_command (Mt, unicode, start_command, key_seq_list);
5180   m17n_object_unref (key_seq_list);
5181 }
5182 #endif
5183
5184 int
5185 minput_config_command (MSymbol language, MSymbol name, MSymbol command,
5186                        MPlist *keyseqlist)
5187 {
5188   MInputMethodInfo *im_info, *config;
5189   MPlist *plist;
5190
5191   MINPUT__INIT ();
5192
5193   im_info = get_im_info (language, name, Mnil, Mcommand);
5194   if (! im_info)
5195     MERROR (MERROR_IM, -1);
5196   if (command == Mnil ? (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
5197       : (! im_info->cmds
5198          || ! mplist__assq (im_info->configured_cmds, command)))
5199     MERROR (MERROR_IM, -1);
5200   if (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
5201     {
5202       MPLIST_DO (plist, keyseqlist)
5203         if (! check_command_keyseq (plist))
5204           MERROR (MERROR_IM, -1);
5205     }
5206
5207   config = get_config_info (im_info);
5208   if (! config)
5209     {
5210       if (! im_config_list)
5211         im_config_list = mplist ();
5212       config = new_im_info (NULL, language, name, Mnil, im_config_list);
5213       config->cmds = mplist ();
5214       config->vars = mplist ();
5215     }
5216
5217   if (! keyseqlist && MPLIST_TAIL_P (config->cmds))
5218     /* Nothing to do.  */
5219     return 0;
5220
5221   if (command == Mnil)
5222     {
5223       if (! keyseqlist)
5224         {
5225           /* Cancal the configuration. */
5226           if (MPLIST_TAIL_P (config->cmds))
5227             return 0;
5228           mplist_set (config->cmds, Mnil, NULL);
5229         }
5230       else
5231         {
5232           /* Cancal the customization. */
5233           MInputMethodInfo *custom = get_custom_info (im_info);
5234
5235           if (MPLIST_TAIL_P (config->cmds)
5236               && (! custom || ! custom->cmds || MPLIST_TAIL_P (custom->cmds)))
5237             /* Nothing to do.  */
5238             return 0;
5239           mplist_set (config->cmds, Mnil, NULL);
5240           MPLIST_DO (plist, custom->cmds)
5241             {
5242               command = MPLIST_SYMBOL (MPLIST_PLIST (plist));
5243               plist = mplist ();
5244               mplist_add (plist, Msymbol, command);
5245               mplist_push (config->cmds, Mplist, plist);
5246               M17N_OBJECT_UNREF (plist);
5247             }
5248         }
5249     }
5250   else
5251     {
5252       plist = mplist__assq (config->cmds, command);
5253       if (! keyseqlist)
5254         {
5255           /* Cancel the configuration.  */
5256           if (! plist)
5257             return 0;
5258           mplist__pop_unref (plist);
5259         }
5260       else if (MPLIST_TAIL_P (keyseqlist))
5261         {
5262           /* Cancel the customization.  */
5263           MInputMethodInfo *custom = get_custom_info (im_info);
5264           int no_custom = (! custom || ! custom->cmds
5265                            || ! mplist__assq (custom->cmds, command));
5266           if (! plist)
5267             {
5268               if (no_custom)
5269                 return 0;
5270               plist = mplist ();
5271               mplist_add (config->cmds, Mplist, plist);
5272               M17N_OBJECT_UNREF (plist);
5273               plist = mplist_add (plist, Msymbol, command);
5274             }
5275           else
5276             {
5277               if (no_custom)
5278                 mplist__pop_unref (plist);
5279               else
5280                 {
5281                   plist = MPLIST_PLIST (plist); /* (NAME nil KEYSEQ ...) */
5282                   plist = MPLIST_NEXT (plist);
5283                   mplist_set (plist, Mnil, NULL);
5284                 }
5285             }
5286         }
5287       else
5288         {
5289           MPlist *pl;
5290
5291           if (plist)
5292             {
5293               plist = MPLIST_NEXT (MPLIST_PLIST (plist));
5294               if (! MPLIST_TAIL_P (plist))
5295                 mplist_set (plist, Mnil, NULL);
5296             }
5297           else
5298             {
5299               plist = mplist ();
5300               mplist_add (config->cmds, Mplist, plist);
5301               M17N_OBJECT_UNREF (plist);
5302               plist = mplist_add (plist, Msymbol, command);
5303               plist = MPLIST_NEXT (plist);
5304             }
5305           MPLIST_DO (keyseqlist, keyseqlist)
5306             {
5307               pl = mplist_copy (MPLIST_VAL (keyseqlist));
5308               plist = mplist_add (plist, Mplist, pl);
5309               M17N_OBJECT_UNREF (pl);
5310             }
5311         }
5312     }
5313   config_all_commands (im_info);
5314   im_info->tick = time (NULL);
5315   return 0;
5316 }
5317
5318 /*=*/
5319
5320 /***en
5321     @brief Get information about input method variable(s).
5322
5323     The minput_get_variable () function returns information about
5324     variable $VARIABLE of the input method specified by $LANGUAGE and $NAME.
5325     An input method variable controls behavior of an input method.
5326
5327     There are two kinds of variables, global and local.  A global
5328     variable has a global definition, and the description and the value
5329     may be inherited by a local variable.  Each input method defines a
5330     local variable which has local value.  It may also declare a
5331     local variable that inherits definition of a global variable of
5332     the same name.
5333
5334     If $LANGUAGE is #Mt and $NAME is #Mnil, information about a global
5335     variable is returned.  Otherwise information about a local variable
5336     is returned.
5337
5338     If $VARIABLE is #Mnil, information about all variables is
5339     returned.
5340
5341     The return value is a @e well-formed plist (@ref m17nPlist) of this
5342     format:
5343 @verbatim
5344   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
5345 @endverbatim
5346     @c NAME is a symbol representing the variable name.
5347
5348     @c DESCRIPTION is an M-text describing the variable, or #Mnil if the
5349     variable has no description.
5350
5351     @c STATUS is a symbol representing how the value is decided.  The
5352     value is #Mnil (the default value), @b Mcustomized (the value is
5353     customized by per-user customization file), or @b Mconfigured (the
5354     value is set by the call of minput_config_variable ()).  For a
5355     local variable only, it may also be @b Minherited (the value is
5356     inherited from the corresponding global variable).
5357
5358     @c VALUE is the initial value of the variable.  If the key of this
5359     element is #Mt, the variable has no initial value.  Otherwise, the
5360     key is #Minteger, #Msymbol, or #Mtext and the value is of the
5361     corresponding type.
5362
5363     @c VALID-VALUEs (if any) specify which values the variable can have.
5364     They have the same type (i.e. having the same key) as @c VALUE except
5365     for the case that VALUE is an integer.  In that case, @c VALID-VALUE
5366     may be a plist of two integers specifying the range of possible
5367     values.
5368
5369     If there no @c VALID-VALUE, the variable can have any value as long
5370     as the type is the same as @c VALUE.
5371
5372     If $VARIABLE is not #Mnil, the first element of the returned plist
5373     contains the information about $VARIABLE.
5374
5375     @return
5376
5377     If the requested information was found, a pointer to a non-empty
5378     plist is returned.  As the plist is kept in the library, the
5379     caller must not modify nor free it.
5380
5381     Otherwise (the specified input method or the specified variable
5382     does not exist), @c NULL is returned.  */
5383 /***ja
5384     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
5385
5386     ´Ø¿ô minput_get_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
5387     ¥á¥½¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤È¤Ï¡¢
5388     ÆþÎϥ᥽¥Ã¥É¤Î¿¶Éñ¤òÀ©¸æ¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£
5389
5390     ÊÑ¿ô¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤Ï¥°
5391     ¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤Ï¤½¤ÎÀâÌÀ¤ÈÃͤò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç
5392     ¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤ÊÃͤò»ý¤Ä¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÄêµÁ¤¹¤ë¡£
5393     ¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤ÎÄêµÁ¤ò·Ñ¾µ¤¹¤ë¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÀë¸À¤¹¤ë
5394     ¤³¤È¤â¤Ç¤­¤ë¡£
5395
5396     $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ëÊÑ
5397     ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ëÊÑ¿ô¤Ë´Ø¤¹¤ë¤â¤Î¤òÊÖ¤¹¡£
5398
5399     $VARIABLE ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
5400
5401     Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
5402 @verbatim
5403   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
5404 @endverbatim
5405
5406     @c NAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
5407
5408     @c DESCRIPTION ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë¤Ï
5409     #Mnil ¤Ç¤¢¤ë¡£
5410
5411     @c STATUS ¤ÏÃͤ¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢
5412     @c STATUS ¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, @b Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤Î
5413     ¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, @b Mconfigured
5414     ¡Êminput_config_variable ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ëÃ͡ˤΤ¤¤º¤ì
5415     ¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ëÊÑ¿ô¤Î¾ì¹ç¤Ë¤Ï¡¢@b Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë
5416     ÊÑ¿ô¤«¤é·Ñ¾µ¤·¤¿Ã͡ˤǤâ¤è¤¤¡£
5417
5418     @c VALUE ¤ÏÊÑ¿ô¤Î½é´üÃͤǤ¢¤ë¡£¤³¤ÎÍ×ÁǤΥ­¡¼¤¬#Mt ¤Ç¤¢¤ì¤Ð½é´üÃͤò»ý
5419     ¤¿¤Ê¤¤¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤Ï #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì
5420     ¤«¤Ç¤¢¤ê¡¢ÃͤϤ½¤ì¤¾¤ìÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
5421
5422     @c VALID-VALUE ¤Ï¤â¤·¤¢¤ì¤Ð¡¢ÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò»ØÄꤹ¤ë¡£¤³¤ì¤Ï @c VALUE
5423     ¤ÈƱ¤¸·¿(¤¹¤Ê¤ï¤ÁƱ¤¸¥­¡¼¤ò»ý¤Ä) ¤Ç¤¢¤ë¤¬¡¢Îã³°¤È¤·¤Æ @c VALUE ¤¬
5424     integer ¤Î¾ì¹ç¤Ï @c VALID-VALUE ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹Æó¤Ä¤ÎÀ°¿ô¤«¤é
5425     ¤Ê¤ë plist ¤È¤Ê¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
5426
5427     @c VALID-VALUE ¤¬¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô¤Ï @c VALUE ¤ÈƱ¤¸·¿¤Ç¤¢¤ë¸Â¤ê¤¤¤«¤Ê¤ëÃͤâ
5428     ¤È¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
5429
5430     $VARIABLE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤÏ
5431     $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
5432
5433     @return
5434
5435     µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
5436     ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
5437     ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5438
5439     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤äÊÑ¿ô¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
5440     @c NULL ¤òÊÖ¤¹¡£ */
5441
5442 MPlist *
5443 minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
5444 {
5445   MInputMethodInfo *im_info;
5446
5447   MINPUT__INIT ();
5448
5449   im_info = get_im_info (language, name, Mnil, Mvariable);
5450   if (! im_info || ! im_info->configured_vars)
5451     return NULL;
5452   if (variable == Mnil)
5453     return im_info->configured_vars;
5454   return mplist__assq (im_info->configured_vars, variable);
5455 }
5456
5457 /*=*/
5458
5459 /***en
5460     @brief Configure the value of an input method variable.
5461
5462     The minput_config_variable () function assigns $VALUE to the
5463     variable $VARIABLE of the input method specified by $LANGUAGE and
5464     $NAME.
5465
5466     If $VALUE is a non-empty plist, it must be a plist of one element
5467     whose key is #Minteger, #Msymbol, or #Mtext, and the value is of
5468     the corresponding type.  That value is assigned to the variable.
5469
5470     If $VALUE is an empty plist, any configuration and customization
5471     of the variable are canceled, and the default value is assigned to
5472     the variable.
5473
5474     If $VALUE is NULL, the configuration of the variable is canceled,
5475     and the original value (what saved in per-user customization file,
5476     or the default value) is assigned to the variable.
5477
5478     In the latter two cases, $VARIABLE can be #Mnil to make all the
5479     variables of the input method the target of the operation.
5480
5481     If $NAME is #Mnil, this function configures the value of global
5482     variable, not that of a specific input method.
5483
5484     The configuration takes effect for input methods opened or
5485     re-opened later in the current session.  To make the configuration
5486     take effect for the future session, it must be saved in a per-user
5487     customization file by the function minput_save_config ().
5488
5489     @return
5490
5491     If the operation was successful, this function returns 0,
5492     otherwise returns -1.  The operation fails in these cases:
5493     <ul>
5494     <li>$VALUE is not in a valid form, the type does not match the
5495     definition, or the value is our of range.
5496     <li>$VARIABLE is not available for the input method.
5497     <li>$LANGUAGE and $NAME do not specify an existing input method.  
5498     </ul>
5499
5500     @seealso
5501     minput_get_variable (), minput_save_config ().  */
5502 /***ja
5503     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë.
5504
5505     ´Ø¿ô minput_config_variable () ¤ÏÃÍ $VALUE ¤ò¡¢$LANGUAGE ¤È $NAME
5506     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤ë¡£
5507
5508     $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï
5509     #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì¤«¡¢ÃͤÏÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
5510     ¤³¤ÎÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
5511
5512     $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤È¥«¥¹¥¿¥Þ¥¤¥º¤¬¥­¥ã¥ó¥»¥ë¤µ
5513     ¤ì¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
5514
5515     $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¸µ¤ÎÃ͡ʥ桼¥¶
5516     Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ëÃæ¤ÎÃÍ¡¢¤Þ¤¿¤Ï¥Ç¥Õ¥©¥ë¥È¤ÎÃ͡ˤ¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
5517
5518     ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$VARIABLE ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄꤵ¤ì
5519     ¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ôÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
5520
5521     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
5522     ¥ë¤ÊÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë¡£
5523
5524     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
5525     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
5526     ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
5527     ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
5528
5529     @return
5530
5531     ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
5532     <ul>
5533     <li>$VALUE¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£·¿¤¬ÄêµÁ¤Ë¹ç¤ï¤Ê¤¤¡¢¤Þ¤¿¤ÏÃͤ¬Èϰϳ°¤Ç¤¢¤ë¡£
5534     <li>$VARIABLE ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
5535     <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
5536     </ul>
5537
5538     @seealso
5539     minput_get_commands (), minput_save_config ().
5540 */
5541 int
5542 minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
5543                         MPlist *value)
5544 {
5545   MInputMethodInfo *im_info, *config;
5546   MPlist *plist;
5547
5548   MINPUT__INIT ();
5549
5550   im_info = get_im_info (language, name, Mnil, Mvariable);
5551   if (! im_info)
5552     MERROR (MERROR_IM, -1);
5553   if (variable == Mnil ? (value && ! MPLIST_TAIL_P (value))
5554       : (! im_info->vars
5555          || ! (plist = mplist__assq (im_info->configured_vars, variable))))
5556     MERROR (MERROR_IM, -1);
5557
5558   if (value && ! MPLIST_TAIL_P (value))
5559     {
5560       plist = MPLIST_PLIST (plist);
5561       plist = MPLIST_NEXT (plist); /* (DESC STATUS VALUE VALIDS ...) */
5562       plist = MPLIST_NEXT (plist); /* (STATUS VALUE VALIDS ...) */
5563       plist = MPLIST_NEXT (plist); /* (VALUE VALIDS ...) */
5564       if (MPLIST_KEY (plist) != Mt
5565           && ! check_variable_value (value, plist))
5566         MERROR (MERROR_IM, -1);
5567     }
5568
5569   config = get_config_info (im_info);
5570   if (! config)
5571     {
5572       if (! im_config_list)
5573         im_config_list = mplist ();
5574       config = new_im_info (NULL, language, name, Mnil, im_config_list);
5575       config->cmds = mplist ();
5576       config->vars = mplist ();
5577     }
5578
5579   if (! value && MPLIST_TAIL_P (config->vars))
5580     /* Nothing to do.  */
5581     return 0;
5582
5583   if (variable == Mnil)
5584     {
5585       if (! value)
5586         {
5587           /* Cancel the configuration.  */
5588           if (MPLIST_TAIL_P (config->vars))
5589             return 0;
5590           mplist_set (config->vars, Mnil, NULL);
5591         }
5592       else
5593         {
5594           /* Cancel the customization.  */
5595           MInputMethodInfo *custom = get_custom_info (im_info);
5596
5597           if (MPLIST_TAIL_P (config->vars)
5598               && (! custom || ! custom->vars || MPLIST_TAIL_P (custom->vars)))
5599             /* Nothing to do.  */
5600             return 0;
5601           mplist_set (config->vars, Mnil, NULL);
5602           MPLIST_DO (plist, custom->vars)
5603             {
5604               variable = MPLIST_SYMBOL (MPLIST_PLIST (plist));
5605               plist = mplist ();
5606               mplist_add (plist, Msymbol, variable);
5607               mplist_push (config->vars, Mplist, plist);
5608               M17N_OBJECT_UNREF (plist);
5609             }
5610         }
5611     }
5612   else
5613     {
5614       plist = mplist__assq (config->vars, variable);
5615       if (! value)
5616         {
5617           /* Cancel the configuration.  */
5618           if (! plist)
5619             return 0;
5620           mplist__pop_unref (plist);
5621         }
5622       else if (MPLIST_TAIL_P (value))
5623         {
5624           /* Cancel the customization.  */
5625           MInputMethodInfo *custom = get_custom_info (im_info);
5626           int no_custom = (! custom || ! custom->vars
5627                            || ! mplist__assq (custom->vars, variable));
5628           if (! plist)
5629             {
5630               if (no_custom)
5631                 return 0;
5632               plist = mplist ();
5633               mplist_add (config->vars, Mplist, plist);
5634               M17N_OBJECT_UNREF (plist);
5635               plist = mplist_add (plist, Msymbol, variable);
5636             }
5637           else
5638             {
5639               if (no_custom)
5640                 mplist__pop_unref (plist);
5641               else
5642                 {
5643                   plist = MPLIST_PLIST (plist); /* (NAME nil VALUE) */
5644                   plist = MPLIST_NEXT (plist);  /* ([nil VALUE]) */
5645                   mplist_set (plist, Mnil ,NULL);
5646                 }
5647             }
5648         }
5649       else
5650         {
5651           if (plist)
5652             {
5653               plist = MPLIST_NEXT (MPLIST_PLIST (plist));
5654               if (! MPLIST_TAIL_P (plist))
5655                 mplist_set (plist, Mnil, NULL);
5656             }
5657           else
5658             {
5659               plist = mplist ();
5660               mplist_add (config->vars, Mplist, plist);
5661               M17N_OBJECT_UNREF (plist);
5662               plist = mplist_add (plist, Msymbol, variable);
5663               plist = MPLIST_NEXT (plist);
5664             }
5665           mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value));
5666         }
5667     }
5668   config_all_variables (im_info);
5669   im_info->tick = time (NULL);
5670   return 0;
5671 }
5672
5673 /*=*/
5674
5675 /***en
5676     @brief Get the name of per-user customization file.
5677     
5678     The minput_config_file () function returns the absolute path name
5679     of per-user customization file into which minput_save_config ()
5680     save configurations.  It is usually @c config.mic under the
5681     directory <tt>${HOME}/.m17n.d</tt> (${HOME} is user's home
5682     directory).  It is not assured that the file of the returned name
5683     exists nor is readable/writable.  If minput_save_config () fails
5684     and returns -1, an application program might check the file, make
5685     it writable (if possible), and try minput_save_config () again.
5686
5687     @return
5688
5689     This function returns a string.  As the string is kept in the
5690     library, the caller must not modify nor free it.
5691
5692     @seealso
5693     minput_save_config ()
5694 */
5695 /***ja
5696     @brief ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÆÀ¤ë.
5697     
5698     ´Ø¿ô minput_config_file () ¤Ï¡¢´Ø¿ô minput_save_config () ¤¬ÀßÄê¤ò
5699     Êݸ¤¹¤ë¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ø¤ÎÀäÂХѥ¹Ì¾¤òÊÖ¤¹¡£Ä̾ï¤Ï¡¢¥æ¡¼¥¶
5700     ¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î²¼¤Î¥Ç¥£¥ì¥¯¥È¥ê @c ".m17n.d" ¤Ë¤¢¤ë@c
5701     "config.mic" ¤È¤Ê¤ë¡£ÊÖ¤µ¤ì¤¿Ì¾Á°¤Î¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¡¢Æɤ߽ñ¤­¤Ç
5702     ¤­¤ë¤«¤ÏÊݾڤµ¤ì¤Ê¤¤¡£´Ø¿ôminput_save_config () ¤¬¼ºÇÔ¤·¤Æ -1 ¤òÊÖ
5703     ¤·¤¿¾ì¹ç¤Ë¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò³Îǧ¤·¡¢
5704     ¡Ê¤Ç¤­¤ì¤Ð¡Ë½ñ¤­¹þ¤ß²Äǽ¤Ë¤·ºÆÅÙminput_save_config () ¤ò»î¤¹¤³¤È¤¬
5705     ¤Ç¤­¤ë¡£
5706
5707     @return
5708
5709     ¤³¤Î´Ø¿ô¤Ïʸ»úÎó¤òÊÖ¤¹¡£Ê¸»úÎó¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð
5710     Â¦¤¬½¤Àµ¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
5711
5712     @seealso
5713     minput_save_config ()
5714 */
5715
5716 char *
5717 minput_config_file ()
5718 {
5719   MINPUT__INIT ();
5720
5721   return mdatabase__file (im_custom_mdb);
5722 }
5723
5724 /*=*/
5725
5726 /***en
5727     @brief Save configurations in per-user customization file.
5728
5729     The minput_save_config () function saves the configurations done
5730     so far in the current session into the per-user customization
5731     file.
5732
5733     @return
5734
5735     If the operation was successful, 1 is returned.  If the per-user
5736     customization file is currently locked, 0 is returned.  In that
5737     case, the caller may wait for a while and try again.  If the
5738     configuration file is not writable, -1 is returned.  In that case,
5739     the caller may check the name of the file by calling
5740     minput_config_file (), make it writable if possible, and try
5741     again.
5742
5743     @seealso
5744     minput_config_file ()  */
5745 /***ja
5746     @brief ÀßÄê¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë.
5747
5748     ´Ø¿ô minput_save_config () ¤Ï¸½¹Ô¤Î¥»¥Ã¥·¥ç¥ó¤Ç¤³¤ì¤Þ¤Ç¤Ë¹Ô¤Ã¤¿ÀßÄê
5749     ¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë¡£
5750
5751     @return
5752
5753     À®¸ù¤¹¤ì¤Ð 1 ¤òÊÖ¤¹¡£¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤
5754     ¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢¸Æ½Ð¦¤Ï¤·¤Ð¤é¤¯ÂԤäƺƻî¹Ô¤Ç¤­¤ë¡£ÀßÄê¥Õ¥¡
5755     ¥¤¥ë¤¬½ñ¤­¹þ¤ßÉԲĤξì¹ç¡¢-1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢minput_config_file
5756     () ¤ò¸Æ¤ó¤Ç¥Õ¥¡¥¤¥ë̾¤ò¥Á¥§¥Ã¥¯¤·¡¢¤Ç¤­¤ì¤Ð½ñ¤­¹þ¤ß²Äǽ¤Ë¤·¡¢ºÆ»î¹Ô
5757     ¤Ç¤­¤ë¡£
5758
5759     @seealso
5760     minput_config_file ()  */
5761
5762 int
5763 minput_save_config (void)
5764 {
5765   MPlist *data, *tail, *plist, *p, *elt;
5766   int ret;
5767
5768   MINPUT__INIT ();
5769   ret = mdatabase__lock (im_custom_mdb);
5770   if (ret <= 0)
5771     return ret;
5772   if (! im_config_list)
5773     return 1;
5774   update_custom_info ();
5775   if (! im_custom_list)
5776     im_custom_list = mplist ();
5777
5778   /* At first, reflect configuration in customization.  */
5779   MPLIST_DO (plist, im_config_list)
5780     {
5781       MPlist *pl = MPLIST_PLIST (plist);
5782       MSymbol language, name, extra, command, variable;
5783       MInputMethodInfo *custom, *config;
5784
5785       language = MPLIST_SYMBOL (pl);
5786       pl = MPLIST_NEXT (pl);
5787       name = MPLIST_SYMBOL (pl);
5788       pl = MPLIST_NEXT (pl);
5789       extra = MPLIST_SYMBOL (pl);
5790       pl = MPLIST_NEXT (pl);
5791       config = MPLIST_VAL (pl);
5792       custom = get_custom_info (config);
5793       if (! custom)
5794         custom = new_im_info (NULL, language, name, extra, im_custom_list);
5795       if (config->cmds)
5796         MPLIST_DO (pl, config->cmds)
5797           {
5798             elt = MPLIST_PLIST (pl);
5799             command = MPLIST_SYMBOL (elt);
5800             if (custom->cmds)
5801               p = mplist__assq (custom->cmds, command);
5802             else
5803               custom->cmds = mplist (), p = NULL;
5804             elt = MPLIST_NEXT (elt);
5805             if (p)
5806               {
5807                 p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5808                 mplist_set (p, Mnil, NULL);
5809               }
5810             else
5811               {
5812                 p = mplist ();
5813                 mplist_add (custom->cmds, Mplist, p);
5814                 M17N_OBJECT_UNREF (p);
5815                 mplist_add (p, Msymbol, command);
5816                 p = mplist_add (p, Msymbol, Mnil);
5817                 p = MPLIST_NEXT (p);
5818               }
5819             mplist__conc (p, elt);
5820           }
5821       if (config->vars)
5822         MPLIST_DO (pl, config->vars)
5823           {
5824             elt = MPLIST_PLIST (pl);
5825             variable = MPLIST_SYMBOL (elt);
5826             if (custom->vars)
5827               p = mplist__assq (custom->vars, variable);
5828             else
5829               custom->vars = mplist (), p = NULL;
5830             elt = MPLIST_NEXT (elt);
5831             if (p)
5832               {
5833                 p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
5834                 mplist_set (p, Mnil, NULL);
5835               }
5836             else
5837               {
5838                 p = mplist ();
5839                 mplist_add (custom->vars, Mplist, p);
5840                 M17N_OBJECT_UNREF (p);
5841                 mplist_add (p, Msymbol, variable);
5842                 p = mplist_add (p, Msymbol, Mnil);
5843                 p = MPLIST_NEXT (p);
5844               }
5845             mplist__conc (p, elt);
5846           }
5847     }
5848   free_im_list (im_config_list);
5849   im_config_list = NULL;
5850
5851   /* Next, reflect customization to the actual plist to be written.  */
5852   data = tail = mplist ();
5853   MPLIST_DO (plist, im_custom_list)
5854     {
5855       MPlist *pl = MPLIST_PLIST (plist);
5856       MSymbol language, name, extra;
5857       MInputMethodInfo *custom, *im_info;
5858
5859       language = MPLIST_SYMBOL (pl);
5860       pl  = MPLIST_NEXT (pl);
5861       name = MPLIST_SYMBOL (pl);
5862       pl = MPLIST_NEXT (pl);
5863       extra = MPLIST_SYMBOL (pl);
5864       pl = MPLIST_NEXT (pl);
5865       custom = MPLIST_VAL (pl);
5866       if ((! custom->cmds || MPLIST_TAIL_P (custom->cmds))
5867           && (! custom->vars || MPLIST_TAIL_P (custom->vars)))
5868         continue;
5869       im_info = lookup_im_info (im_info_list, language, name, extra);
5870       if (im_info)
5871         {
5872           if (im_info->cmds)
5873             config_all_commands (im_info);
5874           if (im_info->vars)
5875             config_all_variables (im_info);
5876         }
5877       
5878       elt = NULL;
5879       if (custom->cmds && ! MPLIST_TAIL_P (custom->cmds))
5880         {
5881           MPLIST_DO (p, custom->cmds)
5882             if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5883               break;
5884           if (! MPLIST_TAIL_P (p))
5885             {
5886               elt = mplist ();
5887               pl = mplist ();
5888               mplist_add (elt, Mplist, pl);
5889               M17N_OBJECT_UNREF (pl);
5890               pl = mplist_add (pl, Msymbol, Mcommand);
5891               MPLIST_DO (p, custom->cmds)
5892                 if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5893                   pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5894             }
5895         }
5896       if (custom->vars && ! MPLIST_TAIL_P (custom->vars))
5897         {
5898           MPLIST_DO (p, custom->vars)
5899             if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5900               break;
5901           if (! MPLIST_TAIL_P (p))
5902             {
5903               if (! elt)
5904                 elt = mplist ();
5905               pl = mplist ();
5906               mplist_add (elt, Mplist, pl);
5907               M17N_OBJECT_UNREF (pl);
5908               pl = mplist_add (pl, Msymbol, Mvariable);
5909               MPLIST_DO (p, custom->vars)
5910                 if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
5911                   pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
5912             }
5913         }
5914       if (elt)
5915         {
5916           pl = mplist ();
5917           mplist_push (elt, Mplist, pl);
5918           M17N_OBJECT_UNREF (pl);
5919           pl = mplist_add (pl, Msymbol, Minput_method);
5920           pl = mplist_add (pl, Msymbol, language);
5921           pl = mplist_add (pl, Msymbol, name);
5922           if (extra != Mnil)
5923             pl = mplist_add (pl, Msymbol, extra);
5924           tail = mplist_add (tail, Mplist, elt);
5925           M17N_OBJECT_UNREF (elt);
5926         }
5927     }
5928
5929   mplist_push (data, Mstring, ";; -*- mode:lisp; coding:utf-8 -*-");
5930   ret = mdatabase__save (im_custom_mdb, data);
5931   mdatabase__unlock (im_custom_mdb);
5932   M17N_OBJECT_UNREF (data);
5933   return (ret < 0 ? -1 : 1);
5934 }
5935
5936 /***en
5937     @brief List available input methods.
5938
5939     The minput_list () function returns a list of currently available
5940     input methods whose language is $LANGUAGE.  If $LANGUAGE is #Mnil,
5941     all input methods are listed.
5942
5943     @return
5944     The returned value is a plist of this form:
5945         ((LANGUAGE-NAME INPUT-METHOD-NAME SANE) ...)
5946     The third element SANE of each input method is #Mt if it can be
5947     successfully used, or #Mnil if it has some problem (e.g. syntax
5948     error of MIM file, unavailable external module, unavailable
5949     including input method).  */
5950
5951 #if EXAMPLE_CODE
5952 #include <stdio.h>
5953 #include <string.h>
5954 #include <m17n.h>
5955
5956 int
5957 main (int argc, char **argv)
5958 {
5959   MPlist *imlist, *pl;
5960
5961   M17N_INIT ();
5962   imlist = minput_list ((argc > 1) ? msymbol (argv[1]) : Mnil);
5963   for (pl = imlist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
5964     {
5965       MPlist *p = mplist_value (pl);
5966       MSymbol lang, name, sane;
5967
5968       lang = mplist_value (p);
5969       p = mplist_next (p);
5970       name = mplist_value (p);
5971       p = mplist_next (p);
5972       sane = mplist_value (p);
5973
5974       printf ("%s %s %s\n", msymbol_name (lang), msymbol_name (name),
5975               sane == Mt ? "ok" : "no");
5976     }
5977
5978   m17n_object_unref (imlist);
5979   M17N_FINI ();
5980   exit (0);
5981 }
5982 #endif
5983
5984 MPlist *
5985 minput_list (MSymbol language)
5986 {
5987   MPlist *plist, *pl;
5988   MPlist *imlist = mplist ();
5989   
5990   MINPUT__INIT ();
5991   plist = mdatabase_list (Minput_method, language, Mnil, Mnil);
5992   if (! plist)
5993     return imlist;
5994   MPLIST_DO (pl, plist)
5995     {
5996       MDatabase *mdb = MPLIST_VAL (pl);
5997       MSymbol *tag = mdatabase_tag (mdb);
5998       MPlist *imdata, *p, *elm;
5999       int num_maps = 0, num_states = 0;
6000
6001       if (tag[2] == Mnil)
6002         continue;
6003       imdata = mdatabase_load (mdb);
6004       if (! imdata)
6005         continue;
6006       MPLIST_DO (p, imdata)
6007         if (MPLIST_PLIST_P (p))
6008           {
6009             /* Check these basic functionarity:
6010                All external modules (if any) are loadable.
6011                All included input method (if any) are loadable.
6012                At least one map is defined or included.
6013                At least one state is defined or included. */
6014             MPlist *elt = MPLIST_PLIST (p);
6015             MSymbol key;
6016
6017             if (MFAILP (MPLIST_SYMBOL_P (elt)))
6018               break;
6019             key = MPLIST_SYMBOL (elt);
6020             if (key == Mmap)
6021               num_maps++;
6022             else if (key == Mstate)
6023               num_states++;
6024             else if (key == Mmodule)
6025               {
6026                 MPLIST_DO (elt, MPLIST_NEXT (elt))
6027                   {
6028                     MIMExternalModule *external;
6029
6030                     if (MFAILP (MPLIST_PLIST_P (elt)))
6031                       break;
6032                     external = load_external_module (MPLIST_PLIST (elt));
6033                     if (MFAILP (external))
6034                       break;
6035                     unload_external_module (external);
6036                   }
6037                 if (! MPLIST_TAIL_P (elt))
6038                   break;
6039               }
6040             else if (key == Minclude)
6041               {
6042                 MInputMethodInfo *im_info;
6043
6044                 elt = MPLIST_NEXT (elt);
6045                 if (MFAILP (MPLIST_PLIST_P (elt)))
6046                   break;
6047                 im_info = get_im_info_by_tags (MPLIST_PLIST (elt));
6048                 if (MFAILP (im_info))
6049                   break;
6050                 elt = MPLIST_NEXT (elt);
6051                 if (MFAILP (MPLIST_SYMBOL_P (elt)))
6052                   break;
6053                 key = MPLIST_SYMBOL (elt);
6054                 if (key == Mmap)
6055                   {
6056                     if (! im_info->maps)
6057                       break;
6058                     num_maps++;
6059                   }
6060                 else if (key == Mstate)
6061                   {
6062                     if (! im_info->states)
6063                       break;
6064                     num_states++;
6065                   }
6066               }
6067           }
6068       elm = mplist ();
6069       mplist_add (elm, Msymbol, tag[1]);
6070       mplist_add (elm, Msymbol, tag[2]);
6071       if (MPLIST_TAIL_P (p) && num_maps > 0 && num_states > 0)
6072         mplist_add (elm, Msymbol, Mt);
6073       else
6074         mplist_add (elm, Msymbol, Mnil);
6075       mplist_push (imlist, Mplist, elm);
6076       M17N_OBJECT_UNREF (elm);
6077       M17N_OBJECT_UNREF (imdata);
6078     }
6079   M17N_OBJECT_UNREF (plist);
6080   return imlist;
6081 }
6082
6083 /*=*/
6084 /*** @} */
6085 /*=*/
6086 /***en
6087     @name Obsolete functions
6088 */
6089 /***ja
6090     @name Obsolete ¤Ê´Ø¿ô
6091 */
6092 /*** @{ */
6093
6094 /*=*/
6095 /***en
6096     @brief Get a list of variables of an input method (obsolete).
6097
6098     This function is obsolete.  Use minput_get_variable () instead.
6099
6100     The minput_get_variables () function returns a plist (#MPlist) of
6101     variables used to control the behavior of the input method
6102     specified by $LANGUAGE and $NAME.  The plist is @e well-formed
6103     (@ref m17nPlist) of the following format:
6104
6105 @verbatim
6106     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
6107      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
6108      ...)
6109 @endverbatim
6110
6111     @c VARNAME is a symbol representing the variable name.
6112
6113     @c DOC-MTEXT is an M-text describing the variable.
6114
6115     @c DEFAULT-VALUE is the default value of the variable.  It is a
6116     symbol, integer, or M-text.
6117
6118     @c VALUEs (if any) specifies the possible values of the variable.
6119     If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
6120     @c TO), where @c FROM and @c TO specifies a range of possible
6121     values.
6122
6123     For instance, suppose an input method has the variables:
6124
6125     @li name:intvar, description:"value is an integer",
6126          initial value:0, value-range:0..3,10,20
6127
6128     @li name:symvar, description:"value is a symbol",
6129          initial value:nil, value-range:a, b, c, nil
6130
6131     @li name:txtvar, description:"value is an M-text",
6132          initial value:empty text, no value-range (i.e. any text)
6133
6134     Then, the returned plist is as follows.
6135
6136 @verbatim
6137     (intvar ("value is an integer" 0 (0 3) 10 20)
6138      symvar ("value is a symbol" nil a b c nil)
6139      txtvar ("value is an M-text" ""))
6140 @endverbatim
6141
6142     @return
6143     If the input method uses any variables, a pointer to #MPlist is
6144     returned.  As the plist is kept in the library, the caller must not
6145     modify nor free it.  If the input method does not use any
6146     variable, @c NULL is returned.  */
6147 /***ja
6148     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
6149
6150     ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
6151     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
6152     (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(@ref m17nPlist) °Ê
6153     ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
6154
6155 @verbatim
6156     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
6157      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
6158      ...)
6159 @endverbatim
6160
6161     @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
6162
6163     @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
6164
6165     @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
6166     M-text ¤Ç¤¢¤ë¡£
6167
6168     @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
6169     @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
6170     ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
6171
6172     Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
6173
6174     @li name:intvar, ÀâÌÀ:"value is an integer",
6175         ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
6176
6177     @li name:symvar, ÀâÌÀ:"value is a symbol",
6178          ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
6179
6180     @li name:txtvar, ÀâÌÀ:"value is an M-text",
6181         ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
6182
6183     ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
6184
6185 @verbatim
6186     (intvar ("value is an integer" 0 (0 3) 10 20)
6187      symvar ("value is a symbol" nil a b c nil)
6188      txtvar ("value is an M-text" ""))
6189 @endverbatim
6190
6191     @return 
6192     ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
6193     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
6194     ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
6195
6196 MPlist *
6197 minput_get_variables (MSymbol language, MSymbol name)
6198 {
6199   MInputMethodInfo *im_info;
6200   MPlist *vars;
6201
6202   MINPUT__INIT ();
6203
6204   im_info = get_im_info (language, name, Mnil, Mvariable);
6205   if (! im_info || ! im_info->configured_vars)
6206     return NULL;
6207
6208   M17N_OBJECT_UNREF (im_info->bc_vars);
6209   im_info->bc_vars = mplist ();
6210   MPLIST_DO (vars, im_info->configured_vars)
6211     {
6212       MPlist *plist = MPLIST_PLIST (vars);
6213       MPlist *elt = mplist ();
6214
6215       mplist_push (im_info->bc_vars, Mplist, elt);
6216       mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
6217       elt = MPLIST_NEXT (elt);
6218       mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
6219       M17N_OBJECT_UNREF (elt);
6220     }
6221   return im_info->bc_vars;
6222 }
6223
6224 /*=*/
6225
6226 /***en
6227     @brief Set the initial value of an input method variable.
6228
6229     The minput_set_variable () function sets the initial value of
6230     input method variable $VARIABLE to $VALUE for the input method
6231     specified by $LANGUAGE and $NAME.
6232
6233     By default, the initial value is 0.
6234
6235     This setting gets effective in a newly opened input method.
6236
6237     @return
6238     If the operation was successful, 0 is returned.  Otherwise -1 is
6239     returned, and #merror_code is set to @c MERROR_IM.  */
6240 /***ja
6241     @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
6242
6243     ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
6244     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
6245     ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
6246
6247     ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
6248
6249     ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
6250
6251     @return
6252     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
6253     #merror_code ¤ò @c MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
6254
6255 int
6256 minput_set_variable (MSymbol language, MSymbol name,
6257                      MSymbol variable, void *value)
6258 {
6259   MPlist *plist, *pl;
6260   MInputMethodInfo *im_info;
6261   int ret;
6262
6263   MINPUT__INIT ();
6264
6265   if (variable == Mnil)
6266     MERROR (MERROR_IM, -1);
6267   plist = minput_get_variable (language, name, variable);
6268   plist = MPLIST_PLIST (plist);
6269   plist = MPLIST_NEXT (plist);
6270   pl = mplist ();
6271   mplist_add (pl, MPLIST_KEY (plist), value);
6272   ret = minput_config_variable (language, name, variable, pl);
6273   M17N_OBJECT_UNREF (pl);
6274   if (ret == 0)
6275     {
6276       im_info = get_im_info (language, name, Mnil, Mvariable);
6277       im_info->tick = 0;
6278     }
6279   return ret;
6280 }
6281
6282 /*=*/
6283
6284 /***en
6285     @brief Get information about input method commands.
6286
6287     The minput_get_commands () function returns information about
6288     input method commands of the input method specified by $LANGUAGE
6289     and $NAME.  An input method command is a pseudo key event to which
6290     one or more actual input key sequences are assigned.
6291
6292     There are two kinds of commands, global and local.  Global
6293     commands are used by multiple input methods for the same purpose,
6294     and have global key assignments.  Local commands are used only by
6295     a specific input method, and have only local key assignments.
6296
6297     Each input method may locally change key assignments for global
6298     commands.  The global key assignment for a global command is
6299     effective only when the current input method does not have local
6300     key assignments for that command.
6301
6302     If $NAME is #Mnil, information about global commands is returned.
6303     In this case $LANGUAGE is ignored.
6304
6305     If $NAME is not #Mnil, information about those commands that have
6306     local key assignments in the input method specified by $LANGUAGE
6307     and $NAME is returned.
6308
6309     @return
6310     If no input method commands are found, this function returns @c NULL.
6311
6312     Otherwise, a pointer to a plist is returned.  The key of each
6313     element in the plist is a symbol representing a command, and the
6314     value is a plist of the form COMMAND-INFO described below.
6315
6316     The first element of COMMAND-INFO has the key #Mtext, and the
6317     value is an M-text describing the command.
6318
6319     If there are no more elements, that means no key sequences are
6320     assigned to the command.  Otherwise, each of the remaining
6321     elements has the key #Mplist, and the value is a plist whose keys are
6322     #Msymbol and values are symbols representing input keys, which are
6323     currently assigned to the command.
6324
6325     As the returned plist is kept in the library, the caller must not
6326     modify nor free it.  */
6327 /***ja
6328     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
6329
6330     ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
6331     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
6332     ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
6333     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
6334
6335     ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
6336     ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
6337     ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
6338     ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
6339
6340     ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
6341     ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
6342     ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
6343     ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
6344
6345     $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
6346     ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
6347
6348     $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
6349     Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
6350     ¤òÊÖ¤¹¡£
6351
6352     @return
6353     ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
6354
6355     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
6356     ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
6357     ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
6358
6359     COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
6360     ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
6361     #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
6362     ¤¤¤³¤È¤Ë¤Ê¤ë¡£
6363
6364     ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
6365     ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
6366     ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
6367     ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
6368     ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
6369
6370     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
6371     ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
6372
6373 MPlist *
6374 minput_get_commands (MSymbol language, MSymbol name)
6375 {
6376   MInputMethodInfo *im_info;
6377   MPlist *cmds;
6378
6379   MINPUT__INIT ();
6380
6381   im_info = get_im_info (language, name, Mnil, Mcommand);
6382   if (! im_info || ! im_info->configured_vars)
6383     return NULL;
6384   M17N_OBJECT_UNREF (im_info->bc_cmds);
6385   im_info->bc_cmds = mplist ();
6386   MPLIST_DO (cmds, im_info->configured_cmds)
6387     {
6388       MPlist *plist = MPLIST_PLIST (cmds);
6389       MPlist *elt = mplist ();
6390
6391       mplist_push (im_info->bc_cmds, Mplist, elt);
6392       mplist_add (elt, MPLIST_SYMBOL (plist),
6393                   mplist_copy (MPLIST_NEXT (plist)));
6394       M17N_OBJECT_UNREF (elt);
6395     }
6396   return im_info->bc_cmds;
6397 }
6398
6399 /*=*/
6400
6401 /***en
6402     @brief Assign a key sequence to an input method command (obsolete).
6403
6404     This function is obsolete.  Use minput_config_command () instead.
6405
6406     The minput_assign_command_keys () function assigns input key
6407     sequence $KEYSEQ to input method command $COMMAND for the input
6408     method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
6409     key sequence is assigned globally no matter what $LANGUAGE is.
6410     Otherwise the key sequence is assigned locally.
6411
6412     Each element of $KEYSEQ must have the key $Msymbol and the value
6413     must be a symbol representing an input key.
6414
6415     $KEYSEQ may be @c NULL, in which case, all assignments are deleted
6416     globally or locally.
6417
6418     This assignment gets effective in a newly opened input method.
6419
6420     @return
6421     If the operation was successful, 0 is returned.  Otherwise -1 is
6422     returned, and #merror_code is set to @c MERROR_IM.  */
6423 /***ja
6424     @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
6425
6426     ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
6427     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
6428     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
6429     $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
6430     ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
6431
6432     $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
6433     ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
6434
6435     $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
6436     ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
6437
6438     ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
6439     ¸ú¤Ë¤Ê¤ë¡£
6440
6441     @return 
6442     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
6443     #merror_code ¤ò @c MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
6444
6445 int
6446 minput_assign_command_keys (MSymbol language, MSymbol name,
6447                             MSymbol command, MPlist *keyseq)
6448 {
6449   int ret;
6450
6451   MINPUT__INIT ();
6452
6453   if (command == Mnil)
6454     MERROR (MERROR_IM, -1);
6455   if (keyseq)
6456     {
6457       MPlist *plist;
6458
6459       if  (! check_command_keyseq (keyseq))
6460         MERROR (MERROR_IM, -1);
6461       plist = mplist ();
6462       mplist_add (plist, Mplist, keyseq);
6463       keyseq = plist;
6464     }  
6465   else
6466     keyseq = mplist ();
6467   ret = minput_config_command (language, name, command, keyseq);
6468   M17N_OBJECT_UNREF (keyseq);
6469   return ret;
6470 }
6471
6472 /*=*/
6473
6474 /***en
6475     @brief Call a callback function
6476
6477     The minput_callback () functions calls a callback function
6478     $COMMAND assigned for the input context $IC.  The caller must set
6479     specific elements in $IC->plist if the callback function requires.
6480
6481     @return
6482     If there exists a specified callback function, 0 is returned.
6483     Otherwise -1 is returned.  By side effects, $IC->plist may be
6484     modified.  */
6485
6486 int
6487 minput_callback (MInputContext *ic, MSymbol command)
6488 {
6489   MInputCallbackFunc func;
6490
6491   if (! ic->im->driver.callback_list)
6492     return -1;
6493   func = ((MInputCallbackFunc)
6494           mplist_get_func (ic->im->driver.callback_list, command));
6495   if (! func)
6496     return -1;
6497   (func) (ic, command);
6498   return 0;
6499 }
6500
6501 /*** @} */ 
6502 /*** @} */
6503 /*=*/
6504 /*** @addtogroup m17nDebug */
6505 /*=*/
6506 /*** @{  */
6507 /*=*/
6508
6509 /***en
6510     @brief Dump an input method.
6511
6512     The mdebug_dump_im () function prints the input method $IM in a
6513     human readable way to the stderr or to what specified by the
6514     environment variable MDEBUG_OUTPUT_FILE.  $INDENT specifies how
6515     many columns to indent the lines but the first one.
6516
6517     @return
6518     This function returns $IM.  */
6519 /***ja
6520     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
6521
6522     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤òɸ½à¥¨¥é¡¼½ÐÎϤ⤷¤¯¤Ï
6523     ´Ä¶­ÊÑ¿ô MDEBUG_DUMP_FONT ¤Ç»ØÄꤵ¤ì¤¿¥Õ¥¡¥¤¥ë¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç½Ð
6524     ÎϤ¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
6525
6526     @return
6527     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
6528
6529 MInputMethod *
6530 mdebug_dump_im (MInputMethod *im, int indent)
6531 {
6532   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
6533   char *prefix;
6534
6535   prefix = (char *) alloca (indent + 1);
6536   memset (prefix, 32, indent);
6537   prefix[indent] = '\0';
6538
6539   fprintf (mdebug__output, "(input-method %s %s ", msymbol_name (im->language),
6540            msymbol_name (im->name));
6541   mdebug_dump_mtext (im_info->title, 0, 0);
6542   if (im->name != Mnil)
6543     {
6544       MPlist *state;
6545
6546       MPLIST_DO (state, im_info->states)
6547         {
6548           fprintf (mdebug__output, "\n%s  ", prefix);
6549           dump_im_state (MPLIST_VAL (state), indent + 2);
6550         }
6551     }
6552   fprintf (mdebug__output, ")");
6553   return im;
6554 }
6555
6556 /*** @} */ 
6557
6558 /*
6559   Local Variables:
6560   coding: euc-japan
6561   End:
6562 */