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