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