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