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