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