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