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