*** empty log message ***
[m17n/m17n-lib.git] / example / mimx-anthy.c
1 /* mimx-anthy.c -- Anthy input method external module.  -*- coding: euc-jp; -*-
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @enpage mimx-anthy external module for the input method <ja, anthy>
25
26     @section mimx-anthy-description DESCRIPTION
27
28     The shared library mimx-anthy.so is an external module used by the
29     input method <ja, anthy>.  It exports these functions.
30
31     <ul>
32     <li> init
33
34     Initialize this module.
35
36     <li> fini
37
38     Finalize this module.
39
40     <li> convert
41
42     Convert the current preedit text (Hiragana sequence) into
43     Kana-Kanji mixed text.
44
45     <li> change
46
47     Record the change of candidate of the current segment.
48
49     <li> resize
50
51     Enlarge or shorten the length of the current segment.
52
53     <li> commit
54
55     Commit the lastly selected candidates of all the segments.
56
57     </ul>
58
59     @section mimx-anthy-seealso See also
60     @ref mdbIM
61 */
62 /***ja
63     @japage mimx-anthy ÆþÎϥ᥽¥Ã¥É <ja, anthy> Íѳ°Éô¥â¥¸¥å¡¼¥ë.
64
65     @section mimx-anthy-description DESCRIPTION
66
67     ¶¦Í­¥é¥¤¥Ö¥é¥ê mimx-anthy.so ¤ÏÆþÎϥ᥽¥Ã¥É<ja, anthy> ¤ËÍѤ¤¤é¤ì 
68     ¤ë³°Éô¥â¥¸¥å¡¼¥ë¤Ç¤¢¤ê¡¢°Ê²¼¤Î´Ø¿ô¤ò export ¤·¤Æ¤¤¤ë¡£
69
70     <ul>
71     <li> init
72
73     ¥â¥¸¥å¡¼¥ë¤Î½é´ü²½¡£ 
74
75     <li> fini
76
77     ¥â¥¸¥å¡¼¥ë¤Î½ªÎ»¡£ 
78
79     <li> convert
80
81     ¸½ºß¤Î preedit ¥Æ¥­¥¹¥È (¤Ò¤é¤¬¤ÊÎó) ¤ò¤«¤Ê´Á»ú¥Æ¥­¥¹¥È¤ËÊÑ´¹¤¹¤ë¡£ 
82
83     <li> change
84
85     ¸½ºß¤Î¥»¥°¥á¥ó¥È¤Î¸õÊä¤ÎÊÑÁ«¤òµ­Ï¿¤¹¤ë¡£ 
86
87     <li> resize
88
89     ¸½ºß¤Î¥»¥°¥á¥ó¥È¤ÎŤµ¤òÊѹ¹¤¹¤ë¡£ 
90
91     <li> commit
92
93     Á´¥»¥°¥á¥ó¥È¤ÎºÇ¿·¤Î¸õÊä¤ò¥³¥ß¥Ã¥È¤¹¤ë¡£
94
95     </ul>
96
97     @section mimx-anthy-seealso »²¾È
98     @ref mdbIM
99 */
100
101 #ifndef FOR_DOXYGEN
102
103 #include <stdio.h>
104 #include <string.h>
105 #include <config.h>
106 #include <m17n.h>
107
108 #ifdef HAVE_ANTHY
109
110 #include <anthy/anthy.h>
111
112 static int initialized;
113 static MSymbol Manthy, Msegment;
114
115 /* A structure to record in MInputContext->plist with key Manthy.  */
116
117 typedef struct {
118   MInputContext *ic;
119   anthy_context_t ac;
120   /* Which candidate is selected in each segment.  */
121   int *candidate_numbers;
122   /* Size of the above array.  */
123   int num_segments;
124   /* Converter for this context.  */
125   MConverter *converter;
126 } AnthyContext;
127
128 static AnthyContext *
129 new_context (MInputContext *ic)
130 {
131   AnthyContext *context;
132   anthy_context_t ac;
133   MSymbol euc_jp = msymbol ("euc-jp");
134   /* Rebound to an actual buffer just before being used.  */
135   MConverter *converter = mconv_buffer_converter (euc_jp, NULL, 0);
136
137   if (! converter)
138     return NULL;
139   ac = anthy_create_context ();
140   if (! ac)
141     return NULL;
142   context = calloc (1, sizeof (AnthyContext));
143   context->ic = ic;
144   context->ac = ac;
145   context->num_segments = 0;
146   context->candidate_numbers = NULL;
147   context->converter = converter;
148   return context;
149 }
150
151 static AnthyContext *
152 get_context (MInputContext *ic)
153 {
154   MPlist *plist = ic->plist;
155   AnthyContext *context;
156
157   for (; plist && mplist_key (plist) != Mnil; plist = mplist_next (plist))
158     {
159       if (mplist_key (plist) != Manthy)
160         continue;
161       context = mplist_value (plist);
162       if (context->ic == ic)
163         return context;
164     }
165   return NULL;
166 }
167
168
169 static void
170 free_context (AnthyContext *context)
171 {
172   anthy_release_context (context->ac);
173   if (context->candidate_numbers)
174     free (context->candidate_numbers);
175   mconv_free_converter (context->converter);
176   free (context);
177 }
178
179 static void
180 allocate_candidate_numbers (AnthyContext *context, int num)
181 {
182   if (context->num_segments < num)
183     {
184       if (context->num_segments == 0)
185         context->candidate_numbers = malloc (sizeof (int) * num);
186       else
187         context->candidate_numbers = realloc (context->candidate_numbers,
188                                               sizeof (int) * num);
189       context->num_segments = num;
190     }
191 }
192
193 static void
194 add_action (MPlist *actions, MSymbol name, MSymbol key, void *val)
195 {
196   MPlist *action = mplist ();
197
198   mplist_add (action, Msymbol, name);
199   mplist_add (action, key, val);
200   mplist_add (actions, Mplist, action);
201   m17n_object_unref (action);
202 }
203
204 /* Return a list of all candidates of the Nth segment.  The return
205    value is a plist whose elements are plists who contains at most 5
206    candidates.  */
207
208 static MPlist *
209 make_candidate_list (AnthyContext *context, int n)
210 {
211   MPlist *plist = mplist (), *pl;
212   int i;
213   char buf[1024];
214   struct anthy_segment_stat ss;
215   MText *mt;
216   
217   anthy_get_segment_stat (context->ac, n, &ss);
218   for (i = 0, pl = mplist (); i < ss.nr_candidate; i++)
219     {
220       anthy_get_segment (context->ac, n, i, buf, sizeof (buf));
221       mconv_rebind_buffer (context->converter,
222                            (unsigned char *) buf, strlen (buf));
223       mt = mconv_decode (context->converter, mtext ());
224       mtext_put_prop (mt, 0, mtext_len (mt), Msegment, (void *) (n + 1));
225       mplist_add (pl, Mtext, mt);
226       m17n_object_unref (mt);
227       if (i % 5 == 4)
228         {
229           mplist_add (plist, Mplist, pl);
230           m17n_object_unref (pl);
231           pl = mplist ();
232         }
233     }
234   if (mplist_key (pl) != Mnil)
235     mplist_add (plist, Mplist, pl);
236   m17n_object_unref (pl);
237   return plist;
238 }
239
240 MPlist *
241 init (MPlist *args)
242 {
243   MInputContext *ic = mplist_value (args);
244   AnthyContext *context;
245
246   if (! initialized++)
247     {
248       anthy_init ();
249       Manthy = msymbol (" anthy");
250       Msegment = msymbol (" segment");
251     }
252   context = new_context (ic);
253   if (context)
254     mplist_push (ic->plist, Manthy, context);
255   return NULL;
256 }
257
258 MPlist *
259 fini (MPlist *args)
260 {
261   MInputContext *ic = mplist_value (args);
262   AnthyContext *context = get_context (ic);
263
264   if (context)
265     free_context (context);
266   return NULL;
267 }
268
269 MPlist *
270 convert (MPlist *args)
271 {
272   MInputContext *ic = mplist_value (args);
273   AnthyContext *context = get_context (ic);
274   struct anthy_conv_stat cs;
275   MPlist *action, *actions;
276   int i;
277   unsigned char buf[1024];
278
279   if (! context)
280     return NULL;
281
282   mconv_rebind_buffer (context->converter, buf, sizeof (buf));
283   mconv_encode (context->converter, ic->preedit);
284   buf[context->converter->nbytes] = '\0';
285   anthy_set_string (context->ac, (char *) buf);
286   anthy_get_stat (context->ac, &cs);
287   allocate_candidate_numbers (context, cs.nr_segment);
288
289   actions = mplist ();
290   add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
291   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
292   for (i = 0; i < cs.nr_segment; i++)
293     {
294       context->candidate_numbers[i] = 0;
295       if (i == 1)
296         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
297       action = make_candidate_list (context, i);
298       mplist_add (actions, Mplist, action);
299       m17n_object_unref (action);
300     }
301   if (cs.nr_segment > 1)
302     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
303
304   return actions;
305 }
306
307 MPlist *
308 change (MPlist *args)
309 {
310   MInputContext *ic = mplist_value (args);
311   AnthyContext *context = get_context (ic);
312   int segment;
313
314   if (! context)
315     return NULL;
316   if (! ic->candidate_list || ic->cursor_pos == 0)
317     return NULL;
318   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
319   if (segment == 0)
320     return NULL;
321   segment--;
322   context->candidate_numbers[segment] = ic->candidate_index;
323   return NULL;
324 }
325
326 MPlist *
327 resize (MPlist *args)
328 {
329   MInputContext *ic = mplist_value (args);
330   AnthyContext *context = get_context (ic);
331   struct anthy_conv_stat cs;
332   MSymbol shorten;
333   int segment;
334   MPlist *actions, *action;
335   int i;
336
337   if (! context)
338     return NULL;
339   if (! ic->candidate_list || ic->cursor_pos == 0)
340     return NULL;
341   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
342   if (segment == 0)
343     return NULL;
344   segment--;
345   args = mplist_next (args);
346   shorten = mplist_value (args);
347   anthy_resize_segment (context->ac, segment, shorten == Mt ? -1 : 1);
348   anthy_get_stat (context->ac, &cs);
349   allocate_candidate_numbers (context, cs.nr_segment);
350
351   actions = mplist ();
352   if (segment == 0)
353     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
354   else
355     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@["));
356   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
357   for (i = segment; i < cs.nr_segment; i++)
358     {
359       context->candidate_numbers[i] = 0;
360       if (i == segment + 1)
361         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
362       action = make_candidate_list (context, i);
363       mplist_add (actions, Mplist, action);
364       m17n_object_unref (action);
365     }
366   if (segment + 1 < cs.nr_segment)
367     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
368   return actions;
369 }
370
371 MPlist *
372 commit (MPlist *args)
373 {
374   MInputContext *ic = mplist_value (args);
375   AnthyContext *context = get_context (ic);
376   struct anthy_conv_stat cs;
377   int i;
378
379   if (! context)
380     return NULL;
381   anthy_get_stat (context->ac, &cs);
382   for (i = 0; i < cs.nr_segment; i++)
383     anthy_commit_segment (context->ac, i, context->candidate_numbers[i]);
384   return NULL;
385 }
386
387 #else  /* not HAVE_ANTHY */
388
389 MPlist *convert (MPlist *args) { return NULL; }
390 MPlist *change (MPlist *args) { return NULL; }
391 MPlist *resize (MPlist *args) { return NULL; }
392 MPlist *commit (MPlist *args) { return NULL; }
393
394 #endif /* not HAVE_ANTHY */
395 #endif /* not FOR_DOXYGEN */