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