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