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