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