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