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