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