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