7b8ea5a1dc3484c24c2b238618eac585368e2d91
[m17n/m17n-lib.git] / src / input.c
1 /* input.c -- input method module.
2    Copyright (C) 2003, 2004, 2005
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nInputMethod
25     @brief API for Input method.
26
27     An input method is an object to enable inputting various
28     characters.  An input method is identified by a pair of symbols,
29     LANGUAGE and NAME.  This pair decides an input method driver of the
30     input method.  An input method driver is a set of functions for
31     handling the input method.  There are two kinds of input methods;
32     internal one and foreign one.
33
34     <ul>
35     <li> Internal Input Method
36
37     An internal input method has non @c Mnil LANGUAGE, and its body is
38     defined in the m17n database by the tag <Minput_method, LANGUAGE,
39     NAME>.  For this kind of input methods, the m17n library uses two
40     predefined input method drivers, one for CUI use and the other for
41     GUI use.  Those drivers utilize the input processing engine
42     provided by the m17n library itself.  The m17n database may
43     provide input methods that are not limited to a specific language.
44     The database uses @c Mt as LANGUAGE of those input methods.
45
46     An internal input method accepts an input key which is a symbol
47     associated with an input event.  As there is no way for the @c
48     m17n @c library to know how input events are represented in an
49     application program, an application programmer has to convert an
50     input event to an input key by himself.  See the documentation of
51     the function minput_event_to_key () for the detail.
52
53     <li> Foreign Input Method
54
55     A foreign input method has @c Mnil LANGUAGE, and its body is
56     defined in an external resource (e.g. XIM of X Window System).
57     For this kind of input methods, the symbol NAME must have a
58     property of key @c Minput_driver, and the value must be a pointer
59     to an input method driver.  Therefore, by preparing a proper
60     driver, any kind of input method can be treated in the framework
61     of the @c m17n @c library.
62
63     For convenience, the m17n-X library provides an input method
64     driver that enables the input style of OverTheSpot for XIM, and
65     stores @c Minput_driver property of the symbol @c Mxim with a
66     pointer to the driver.  See the documentation of m17n GUI API for
67     the detail.
68
69     </ul>
70
71     PROCESSING FLOW
72
73     The typical processing flow of handling an input method is: 
74
75      @li open an input method
76      @li create an input context for the input method
77      @li filter an input key
78      @li look up a produced text in the input context  */
79
80 /*=*/
81 /***ja
82     @addtogroup m17nInputMethod
83     @brief ÆþÎϥ᥽¥Ã¥ÉÍÑAPI.
84
85     ÆþÎϥ᥽¥Ã¥É¤Ï¿ÍͤÊʸ»ú¤òÆþÎϤ¹¤ë¤¿¤á¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£
86     ÆþÎϥ᥽¥Ã¥É¤Ï¥·¥ó¥Ü¥ë LANGUAGE ¤È NAME ¤ÎÁȤˤè¤Ã¤Æ¼±Ê̤µ¤ì¡¢
87     ¤³¤ÎÁȹ礻¤Ë¤è¤Ã¤ÆÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤¬·èÄꤹ¤ë¡£
88     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤È¤Ï¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤ò°·¤¦¤¿¤á¤Î´Ø¿ô¤Î½¸¤Þ¤ê¤Ç¤¢¤ë¡£
89     ÆþÎϥ᥽¥Ã¥É¤Ë¤ÏÆâÉô¥á¥½¥Ã¥É¤È³°Éô¥á¥½¥Ã¥É¤ÎÆó¼ïÎब¤¢¤ë¡£
90
91     <ul> 
92     <li> ÆâÉôÆþÎϥ᥽¥Ã¥É
93
94     ÆâÉôÆþÎϥ᥽¥Ã¥É¤È¤Ï LANGUAGE ¤¬ @c Mnil °Ê³°¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂΤÏm17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë
95     <Minput_method, LANGUAGE, NAME> 
96     ¤È¤¤¤¦¥¿¥°¤òÉÕ¤±¤ÆÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£
97     ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤ËÂФ·¤Æ¡¢m17n ¥é¥¤¥Ö¥é¥ê¤Ç¤Ï
98     CUI ÍѤȠGUI ÍѤ½¤ì¤¾¤ì¤ÎÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤ò¤¢¤é¤«¤¸¤áÄêµÁ¤·¤Æ¤¤¤ë¡£
99     ¤³¤ì¤é¤Î¥É¥é¥¤¥Ð¤Ï m17n ¥é¥¤¥Ö¥é¥ê¼«ÂΤÎÆþÎϽèÍý¥¨¥ó¥¸¥ó¤òÍøÍѤ¹¤ë¡£
100     m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤Ï¡¢ÆÃÄê¤Î¸À¸ìÀìÍѤǤʤ¤ÆþÎϥ᥽¥Ã¥É¤òÄêµÁ¤¹¤ë¤³¤È¤â¤Ç¤­¡¢
101     ¤½¤Î¤è¤¦¤ÊÆþÎϥ᥽¥Ã¥É¤Î LANGUAGE ¤Ï @c Mt ¤Ç¤¢¤ë¡£
102
103     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï¡¢¥æ¡¼¥¶¤ÎÆþÎÏ¥¤¥Ù¥ó¥È¤ËÂбþ¤·¤¿¥·¥ó¥Ü¥ë¤Ç¤¢¤ëÆþÎÏ¥­¡¼¤ò¼õ¤±¼è¤ë¡£
104     @c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÏÆþÎÏ¥¤¥Ù¥ó¥È¤¬¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ç¤É¤¦É½¸½¤µ¤ì¤Æ¤¤¤ë¤«¤òÃΤ뤳¤È¤¬¤Ç¤­¤Ê¤¤¤Î¤Ç¡¢
105     ÆþÎÏ¥¤¥Ù¥ó¥È¤«¤éÆþÎÏ¥­¡¼¤Ø¤ÎÊÑ´¹¤Ï¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥Þ¤ÎÀÕǤ¤Ç¹Ô¤ï¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
106     ¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï´Ø¿ô minput_event_to_key () ¤ÎÀâÌÀ¤ò»²¾È¡£
107
108     <li> ³°ÉôÆþÎϥ᥽¥Ã¥É
109
110     ³°ÉôÆþÎϥ᥽¥Ã¥É¤È¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂΤϳ°Éô¤Î¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£
111     ¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê¤É¡£) 
112     ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï@c Minput_driver 
113     ¤ò¥­¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£
114     ¤³¤Î¤³¤È¤Ë¤è¤ê¡¢Å¬Àڤʥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢¤¤¤«¤Ê¤ë¼ïÎà¤ÎÆþÎϥ᥽¥Ã¥É¤â
115     @c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÎÏÈÁȤÎÃæ¤Ç°·¤¦»ö¤¬¤Ç¤­¤ë¡£
116
117     ÍøÊØÀ­¤Î´ÑÅÀ¤«¤é¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤Ï XIM ¤Î OverTheSpot 
118     ¤ÎÆþÎÏ¥¹¥¿¥¤¥ë¤ò¼Â¸½¤¹¤ëÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤òÄ󶡤·¡¢¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î 
119     @c Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý¤·¤Æ¤¤¤ë¡£
120     ¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï m17n GUI API ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
121
122     </ul> 
123
124     ½èÍý¤Îή¤ì
125
126     ÆþÎϥ᥽¥Ã¥É½èÍý¤Îŵ·¿Åª¤Ê½èÍý¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
127     
128     @li ÆþÎϥ᥽¥Ã¥É¤Î¥ª¡¼¥×¥ó
129     @li ¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ÎÀ¸À®
130     @li ÆþÎÏ¥¤¥Ù¥ó¥È¤Î¥Õ¥£¥ë¥¿
131     @li ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ç¤ÎÀ¸À®¥Æ¥­¥¹¥È¤Î¸¡º÷     */
132
133 /*=*/
134
135 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
136 /*** @addtogroup m17nInternal
137      @{ */
138
139 #include <stdio.h>
140 #include <stdlib.h>
141 #include <string.h>
142 #include <sys/types.h>
143 #include <dirent.h>
144 #include <sys/stat.h>
145 #include <unistd.h>
146
147 #include "config.h"
148
149 #ifdef HAVE_DLFCN_H
150 #include <dlfcn.h>
151 #endif
152
153 #include "m17n-gui.h"
154 #include "m17n-misc.h"
155 #include "internal.h"
156 #include "mtext.h"
157 #include "input.h"
158 #include "symbol.h"
159 #include "plist.h"
160 #include "database.h"
161 #include "charset.h"
162
163 static int mdebug_mask = MDEBUG_INPUT;
164
165 static MSymbol Minput_method;
166
167 /** Symbols to load an input method data.  */
168 static MSymbol Mtitle, Mmacro, Mmodule, Mstate, Minclude;
169
170 /** Symbols for actions.  */
171 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
172 static MSymbol Mselect, Mshow, Mhide, Mcommit, Munhandle;
173 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
174 static MSymbol Mless_equal, Mgreater_equal;
175 static MSymbol Mcond;
176 static MSymbol Mplus, Mminus, Mstar, Mslush, Mand, Mor, Mnot;
177
178 static MSymbol M_candidates;
179
180 static MSymbol Mcandidate_list, Mcandidate_index;
181
182 static MSymbol Minit, Mfini;
183
184 /** Symbols for variables.  */
185 static MSymbol Mcandidates_group_size, Mcandidates_charset;
186
187 /** Symbols for key events.  */
188 static MSymbol one_char_symbol[256];
189
190 static MSymbol M_key_alias;
191
192 static MSymbol M_description, M_command, M_variable;
193
194 /** Structure to hold a map.  */
195
196 struct MIMMap
197 {
198   /** List of actions to take when we reach the map.  In a root map,
199       the actions are executed only when there's no more key.  */
200   MPlist *map_actions;
201
202   /** List of deeper maps.  If NULL, this is a terminal map.  */
203   MPlist *submaps;
204
205   /** List of actions to take when we leave the map successfully.  In
206       a root map, the actions are executed only when none of submaps
207       handle the current key.  */
208   MPlist *branch_actions;
209 };
210
211 typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
212
213 typedef struct
214 {
215   void *handle;
216   MPlist *func_list;            /* function name vs (MIMExternalFunc *) */
217 } MIMExternalModule;
218
219 struct MIMState
220 {
221   M17NObject control;
222
223   /** Name of the state.  */
224   MSymbol name;
225
226   /** Title of the state, or NULL.  */
227   MText *title;
228
229   /** Key translation map of the state.  Built by merging all maps of
230       branches.  */
231   MIMMap *map;
232 };
233
234 /* Lookup keys KEY1,2,3 in the nested plist PLIST, and return the
235    value.  */
236
237 static MPlist *
238 lookup_nested_list (MPlist *plist, MSymbol key1, MSymbol key2, MSymbol key3)
239 {
240   MSymbol key[3];
241   int i;
242
243   key[0] = key1, key[1] = key2, key[2] = key3;
244   for (i = 0; i < 3; i++)
245     {
246       plist = mplist_find_by_value (plist, key[i]);
247       if (! plist)
248         return NULL;
249       plist = MPLIST_NEXT (plist);
250       plist = MPLIST_PLIST (plist);
251     }
252   return plist;
253 }
254
255 /* Set VAL for keys KEY1,2,3 in the nested plist PLIST.  */
256
257 static MPlist *
258 set_nested_list (MPlist *plist, MSymbol key1, MSymbol key2, MSymbol key3,
259                  MPlist *val)
260 {
261   MSymbol key[3];
262   int i;
263   MPlist *pl;
264
265   key[0] = key1, key[1] = key2, key[2] = key3;
266   for (i = 0; i < 3; i++)
267     {
268       pl = mplist_find_by_value (plist, key[i]);
269       if (pl)
270         {
271           pl = MPLIST_NEXT (pl);
272           plist = MPLIST_PLIST (pl);
273         }
274       else
275         {
276           pl = mplist_add (plist, Msymbol, key[i]);
277           plist = mplist ();
278           pl = mplist_add (pl, Mplist, plist);
279           M17N_OBJECT_UNREF (plist);
280         }
281     }
282   mplist_set (pl, Mplist, val);
283   M17N_OBJECT_UNREF (val);
284   return pl;
285 }
286
287 /* Parse PLIST as a value of nested list and return an adjusted list.
288
289    PLIST has this form;
290      (symbol:command
291       plist:(symbol:KEY
292              [ mtext:DESCRIPTION | symbol:nil ]
293              ;; The remaining elements are checked CHECK_FUNC.
294              ...)
295       plist:(symbol:KEY
296              [ mtext:DESCRIPTION | symbol:nil ]
297              ;; The remaining elements are checked CHECK_FUNC.
298              ...)
299       ...)
300
301    GLOBAL is a global list.  If a description text is missing, it is
302    extracted from GLOBAL.
303
304    The return value is a plist of this format:
305      (symbol:KEY
306       plist:([ mtext:DESCRIPTION | symbol:nil ]
307              ...)
308       symbol:KEY
309       plist:([ mtext:DESCRIPTION | symbol:nil ]
310              ...)
311       ...)
312
313    PLIST itself is unref-ed.  */
314
315 static MPlist *
316 parse_nested_list_value (MPlist *plist, MPlist *global, MSymbol key,
317                          int (*check_func) (MPlist *))
318 {
319   MPlist *val, *pl, *p, *p0;
320
321   val = mplist ();
322   if (! MPLIST_PLIST_P (plist))
323     {
324       M17N_OBJECT_UNREF (plist);
325       return val;
326     }
327   pl = MPLIST_PLIST (plist);
328   if (! MPLIST_SYMBOL_P (pl)
329       || MPLIST_SYMBOL (pl) != key)
330     {
331       M17N_OBJECT_UNREF (plist);
332       return val;
333     }
334
335   MPLIST_DO (pl, MPLIST_NEXT (pl))
336     {
337       MSymbol name;
338       MPlist *global_def = NULL;
339
340       if (! MPLIST_PLIST_P (pl))
341         continue;
342       p = MPLIST_PLIST (pl);
343       if (! MPLIST_SYMBOL_P (p))
344         continue;
345       name = MPLIST_SYMBOL (p);
346       p = MPLIST_NEXT (p);
347       if (MPLIST_TAIL_P (p))
348         {
349           if (! global)
350             continue;
351           global_def = mplist_find_by_value (global, name);
352           if (! global_def)
353             continue;
354           global_def = MPLIST_PLIST (MPLIST_NEXT (global_def));
355           mplist__conc (p, global_def);
356         }
357       p0 = MPLIST_NEXT (p);
358       if (MPLIST_TAIL_P (p0))
359         {
360           if (! global || global_def)
361             continue;
362           global_def = mplist_find_by_value (global, name);
363           if (! global_def)
364             continue;
365           global_def = MPLIST_PLIST (MPLIST_NEXT (global_def));
366           global_def = MPLIST_NEXT (global_def);
367           if (MPLIST_TAIL_P (global_def))
368             continue;
369           mplist__conc (p0, global_def);
370         }
371       if ((*check_func) (p0) < 0)
372         continue;
373       mplist_add (val, Msymbol, name);
374       mplist_add (val, Mplist, p);
375     }
376
377   M17N_OBJECT_UNREF (plist);
378   return val;
379 }
380
381 static MPlist *variable_list, *command_list;
382 static int check_variable_list (MPlist *plist);
383 static int check_command_list (MPlist *plist);
384 static MPlist *load_partial_im_info (MSymbol language, MSymbol name,
385                                      MSymbol extra, MSymbol key);
386
387 static MPlist *
388 get_nested_list (MSymbol language, MSymbol name, MSymbol extra, MSymbol key)
389 {
390   MPlist *total_list;
391   int (*check_func) (MPlist *);
392   MPlist *plist, *global;
393
394   if (key == M_variable)
395     {
396       if (! variable_list)
397         variable_list = mplist ();
398       total_list = variable_list;
399       check_func = check_variable_list;
400     }
401   else
402     {
403       if (! command_list)
404         command_list = mplist ();
405       total_list = command_list;
406       check_func = check_command_list;
407     }
408
409   if (MPLIST_TAIL_P (total_list))
410     {
411       plist = load_partial_im_info (Mt, Mnil, key, key);
412       if (plist)
413         global = parse_nested_list_value (plist, NULL, key, check_func);
414       else
415         global = mplist ();
416       set_nested_list (total_list, Mt, Mnil, key, global);
417     }
418   else
419     global = lookup_nested_list (total_list, Mt, Mnil, key);
420
421   if (name == Mnil)
422     return global;
423
424   plist = lookup_nested_list (total_list, language, name, extra);
425   if (plist)
426     return plist;
427
428   plist = load_partial_im_info (language, name, extra, key);
429   if (plist)
430     plist = parse_nested_list_value (plist, global, key, check_func);
431   else
432     plist = mplist ();
433   set_nested_list (total_list, language, name, extra, plist);
434   return plist;
435 }
436
437 static int
438 marker_code (MSymbol sym)
439 {
440   char *name;
441
442   if (sym == Mnil)
443     return -1;
444   name = MSYMBOL_NAME (sym);
445   return ((name[0] == '@'
446            && ((name[1] >= '0' && name[1] <= '9')
447                || name[1] == '<' || name[1] == '>'
448                || name[1] == '=' || name[1] == '+' || name[1] == '-'
449                || name[1] == '[' || name[1] == ']'
450                || name[1] == '@')
451            && name[2] == '\0')
452           ? name[1] : -1);
453 }
454
455
456 static MPlist *
457 resolve_variable (MInputContextInfo *ic_info, MSymbol var)
458 {
459   MPlist *p;
460
461   MPLIST_DO (p, ic_info->vars)
462     {
463       if (MPLIST_SYMBOL (p) == var)
464         break;
465       p = MPLIST_NEXT (p);
466     }
467   if (MPLIST_TAIL_P (p))
468     {
469       p = ic_info->vars;
470       mplist_push (p, Minteger, (void *) 0);
471       mplist_push (p, Msymbol, var);
472     }
473   return (MPLIST_NEXT (p));
474 }
475
476 static MText *
477 get_surrounding_text (MInputContext *ic, int len)
478 {
479   MText *mt = NULL;
480
481   mplist_push (ic->plist, Minteger, (void *) len);
482   minput__callback (ic, Minput_get_surrounding_text);
483   if (MPLIST_MTEXT_P (ic->plist))
484     {
485       mt = MPLIST_MTEXT (ic->plist);
486       mplist_pop (ic->plist);
487     }
488   return mt;
489 }
490
491 static void
492 delete_surrounding_text (MInputContext *ic, int pos)
493 {
494   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
495
496   mplist_push (ic->plist, Minteger, (void *) pos);
497   minput__callback (ic, Minput_delete_surrounding_text);
498   mplist_pop (ic->plist);
499   if (pos < 0)
500     M17N_OBJECT_UNREF (ic_info->preceding_text);
501   else if (pos > 0)
502     M17N_OBJECT_UNREF (ic_info->following_text);
503 }
504
505 static int
506 get_preceding_char (MInputContext *ic, int pos)
507 {
508   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
509   MText *mt;
510   int len;
511
512   if (ic_info->preceding_text)
513     {
514       len = mtext_nchars (ic_info->preceding_text);
515       if (pos <= len)
516         return mtext_ref_char (ic_info->preceding_text, len - pos);
517     }
518   mt = get_surrounding_text (ic, - pos);
519   if (! mt)
520     return -1;
521   len = mtext_nchars (mt);
522   if (ic_info->preceding_text)
523     {
524       if (mtext_nchars (ic_info->preceding_text) < len)
525         {
526           M17N_OBJECT_UNREF (ic_info->preceding_text);
527           ic_info->preceding_text = mt;
528         }
529     }
530   else
531     ic_info->preceding_text = mt;
532   if (pos > len)
533     return -1;
534   return mtext_ref_char (ic_info->preceding_text, len - pos);
535 }
536
537 static int
538 get_following_char (MInputContext *ic, int pos)
539 {
540   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
541   MText *mt;
542   int len;
543
544   if (ic_info->following_text)
545     {
546       len = mtext_nchars (ic_info->following_text);
547       if (pos <= len)
548         return mtext_ref_char (ic_info->following_text, pos - 1);
549     }
550   mt = get_surrounding_text (ic, pos);
551   if (! mt)
552     return -1;
553   len = mtext_nchars (mt);
554   if (ic_info->following_text)
555     {
556       if (mtext_nchars (ic_info->following_text) < len)
557         {
558           M17N_OBJECT_UNREF (ic_info->following_text);
559           ic_info->following_text = mt;
560         }
561     }
562   else
563     ic_info->following_text = mt;
564   if (pos > len)
565     return -1;
566   return mtext_ref_char (ic_info->following_text, pos - 1);
567 }
568
569 static int
570 surrounding_pos (MSymbol sym)
571 {
572   char *name;
573
574   if (sym == Mnil)
575     return 0;
576   name = MSYMBOL_NAME (sym);
577   if ((name[1] == '-' || name[1] == '+')
578       && name[2] >= '1' && name[2] <= '9')
579     return (name[1] == '-' ? - atoi (name + 2) : atoi (name + 2));
580   return 0;
581 }
582
583 static int
584 integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
585 {
586   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
587   int code;
588   MText *preedit = ic->preedit;
589   int len = mtext_nchars (preedit);
590
591   if (value)
592     *value = NULL;
593   if (MPLIST_INTEGER_P (arg))
594     return MPLIST_INTEGER (arg);
595   if (surrounding
596       && (surrounding = surrounding_pos (MPLIST_SYMBOL (arg))) != 0)
597     return (surrounding < 0
598             ? get_preceding_char (ic, - surrounding)
599             : get_following_char (ic, surrounding));
600   code = marker_code (MPLIST_SYMBOL (arg));
601   if (code < 0)
602     {
603       MPlist *val = resolve_variable (ic_info, MPLIST_SYMBOL (arg));
604
605       if (value)
606         *value = val;
607       return (MPLIST_INTEGER_P (val) ? MPLIST_INTEGER (val) : 0);
608     }
609   if (code == '@')
610     return ic_info->key_head;
611   if (code >= '0' && code <= '9')
612     code -= '0';
613   else if (code == '=')
614     code = ic->cursor_pos;
615   else if (code == '-' || code == '[')
616     code = ic->cursor_pos - 1;
617   else if (code == '+' || code == ']')
618     code = ic->cursor_pos + 1;
619   else if (code == '<')
620     code = 0;
621   else if (code == '>')
622     code = len;
623   return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
624 }
625
626 static int
627 parse_expression (MPlist *plist)
628 {
629   MSymbol op;
630
631   if (MPLIST_INTEGER_P (plist) || MPLIST_SYMBOL_P (plist))
632     return 0;
633   if (! MPLIST_PLIST_P (plist))
634     return -1;
635   plist = MPLIST_PLIST (plist);
636   op = MPLIST_SYMBOL (plist);
637   if (op != Mplus && op != Mminus && op != Mstar && op != Mslush
638       && op != Mand && op != Mor && op != Mnot
639       && op != Mless && op != Mgreater && op != Mequal
640       && op != Mless_equal && op != Mgreater_equal)
641     MERROR (MERROR_IM, -1);
642   MPLIST_DO (plist, MPLIST_NEXT (plist))
643     if (parse_expression (plist) < 0)
644       return -1;
645   return 0;
646 }
647
648 static int
649 resolve_expression (MInputContext *ic, MPlist *plist)
650 {
651   int val;
652   MSymbol op;
653   
654   if (MPLIST_INTEGER_P (plist))
655     return MPLIST_INTEGER (plist);
656   if (MPLIST_SYMBOL_P (plist))
657     return integer_value (ic, plist, NULL, 1);
658   if (! MPLIST_PLIST_P (plist))
659     return 0;
660   plist = MPLIST_PLIST (plist);
661   if (! MPLIST_SYMBOL_P (plist))
662     return val;
663   op = MPLIST_SYMBOL (plist);
664   plist = MPLIST_NEXT (plist);
665   val = resolve_expression (ic, plist);
666   if (op == Mplus)
667     MPLIST_DO (plist, MPLIST_NEXT (plist))
668       val += resolve_expression (ic, plist);
669   else if (op == Mminus)
670     MPLIST_DO (plist, MPLIST_NEXT (plist))
671       val -= resolve_expression (ic, plist);
672   else if (op == Mstar)
673     MPLIST_DO (plist, MPLIST_NEXT (plist))
674       val *= resolve_expression (ic, plist);
675   else if (op == Mslush)
676     MPLIST_DO (plist, MPLIST_NEXT (plist))
677       val /= resolve_expression (ic, plist);
678   else if (op == Mand)
679     MPLIST_DO (plist, MPLIST_NEXT (plist))
680       val &= resolve_expression (ic, plist);
681   else if (op == Mor)
682     MPLIST_DO (plist, MPLIST_NEXT (plist))
683       val |= resolve_expression (ic, plist);
684   else if (op == Mnot)
685     val = ! val;
686   else if (op == Mless)
687     val = val < resolve_expression (ic, MPLIST_NEXT (plist));
688   else if (op == Mequal)
689     val = val == resolve_expression (ic, MPLIST_NEXT (plist));
690   else if (op == Mgreater)
691     val = val > resolve_expression (ic, MPLIST_NEXT (plist));
692   else if (op == Mless_equal)
693     val = val <= resolve_expression (ic, MPLIST_NEXT (plist));
694   else if (op == Mgreater_equal)
695     val = val >= resolve_expression (ic, MPLIST_NEXT (plist));
696   return val;
697 }
698
699 /* Parse PLIST as an action list.  PLIST should have this form:
700       PLIST ::= ( (ACTION-NAME ACTION-ARG *) *).
701    Return 0 if successfully parsed, otherwise return -1.  */
702
703 static int
704 parse_action_list (MPlist *plist, MPlist *macros)
705 {
706   MPLIST_DO (plist, plist)
707     {
708       if (MPLIST_MTEXT_P (plist))
709         {
710           /* This is a short form of (insert MTEXT).  */
711           /* if (mtext_nchars (MPLIST_MTEXT (plist)) == 0)
712              MERROR (MERROR_IM, -1); */
713         }
714       else if (MPLIST_PLIST_P (plist)
715                && (MPLIST_MTEXT_P (MPLIST_PLIST (plist))
716                    || MPLIST_PLIST_P (MPLIST_PLIST (plist))))
717         {
718           MPlist *pl;
719
720           /* This is a short form of (insert (GROUPS *)).  */
721           MPLIST_DO (pl, MPLIST_PLIST (plist))
722             {
723               if (MPLIST_PLIST_P (pl))
724                 {
725                   MPlist *elt;
726
727                   MPLIST_DO (elt, MPLIST_PLIST (pl))
728                     if (! MPLIST_MTEXT_P (elt)
729                         || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
730                       MERROR (MERROR_IM, -1);
731                 }
732               else
733                 {
734                   if (! MPLIST_MTEXT_P (pl)
735                       || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
736                     MERROR (MERROR_IM, -1);
737                 }
738             }
739         }
740       else if (MPLIST_INTEGER_P (plist))
741         {
742           int c = MPLIST_INTEGER (plist);
743
744           if (c < 0 || c > MCHAR_MAX)
745             MERROR (MERROR_IM, -1);
746         }
747       else if (MPLIST_PLIST_P (plist)
748                && MPLIST_SYMBOL_P (MPLIST_PLIST (plist)))
749         {
750           MPlist *pl = MPLIST_PLIST (plist);
751           MSymbol action_name = MPLIST_SYMBOL (pl);
752
753           pl = MPLIST_NEXT (pl);
754
755           if (action_name == Minsert)
756             {
757               if (MPLIST_MTEXT_P (pl))
758                 {
759                   if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
760                     MERROR (MERROR_IM, -1);
761                 }
762               else if (MPLIST_PLIST_P (pl))
763                 {
764                   MPLIST_DO (pl, pl)
765                     {
766                       if (MPLIST_PLIST_P (pl))
767                         {
768                           MPlist *elt;
769
770                           MPLIST_DO (elt, MPLIST_PLIST (pl))
771                             if (! MPLIST_MTEXT_P (elt)
772                                 || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
773                               MERROR (MERROR_IM, -1);
774                         }
775                       else
776                         {
777                           if (! MPLIST_MTEXT_P (pl)
778                               || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
779                             MERROR (MERROR_IM, -1);
780                         }
781                     }
782                 }
783               else if (! MPLIST_SYMBOL_P (pl))
784                 MERROR (MERROR_IM, -1); 
785             }
786           else if (action_name == Mselect
787                    || action_name == Mdelete
788                    || action_name == Mmove)
789             {
790               if (parse_expression (pl) < 0)
791                 return -1;
792             }
793           else if (action_name == Mmark
794                    || action_name == Mcall
795                    || action_name == Mshift)
796             {
797               if (! MPLIST_SYMBOL_P (pl))
798                 MERROR (MERROR_IM, -1);
799             }
800           else if (action_name == Mundo)
801             {
802               if (! MPLIST_TAIL_P (pl))
803                 {
804                   if (! MPLIST_SYMBOL_P (pl)
805                       && (! MPLIST_INTEGER_P (pl)
806                           || MPLIST_INTEGER (pl) == 0))
807                     MERROR (MERROR_IM, -1);                 
808                 }
809             }
810           else if (action_name == Mpushback)
811             {
812               if (MPLIST_MTEXT_P (pl))
813                 {
814                   MText *mt = MPLIST_MTEXT (pl);
815
816                   if (mtext_nchars (mt) != mtext_nbytes (mt))
817                     MERROR (MERROR_IM, -1);                 
818                 }
819               else if (MPLIST_PLIST_P (pl))
820                 {
821                   MPlist *p;
822
823                   MPLIST_DO (p, MPLIST_PLIST (pl))
824                     if (! MPLIST_SYMBOL_P (p))
825                       MERROR (MERROR_IM, -1);
826                 }
827               else if (! MPLIST_INTEGER_P (pl))
828                 MERROR (MERROR_IM, -1);
829             }
830           else if (action_name == Mset || action_name == Madd
831                    || action_name == Msub || action_name == Mmul
832                    || action_name == Mdiv)
833             {
834               if (! MPLIST_SYMBOL_P (pl))
835                 MERROR (MERROR_IM, -1);
836               if (parse_expression (MPLIST_NEXT (pl)) < 0)
837                 return -1;
838             }
839           else if (action_name == Mequal || action_name == Mless
840                    || action_name == Mgreater || action_name == Mless_equal
841                    || action_name == Mgreater_equal)
842             {
843               if (parse_expression (pl) < 0
844                   || parse_expression (MPLIST_NEXT (pl)) < 0)
845                 return -1;
846               pl = MPLIST_NEXT (MPLIST_NEXT (pl));
847               if (! MPLIST_PLIST_P (pl))
848                 MERROR (MERROR_IM, -1);
849               if (parse_action_list (MPLIST_PLIST (pl), macros) < 0)
850                 MERROR (MERROR_IM, -1);
851               pl = MPLIST_NEXT (pl);
852               if (MPLIST_PLIST_P (pl)
853                   && parse_action_list (MPLIST_PLIST (pl), macros) < 0)
854                 MERROR (MERROR_IM, -1);
855             }
856           else if (action_name == Mshow || action_name == Mhide
857                    || action_name == Mcommit || action_name == Munhandle)
858             ;
859           else if (action_name == Mcond)
860             {
861               MPLIST_DO (pl, pl)
862                 if (! MPLIST_PLIST_P (pl))
863                   MERROR (MERROR_IM, -1);
864             }
865           else if (! macros || ! mplist_get (macros, action_name))
866             MERROR (MERROR_IM, -1);
867         }
868       else
869         MERROR (MERROR_IM, -1);
870     }
871
872   return 0;
873 }
874
875 static MPlist *
876 resolve_command (MSymbol language, MSymbol name, MSymbol command)
877 {
878   MPlist *plist = get_nested_list (language, name, Mnil, M_command);
879
880   if (! plist)
881     MERROR (MERROR_IM, NULL);
882   MPLIST_DO (plist, plist)
883     {
884       if (MPLIST_SYMBOL (plist) == command)
885         break;
886       plist = MPLIST_NEXT (plist);
887     }
888   if (MPLIST_TAIL_P (plist))
889     MERROR (MERROR_IM, NULL);
890   plist = MPLIST_NEXT (plist);  
891   if (! MPLIST_PLIST_P (plist))
892     MERROR (MERROR_IM, NULL);
893   plist = MPLIST_NEXT (MPLIST_PLIST (plist));
894   return plist;
895 }
896
897 /* Load a translation into MAP from PLIST.
898    PLIST has this form:
899       PLIST ::= ( KEYSEQ MAP-ACTION * )  */
900
901 static int
902 load_translation (MIMMap *map, MPlist *keylist, MPlist *map_actions,
903                   MPlist *branch_actions, MPlist *macros)
904 {
905   MSymbol *keyseq;
906   int len, i;
907
908   if (MPLIST_MTEXT_P (keylist))
909     {
910       MText *mt = MPLIST_MTEXT (keylist);
911
912       len = mtext_nchars (mt);
913       if (len == 0 || len != mtext_nbytes (mt))
914         MERROR (MERROR_IM, -1);
915       keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len);
916       for (i = 0; i < len; i++)
917         keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]];
918     }
919   else if (MPLIST_PLIST_P (keylist))
920     {
921       MPlist *elt = MPLIST_PLIST (keylist);
922           
923       len = MPLIST_LENGTH (elt);
924       if (len == 0)
925         MERROR (MERROR_IM, -1);
926       keyseq = (MSymbol *) alloca (sizeof (int) * len);
927       for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
928         {
929           if (MPLIST_INTEGER_P (elt))
930             {
931               int c = MPLIST_INTEGER (elt);
932
933               if (c < 0 || c >= 0x100)
934                 MERROR (MERROR_IM, -1);
935               keyseq[i] = one_char_symbol[c];
936             }
937           else if (MPLIST_SYMBOL_P (elt))
938             keyseq[i] = MPLIST_SYMBOL (elt);
939           else
940             MERROR (MERROR_IM, -1);
941         }
942     }
943   else
944     MERROR (MERROR_IM, -1);
945
946   for (i = 0; i < len; i++)
947     {
948       MIMMap *deeper = NULL;
949
950       if (map->submaps)
951         deeper = mplist_get (map->submaps, keyseq[i]);
952       else
953         map->submaps = mplist ();
954       if (! deeper)
955         {
956           /* Fixme: It is better to make all deeper maps at once.  */
957           MSTRUCT_CALLOC (deeper, MERROR_IM);
958           mplist_put (map->submaps, keyseq[i], deeper);
959         }
960       map = deeper;
961     }
962
963   /* We reach a terminal map.  */
964   if (map->map_actions
965       || map->branch_actions)
966     /* This map is already defined.  We avoid overriding it.  */
967     return 0;
968
969   if (! MPLIST_TAIL_P (map_actions))
970     {
971       if (parse_action_list (map_actions, macros) < 0)
972         MERROR (MERROR_IM, -1);
973       map->map_actions = map_actions;
974     }
975   if (branch_actions)
976     {
977       map->branch_actions = branch_actions;
978       M17N_OBJECT_REF (branch_actions);
979     }
980
981   return 0;
982 }
983
984 /* Load a branch from PLIST into MAP.  PLIST has this form:
985       PLIST ::= ( MAP-NAME BRANCH-ACTION * )
986    MAPS is a plist of raw maps.
987    STATE is the current state.  */
988
989 static int
990 load_branch (MPlist *plist, MPlist *maps, MIMMap *map,
991              MSymbol language, MSymbol name, MPlist *macros)
992 {
993   MSymbol map_name;
994   MPlist *branch_actions;
995
996   if (! MPLIST_SYMBOL_P (plist))
997     MERROR (MERROR_IM, -1);
998   map_name = MPLIST_SYMBOL (plist);
999   plist = MPLIST_NEXT (plist);
1000   if (MPLIST_TAIL_P (plist))
1001     branch_actions = NULL;
1002   else if (parse_action_list (plist, macros) < 0)
1003     MERROR (MERROR_IM, -1);
1004   else
1005     branch_actions = plist;
1006   if (map_name == Mnil)
1007     {
1008       map->branch_actions = branch_actions;
1009       if (branch_actions)
1010         M17N_OBJECT_REF (branch_actions);
1011     }
1012   else if (map_name == Mt)
1013     {
1014       map->map_actions = branch_actions;
1015       if (branch_actions)
1016         M17N_OBJECT_REF (branch_actions);
1017     }
1018   else if ((plist = (MPlist *) mplist_get (maps, map_name)))
1019     {
1020       MPLIST_DO (plist, plist)
1021         {
1022           MPlist *keylist, *map_actions;
1023
1024           if (! MPLIST_PLIST_P (plist))
1025             MERROR (MERROR_IM, -1);
1026           keylist = MPLIST_PLIST (plist);
1027           map_actions = MPLIST_NEXT (keylist);
1028           if (MPLIST_SYMBOL_P (keylist))
1029             {
1030               MSymbol command = MPLIST_SYMBOL (keylist);
1031               MPlist *pl = resolve_command (language, name, command);
1032
1033               if (! pl)
1034                 return -1;
1035               MPLIST_DO (pl, pl)
1036                 if (load_translation (map, pl, map_actions, branch_actions,
1037                                       macros) < 0)
1038                   MERROR (MERROR_IM, -1);
1039             }
1040           else
1041             if (load_translation (map, keylist, map_actions, branch_actions,
1042                                   macros) < 0)
1043               MERROR (MERROR_IM, -1);
1044         }
1045     }
1046
1047   return 0;
1048 }
1049
1050 /* Load a macro from PLIST into MACROS.
1051    PLIST has this from:
1052       PLIST ::= ( MACRO-NAME ACTION * )
1053    MACROS is a plist of macro names vs action list.  */
1054 static int
1055 load_macros (MPlist *plist, MPlist *macros)
1056 {
1057   MSymbol name; 
1058   MPlist *pl;
1059
1060   if (! MPLIST_SYMBOL_P (plist))
1061     MERROR (MERROR_IM, -1);
1062   name = MPLIST_SYMBOL (plist);
1063   plist = MPLIST_NEXT (plist);
1064   if (MPLIST_TAIL_P (plist)
1065       || parse_action_list (plist, macros) < 0)
1066     MERROR (MERROR_IM, -1);
1067   pl = mplist_get (macros, name);
1068   if (pl)
1069     M17N_OBJECT_UNREF (pl);
1070   mplist_put (macros, name, plist);
1071   M17N_OBJECT_REF (plist);
1072   return 0;
1073 }
1074
1075 /* Load an external module from PLIST into EXTERNALS.
1076    PLIST has this form:
1077       PLIST ::= ( MODULE-NAME FUNCTION * )
1078    EXTERNALS is a plist of MODULE-NAME vs (MIMExternalModule *).  */
1079
1080 static int
1081 load_external_module (MPlist *plist, MPlist *externals)
1082 {
1083   void *handle;
1084   MSymbol module;
1085   char *module_file;
1086   MIMExternalModule *external;
1087   MPlist *func_list;
1088   void *func;
1089
1090   if (MPLIST_MTEXT_P (plist))
1091     module = msymbol ((char *) MTEXT_DATA (MPLIST_MTEXT (plist)));
1092   else if (MPLIST_SYMBOL_P (plist))
1093     module = MPLIST_SYMBOL (plist);
1094   module_file = alloca (strlen (MSYMBOL_NAME (module))
1095                         + strlen (DLOPEN_SHLIB_EXT) + 1);
1096   sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
1097
1098   handle = dlopen (module_file, RTLD_NOW);
1099   if (! handle)
1100     {
1101       fprintf (stderr, "%s\n", dlerror ());
1102       MERROR (MERROR_IM, -1);
1103     }
1104   func_list = mplist ();
1105   MPLIST_DO (plist, MPLIST_NEXT (plist))
1106     {
1107       if (! MPLIST_SYMBOL_P (plist))
1108         MERROR_GOTO (MERROR_IM, err_label);
1109       func = dlsym (handle, MSYMBOL_NAME (MPLIST_SYMBOL (plist)));
1110       if (! func)
1111         MERROR_GOTO (MERROR_IM, err_label);
1112       mplist_add (func_list, MPLIST_SYMBOL (plist), func);
1113     }
1114
1115   MSTRUCT_MALLOC (external, MERROR_IM);
1116   external->handle = handle;
1117   external->func_list = func_list;
1118   mplist_add (externals, module, external);
1119   return 0;
1120
1121  err_label:
1122   dlclose (handle);
1123   M17N_OBJECT_UNREF (func_list);
1124   return -1;
1125 }
1126
1127 static void
1128 free_map (MIMMap *map, int top)
1129 {
1130   MPlist *plist;
1131
1132   if (top)
1133     M17N_OBJECT_UNREF (map->map_actions);
1134   if (map->submaps)
1135     {
1136       MPLIST_DO (plist, map->submaps)
1137         free_map ((MIMMap *) MPLIST_VAL (plist), 0);
1138       M17N_OBJECT_UNREF (map->submaps);
1139     }
1140   M17N_OBJECT_UNREF (map->branch_actions);
1141   free (map);
1142 }
1143
1144 static void
1145 free_state (void *object)
1146 {
1147   MIMState *state = object;
1148
1149   if (state->title)
1150     M17N_OBJECT_UNREF (state->title);
1151   if (state->map)
1152     free_map (state->map, 1);
1153   free (state);
1154 }
1155
1156 /** Load a state from PLIST into a newly allocated state object.
1157     PLIST has this form:
1158       PLIST ::= ( STATE-NAME STATE-TITLE ? BRANCH * )
1159       BRANCH ::= ( MAP-NAME BRANCH-ACTION * )
1160    MAPS is a plist of defined maps.
1161    Return the state object.  */
1162
1163 static MIMState *
1164 load_state (MPlist *plist, MPlist *maps, MSymbol language, MSymbol name,
1165             MPlist *macros)
1166 {
1167   MIMState *state;
1168
1169   if (! MPLIST_SYMBOL_P (plist))
1170     MERROR (MERROR_IM, NULL);
1171   M17N_OBJECT (state, free_state, MERROR_IM);
1172   state->name = MPLIST_SYMBOL (plist);
1173   plist = MPLIST_NEXT (plist);
1174   if (MPLIST_MTEXT_P (plist))
1175     {
1176       state->title = MPLIST_MTEXT (plist);
1177       mtext_put_prop (state->title, 0, mtext_nchars (state->title),
1178                       Mlanguage, language);
1179       M17N_OBJECT_REF (state->title);
1180       plist = MPLIST_NEXT (plist);
1181     }
1182   MSTRUCT_CALLOC (state->map, MERROR_IM);
1183   MPLIST_DO (plist, plist)
1184     if (! MPLIST_PLIST_P (plist)
1185         || load_branch (MPLIST_PLIST (plist), maps, state->map, language, name,
1186                         macros) < 0)
1187       MERROR (MERROR_IM, NULL);
1188   return state;
1189 }
1190
1191
1192 static MPlist *im_info_list;
1193
1194 static void
1195 free_im_info (MInputMethodInfo *im_info)
1196 {
1197   MPlist *plist;
1198
1199   if (im_info->title)
1200     M17N_OBJECT_UNREF (im_info->title);
1201   if (im_info->states)
1202     {
1203       MPLIST_DO (plist, im_info->states)
1204         {
1205           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1206
1207           M17N_OBJECT_UNREF (state);
1208         }
1209       M17N_OBJECT_UNREF (im_info->states);
1210     }
1211
1212   if (im_info->macros)
1213     {
1214       MPLIST_DO (plist, im_info->macros)
1215         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1216       M17N_OBJECT_UNREF (im_info->macros);
1217     }
1218
1219   if (im_info->externals)
1220     {
1221       MPLIST_DO (plist, im_info->externals)
1222         {
1223           MIMExternalModule *external = MPLIST_VAL (plist);
1224
1225           dlclose (external->handle);
1226           M17N_OBJECT_UNREF (external->func_list);
1227           free (external);
1228           MPLIST_KEY (plist) = Mt;
1229         }
1230       M17N_OBJECT_UNREF (im_info->externals);
1231     }
1232   if (im_info->maps)
1233     {
1234       MPLIST_DO (plist, im_info->maps)
1235         {
1236           MPlist *p = MPLIST_PLIST (plist);
1237
1238           M17N_OBJECT_UNREF (p);
1239         }
1240       M17N_OBJECT_UNREF (im_info->maps);
1241     }
1242
1243   free (im_info);
1244 }
1245
1246 static MInputMethodInfo *get_im_info (MSymbol language, MSymbol name,
1247                                       MSymbol extra);
1248
1249 static MInputMethodInfo *
1250 get_im_info_by_tags (MPlist *plist)
1251 {
1252   MSymbol tag[3];
1253   int i;
1254
1255   for (i = 0; i < 3 && MPLIST_SYMBOL_P (plist);
1256        i++, plist = MPLIST_NEXT (plist))
1257     tag[i] = MPLIST_SYMBOL (plist);
1258   if (i < 2)
1259     return NULL;
1260   for (; i < 3; i++)
1261     tag[i] = Mnil;
1262   return get_im_info (tag[0], tag[1], tag[2]);
1263 }
1264
1265 /* Load an input method from PLIST into IM_INTO, and return it.  */
1266
1267 static MInputMethodInfo *
1268 load_im_info (MSymbol language, MSymbol name, MPlist *plist)
1269 {
1270   MInputMethodInfo *im_info;
1271   MText *title = NULL;
1272   MPlist *maps = NULL;
1273   MPlist *states = NULL;
1274   MPlist *externals = NULL;
1275   MPlist *macros = NULL;
1276   MPlist *elt;
1277
1278   MSTRUCT_CALLOC (im_info, MERROR_IM);
1279
1280   while (MPLIST_PLIST_P (plist))
1281     {
1282       elt = MPLIST_PLIST (plist);
1283       if (! MPLIST_SYMBOL_P (elt))
1284         MERROR_GOTO (MERROR_IM, err);
1285       if (MPLIST_SYMBOL (elt) == Mtitle)
1286         {
1287           elt = MPLIST_NEXT (elt);
1288           if (! MPLIST_MTEXT_P (elt))
1289             MERROR_GOTO (MERROR_IM, err);
1290           im_info->title = title = MPLIST_MTEXT (elt);
1291           M17N_OBJECT_REF (title);
1292         }
1293       else if (MPLIST_SYMBOL (elt) == Mmap)
1294         {
1295           MPlist *pl = mplist__from_alist (MPLIST_NEXT (elt));
1296
1297           if (! pl)
1298             MERROR_GOTO (MERROR_IM, err);
1299           if (! maps)
1300             im_info->maps = maps = pl;
1301           else
1302             maps = mplist__conc (maps, pl);
1303         }
1304       else if (MPLIST_SYMBOL (elt) == Mmacro)
1305         {
1306           if (! macros)
1307             im_info->macros = macros = mplist ();
1308           MPLIST_DO (elt, MPLIST_NEXT (elt))
1309             {
1310               if (! MPLIST_PLIST_P (elt)
1311                   || load_macros (MPLIST_PLIST (elt), macros) < 0)
1312                 MERROR_GOTO (MERROR_IM, err);
1313             }
1314         }
1315       else if (MPLIST_SYMBOL (elt) == Mmodule)
1316         {
1317           if (! externals)
1318             im_info->externals = externals = mplist ();
1319           MPLIST_DO (elt, MPLIST_NEXT (elt))
1320             {
1321               if (! MPLIST_PLIST_P (elt)
1322                   || load_external_module (MPLIST_PLIST (elt), externals) < 0)
1323                 MERROR_GOTO (MERROR_IM, err);
1324             }
1325         }
1326       else if (MPLIST_SYMBOL (elt) == Mstate)
1327         {
1328           MPLIST_DO (elt, MPLIST_NEXT (elt))
1329             {
1330               MIMState *state;
1331
1332               if (! MPLIST_PLIST_P (elt))
1333                 MERROR_GOTO (MERROR_IM, err);
1334               state = load_state (MPLIST_PLIST (elt), maps, language, name,
1335                                   macros);
1336               if (! state)
1337                 MERROR_GOTO (MERROR_IM, err);
1338               if (! states)
1339                 im_info->states = states = mplist ();
1340               mplist_put (states, state->name, state);
1341             }
1342         }
1343       else if (MPLIST_SYMBOL (elt) == Minclude)
1344         {
1345           /* elt ::= include (tag1 tag2 ...) key item ... */
1346           MSymbol key;
1347           MInputMethodInfo *temp;
1348           MPlist *pl, *p;
1349
1350           elt = MPLIST_NEXT (elt);
1351           if (! MPLIST_PLIST_P (elt))
1352             MERROR_GOTO (MERROR_IM, err);
1353           temp = get_im_info_by_tags (MPLIST_PLIST (elt));
1354           if (! temp)
1355             MERROR_GOTO (MERROR_IM, err);
1356           elt = MPLIST_NEXT (elt);
1357           if (! MPLIST_SYMBOL_P (elt))
1358             MERROR_GOTO (MERROR_IM, err);
1359           key = MPLIST_SYMBOL (elt);
1360           elt = MPLIST_NEXT (elt);
1361           if (key == Mmap)
1362             {
1363               if (! maps)
1364                 im_info->maps = maps = mplist ();
1365               MPLIST_DO (pl, temp->maps)
1366                 {
1367                   p = MPLIST_VAL (pl);
1368                   MPLIST_ADD_PLIST (maps, MPLIST_KEY (pl), p);
1369                   M17N_OBJECT_REF (p);
1370                 }
1371             }
1372           else if (key == Mmacro)
1373             {
1374               if (! macros)
1375                 im_info->macros = macros = mplist ();
1376               MPLIST_DO (pl, temp->macros)
1377                 {
1378                   p = MPLIST_VAL (pl);
1379                   MPLIST_ADD_PLIST (macros, MPLIST_KEY (pl), p);
1380                   M17N_OBJECT_REF (p);
1381                 }
1382             }
1383           else if (key == Mstate)
1384             {
1385               if (! states)
1386                 im_info->states = states = mplist ();
1387               MPLIST_DO (pl, temp->states)
1388                 {
1389                   MIMState *state = MPLIST_VAL (pl);
1390
1391                   mplist_add (states, MPLIST_KEY (pl), state);
1392                   M17N_OBJECT_REF (state);
1393                 }
1394             }
1395           else
1396             MERROR_GOTO (MERROR_IM, err);
1397         }
1398       plist = MPLIST_NEXT (plist);
1399     }
1400
1401   if (! states)
1402     goto err;
1403   if (! title && name)
1404     im_info->title
1405       = title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name),
1406                                  MTEXT_FORMAT_US_ASCII);
1407   return im_info;
1408
1409  err:
1410   free_im_info (im_info);
1411   return NULL;
1412 }
1413
1414 \f
1415
1416 static int take_action_list (MInputContext *ic, MPlist *action_list);
1417 static void preedit_commit (MInputContext *ic);
1418
1419 static void
1420 shift_state (MInputContext *ic, MSymbol state_name)
1421 {
1422   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1423   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1424   MIMState *orig_state = ic_info->state, *state;
1425
1426   /* Find a state to shift to.  If not found, shift to the initial
1427      state.  */
1428   if (state_name == Mt)
1429     {
1430       if (! ic_info->prev_state)
1431         return;
1432       state = ic_info->prev_state;
1433     }
1434   else
1435     {
1436       state = (MIMState *) mplist_get (im_info->states, state_name);
1437       if (! state)
1438         state = (MIMState *) MPLIST_VAL (im_info->states);
1439     }
1440
1441   MDEBUG_PRINT1 ("\n  [IM] (shift %s)", MSYMBOL_NAME (state->name));
1442
1443   /* Enter the new state.  */
1444   ic_info->state = state;
1445   ic_info->map = state->map;
1446   ic_info->state_key_head = ic_info->key_head;
1447   if (state == (MIMState *) MPLIST_VAL (im_info->states))
1448     /* We have shifted to the initial state.  */
1449     preedit_commit (ic);
1450   mtext_cpy (ic_info->preedit_saved, ic->preedit);
1451   ic_info->state_pos = ic->cursor_pos;
1452   if (state != orig_state )
1453     {
1454       if (state == (MIMState *) MPLIST_VAL (im_info->states))
1455         ic_info->prev_state = NULL;
1456       else
1457         ic_info->prev_state = orig_state;
1458
1459       if (state->title)
1460         ic->status = state->title;
1461       else
1462         ic->status = im_info->title;
1463       ic->status_changed = 1;
1464       if (ic_info->map == ic_info->state->map
1465           && ic_info->map->map_actions)
1466         {
1467           MDEBUG_PRINT (" init-actions:");
1468           take_action_list (ic, ic_info->map->map_actions);
1469         }
1470     }
1471 }
1472
1473 /* Find a candidate group that contains a candidate number INDEX from
1474    PLIST.  Set START_INDEX to the first candidate number of the group,
1475    END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
1476    candidate group number if they are non-NULL.  If INDEX is -1, find
1477    the last candidate group.  */
1478
1479 static MPlist *
1480 find_candidates_group (MPlist *plist, int index,
1481                        int *start_index, int *end_index, int *group_index)
1482 {
1483   int i = 0, gidx = 0, len;
1484
1485   MPLIST_DO (plist, plist)
1486     {
1487       if (MPLIST_MTEXT_P (plist))
1488         len = mtext_nchars (MPLIST_MTEXT (plist));
1489       else
1490         len = mplist_length (MPLIST_PLIST (plist));
1491       if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
1492           : i + len > index)
1493         {
1494           if (start_index)
1495             *start_index = i;
1496           if (end_index)
1497             *end_index = i + len;
1498           if (group_index)
1499             *group_index = gidx;
1500           return plist;
1501         }
1502       i += len;
1503       gidx++;
1504     }
1505   return NULL;
1506 }
1507
1508 static void
1509 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
1510 {
1511   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
1512   MPlist *markers;
1513   int nchars = mt ? mtext_nchars (mt) : 1;
1514
1515   if (mt)
1516     mtext_ins (ic->preedit, pos, mt);
1517   else
1518     mtext_ins_char (ic->preedit, pos, c, 1);
1519   MPLIST_DO (markers, ic_info->markers)
1520     if (MPLIST_INTEGER (markers) > pos)
1521       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
1522   if (ic->cursor_pos >= pos)
1523     ic->cursor_pos += nchars;
1524   ic->preedit_changed = 1;
1525 }
1526
1527
1528 static void
1529 preedit_delete (MInputContext *ic, int from, int to)
1530 {
1531   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
1532   MPlist *markers;
1533
1534   mtext_del (ic->preedit, from, to);
1535   MPLIST_DO (markers, ic_info->markers)
1536     {
1537       if (MPLIST_INTEGER (markers) > to)
1538         MPLIST_VAL (markers)
1539           = (void *) (MPLIST_INTEGER (markers) - (to - from));
1540       else if (MPLIST_INTEGER (markers) > from);
1541         MPLIST_VAL (markers) = (void *) from;
1542     }
1543   if (ic->cursor_pos >= to)
1544     ic->cursor_pos -= to - from;
1545   else if (ic->cursor_pos > from)
1546     ic->cursor_pos = from;
1547   ic->preedit_changed = 1;
1548 }
1549
1550 static void
1551 preedit_commit (MInputContext *ic)
1552 {
1553   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1554   int preedit_len = mtext_nchars (ic->preedit);
1555
1556   if (preedit_len > 0)
1557     {
1558       MPlist *p;
1559
1560       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
1561                              Mcandidate_list, NULL, 0);
1562       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
1563                              Mcandidate_index, NULL, 0);
1564       mtext_cat (ic->produced, ic->preedit);
1565       if ((mdebug__flag & mdebug_mask)
1566           && mtext_nchars (ic->produced) > 0)
1567         {
1568           int i;
1569
1570           MDEBUG_PRINT (" (produced");
1571           for (i = 0; i < mtext_nchars (ic->produced); i++)
1572             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
1573           MDEBUG_PRINT (")");
1574         }
1575       mtext_reset (ic->preedit);
1576       mtext_reset (ic_info->preedit_saved);
1577       MPLIST_DO (p, ic_info->markers)
1578         MPLIST_VAL (p) = 0;
1579       ic->cursor_pos = ic_info->state_pos = 0;
1580       ic->preedit_changed = 1;
1581     }
1582   if (ic->candidate_list)
1583     {
1584       M17N_OBJECT_UNREF (ic->candidate_list);
1585       ic->candidate_list = NULL;
1586       ic->candidate_show = 0;
1587       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
1588       if (ic->candidate_show)
1589         {
1590           ic->candidate_show = 0;
1591           ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
1592         }
1593     }
1594
1595   memmove (ic_info->keys, ic_info->keys + ic_info->key_head,
1596            sizeof (int) * (ic_info->used - ic_info->key_head));
1597   ic_info->used -= ic_info->key_head;
1598   ic_info->state_key_head = ic_info->key_head = 0;
1599 }
1600
1601 static int
1602 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
1603 {
1604   int code = marker_code (sym);
1605
1606   if (mt && (code == '[' || code == ']'))
1607     {
1608       int pos = current;
1609
1610       if (code == '[' && current > 0)
1611         {
1612           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
1613               && pos > 0)
1614             current = pos;
1615         }
1616       else if (code == ']' && current < mtext_nchars (mt))
1617         {
1618           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
1619             current = pos;
1620         }
1621       return current;
1622     }
1623   if (code >= 0)
1624     return (code == '<' ? 0
1625             : code == '>' ? limit
1626             : code == '-' ? current - 1
1627             : code == '+' ? current + 1
1628             : code == '=' ? current
1629             : code - '0' > limit ? limit
1630             : code - '0');
1631   if (! ic)  
1632     return 0;
1633   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
1634 }
1635
1636 static void
1637 update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
1638 {
1639   int from = mtext_property_start (prop);
1640   int to = mtext_property_end (prop);
1641   int start;
1642   MPlist *candidate_list = mtext_property_value (prop);
1643   MPlist *group = find_candidates_group (candidate_list, idx, &start,
1644                                          NULL, NULL);
1645   int ingroup_index = idx - start;
1646   MText *mt;
1647
1648   preedit_delete (ic, from, to);
1649   if (MPLIST_MTEXT_P (group))
1650     {
1651       mt = MPLIST_MTEXT (group);
1652       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
1653       to = from + 1;
1654     }
1655   else
1656     {
1657       int i;
1658       MPlist *plist;
1659
1660       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
1661            i++, plist = MPLIST_NEXT (plist));
1662       mt = MPLIST_MTEXT (plist);
1663       preedit_insert (ic, from, mt, 0);
1664       to = from + mtext_nchars (mt);
1665     }
1666   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
1667   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
1668   ic->cursor_pos = to;
1669 }
1670
1671 static MCharset *
1672 get_select_charset (MInputContextInfo * ic_info)
1673 {
1674   MPlist *plist = resolve_variable (ic_info, Mcandidates_charset);
1675   MSymbol sym;
1676
1677   if (! MPLIST_VAL (plist))
1678     return NULL;
1679   sym = MPLIST_SYMBOL (plist);
1680   if (sym == Mnil)
1681     return NULL;
1682   return MCHARSET (sym);
1683 }
1684
1685 static MPlist *
1686 adjust_candidates (MPlist *plist, MCharset *charset)
1687 {
1688   MPlist *pl;
1689
1690   /* plist ::= MTEXT ... | PLIST ... */
1691   plist = mplist_copy (plist);
1692   if (MPLIST_MTEXT_P (plist))
1693     {
1694       pl = plist;
1695       while (! MPLIST_TAIL_P (pl))
1696         {
1697           /* pl ::= MTEXT ... */
1698           MText *mt = MPLIST_MTEXT (pl);
1699           int mt_copied = 0;
1700           int i, c;
1701
1702           for (i = mtext_nchars (mt) - 1; i >= 0; i--)
1703             {
1704               c = mtext_ref_char (mt, i);
1705               if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
1706                 {
1707                   if (! mt_copied)
1708                     {
1709                       mt = mtext_dup (mt);
1710                       mplist_set (pl, Mtext, mt);
1711                       M17N_OBJECT_UNREF (mt);
1712                       mt_copied = 1;
1713                     }
1714                   mtext_del (mt, i, i + 1);
1715                 }
1716             }
1717           if (mtext_len (mt) > 0)
1718             pl = MPLIST_NEXT (pl);
1719           else
1720             {
1721               mplist_pop (pl);
1722               M17N_OBJECT_UNREF (mt);
1723             }
1724         }
1725     }
1726   else                          /* MPLIST_PLIST_P (plist) */
1727     {
1728       pl = plist;
1729       while (! MPLIST_TAIL_P (pl))
1730         {
1731           /* pl ::= (MTEXT ...) ... */
1732           MPlist *p = MPLIST_PLIST (pl);
1733           int p_copied = 0;
1734           /* p ::= MTEXT ... */
1735           MPlist *p0 = p;
1736           int n = 0;
1737
1738           while (! MPLIST_TAIL_P (p0))
1739             {
1740               MText *mt = MPLIST_MTEXT (p0);
1741               int i, c;
1742
1743               for (i = mtext_nchars (mt) - 1; i >= 0; i--)
1744                 {
1745                   c = mtext_ref_char (mt, i);
1746                   if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
1747                     break;
1748                 }
1749               if (i < 0)
1750                 {
1751                   p0 = MPLIST_NEXT (p0);
1752                   n++;
1753                 }
1754               else
1755                 {
1756                   if (! p_copied)
1757                     {
1758                       p = mplist_copy (p);
1759                       mplist_set (pl, Mplist, p);
1760                       M17N_OBJECT_UNREF (p);
1761                       p_copied = 1;
1762                       p0 = p;
1763                       while (n-- > 0)
1764                         p0 = MPLIST_NEXT (p0);
1765                     }     
1766                   mplist_pop (p0);
1767                   M17N_OBJECT_UNREF (mt);
1768                 }
1769             }
1770           if (! MPLIST_TAIL_P (p))
1771             pl = MPLIST_NEXT (pl);
1772           else
1773             {
1774               mplist_pop (pl);
1775               M17N_OBJECT_UNREF (p);
1776             }
1777         }
1778     }
1779   if (MPLIST_TAIL_P (plist))
1780     {
1781       M17N_OBJECT_UNREF (plist);
1782       return NULL;
1783     }      
1784   return plist;
1785 }
1786
1787 static MPlist *
1788 get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
1789 {
1790   MCharset *charset = get_select_charset (ic_info);
1791   MPlist *plist;
1792   int column;
1793   int i, len;
1794
1795   plist = resolve_variable (ic_info, Mcandidates_group_size);
1796   column = MPLIST_INTEGER (plist);
1797
1798   plist = MPLIST_PLIST (args);
1799   if (charset)
1800     {
1801       if (! (plist = adjust_candidates (plist, charset)))
1802         return NULL;
1803     }
1804   else
1805     M17N_OBJECT_REF (plist);
1806
1807   if (column > 0)
1808     {
1809       if (MPLIST_MTEXT_P (plist))
1810         {
1811           MText *mt = MPLIST_MTEXT (plist);
1812           MPlist *next = MPLIST_NEXT (plist);
1813
1814           if (MPLIST_TAIL_P (next))
1815             M17N_OBJECT_REF (mt);
1816           else
1817             {
1818               mt = mtext_dup (mt);
1819               while (! MPLIST_TAIL_P (next))
1820                 {
1821                   mt = mtext_cat (mt, MPLIST_MTEXT (next));
1822                   next = MPLIST_NEXT (next);
1823                 }
1824             }
1825           M17N_OBJECT_UNREF (plist);
1826           plist = mplist ();
1827           len = mtext_nchars (mt);
1828           if (len <= column)
1829             mplist_add (plist, Mtext, mt);
1830           else
1831             {
1832               for (i = 0; i < len; i += column)
1833                 {
1834                   int to = (i + column < len ? i + column : len);
1835                   MText *sub = mtext_copy (mtext (), 0, mt, i, to);
1836                                                        
1837                   mplist_add (plist, Mtext, sub);
1838                   M17N_OBJECT_UNREF (sub);
1839                 }
1840             }
1841           M17N_OBJECT_UNREF (mt);
1842         }
1843       else              /* MPLIST_PLIST_P (plist) */
1844         {
1845           MPlist *pl = MPLIST_PLIST (plist), *p;
1846           MPlist *next = MPLIST_NEXT (plist);
1847           int j;
1848
1849           if (MPLIST_TAIL_P (next))
1850             M17N_OBJECT_REF (pl);
1851           else
1852             {
1853               pl = mplist_copy (pl);
1854               while (! MPLIST_TAIL_P (next))
1855                 {
1856                   p = mplist_copy (MPLIST_PLIST (next));
1857                   pl = mplist__conc (pl, p);
1858                   M17N_OBJECT_UNREF (p);
1859                   next = MPLIST_NEXT (next);
1860                 }
1861             }
1862           M17N_OBJECT_UNREF (plist);
1863           plist = mplist ();
1864           len = mplist_length (pl);
1865           if (len <= column)
1866             mplist_add (plist, Mplist, pl);
1867           else
1868             {
1869               MPlist *p0 = pl;
1870
1871               for (i = 0; i < len; i += column)
1872                 {
1873                   p = mplist ();
1874                   mplist_add (plist, Mplist, p);
1875                   M17N_OBJECT_UNREF (p);
1876                   for (j = 0; j < column && i + j < len; j++)
1877                     {
1878                       p = mplist_add (p, Mtext, MPLIST_VAL (p0));
1879                       p0 = MPLIST_NEXT (p0);
1880                     }
1881                 }
1882             }
1883           M17N_OBJECT_UNREF (pl);
1884         }
1885     }
1886
1887   return plist;
1888 }
1889
1890
1891 static MPlist *
1892 regularize_action (MPlist *action_list)
1893 {
1894   MPlist *action = NULL;
1895   MSymbol name;
1896   MPlist *args;
1897
1898   if (MPLIST_PLIST_P (action_list))
1899     {
1900       action = MPLIST_PLIST (action_list);
1901       if (MPLIST_SYMBOL_P (action))
1902         {
1903           name = MPLIST_SYMBOL (action);
1904           args = MPLIST_NEXT (action);
1905           if (name == Minsert
1906               && MPLIST_PLIST_P (args))
1907             mplist_set (action, Msymbol, M_candidates);
1908         }
1909       else if (MPLIST_MTEXT_P (action) || MPLIST_PLIST_P (action))
1910         {
1911           action = mplist ();
1912           mplist_push (action, Mplist, MPLIST_VAL (action_list));
1913           mplist_push (action, Msymbol, M_candidates);
1914           mplist_set (action_list, Mplist, action);
1915           M17N_OBJECT_UNREF (action);
1916         }
1917     }
1918   else if (MPLIST_MTEXT_P (action_list) || MPLIST_INTEGER_P (action_list))
1919     {
1920       action = mplist ();
1921       mplist_push (action, MPLIST_KEY (action_list), MPLIST_VAL (action_list));
1922       mplist_push (action, Msymbol, Minsert);
1923       mplist_set (action_list, Mplist, action);
1924       M17N_OBJECT_UNREF (action);
1925     }
1926   return action;
1927 }
1928
1929 static int
1930 take_action_list (MInputContext *ic, MPlist *action_list)
1931 {
1932   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1933   MPlist *candidate_list = ic->candidate_list;
1934   int candidate_index = ic->candidate_index;
1935   int candidate_show = ic->candidate_show;
1936   MTextProperty *prop;
1937
1938   MPLIST_DO (action_list, action_list)
1939     {
1940       MPlist *action = regularize_action (action_list);
1941       MSymbol name;
1942       MPlist *args;
1943
1944       if (! action)
1945         continue;
1946       name = MPLIST_SYMBOL (action);
1947       args = MPLIST_NEXT (action);
1948
1949       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
1950       if (name == Minsert)
1951         {
1952           if (MPLIST_SYMBOL_P (args))
1953             {
1954               args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
1955               if (! MPLIST_MTEXT_P (args) && ! MPLIST_INTEGER_P (args))
1956                 continue;
1957             }
1958           if (MPLIST_MTEXT_P (args))
1959             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
1960           else                  /* MPLIST_INTEGER_P (args)) */
1961             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
1962         }
1963       else if (name == M_candidates)
1964         {
1965           MPlist *plist = get_candidate_list (ic_info, args);
1966           int len;
1967
1968           if (! plist)
1969             continue;
1970           if (MPLIST_MTEXT_P (plist))
1971             {
1972               preedit_insert (ic, ic->cursor_pos, NULL,
1973                               mtext_ref_char (MPLIST_MTEXT (plist), 0));
1974               len = 1;
1975             }
1976           else
1977             {
1978               MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
1979
1980               preedit_insert (ic, ic->cursor_pos, mt, 0);
1981               len = mtext_nchars (mt);
1982             }
1983           mtext_put_prop (ic->preedit,
1984                           ic->cursor_pos - len, ic->cursor_pos,
1985                           Mcandidate_list, plist);
1986           mtext_put_prop (ic->preedit,
1987                           ic->cursor_pos - len, ic->cursor_pos,
1988                           Mcandidate_index, (void *) 0);
1989           M17N_OBJECT_UNREF (plist);
1990         }
1991       else if (name == Mselect)
1992         {
1993           int start, end;
1994           int code, idx, gindex;
1995           int pos = ic->cursor_pos;
1996           MPlist *group;
1997
1998           if (pos == 0
1999               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
2000                                                Mcandidate_list)))
2001             continue;
2002           if (MPLIST_SYMBOL_P (args))
2003             {
2004               code = marker_code (MPLIST_SYMBOL (args));
2005               if (code < 0)
2006                 continue;
2007             }
2008           else
2009             code = -1;
2010           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
2011           group = find_candidates_group (mtext_property_value (prop), idx,
2012                                          &start, &end, &gindex);
2013
2014           if (code != '[' && code != ']')
2015             {
2016               idx = (start
2017                      + (code >= 0
2018                         ? new_index (NULL, ic->candidate_index - start,
2019                                      end - start - 1, MPLIST_SYMBOL (args),
2020                                      NULL)
2021                         : MPLIST_INTEGER (args)));
2022               if (idx < 0)
2023                 {
2024                   find_candidates_group (mtext_property_value (prop), -1,
2025                                          NULL, &end, NULL);
2026                   idx = end - 1;
2027                 }
2028               else if (idx >= end
2029                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
2030                 idx = 0;
2031             }
2032           else
2033             {
2034               int ingroup_index = idx - start;
2035               int len;
2036
2037               group = mtext_property_value (prop);
2038               len = mplist_length (group);
2039               if (code == '[')
2040                 {
2041                   gindex--;
2042                   if (gindex < 0)
2043                     gindex = len - 1;;
2044                 }
2045               else
2046                 {
2047                   gindex++;
2048                   if (gindex >= len)
2049                     gindex = 0;
2050                 }
2051               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
2052                 idx += (MPLIST_MTEXT_P (group)
2053                         ? mtext_nchars (MPLIST_MTEXT (group))
2054                         : mplist_length (MPLIST_PLIST (group)));
2055               len = (MPLIST_MTEXT_P (group)
2056                      ? mtext_nchars (MPLIST_MTEXT (group))
2057                      : mplist_length (MPLIST_PLIST (group)));
2058               if (ingroup_index >= len)
2059                 ingroup_index = len - 1;
2060               idx += ingroup_index;
2061             }
2062           update_candidate (ic, prop, idx);
2063         }
2064       else if (name == Mshow)
2065         ic->candidate_show = 1;
2066       else if (name == Mhide)
2067         ic->candidate_show = 0;
2068       else if (name == Mdelete)
2069         {
2070           int len = mtext_nchars (ic->preedit);
2071           int pos;
2072           int to;
2073
2074           if (MPLIST_SYMBOL_P (args)
2075               && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
2076             {
2077               delete_surrounding_text (ic, pos);
2078             }
2079           else
2080             {
2081               to = (MPLIST_SYMBOL_P (args)
2082                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
2083                                  ic->preedit)
2084                     : MPLIST_INTEGER (args));
2085               if (to < 0)
2086                 to = 0;
2087               else if (to > len)
2088                 to = len;
2089               MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
2090               if (to < ic->cursor_pos)
2091                 preedit_delete (ic, to, ic->cursor_pos);
2092               else if (to > ic->cursor_pos)
2093                 preedit_delete (ic, ic->cursor_pos, to);
2094             }
2095         }
2096       else if (name == Mmove)
2097         {
2098           int len = mtext_nchars (ic->preedit);
2099           int pos
2100             = (MPLIST_SYMBOL_P (args)
2101                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
2102                             ic->preedit)
2103                : MPLIST_INTEGER (args));
2104
2105           if (pos < 0)
2106             pos = 0;
2107           else if (pos > len)
2108             pos = len;
2109           if (pos != ic->cursor_pos)
2110             {
2111               ic->cursor_pos = pos;
2112               ic->preedit_changed = 1;
2113             }
2114         }
2115       else if (name == Mmark)
2116         {
2117           int code = marker_code (MPLIST_SYMBOL (args));
2118
2119           if (code < 0)
2120             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
2121                         (void *) ic->cursor_pos);
2122         }
2123       else if (name == Mpushback)
2124         {
2125           if (MPLIST_INTEGER_P (args))
2126             {
2127               int num = MPLIST_INTEGER (args);
2128
2129               if (num > 0)
2130                 ic_info->key_head -= num;
2131               else
2132                 ic_info->key_head = num;
2133               if (ic_info->key_head > ic_info->used)
2134                 ic_info->key_head = ic_info->used;
2135             }
2136           else if (MPLIST_MTEXT_P (args))
2137             {
2138               MText *mt = MPLIST_MTEXT (args);
2139               int i, len = mtext_nchars (mt);
2140               MSymbol key;
2141
2142               ic_info->key_head--;
2143               for (i = 0; i < len; i++)
2144                 {
2145                   key = one_char_symbol[MTEXT_DATA (mt)[i]];
2146                   if (ic_info->key_head + i < ic_info->used)
2147                     ic_info->keys[ic_info->key_head + i] = key;
2148                   else
2149                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2150                 }
2151             }
2152           else
2153             {
2154               MPlist *plist = MPLIST_PLIST (args), *pl;
2155               int i = 0;
2156               MSymbol key;
2157
2158               ic_info->key_head--;
2159
2160               MPLIST_DO (pl, plist)
2161                 {
2162                   key = MPLIST_SYMBOL (pl);
2163                   if (ic_info->key_head < ic_info->used)
2164                     ic_info->keys[ic_info->key_head + i] = key;
2165                   else
2166                     MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2167                   i++;
2168                 }
2169             }
2170         }
2171       else if (name == Mcall)
2172         {
2173           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2174           MIMExternalFunc func = NULL;
2175           MSymbol module, func_name;
2176           MPlist *func_args, *val;
2177           int ret = 0;
2178
2179           module = MPLIST_SYMBOL (args);
2180           args = MPLIST_NEXT (args);
2181           func_name = MPLIST_SYMBOL (args);
2182
2183           if (im_info->externals)
2184             {
2185               MIMExternalModule *external
2186                 = (MIMExternalModule *) mplist_get (im_info->externals,
2187                                                     module);
2188               if (external)
2189                 func = (MIMExternalFunc) mplist_get (external->func_list,
2190                                                      func_name);
2191             }
2192           if (! func)
2193             continue;
2194           func_args = mplist ();
2195           mplist_add (func_args, Mt, ic);
2196           MPLIST_DO (args, MPLIST_NEXT (args))
2197             {
2198               int code;
2199
2200               if (MPLIST_KEY (args) == Msymbol
2201                   && MPLIST_KEY (args) != Mnil
2202                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
2203                 {
2204                   code = new_index (ic, ic->cursor_pos, 
2205                                     mtext_nchars (ic->preedit),
2206                                     MPLIST_SYMBOL (args), ic->preedit);
2207                   mplist_add (func_args, Minteger, (void *) code);
2208                 }
2209               else
2210                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
2211             }
2212           val = (func) (func_args);
2213           M17N_OBJECT_UNREF (func_args);
2214           if (val && ! MPLIST_TAIL_P (val))
2215             ret = take_action_list (ic, val);
2216           M17N_OBJECT_UNREF (val);
2217           if (ret < 0)
2218             return ret;
2219         }
2220       else if (name == Mshift)
2221         {
2222           shift_state (ic, MPLIST_SYMBOL (args));
2223         }
2224       else if (name == Mundo)
2225         {
2226           int intarg = (MPLIST_TAIL_P (args)
2227                         ? ic_info->used - 2
2228                         : integer_value (ic, args, NULL, 0));
2229
2230           mtext_reset (ic->preedit);
2231           mtext_reset (ic_info->preedit_saved);
2232           ic->cursor_pos = ic_info->state_pos = 0;
2233           ic_info->state_key_head = ic_info->key_head = 0;
2234
2235           if (intarg < 0)
2236             ic_info->used += intarg;
2237           else
2238             ic_info->used = intarg;
2239           shift_state (ic, Mnil);
2240           break;
2241         }
2242       else if (name == Mset || name == Madd || name == Msub
2243                || name == Mmul || name == Mdiv)
2244         {
2245           MSymbol sym = MPLIST_SYMBOL (args);
2246           int val1, val2;
2247           MPlist *value;
2248           char *op;
2249
2250           val1 = integer_value (ic, args, &value, 0);
2251           args = MPLIST_NEXT (args);
2252           val2 = resolve_expression (ic, args);
2253           if (name == Mset)
2254             val1 = val2, op = "=";
2255           else if (name == Madd)
2256             val1 += val2, op = "+=";
2257           else if (name == Msub)
2258             val1 -= val2, op = "-=";
2259           else if (name == Mmul)
2260             val1 *= val2, op = "*=";
2261           else
2262             val1 /= val2, op = "/=";
2263           MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
2264                          MSYMBOL_NAME (sym), op, val1, val1);
2265           if (value)
2266             mplist_set (value, Minteger, (void *) val1);
2267         }
2268       else if (name == Mequal || name == Mless || name == Mgreater
2269                || name == Mless_equal || name == Mgreater_equal)
2270         {
2271           int val1, val2;
2272           MPlist *actions1, *actions2;
2273           int ret = 0;
2274
2275           val1 = resolve_expression (ic, args);
2276           args = MPLIST_NEXT (args);
2277           val2 = resolve_expression (ic, args);
2278           args = MPLIST_NEXT (args);
2279           actions1 = MPLIST_PLIST (args);
2280           args = MPLIST_NEXT (args);
2281           if (MPLIST_TAIL_P (args))
2282             actions2 = NULL;
2283           else
2284             actions2 = MPLIST_PLIST (args);
2285           MDEBUG_PRINT3 ("(%d %s %d)? ", val1, MSYMBOL_NAME (name), val2);
2286           if (name == Mequal ? val1 == val2
2287               : name == Mless ? val1 < val2
2288               : name == Mgreater ? val1 > val2
2289               : name == Mless_equal ? val1 <= val2
2290               : val1 >= val2)
2291             {
2292               MDEBUG_PRINT ("ok");
2293               ret = take_action_list (ic, actions1);
2294             }
2295           else
2296             {
2297               MDEBUG_PRINT ("no");
2298               if (actions2)
2299                 ret = take_action_list (ic, actions2);
2300             }
2301           if (ret < 0)
2302             return ret;
2303         }
2304       else if (name == Mcond)
2305         {
2306           int idx = 0;
2307
2308           MPLIST_DO (args, args)
2309             {
2310               MPlist *cond;
2311
2312               idx++;
2313               if (! MPLIST_PLIST (args))
2314                 continue;
2315               cond = MPLIST_PLIST (args);
2316               if (resolve_expression (ic, cond) != 0)
2317                 {
2318                   MDEBUG_PRINT1 ("(%dth)", idx);
2319                   if (take_action_list (ic, MPLIST_NEXT (cond)) < 0)
2320                     return -1;;
2321                   break;
2322                 }
2323             }
2324         }
2325       else if (name == Mcommit)
2326         {
2327           preedit_commit (ic);
2328         }
2329       else if (name == Munhandle)
2330         {
2331           preedit_commit (ic);
2332           return -1;
2333         }
2334       else
2335         {
2336           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2337           MPlist *actions;
2338
2339           if (im_info->macros
2340               && (actions = mplist_get (im_info->macros, name)))
2341             {
2342               if (take_action_list (ic, actions) < 0)
2343                 return -1;
2344             };
2345         }
2346     }
2347
2348   prop = NULL;
2349   if (ic->candidate_list)
2350     {
2351       M17N_OBJECT_UNREF (ic->candidate_list);
2352       ic->candidate_list = NULL;
2353     }
2354   if (ic->cursor_pos > 0
2355       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
2356                                      Mcandidate_list)))
2357     {
2358       ic->candidate_list = mtext_property_value (prop);
2359       M17N_OBJECT_REF (ic->candidate_list);
2360       ic->candidate_index
2361         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
2362                                 Mcandidate_index);
2363       ic->candidate_from = mtext_property_start (prop);
2364       ic->candidate_to = mtext_property_end (prop);
2365     }
2366
2367   if (candidate_list != ic->candidate_list)
2368     ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
2369   if (candidate_index != ic->candidate_index)
2370     ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
2371   if (candidate_show != ic->candidate_show)
2372     ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
2373   return 0;
2374 }
2375
2376
2377 /* Handle the input key KEY in the current state and map specified in
2378    the input context IC.  If KEY is handled correctly, return 0.
2379    Otherwise, return -1.  */
2380
2381 static int
2382 handle_key (MInputContext *ic)
2383 {
2384   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2385   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2386   MIMMap *map = ic_info->map;
2387   MIMMap *submap = NULL;
2388   MSymbol key = ic_info->keys[ic_info->key_head];
2389   MSymbol alias = Mnil;
2390   int i;
2391
2392   MDEBUG_PRINT2 ("  [IM] handle `%s' in state %s", 
2393                  MSYMBOL_NAME (key), MSYMBOL_NAME (ic_info->state->name));
2394
2395   if (map->submaps)
2396     {
2397       submap = mplist_get (map->submaps, key);
2398       if (! submap && (alias = msymbol_get (key, M_key_alias)) != Mnil)
2399         submap = mplist_get (map->submaps, alias);
2400     }
2401
2402   if (submap)
2403     {
2404       if (alias == Mnil)
2405         MDEBUG_PRINT (" submap-found");
2406       else
2407         MDEBUG_PRINT1 (" submap-found (by alias `%s')", MSYMBOL_NAME (alias));
2408       mtext_cpy (ic->preedit, ic_info->preedit_saved);
2409       ic->preedit_changed = 1;
2410       ic->cursor_pos = ic_info->state_pos;
2411       ic_info->key_head++;
2412       ic_info->map = map = submap;
2413       if (map->map_actions)
2414         {
2415           MDEBUG_PRINT (" map-actions:");
2416           if (take_action_list (ic, map->map_actions) < 0)
2417             {
2418               MDEBUG_PRINT ("\n");
2419               return -1;
2420             }
2421         }
2422       else if (map->submaps)
2423         {
2424           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
2425             {
2426               MSymbol key = ic_info->keys[i];
2427               char *name = msymbol_name (key);
2428
2429               if (! name[0] || ! name[1])
2430                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
2431             }
2432         }
2433
2434       /* If this is the terminal map or we have shifted to another
2435          state, perform branch actions (if any).  */
2436       if (! map->submaps || map != ic_info->map)
2437         {
2438           if (map->branch_actions)
2439             {
2440               MDEBUG_PRINT (" branch-actions:");
2441               if (take_action_list (ic, map->branch_actions) < 0)
2442                 {
2443                   MDEBUG_PRINT ("\n");
2444                   return -1;
2445                 }
2446             }
2447           /* If MAP is still not the root map, shift to the current
2448              state.  */
2449           if (ic_info->map != ic_info->state->map)
2450             shift_state (ic, ic_info->state->name);
2451         }
2452     }
2453   else
2454     {
2455       /* MAP can not handle KEY.  */
2456
2457       /* If MAP is the root map of the initial state, it means that
2458          the current input method can not handle KEY.  */
2459       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
2460         {
2461           MDEBUG_PRINT (" unhandled\n");
2462           return -1;
2463         }
2464
2465       if (map != ic_info->state->map)
2466         {
2467           /* If MAP is not the root map... */
2468           /* If MAP has branch actions, perform them.  */
2469           if (map->branch_actions)
2470             {
2471               MDEBUG_PRINT (" branch-actions:");
2472               if (take_action_list (ic, map->branch_actions) < 0)
2473                 {
2474                   MDEBUG_PRINT ("\n");
2475                   return -1;
2476                 }
2477             }
2478           /* If MAP is still not the root map, shift to the current
2479              state. */
2480           if (ic_info->map != ic_info->state->map)
2481             {
2482               shift_state (ic, ic_info->state->name);
2483               /* If MAP has branch_actions, perform them.  */
2484               if (ic_info->map->branch_actions)
2485                 {
2486                   MDEBUG_PRINT (" brank-actions:");
2487                   if (take_action_list (ic, ic_info->map->branch_actions) < 0)
2488                     return -1;
2489                 }
2490             }
2491         }
2492       else
2493         {
2494           /* MAP is the root map, perform branch actions (if any) or
2495              shift to the initial state.  */
2496           if (map->branch_actions)
2497             {
2498               MDEBUG_PRINT (" branch-actions:");
2499               if (take_action_list (ic, map->branch_actions) < 0)
2500                 {
2501                   MDEBUG_PRINT ("\n");
2502                   return -1;
2503                 }
2504             }
2505           else
2506             shift_state (ic, Mnil);
2507         }
2508     }
2509   MDEBUG_PRINT ("\n");
2510   return 0;
2511 }
2512
2513 static void
2514 reset_ic (MInputContext *ic, MSymbol ignore)
2515 {
2516   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2517   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2518   MText *status;
2519
2520   MDEBUG_PRINT ("\n  [IM] reset\n");
2521
2522   ic_info->state = (MIMState *) MPLIST_VAL (im_info->states);
2523   ic_info->prev_state = NULL;
2524   ic_info->map = ic_info->state->map;
2525   ic_info->state_key_head = ic_info->key_head;
2526   MLIST_RESET (ic_info);
2527   ic_info->key_unhandled = 0;
2528
2529   if (mtext_nchars (ic->produced) > 0)
2530     mtext_reset (ic->produced);
2531   if (mtext_nchars (ic->preedit) > 0)
2532     {
2533       MPlist *plist;
2534
2535       mtext_reset (ic->preedit);
2536       MPLIST_DO (plist, ic_info->markers)
2537         MPLIST_VAL (plist) = 0;
2538       ic->preedit_changed = 1;
2539     }
2540   if (ic->candidate_show)
2541     {
2542       ic->candidate_show = 0;
2543       ic->candidates_changed = MINPUT_CANDIDATES_SHOW_CHANGED;
2544       if (ic->candidate_list)
2545         {
2546           M17N_OBJECT_UNREF (ic->candidate_list);
2547           ic->candidate_list = NULL;
2548           ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
2549         }
2550     }
2551   mtext_reset (ic_info->preedit_saved);
2552   ic_info->state_pos = ic->cursor_pos = 0;
2553
2554   status = ic_info->state->title ? ic_info->state->title : im_info->title;
2555   if (ic->status != status)
2556     {
2557       ic->status = status;
2558       ic->status_changed = 1;
2559     }
2560 }
2561
2562 static int
2563 open_im (MInputMethod *im)
2564 {
2565   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil);
2566
2567   if (! im_info)
2568     MERROR (MERROR_IM, -1);
2569   im->info = im_info;
2570   im_info->im = im;
2571   return 0;
2572 }
2573
2574 static void
2575 close_im (MInputMethod *im)
2576 {
2577   im->info = NULL;
2578 }
2579
2580 static int
2581 create_ic (MInputContext *ic)
2582 {
2583   MInputMethod *im = ic->im;
2584   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2585   MInputContextInfo *ic_info;
2586   MPlist *plist;
2587
2588   if (ic->info)
2589     ic_info = (MInputContextInfo *) ic->info;
2590   else
2591     {
2592       MSTRUCT_CALLOC (ic_info, MERROR_IM);
2593       ic->info = ic_info;
2594     }
2595   MLIST_INIT1 (ic_info, keys, 8);
2596   ic_info->markers = mplist ();
2597   ic_info->vars = mplist ();
2598   plist = get_nested_list (im->language, im->name, Mnil, M_variable);
2599   MPLIST_DO (plist, plist)
2600     {
2601       MSymbol var = MPLIST_SYMBOL (plist);
2602       MPlist *pl;
2603
2604       plist = MPLIST_NEXT (plist);
2605       pl = MPLIST_PLIST (plist);
2606       pl = MPLIST_NEXT (pl);    /* Skip description.  */
2607       mplist_push (ic_info->vars, MPLIST_KEY (pl), MPLIST_VAL (pl));
2608       mplist_push (ic_info->vars, Msymbol, var);
2609     }
2610
2611   ic_info->preedit_saved = mtext ();
2612   if (im_info->externals)
2613     {
2614       MPlist *func_args = mplist (), *plist;
2615
2616       mplist_add (func_args, Mt, ic);
2617       MPLIST_DO (plist, im_info->externals)
2618         {
2619           MIMExternalModule *external = MPLIST_VAL (plist);
2620           MIMExternalFunc func
2621             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
2622
2623           if (func)
2624             (func) (func_args);
2625         }
2626       M17N_OBJECT_UNREF (func_args);
2627     }
2628   reset_ic (ic, Mnil);
2629   return 0;
2630 }
2631
2632 static void
2633 destroy_ic (MInputContext *ic)
2634 {
2635   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2636   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2637
2638   if (im_info->externals)
2639     {
2640       MPlist *func_args = mplist (), *plist;
2641
2642       mplist_add (func_args, Mt, ic);
2643       MPLIST_DO (plist, im_info->externals)
2644         {
2645           MIMExternalModule *external = MPLIST_VAL (plist);
2646           MIMExternalFunc func
2647             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
2648
2649           if (func)
2650             (func) (func_args);
2651         }
2652       M17N_OBJECT_UNREF (func_args);
2653     }
2654   MLIST_FREE1 (ic_info, keys);
2655   M17N_OBJECT_UNREF (ic_info->preedit_saved);
2656   M17N_OBJECT_UNREF (ic_info->markers);
2657   M17N_OBJECT_UNREF (ic_info->vars);
2658   M17N_OBJECT_UNREF (ic_info->preceding_text);
2659   M17N_OBJECT_UNREF (ic_info->following_text);
2660   free (ic->info);
2661 }
2662
2663
2664 /** Handle the input key KEY in the current state and map of IC->info.
2665     If KEY is handled but no text is produced, return 0, otherwise
2666     return 1.
2667
2668     Ignore ARG.  */
2669
2670 static int
2671 filter (MInputContext *ic, MSymbol key, void *arg)
2672 {
2673   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
2674   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
2675   int i = 0;
2676
2677   if (! ic_info->state)
2678     {
2679       ic_info->key_unhandled = 1;
2680       return 0;
2681     }
2682   mtext_reset (ic->produced);
2683   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
2684   M17N_OBJECT_UNREF (ic_info->preceding_text);
2685   M17N_OBJECT_UNREF (ic_info->following_text);
2686   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
2687   ic_info->key_unhandled = 0;
2688
2689   /* If KEY has Meta or Alt modifier, put M_key_alias property.  */
2690   if (! msymbol_get (key, M_key_alias)
2691       && (strchr (MSYMBOL_NAME (key), 'M')
2692           || strchr (MSYMBOL_NAME (key), 'A')))
2693     {
2694       char *name = MSYMBOL_NAME (key);
2695       char *meta_or_alt;
2696
2697       while (name[0] && name[1] == '-'
2698              && (name[0] != 'M' && name[0] != 'A'))
2699         name += 2;
2700       if ((name[0] == 'M' || name[0] == 'A') && name[1] == '-')
2701         {
2702           MSymbol alias;
2703
2704           meta_or_alt = name;
2705           name = alloca (MSYMBOL_NAMELEN (key) + 1);
2706           memcpy (name, MSYMBOL_NAME (key), MSYMBOL_NAMELEN (key) + 1);
2707           name[meta_or_alt - MSYMBOL_NAME (key)]
2708             = *meta_or_alt == 'M' ? 'A' : 'M';
2709           alias = msymbol (name);
2710           msymbol_put (key, M_key_alias, alias);
2711         }
2712     }
2713   else if (MSYMBOL_NAME (key)[0] == 'S'
2714            && MSYMBOL_NAME (key)[1] == '-'
2715            && MSYMBOL_NAME (key)[2] >= 'A' && MSYMBOL_NAME (key)[2] <= 'Z')
2716     msymbol_put (key, M_key_alias, one_char_symbol[(int)MSYMBOL_NAME (key)[2]]);
2717
2718   do {
2719     if (handle_key (ic) < 0)
2720       {
2721         /* KEY was not handled.  Delete it from the current key sequence.  */
2722         if (ic_info->used > 0)
2723           {
2724             memmove (ic_info->keys, ic_info->keys + 1,
2725                      sizeof (int) * (ic_info->used - 1));
2726             ic_info->used--;
2727           }
2728         /* This forces returning 1.  */
2729         ic_info->key_unhandled = 1;
2730         break;
2731       }
2732     if (i++ == 100)
2733       {
2734         mdebug_hook ();
2735         reset_ic (ic, Mnil);
2736         ic_info->key_unhandled = 1;
2737         break;
2738       }
2739     /* Break the loop if all keys were handled.  */
2740   } while (ic_info->key_head < ic_info->used);
2741
2742   /* If the current map is the root of the initial state, we should
2743      produce any preedit text in ic->produced.  */
2744   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
2745       && mtext_nchars (ic->preedit) > 0)
2746     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
2747
2748   if (mtext_nchars (ic->produced) > 0)
2749     {
2750       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
2751
2752       if (lang != Mnil)
2753         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
2754                         Mlanguage, ic->im->language);
2755     }
2756
2757   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
2758 }
2759
2760
2761 /** Return 1 if the last event or key was not handled, otherwise
2762     return 0.
2763
2764     There is no need of looking up because ic->produced should already
2765     contain the produced text (if any).
2766
2767     Ignore KEY.  */
2768
2769 static int
2770 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2771 {
2772   mtext_cat (mt, ic->produced);
2773   mtext_reset (ic->produced);
2774   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
2775 }
2776
2777 static MPlist *load_im_info_keys;
2778
2779 static MPlist *
2780 load_partial_im_info (MSymbol language, MSymbol name,
2781                       MSymbol extra, MSymbol key)
2782 {
2783   MDatabase *mdb;
2784   MPlist *plist;
2785
2786   if (language == Mnil)
2787     MERROR (MERROR_IM, NULL);
2788   mdb = mdatabase_find (Minput_method, language, name, extra);
2789   if (! mdb)
2790     MERROR (MERROR_IM, NULL);
2791
2792   mplist_push (load_im_info_keys, key, Mt);
2793   plist = mdatabase__load_for_keys (mdb, load_im_info_keys);
2794   mplist_pop (load_im_info_keys);
2795   return plist;
2796 }
2797
2798
2799 static MInputMethodInfo *
2800 get_im_info (MSymbol language, MSymbol name, MSymbol extra)
2801 {
2802   MDatabase *mdb;
2803   MPlist *plist;
2804   MInputMethodInfo *im_info = NULL;
2805
2806   if (language == Mnil)
2807     MERROR (MERROR_IM, NULL);
2808   mdb = mdatabase_find (Minput_method, language, name, extra);
2809   if (! mdb)
2810     MERROR (MERROR_IM, NULL);
2811
2812   if (! im_info_list)
2813     im_info_list = mplist ();
2814   else if ((plist = mplist_find_by_value (im_info_list, mdb)))
2815     {
2816       if (mdatabase__check (mdb))
2817         {
2818           plist = MPLIST_NEXT (plist);
2819           im_info = MPLIST_VAL (plist);
2820           return im_info;
2821         }
2822       mplist_pop (plist);
2823       free_im_info (MPLIST_VAL (plist));
2824       mplist_pop (plist);
2825     }
2826
2827   plist = mdatabase_load (mdb);
2828   if (! plist)
2829     MERROR (MERROR_IM, NULL);
2830   im_info = load_im_info (language, name, plist);
2831   M17N_OBJECT_UNREF (plist);
2832   if (! im_info)
2833     MERROR (MERROR_IM, NULL);
2834   mplist_push (im_info_list, Mt, im_info);
2835   mplist_push (im_info_list, Mt, mdb);
2836   return im_info;
2837 }
2838
2839 \f
2840 /* Input method command handler.  */
2841
2842 /* List of all (global and local) commands. 
2843    (LANG:(IM-NAME:(COMMAND ...) ...) ...) ...
2844    COMMAND is CMD-NAME:(mtext:DESCRIPTION plist:KEYSEQ ...))
2845    Global commands are storead as (t (t COMMAND ...))  */
2846
2847 /* Check if PLIST is a valid command key sequence.
2848    PLIST must be NULL or:
2849    [ symbol:KEY | integer:KEY ] ...  */
2850
2851 static int
2852 check_command_keyseq (MPlist *plist)
2853 {
2854   if (! plist)
2855     return 0;
2856   MPLIST_DO (plist, plist)
2857     {
2858       if (MPLIST_SYMBOL_P (plist))
2859         continue;
2860       else if (MPLIST_INTEGER_P (plist))
2861         {
2862           int n = MPLIST_INTEGER (plist);
2863
2864           if (n < 0 || n > 9)
2865             return -1;
2866           MPLIST_KEY (plist) = Msymbol;
2867           MPLIST_VAL (plist) = one_char_symbol['0' + 9];
2868         }
2869       else
2870         return -1;
2871     }
2872   return 0;
2873 }
2874
2875 /* Check if PLIST has this form:
2876      ([ plist:([ symbol:KEY | integer:KEY ]) | mtext:KEYSEQ ]
2877       ...)
2878    If the form of PLIST matches, return 0, otherwise return -1.  */
2879
2880 static int
2881 check_command_list (MPlist *plist)
2882 {
2883   MPLIST_DO (plist, plist)
2884     {
2885       if (MPLIST_PLIST_P (plist))
2886         {
2887           MPlist *pl = MPLIST_PLIST (plist);
2888
2889           MPLIST_DO (pl, pl)
2890             if (! MPLIST_SYMBOL_P (pl) && ! MPLIST_INTEGER_P (pl))
2891               return -1;
2892         }
2893       else if (! MPLIST_MTEXT_P (plist))
2894         return -1;
2895     }
2896   return 0;
2897 }
2898
2899
2900 \f
2901 /* Input method variable handler.  */
2902
2903 /* Check if PLIST has this form:
2904      (TYPE:VAL   ;; TYPE ::= integer | mtext | symbol
2905       VALID-VALUE
2906       ...)
2907    If the form of PLIST matches, return 0, otherwise return -1.  */
2908
2909 static int
2910 check_variable_list (MPlist *plist)
2911 {
2912   MSymbol type = MPLIST_KEY (plist);
2913   MPlist *p; 
2914
2915   if (type != Minteger && type != Mtext && type != Msymbol)
2916     return -1;
2917   MPLIST_DO (plist, MPLIST_NEXT (plist))
2918     {
2919       if (type == Minteger && MPLIST_PLIST_P (plist))
2920         {
2921           MPLIST_DO (p, MPLIST_PLIST (plist))
2922             if (! MPLIST_INTEGER_P (p))
2923               return -1;
2924         }
2925       else if (type != MPLIST_KEY (plist))
2926         return -1;
2927     }
2928   return 0;
2929 }
2930
2931 /* Support functions for mdebug_dump_im.  */
2932
2933 static void
2934 dump_im_map (MPlist *map_list, int indent)
2935 {
2936   char *prefix;
2937   MSymbol key = MPLIST_KEY (map_list);
2938   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
2939
2940   prefix = (char *) alloca (indent + 1);
2941   memset (prefix, 32, indent);
2942   prefix[indent] = '\0';
2943
2944   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
2945   if (map->map_actions)
2946     mdebug_dump_plist (map->map_actions, indent + 2);
2947   if (map->submaps)
2948     {
2949       MPLIST_DO (map_list, map->submaps)
2950         {
2951           fprintf (stderr, "\n%s  ", prefix);
2952           dump_im_map (map_list, indent + 2);
2953         }
2954     }
2955   if (map->branch_actions)
2956     {
2957       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
2958       mdebug_dump_plist (map->branch_actions, indent + 4);
2959       fprintf (stderr, ")");      
2960     }
2961   fprintf (stderr, ")");
2962 }
2963
2964
2965 static void
2966 dump_im_state (MIMState *state, int indent)
2967 {
2968   char *prefix;
2969   MPlist *map_list;
2970
2971   prefix = (char *) alloca (indent + 1);
2972   memset (prefix, 32, indent);
2973   prefix[indent] = '\0';
2974
2975   fprintf (stderr, "(%s", msymbol_name (state->name));
2976   if (state->map->submaps)
2977     {
2978       MPLIST_DO (map_list, state->map->submaps)
2979         {
2980           fprintf (stderr, "\n%s  ", prefix);
2981           dump_im_map (map_list, indent + 2);
2982         }
2983     }
2984   fprintf (stderr, ")");
2985 }
2986
2987 \f
2988
2989 int
2990 minput__init ()
2991 {
2992   char *key_names[32]
2993     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2994         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
2995         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2996         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
2997   char buf[6], buf2[256];
2998   int i;
2999
3000   Minput_method = msymbol ("input-method");
3001   Minput_driver = msymbol ("input-driver");
3002   Mtitle = msymbol ("title");
3003   Mmacro = msymbol ("macro");
3004   Mmodule = msymbol ("module");
3005   Mmap = msymbol ("map");
3006   Mstate = msymbol ("state");
3007   Minclude = msymbol ("include");
3008   Minsert = msymbol ("insert");
3009   M_candidates = msymbol ("  candidates");
3010   Mdelete = msymbol ("delete");
3011   Mmove = msymbol ("move");
3012   Mmark = msymbol ("mark");
3013   Mpushback = msymbol ("pushback");
3014   Mundo = msymbol ("undo");
3015   Mcall = msymbol ("call");
3016   Mshift = msymbol ("shift");
3017   Mselect = msymbol ("select");
3018   Mshow = msymbol ("show");
3019   Mhide = msymbol ("hide");
3020   Mcommit = msymbol ("commit");
3021   Munhandle = msymbol ("unhandle");
3022   Mset = msymbol ("set");
3023   Madd = msymbol ("add");
3024   Msub = msymbol ("sub");
3025   Mmul = msymbol ("mul");
3026   Mdiv = msymbol ("div");
3027   Mequal = msymbol ("=");
3028   Mless = msymbol ("<");
3029   Mgreater = msymbol (">");
3030   Mless_equal = msymbol ("<=");
3031   Mgreater_equal = msymbol (">=");
3032   Mcond = msymbol ("cond");
3033   Mplus = msymbol ("+");
3034   Mminus = msymbol ("-");
3035   Mstar = msymbol ("*");
3036   Mslush = msymbol ("/");
3037   Mand = msymbol ("&");
3038   Mor = msymbol ("|");
3039   Mnot = msymbol ("!");
3040
3041   Mcandidates_group_size = msymbol ("candidates-group-size");
3042   Mcandidates_charset = msymbol ("candidates-charset");
3043
3044   Minput_preedit_start = msymbol ("input-preedit-start");
3045   Minput_preedit_done = msymbol ("input-preedit-done");
3046   Minput_preedit_draw = msymbol ("input-preedit-draw");
3047   Minput_status_start = msymbol ("input-status-start");
3048   Minput_status_done = msymbol ("input-status-done");
3049   Minput_status_draw = msymbol ("input-status-draw");
3050   Minput_candidates_start = msymbol ("input-candidates-start");
3051   Minput_candidates_done = msymbol ("input-candidates-done");
3052   Minput_candidates_draw = msymbol ("input-candidates-draw");
3053   Minput_set_spot = msymbol ("input-set-spot");
3054   Minput_focus_move = msymbol ("input-focus-move");
3055   Minput_focus_in = msymbol ("input-focus-in");
3056   Minput_focus_out = msymbol ("input-focus-out");
3057   Minput_toggle = msymbol ("input-toggle");
3058   Minput_reset = msymbol ("input-reset");
3059   Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
3060   Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
3061
3062   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
3063   Mcandidate_index = msymbol ("  candidate-index");
3064
3065   Minit = msymbol ("init");
3066   Mfini = msymbol ("fini");
3067
3068   M_key_alias = msymbol ("  key-alias");
3069   M_description = msymbol ("description");
3070   M_command = msymbol ("command");
3071   M_variable = msymbol ("variable");
3072
3073   load_im_info_keys = mplist ();
3074   mplist_add (load_im_info_keys, Mstate, Mnil);
3075   mplist_push (load_im_info_keys, Mmap, Mnil);
3076
3077   buf[0] = 'C';
3078   buf[1] = '-';
3079   buf[3] = '\0';
3080   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
3081     {
3082       MSymbol alias;
3083
3084       one_char_symbol[i] = msymbol (buf);
3085       if (key_names[i])
3086         {
3087           alias = msymbol (key_names[i]);
3088           msymbol_put (one_char_symbol[i], M_key_alias,  alias);
3089         }
3090       else
3091         alias = one_char_symbol[i];
3092       buf[2] += (i == 0) ? -32 : 32;
3093       msymbol_put (alias, M_key_alias,  msymbol (buf));
3094       buf[2] -= (i == 0) ? -32 : 32;
3095     }
3096   for (buf[2] = i; i < 127; i++, buf[2]++)
3097     one_char_symbol[i] = msymbol (buf + 2);
3098   one_char_symbol[i++] = msymbol ("Delete");
3099   buf[2] = 'M';
3100   buf[3] = '-';
3101   buf[5] = '\0';
3102   buf2[0] = 'M';
3103   buf2[1] = '-';
3104   for (buf[4] = '@'; i < 160; i++, buf[4]++)
3105     {
3106       one_char_symbol[i] = msymbol (buf);
3107       if (key_names[i - 128])
3108         {
3109           strcpy (buf2 + 2, key_names[i - 128]);
3110           msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (buf2));
3111         }
3112     }
3113   for (buf[4] = i - 128; i < 255; i++, buf[4]++)
3114     one_char_symbol[i] = msymbol (buf + 2);
3115   one_char_symbol[i] = msymbol ("M-Delete");
3116
3117   command_list = variable_list = NULL;
3118
3119   minput_default_driver.open_im = open_im;
3120   minput_default_driver.close_im = close_im;
3121   minput_default_driver.create_ic = create_ic;
3122   minput_default_driver.destroy_ic = destroy_ic;
3123   minput_default_driver.filter = filter;
3124   minput_default_driver.lookup = lookup;
3125   minput_default_driver.callback_list = mplist ();
3126   mplist_put (minput_default_driver.callback_list, Minput_reset,
3127               (void *) reset_ic);
3128   minput_driver = &minput_default_driver;
3129   return 0;
3130 }
3131
3132 void
3133 minput__fini ()
3134 {
3135   if (command_list)
3136     {
3137       M17N_OBJECT_UNREF (command_list);
3138       command_list = NULL;
3139     }
3140   if (variable_list)
3141     {
3142       M17N_OBJECT_UNREF (variable_list);
3143       variable_list = NULL;
3144     }
3145
3146   if (minput_default_driver.callback_list)
3147     {
3148       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
3149       minput_default_driver.callback_list = NULL;
3150     }
3151   if (minput_driver->callback_list)
3152     {
3153       M17N_OBJECT_UNREF (minput_driver->callback_list);
3154       minput_driver->callback_list = NULL;
3155     }
3156
3157   if (im_info_list)
3158     {
3159       while (! MPLIST_TAIL_P (im_info_list))
3160         {
3161           /* Pop (t . mdb) */
3162           mplist_pop (im_info_list);
3163           free_im_info ((MInputMethodInfo *) MPLIST_VAL (im_info_list));
3164           /* Pop (t . im_info) */
3165           mplist_pop (im_info_list);
3166         }
3167       M17N_OBJECT_UNREF (im_info_list);
3168       im_info_list = NULL;
3169     }
3170  
3171   M17N_OBJECT_UNREF (load_im_info_keys);
3172 }
3173
3174 void
3175 minput__callback (MInputContext *ic, MSymbol command)
3176 {
3177   if (ic->im->driver.callback_list)
3178     {
3179       MInputCallbackFunc func
3180         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
3181                                            command);
3182
3183       if (func)
3184         (func) (ic, command);
3185     }
3186 }
3187
3188 MSymbol
3189 minput__char_to_key (int c)
3190 {
3191   if (c < 0 || c >= 0x100)
3192     return Mnil;
3193
3194   return one_char_symbol[c];
3195 }
3196
3197 /*** @} */
3198 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
3199
3200 \f
3201 /* External API */
3202
3203 /*** @addtogroup m17nInputMethod */
3204 /*** @{ */
3205 /*=*/
3206
3207 /***en
3208     @name Variables: Predefined symbols for callback commands.
3209
3210     These are the predefined symbols that are used as the @c COMMAND
3211     argument of callback functions of an input method driver (see
3212     #MInputDriver::callback_list ).  
3213
3214     Most of them don't require extra argument nor return any value;
3215     exceptions are these:
3216
3217     Minput_get_surrounding_text: When a callback function assigned for
3218     this command is called, the first element of #MInputContext::plist
3219     has key #Msymbol and the value specifies which portion of the
3220     surrounding text should be retrieved.  If the value is positive,
3221     it specifies the number of characters following the current cursor
3222     position.  If the value is negative, the absolute value specifies
3223     the number of characters preceding the current cursor position.
3224     The callback function must set the key of this element to #Mtext
3225     and the value to the retrived M-text (whose length may be shorter
3226     than the requested number of characters if the available text is
3227     not that long, or it may be longer if an application thinks it's
3228     more efficient to return that length).
3229
3230     Minput_delete_surrounding_text: When a callback function assigned
3231     for this command is called, the first element of
3232     #MInputContext::plist has key #Msymbol and the value specifies
3233     which portion of the surrounding text should be deleted in the
3234     same way as the case of Minput_get_surrounding_text.  The callback
3235     function must delete the specified text.  It should not alter
3236     #MInputContext::plist.  */ 
3237
3238 /***ja
3239     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
3240
3241     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND 
3242     °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
3243       */ 
3244 /*** @{ */ 
3245 /*=*/
3246
3247 MSymbol Minput_preedit_start;
3248 MSymbol Minput_preedit_done;
3249 MSymbol Minput_preedit_draw;
3250 MSymbol Minput_status_start;
3251 MSymbol Minput_status_done;
3252 MSymbol Minput_status_draw;
3253 MSymbol Minput_candidates_start;
3254 MSymbol Minput_candidates_done;
3255 MSymbol Minput_candidates_draw;
3256 MSymbol Minput_set_spot;
3257 MSymbol Minput_toggle;
3258 MSymbol Minput_reset;
3259 MSymbol Minput_get_surrounding_text;
3260 MSymbol Minput_delete_surrounding_text;
3261 /*** @} */
3262
3263 /*=*/
3264
3265 /***en
3266     @name Variables: Predefined symbols for special input events.
3267
3268     These are the predefined symbols that are used as the @c KEY
3269     argument of minput_filter ().  */ 
3270
3271 /*** @{ */ 
3272 /*=*/
3273
3274 MSymbol Minput_focus_out;
3275 MSymbol Minput_focus_in;
3276 MSymbol Minput_focus_move;
3277
3278 /*** @} */
3279
3280 /*=*/
3281
3282 /***en
3283     @brief The default driver for internal input methods.
3284
3285     The variable #minput_default_driver is the default driver for
3286     internal input methods.
3287
3288     The member MInputDriver::open_im () searches the m17n database for
3289     an input method that matches the tag \< #Minput_method, $LANGUAGE,
3290     $NAME\> and loads it.
3291
3292     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
3293     programmers responsibility to set it to a plist of proper callback
3294     functions.  Otherwise, no feedback information (e.g. preedit text)
3295     can be shown to users.
3296
3297     The macro M17N_INIT () sets the variable #minput_driver to the
3298     pointer to this driver so that all internal input methods use it.
3299
3300     Therefore, unless @c minput_driver is set differently, the driver
3301     dependent arguments $ARG of the functions whose name begins with
3302     "minput_" are all ignored.  */
3303
3304 /***ja
3305     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
3306
3307     ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£
3308
3309     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
3310     \< #Minput_method, $LANGUAGE, $NAME\> 
3311     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
3312
3313     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢
3314     ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist
3315     ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit 
3316     ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
3317
3318     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver 
3319     ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
3320
3321     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
3322     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
3323
3324 MInputDriver minput_default_driver;
3325 /*=*/
3326
3327 /***en
3328     @brief The driver for internal input methods.
3329
3330     The variable #minput_driver is a pointer to the input method
3331     driver that is used by internal input methods.  The macro
3332     M17N_INIT () initializes it to a pointer to #minput_default_driver
3333     if <m17n<EM></EM>.h> is included.  */ 
3334 /***ja
3335     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
3336
3337     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
3338     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
3339     ¥¿¤ò#minput_default_driver (<m17n<EM></EM>.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë
3340     »þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
3341
3342 MInputDriver *minput_driver;
3343
3344 MSymbol Minput_driver;
3345
3346 /*=*/
3347
3348 /***en
3349     @brief Open an input method.
3350
3351     The minput_open_im () function opens an input method whose
3352     language and name match $LANGUAGE and $NAME, and returns a pointer
3353     to the input method object newly allocated.
3354
3355     This function at first decides a driver for the input method as
3356     described below.
3357
3358     If $LANGUAGE is not #Mnil, the driver pointed by the variable
3359     #minput_driver is used.
3360
3361     If $LANGUAGE is #Mnil and $NAME has the property #Minput_driver, the
3362     driver pointed to by the property value is used to open the input
3363     method.  If $NAME has no such a property, @c NULL is returned.
3364
3365     Then, the member MInputDriver::open_im () of the driver is
3366     called.  
3367
3368     $ARG is set in the member @c arg of the structure MInputMethod so
3369     that the driver can refer to it.  */
3370
3371 /***ja
3372     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
3373
3374     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME 
3375     ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
3376     
3377     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
3378
3379     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver 
3380     ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
3381
3382     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver
3383     ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£
3384     $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
3385
3386     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
3387
3388     $ARG ¤Ï¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£
3389
3390     @latexonly \IPAlabel{minput_open} @endlatexonly
3391
3392 */
3393
3394 MInputMethod *
3395 minput_open_im (MSymbol language, MSymbol name, void *arg)
3396 {
3397   MInputMethod *im;
3398   MInputDriver *driver;
3399
3400   MDEBUG_PRINT2 ("  [IM] opening (%s %s) ... ",
3401          msymbol_name (language), msymbol_name (name));
3402   if (language)
3403     driver = minput_driver;
3404   else
3405     {
3406       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
3407       if (! driver)
3408         MERROR (MERROR_IM, NULL);
3409     }
3410
3411   MSTRUCT_CALLOC (im, MERROR_IM);
3412   im->language = language;
3413   im->name = name;
3414   im->arg = arg;
3415   im->driver = *driver;
3416   if ((*im->driver.open_im) (im) < 0)
3417     {
3418       MDEBUG_PRINT (" failed\n");
3419       free (im);
3420       return NULL;
3421     }
3422   MDEBUG_PRINT (" ok\n");
3423   return im;
3424 }
3425
3426 /*=*/
3427
3428 /***en
3429     @brief Close an input method.
3430
3431     The minput_close_im () function closes the input method $IM, which
3432     must have been created by minput_open_im ().  */
3433
3434 /***ja
3435     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
3436
3437     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£
3438     ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
3439
3440 void
3441 minput_close_im (MInputMethod *im)
3442 {
3443   MDEBUG_PRINT2 ("  [IM] closing (%s %s) ... ",
3444                  msymbol_name (im->name), msymbol_name (im->language));
3445   (*im->driver.close_im) (im);
3446   free (im);
3447   MDEBUG_PRINT (" done\n");
3448 }
3449
3450 /*=*/
3451
3452 /***en
3453     @brief Create an input context.
3454
3455     The minput_create_ic () function creates an input context object
3456     associated with input method $IM, and calls callback functions
3457     corresponding to #Minput_preedit_start, #Minput_status_start, and
3458     #Minput_status_draw in this order.
3459
3460     @return
3461     If an input context is successfully created, minput_create_ic ()
3462     returns a pointer to it.  Otherwise it returns @c NULL.  */
3463
3464 /***ja
3465     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
3466
3467     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
3468     ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
3469     #Minput_preedit_start, #Minput_status_start, #Minput_status_draw
3470     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
3471
3472     @return
3473     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () 
3474     ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
3475       */
3476
3477 MInputContext *
3478 minput_create_ic (MInputMethod *im, void *arg)
3479 {
3480   MInputContext *ic;
3481
3482   MDEBUG_PRINT2 ("  [IM] creating context (%s %s) ... ",
3483                  msymbol_name (im->name), msymbol_name (im->language));
3484   MSTRUCT_CALLOC (ic, MERROR_IM);
3485   ic->im = im;
3486   ic->arg = arg;
3487   ic->preedit = mtext ();
3488   ic->candidate_list = NULL;
3489   ic->produced = mtext ();
3490   ic->spot.x = ic->spot.y = 0;
3491   ic->active = 1;
3492   ic->plist = mplist ();
3493   if ((*im->driver.create_ic) (ic) < 0)
3494     {
3495       MDEBUG_PRINT (" failed\n");
3496       M17N_OBJECT_UNREF (ic->preedit);
3497       M17N_OBJECT_UNREF (ic->produced);
3498       M17N_OBJECT_UNREF (ic->plist);
3499       free (ic);
3500       return NULL;
3501     };
3502
3503   if (im->driver.callback_list)
3504     {
3505       minput__callback (ic, Minput_preedit_start);
3506       minput__callback (ic, Minput_status_start);
3507       minput__callback (ic, Minput_status_draw);
3508     }
3509
3510   MDEBUG_PRINT (" ok\n");
3511   return ic;
3512 }
3513
3514 /*=*/
3515
3516 /***en
3517     @brief Destroy an input context.
3518
3519     The minput_destroy_ic () function destroys the input context $IC,
3520     which must have been created by minput_create_ic ().  It calls
3521     callback functions corresponding to #Minput_preedit_done,
3522     #Minput_status_done, and #Minput_candidates_done in this order.  */
3523
3524 /***ja
3525     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
3526
3527     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
3528     ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () 
3529     ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï 
3530     #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done 
3531     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
3532   */
3533
3534 void
3535 minput_destroy_ic (MInputContext *ic)
3536 {
3537   MDEBUG_PRINT2 ("  [IM] destroying context (%s %s) ... ",
3538                  msymbol_name (ic->im->name), msymbol_name (ic->im->language));
3539   if (ic->im->driver.callback_list)
3540     {
3541       minput__callback (ic, Minput_preedit_done);
3542       minput__callback (ic, Minput_status_done);
3543       minput__callback (ic, Minput_candidates_done);
3544     }
3545   (*ic->im->driver.destroy_ic) (ic);
3546   M17N_OBJECT_UNREF (ic->preedit);
3547   M17N_OBJECT_UNREF (ic->produced);
3548   M17N_OBJECT_UNREF (ic->plist);
3549   MDEBUG_PRINT (" done\n");
3550   free (ic);
3551 }
3552
3553 /*=*/
3554
3555 /***en
3556     @brief Filter an input key.
3557
3558     The minput_filter () function filters input key $KEY according to
3559     input context $IC, and calls callback functions corresponding to
3560     #Minput_preedit_draw, #Minput_status_draw, and
3561     #Minput_candidates_draw if the preedit text, the status, and the
3562     current candidate are changed respectively.
3563
3564     To make the input method commit the current preedit text (if any)
3565     and shift to the initial state, call this function with #Mnil as
3566     $KEY.
3567
3568     To inform the input method about the focus-out event, call this
3569     function with #Minput_focus_out as $KEY.
3570
3571     To inform the input method about the focus-in event, call this
3572     function with #Minput_focus_in as $KEY.
3573
3574     To inform the input method about the focus-move event (i.e. input
3575     spot change within the same input context), call this function
3576     with #Minput_focus_move as $KEY.
3577
3578     @return
3579     If $KEY is filtered out, this function returns 1.  In that case,
3580     the caller should discard the key.  Otherwise, it returns 0, and
3581     the caller should handle the key, for instance, by calling the
3582     function minput_lookup () with the same key.  */
3583
3584 /***ja
3585     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
3586
3587     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
3588     ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
3589     #Minput_preedit_draw, #Minput_status_draw,
3590     #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
3591
3592     @return 
3593     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
3594     ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
3595     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup ()
3596     ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
3597
3598     @latexonly \IPAlabel{minput_filter} @endlatexonly
3599 */
3600
3601 int
3602 minput_filter (MInputContext *ic, MSymbol key, void *arg)
3603 {
3604   int ret;
3605
3606   if (! ic
3607       || ! ic->active)
3608     return 0;
3609   ret = (*ic->im->driver.filter) (ic, key, arg);
3610
3611   if (ic->im->driver.callback_list)
3612     {
3613       if (ic->preedit_changed)
3614         minput__callback (ic, Minput_preedit_draw);
3615       if (ic->status_changed)
3616         minput__callback (ic, Minput_status_draw);
3617       if (ic->candidates_changed)
3618         minput__callback (ic, Minput_candidates_draw);
3619     }
3620
3621   return ret;
3622 }
3623
3624 /*=*/
3625
3626 /***en
3627     @brief Look up a text produced in the input context.
3628
3629     The minput_lookup () function looks up a text in the input context
3630     $IC.  $KEY must be identical to the one that was used in the previous call of
3631     minput_filter ().
3632
3633     If a text was produced by the input method, it is concatenated
3634     to M-text $MT.
3635
3636     This function calls #MInputDriver::lookup .
3637
3638     @return
3639     If $KEY was correctly handled by the input method, this function
3640     returns 0.  Otherwise, it returns -1, even though some text
3641     might be produced in $MT.  */
3642
3643 /***ja
3644     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹.
3645
3646     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£
3647     $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3648
3649     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
3650     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
3651
3652     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
3653
3654     @return 
3655     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
3656     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
3657     ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
3658
3659     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
3660
3661 int
3662 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
3663 {
3664   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
3665 }
3666 /*=*/
3667
3668 /***en
3669     @brief Set the spot of the input context.
3670
3671     The minput_set_spot () function sets the spot of input context $IC
3672     to coordinate ($X, $Y ) with the height specified by $ASCENT and $DESCENT .
3673     The semantics of these values depends on the input method driver.
3674
3675     For instance, a driver designed to work in a CUI environment may
3676     use $X and $Y as the column- and row numbers, and may ignore $ASCENT and
3677     $DESCENT .  A driver designed to work in a window system may
3678     interpret $X and $Y as the pixel offsets relative to the origin of the
3679     client window, and may interpret $ASCENT and $DESCENT as the ascent- and
3680     descent pixels of the line at ($X . $Y ).
3681
3682     $FONTSIZE specifies the fontsize of preedit text in 1/10 point.
3683
3684     $MT and $POS are the M-text and the character position at the spot.
3685     $MT may be @c NULL, in which case, the input method cannot get
3686     information about the text around the spot.  */
3687
3688 /***ja
3689     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë.
3690
3691     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y )
3692     ¤Î°ÌÃ֤ˠ¡¢¹â¤µ $ASCENT¡¢ $DESCENT 
3693     ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£
3694
3695     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y 
3696     ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT 
3697     ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï
3698     $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
3699     $ASCENT ¤È $DESCENT ¤ò ($X . $Y )
3700     ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
3701
3702     $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
3703
3704     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
3705     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
3706     */
3707
3708 void
3709 minput_set_spot (MInputContext *ic, int x, int y,
3710                  int ascent, int descent, int fontsize,
3711                  MText *mt, int pos)
3712 {
3713   ic->spot.x = x;
3714   ic->spot.y = y;
3715   ic->spot.ascent = ascent;
3716   ic->spot.descent = descent;
3717   ic->spot.fontsize = fontsize;
3718   ic->spot.mt = mt;
3719   ic->spot.pos = pos;
3720   if (ic->im->driver.callback_list)
3721     minput__callback (ic, Minput_set_spot);
3722 }
3723 /*=*/
3724
3725 /***en
3726     @brief Toggle input method.
3727
3728     The minput_toggle () function toggles the input method associated
3729     with input context $IC.  */
3730 /***ja
3731     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
3732
3733     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
3734     ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
3735     */
3736
3737 void
3738 minput_toggle (MInputContext *ic)
3739 {
3740   if (ic->im->driver.callback_list)
3741     minput__callback (ic, Minput_toggle);
3742   ic->active = ! ic->active;
3743 }
3744
3745 /*=*/
3746
3747 /***en
3748     @brief Reset an input context.
3749
3750     The minput_reset_ic () function resets input context $IC by
3751     calling a callback function corresponding to #Minput_reset.  It
3752     resets the status of $IC to its initial one.  As the
3753     current preedit text is deleted without commitment, if necessary,
3754     call minput_filter () with the arg @r key #Mnil to force the input
3755     method to commit the preedit in advance.  */
3756
3757 /***ja
3758     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
3759
3760     ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset 
3761     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
3762     ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ê¡¢¤·¤¿¤¬¤Ã¤Æ¡¢¤â¤·¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹¥È¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¡£
3763     É¬Íפʤé¤Ð¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï minput_lookup () 
3764     ¤òÆɤó¤Ç¤½¤Î¥³¥ß¥Ã¥È¤µ¤ì¤¿¥Æ¥­¥¹¥È¤ò¼è¤ê½Ð¤¹¤³¤È¤¬¤Ç¤­¡¢¤½¤ÎºÝ¡¢
3765     minput_lookup () ¤Î°ú¿ô @c KEY ¤È @c ARG 
3766     ¤Ï̵»ë¤µ¤ì¤ë¡£ */
3767 void
3768 minput_reset_ic (MInputContext *ic)
3769 {
3770   if (ic->im->driver.callback_list)
3771     minput__callback (ic, Minput_reset);
3772 }
3773
3774 /*=*/
3775
3776 /***en
3777     @brief Get title and icon filename of an input method.
3778
3779     The minput_get_title_icon () function returns a plist containing a
3780     title and icon filename (if any) of the input method specifies by
3781     $LANGUAGE and $NAME.
3782
3783     The first element of the plist has key Mtext and the value is an
3784     M-text of the title for identifying the input method.  The second
3785     element (if any) has key M-text and the value is an M-text of the
3786     icon image (absolute) filename for the same purpose.
3787
3788     @return
3789     If there exists the specified input method and it defines an
3790     title, a plist is retured.  Otherwise, NULL is returned.  A caller
3791     must free the plist by m17n_object_unref ().
3792 */
3793
3794 MPlist *
3795 minput_get_title_icon (MSymbol language, MSymbol name)
3796 {
3797   MPlist *plist = load_partial_im_info (language, name, Mnil, Mtitle);
3798   MPlist *pl;
3799   char *file = NULL;
3800   MText *mt;
3801
3802   if (! plist)
3803     return NULL;
3804   if (MPLIST_TAIL_P (plist))
3805     goto no_title;
3806   pl = MPLIST_PLIST (plist);
3807   pl = MPLIST_NEXT (pl);
3808   if (! MPLIST_MTEXT_P (pl))
3809     goto no_title;
3810   M17N_OBJECT_REF (pl);
3811   M17N_OBJECT_UNREF (plist);
3812   plist = pl;
3813   pl = MPLIST_NEXT (pl);  
3814   if (MPLIST_MTEXT_P (pl))
3815     {
3816       if (mtext_nchars (MPLIST_MTEXT (pl)) > 0)
3817         {
3818           mt = MPLIST_MTEXT (pl);
3819           file = mdatabase__find_file ((char *) MTEXT_DATA (mt));
3820         }
3821     }
3822   else if (language != Mnil && name != Mnil)
3823
3824     {
3825       char *buf = alloca (MSYMBOL_NAMELEN (language) + MSYMBOL_NAMELEN (name)
3826                           + 12);
3827
3828       sprintf (buf, "icons/%s-%s.png", (char *) MSYMBOL_NAME (language), 
3829                (char *) MSYMBOL_NAME (name));
3830       file = mdatabase__find_file (buf);
3831       if (! file && language == Mt)
3832         {
3833           sprintf (buf, "icons/%s.png", (char *) MSYMBOL_NAME (name));
3834           file = mdatabase__find_file (buf);
3835         }
3836     }
3837
3838   if (file)
3839     {
3840       mt = mtext__from_data (file, strlen (file), MTEXT_FORMAT_UTF_8, 1);
3841       free (file);
3842       mplist_set (pl, Mtext, mt);
3843       M17N_OBJECT_UNREF (mt);
3844     }
3845   else
3846     mplist_set (pl, Mnil, NULL);
3847   return plist;
3848
3849  no_title:
3850   M17N_OBJECT_UNREF (plist);
3851   return NULL;
3852 }
3853
3854 /*=*/
3855
3856 /***en
3857     @brief Get description text of an input method.
3858
3859     The minput_get_description () function returns an M-text that
3860     describes the input method specified by $LANGUAGE and $NAME.
3861
3862     @return
3863     If the specified input method has a description text, a pointer to
3864     #MText is returned.  The caller has to free it by m17n_object_unref ().
3865     If the input method does not have a description text, @c NULL is
3866     returned.  */
3867 /***ja
3868     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë.
3869
3870     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
3871     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
3872
3873     @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
3874     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
3875     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
3876     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
3877
3878 MText *
3879 minput_get_description (MSymbol language, MSymbol name)
3880 {
3881   MPlist *plist = load_partial_im_info (language, name, Mnil, M_description);
3882   MPlist *pl;
3883   MText *mt = NULL;
3884
3885   if (! plist)
3886     return NULL;
3887   if (MPLIST_TAIL_P (plist))
3888     {
3889       M17N_OBJECT_UNREF (plist);
3890       return NULL;
3891     }
3892   pl = MPLIST_PLIST (plist);
3893   pl = MPLIST_NEXT (pl);
3894   if (MPLIST_MTEXT_P (pl))
3895     {
3896       mt = MPLIST_MTEXT (pl);
3897       M17N_OBJECT_REF (mt);
3898     }
3899   M17N_OBJECT_UNREF (plist);
3900   return mt;
3901 }
3902
3903 /***en
3904     @brief Get information about input method commands.
3905
3906     The minput_get_commands () function returns information about
3907     input method commands of the input method specified by $LANGUAGE
3908     and $NAME.  An input method command is a pseudo key event to which
3909     one or more actual input key sequences are assigned.
3910
3911     There are two kinds of commands, global and local.  Global
3912     commands are used by multiple input methods for the same purpose,
3913     and have global key assignments.  Local commands are used only by
3914     a specific input method, and have only local key assignments.
3915
3916     Each input method may locally change key assignments for global
3917     commands.  The global key assignment for a global command is
3918     effective only when the current input method does not have local
3919     key assignments for that command.
3920
3921     If $NAME is #Mnil, information about global commands is returned.
3922     In this case $LANGUAGE is ignored.
3923
3924     If $NAME is not #Mnil, information about those commands that have
3925     local key assignments in the input method specified by $LANGUAGE
3926     and $NAME is returned.
3927
3928     @return
3929     If no input method commands are found, this function returns @c NULL.
3930
3931     Otherwise, a pointer to a plist is returned.  The key of each
3932     element in the plist is a symbol representing a command, and the
3933     value is a plist of the form COMMAND-INFO described below.
3934
3935     The first element of COMMAND-INFO has the key #Mtext, and the
3936     value is an M-text describing the command.
3937
3938     If there are no more elements, that means no key sequences are
3939     assigned to the command.  Otherwise, each of the remaining
3940     elements has the key #Mplist, and the value is a plist whose keys are
3941     #Msymbol and values are symbols representing input keys, which are
3942     currently assigned to the command.
3943
3944     As the returned plist is kept in the library, the caller must not
3945     modify nor free it.  */
3946 /***ja
3947     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
3948
3949     ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
3950     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
3951     ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
3952     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
3953
3954     ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
3955     ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
3956     ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
3957     ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
3958
3959     ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
3960     ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
3961     ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
3962     ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
3963
3964     $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
3965     ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
3966
3967     $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
3968     Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
3969     ¤òÊÖ¤¹¡£
3970
3971     @return
3972     ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
3973
3974     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
3975     ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
3976     ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
3977
3978     COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
3979     ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
3980     #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
3981     ¤¤¤³¤È¤Ë¤Ê¤ë¡£
3982
3983     ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
3984     ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
3985     ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
3986     ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
3987     ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
3988
3989     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
3990     ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
3991
3992 MPlist *
3993 minput_get_commands (MSymbol language, MSymbol name)
3994 {
3995   MPlist *plist = get_nested_list (language, name, Mnil, M_command);
3996
3997   return (MPLIST_TAIL_P (plist) ? NULL : plist);
3998 }
3999
4000 /***en
4001     @brief Assign a key sequence to an input method command.
4002
4003     The minput_assign_command_keys () function assigns input key
4004     sequence $KEYSEQ to input method command $COMMAND for the input
4005     method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
4006     key sequence is assigned globally no matter what $LANGUAGE is.
4007     Otherwise the key sequence is assigned locally.
4008
4009     Each element of $KEYSEQ must have the key $Msymbol and the value
4010     must be a symbol representing an input key.
4011
4012     $KEYSEQ may be @c NULL, in which case, all assignments are deleted
4013     globally or locally.
4014
4015     This assignment gets effective in a newly opened input method.
4016
4017     @return
4018     If the operation was successful, 0 is returned.  Otherwise -1 is
4019     returned, and #merror_code is set to #MERROR_IM.  */
4020 /***ja
4021     @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
4022
4023     ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
4024     »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
4025     ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
4026     $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
4027     ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
4028
4029     $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
4030     ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4031
4032     $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
4033     ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
4034
4035     ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
4036     ¸ú¤Ë¤Ê¤ë¡£
4037
4038     @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
4039     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
4040
4041 int
4042 minput_assign_command_keys (MSymbol language, MSymbol name,
4043                             MSymbol command, MPlist *keyseq)
4044 {
4045   MPlist *plist, *pl, *p;
4046
4047   if (check_command_keyseq (keyseq) < 0
4048       || ! (plist = get_nested_list (language, name, Mnil, M_command)))
4049     MERROR (MERROR_IM, -1);
4050   pl = mplist_get (plist, command);
4051   if (pl)
4052     {
4053       pl = MPLIST_NEXT (pl);
4054       if (! keyseq)
4055         while ((p = mplist_pop (pl)))
4056           M17N_OBJECT_UNREF (p);
4057       else
4058         {
4059           keyseq = mplist_copy (keyseq);
4060           mplist_push (pl, Mplist, keyseq);
4061           M17N_OBJECT_UNREF (keyseq);
4062         }
4063     }
4064   else
4065     {
4066       if (name == Mnil)
4067         MERROR (MERROR_IM, -1);
4068       if (! keyseq)
4069         return 0;
4070       /* Get global commands.  */
4071       pl = get_nested_list (Mnil, Mnil, Mnil, M_command);
4072       pl = mplist_get (pl, command);
4073       if (! pl)
4074         MERROR (MERROR_IM, -1);
4075       p = mplist ();
4076       mplist_add (p, Mtext, mplist_value (pl));
4077       keyseq = mplist_copy (keyseq);
4078       mplist_add (p, Mplist, keyseq);
4079       M17N_OBJECT_UNREF (keyseq);
4080       mplist_push (plist, command, p);
4081     }
4082   return 0;
4083 }
4084
4085 /***en
4086     @brief Get a list of variables of an input method.
4087
4088     The minput_get_variables () function returns a plist (#MPlist) of
4089     variables used to control the behavior of the input method
4090     specified by $LANGUAGE and $NAME.  The plist is @e well-formed
4091     (#m17nPlist) of the following format:
4092
4093 @verbatim
4094     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4095      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4096      ...)
4097 @endverbatim
4098
4099     @c VARNAME is a symbol representing the variable name.
4100
4101     @c DOC-MTEXT is an M-text describing the variable.
4102
4103     @c DEFAULT-VALUE is the default value of the varible.  It is a
4104     symbol, integer, or M-text.
4105
4106     @c VALUEs (if any) specifies the possible values of the variable.
4107     If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
4108     @c TO), where @c FROM and @c TO specifies a range of possible
4109     values.
4110
4111     For instance, suppose an input method has the variables:
4112
4113     @li name:intvar, description:"value is an integer",
4114          initial value:0, value-range:0..3,10,20
4115
4116     @li name:symvar, description:"value is a symbol",
4117          initial value:nil, value-range:a, b, c, nil
4118
4119     @li name:txtvar, description:"value is an M-text",
4120          initial value:empty text, no value-range (i.e. any text)
4121
4122     Then, the returned plist is as follows.
4123
4124 @verbatim
4125     (intvar ("value is an integer" 0 (0 3) 10 20)
4126      symvar ("value is a symbol" nil a b c nil)
4127      txtvar ("value is an M-text" ""))
4128 @endverbatim
4129
4130     @return
4131     If the input method uses any variables, a pointer to #MPlist is
4132     returned.  As the plist is kept in the library, a caller must not
4133     modify nor free it.  If the input method does not use any
4134     variable, @c NULL is returned.  */
4135 /***ja
4136     @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
4137
4138     ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
4139     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
4140     (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
4141     ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
4142
4143 @verbatim
4144     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4145      VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
4146      ...)
4147 @endverbatim
4148
4149     @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
4150
4151     @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
4152
4153     @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
4154     M-text ¤Ç¤¢¤ë¡£
4155
4156     @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
4157     @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
4158     ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
4159
4160     Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
4161
4162     @li name:intvar, ÀâÌÀ:"value is an integer",
4163         ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
4164
4165     @li name:symvar, ÀâÌÀ:"value is a symbol",
4166          ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
4167
4168     @li name:txtvar, ÀâÌÀ:"value is an M-text",
4169         ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
4170
4171     ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
4172
4173 @verbatim
4174     (intvar ("value is an integer" 0 (0 3) 10 20)
4175      symvar ("value is a symbol" nil a b c nil)
4176      txtvar ("value is an M-text" ""))
4177 @endverbatim
4178
4179     @return 
4180     ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
4181     ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
4182     ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
4183
4184 MPlist *
4185 minput_get_variables (MSymbol language, MSymbol name)
4186 {
4187   MPlist *plist = get_nested_list (language, name, Mnil, M_variable);
4188
4189   return (MPLIST_TAIL_P (plist) ? NULL : plist);
4190 }
4191
4192 /***en
4193     @brief Set the initial value of an input method variable.
4194
4195     The minput_set_variable () function sets the initial value of
4196     input method variable $VARIABLE to $VALUE for the input method
4197     specified by $LANGUAGE and $NAME.
4198
4199     By default, the initial value is 0.
4200
4201     This setting gets effective in a newly opened input method.
4202
4203     @return
4204     If the operation was successful, 0 is returned.  Otherwise -1 is
4205     returned, and #merror_code is set to #MERROR_IM.  */
4206 /***ja
4207     @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
4208
4209     ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
4210     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
4211     ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
4212
4213     ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
4214
4215     ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
4216
4217     @return
4218     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
4219     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
4220
4221 int
4222 minput_set_variable (MSymbol language, MSymbol name,
4223                      MSymbol variable, void *value)
4224 {
4225   MPlist *plist, *val_element, *range_element;
4226   MSymbol type;
4227
4228   plist = get_nested_list (language, name, Mnil, M_variable);
4229   if (! plist)
4230     MERROR (MERROR_IM, -1);
4231   plist = mplist_find_by_value (plist, variable);
4232   if (! plist)
4233     MERROR (MERROR_IM, -1);
4234   plist = MPLIST_PLIST (MPLIST_NEXT (plist));
4235   val_element = MPLIST_NEXT (plist);
4236   type = MPLIST_KEY (val_element);
4237   range_element = MPLIST_NEXT (val_element);
4238     
4239   if (! MPLIST_TAIL_P (range_element))
4240     {
4241       if (type == Minteger)
4242         {
4243           int val = (int) value, this_val;
4244       
4245           MPLIST_DO (plist, range_element)
4246             {
4247               this_val = (int) MPLIST_VAL (plist);
4248               if (MPLIST_PLIST_P (plist))
4249                 {
4250                   int min_bound, max_bound;
4251                   MPlist *pl = MPLIST_PLIST (plist);
4252
4253                   min_bound = (int) MPLIST_VAL (pl);
4254                   pl = MPLIST_NEXT (pl);
4255                   max_bound = (int) MPLIST_VAL (pl);
4256                   if (val >= min_bound && val <= max_bound)
4257                     break;
4258                 }
4259               else if (val == this_val)
4260                 break;
4261             }
4262           if (MPLIST_TAIL_P (plist))
4263             MERROR (MERROR_IM, -1);
4264         }
4265       else if (type == Msymbol)
4266         {
4267           MPLIST_DO (plist, range_element)
4268             if (MPLIST_SYMBOL (plist) == (MSymbol) value)
4269               break;
4270           if (MPLIST_TAIL_P (plist))
4271             MERROR (MERROR_IM, -1);
4272         }
4273       else                      /* type == Mtext */
4274         {
4275           MPLIST_DO (plist, range_element)
4276             if (mtext_cmp (MPLIST_MTEXT (plist), (MText *) value) == 0)
4277               break;
4278           if (MPLIST_TAIL_P (plist))
4279             MERROR (MERROR_IM, -1);
4280           M17N_OBJECT_REF (value);
4281         }
4282     }
4283
4284   mplist_set (val_element, type, value);
4285   return 0;
4286 }
4287
4288 /*** @} */
4289 /*=*/
4290 /*** @addtogroup m17nDebug */
4291 /*=*/
4292 /*** @{  */
4293 /*=*/
4294
4295 /***en
4296     @brief Dump an input method.
4297
4298     The mdebug_dump_im () function prints the input method $IM in a
4299     human readable way to the stderr.  $INDENT specifies how many
4300     columns to indent the lines but the first one.
4301
4302     @return
4303     This function returns $IM.  */
4304 /***ja
4305     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
4306
4307     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
4308     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
4309
4310     @return
4311     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
4312
4313 MInputMethod *
4314 mdebug_dump_im (MInputMethod *im, int indent)
4315 {
4316   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
4317   char *prefix;
4318
4319   prefix = (char *) alloca (indent + 1);
4320   memset (prefix, 32, indent);
4321   prefix[indent] = '\0';
4322
4323   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
4324            msymbol_name (im->name));
4325   mdebug_dump_mtext (im_info->title, 0, 0);
4326   if (im->name != Mnil)
4327     {
4328       MPlist *state;
4329
4330       MPLIST_DO (state, im_info->states)
4331         {
4332           fprintf (stderr, "\n%s  ", prefix);
4333           dump_im_state (MPLIST_VAL (state), indent + 2);
4334         }
4335     }
4336   fprintf (stderr, ")");
4337   return im;
4338 }
4339
4340 /*** @} */ 
4341
4342 /*
4343   Local Variables:
4344   coding: euc-japan
4345   End:
4346 */