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