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