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