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