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