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