*** 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., 51 Franklin Street, Fifth Floor,
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 <m17n.h>
106
107 #ifdef HAVE_ANTHY
108
109 #include <anthy/anthy.h>
110
111 static int initialized;
112 static MSymbol Manthy, Msegment;
113
114 /* A structure to record in MInputContext->plist with key Manthy.  */
115
116 typedef struct {
117   MInputContext *ic;
118   anthy_context_t ac;
119   /* Which candidate is selected in each segment.  */
120   int *candidate_numbers;
121   /* Size of the above array.  */
122   int num_segments;
123   /* Converter for this context.  */
124   MConverter *converter;
125 } AnthyContext;
126
127 static AnthyContext *
128 new_context (MInputContext *ic)
129 {
130   AnthyContext *context;
131   anthy_context_t ac;
132   MSymbol euc_jp = msymbol ("euc-jp");
133   /* Rebound to an actual buffer just before being used.  */
134   MConverter *converter = mconv_buffer_converter (euc_jp, NULL, 0);
135
136   if (! converter)
137     return NULL;
138   ac = anthy_create_context ();
139   if (! ac)
140     return NULL;
141   context = calloc (1, sizeof (AnthyContext));
142   context->ic = ic;
143   context->ac = ac;
144   context->num_segments = 0;
145   context->candidate_numbers = NULL;
146   context->converter = converter;
147   return context;
148 }
149
150 static AnthyContext *
151 get_context (MInputContext *ic)
152 {
153   MPlist *plist = ic->plist;
154   AnthyContext *context;
155
156   for (; plist && mplist_key (plist) != Mnil; plist = mplist_next (plist))
157     {
158       if (mplist_key (plist) != Manthy)
159         continue;
160       context = mplist_value (plist);
161       if (context->ic == ic)
162         return context;
163     }
164   return NULL;
165 }
166
167
168 static void
169 free_context (AnthyContext *context)
170 {
171   anthy_release_context (context->ac);
172   if (context->candidate_numbers)
173     free (context->candidate_numbers);
174   mconv_free_converter (context->converter);
175   free (context);
176 }
177
178 static void
179 allocate_candidate_numbers (AnthyContext *context, int num)
180 {
181   if (context->num_segments < num)
182     {
183       if (context->num_segments == 0)
184         context->candidate_numbers = malloc (sizeof (int) * num);
185       else
186         context->candidate_numbers = realloc (context->candidate_numbers,
187                                               sizeof (int) * num);
188       context->num_segments = num;
189     }
190 }
191
192 static void
193 add_action (MPlist *actions, MSymbol name, MSymbol key, void *val)
194 {
195   MPlist *action = mplist ();
196
197   mplist_add (action, Msymbol, name);
198   mplist_add (action, key, val);
199   mplist_add (actions, Mplist, action);
200   m17n_object_unref (action);
201 }
202
203 /* Return a list of all candidates of the Nth segment.  The return
204    value is a plist whose elements are plists who contains at most 5
205    candidates.  */
206
207 static MPlist *
208 make_candidate_list (AnthyContext *context, int n)
209 {
210   MPlist *plist = mplist (), *pl;
211   int i;
212   char buf[1024];
213   struct anthy_segment_stat ss;
214   MText *mt;
215   
216   anthy_get_segment_stat (context->ac, n, &ss);
217   for (i = 0, pl = mplist (); i < ss.nr_candidate; i++)
218     {
219       anthy_get_segment (context->ac, n, i, buf, sizeof (buf));
220       mconv_rebind_buffer (context->converter,
221                            (unsigned char *) buf, strlen (buf));
222       mt = mconv_decode (context->converter, mtext ());
223       mtext_put_prop (mt, 0, mtext_len (mt), Msegment, (void *) (n + 1));
224       mplist_add (pl, Mtext, mt);
225       m17n_object_unref (mt);
226       if (i % 5 == 4)
227         {
228           mplist_add (plist, Mplist, pl);
229           m17n_object_unref (pl);
230           pl = mplist ();
231         }
232     }
233   if (mplist_key (pl) != Mnil)
234     mplist_add (plist, Mplist, pl);
235   m17n_object_unref (pl);
236   return plist;
237 }
238
239 MPlist *
240 init (MPlist *args)
241 {
242   MInputContext *ic = mplist_value (args);
243   AnthyContext *context;
244
245   if (! initialized++)
246     {
247       anthy_init ();
248       Manthy = msymbol (" anthy");
249       Msegment = msymbol (" segment");
250     }
251   context = new_context (ic);
252   if (context)
253     mplist_push (ic->plist, Manthy, context);
254   return NULL;
255 }
256
257 MPlist *
258 fini (MPlist *args)
259 {
260   MInputContext *ic = mplist_value (args);
261   AnthyContext *context = get_context (ic);
262
263   if (context)
264     free_context (context);
265   return NULL;
266 }
267
268 MPlist *
269 convert (MPlist *args)
270 {
271   MInputContext *ic = mplist_value (args);
272   AnthyContext *context = get_context (ic);
273   struct anthy_conv_stat cs;
274   MPlist *action, *actions;
275   int i;
276   unsigned char buf[1024];
277
278   if (! context)
279     return NULL;
280
281   mconv_rebind_buffer (context->converter, buf, sizeof (buf));
282   mconv_encode (context->converter, ic->preedit);
283   buf[context->converter->nbytes] = '\0';
284   anthy_set_string (context->ac, (char *) buf);
285   anthy_get_stat (context->ac, &cs);
286   allocate_candidate_numbers (context, cs.nr_segment);
287
288   actions = mplist ();
289   add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
290   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
291   for (i = 0; i < cs.nr_segment; i++)
292     {
293       context->candidate_numbers[i] = 0;
294       if (i == 1)
295         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
296       action = make_candidate_list (context, i);
297       mplist_add (actions, Mplist, action);
298       m17n_object_unref (action);
299     }
300   if (cs.nr_segment > 1)
301     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
302
303   return actions;
304 }
305
306 MPlist *
307 change (MPlist *args)
308 {
309   MInputContext *ic = mplist_value (args);
310   AnthyContext *context = get_context (ic);
311   int segment;
312
313   if (! context)
314     return NULL;
315   if (! ic->candidate_list || ic->cursor_pos == 0)
316     return NULL;
317   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
318   if (segment == 0)
319     return NULL;
320   segment--;
321   context->candidate_numbers[segment] = ic->candidate_index;
322   return NULL;
323 }
324
325 MPlist *
326 resize (MPlist *args)
327 {
328   MInputContext *ic = mplist_value (args);
329   AnthyContext *context = get_context (ic);
330   struct anthy_conv_stat cs;
331   MSymbol shorten;
332   int segment;
333   MPlist *actions, *action;
334   int i;
335
336   if (! context)
337     return NULL;
338   if (! ic->candidate_list || ic->cursor_pos == 0)
339     return NULL;
340   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
341   if (segment == 0)
342     return NULL;
343   segment--;
344   args = mplist_next (args);
345   shorten = mplist_value (args);
346   anthy_resize_segment (context->ac, segment, shorten == Mt ? -1 : 1);
347   anthy_get_stat (context->ac, &cs);
348   allocate_candidate_numbers (context, cs.nr_segment);
349
350   actions = mplist ();
351   if (segment == 0)
352     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
353   else
354     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@["));
355   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
356   for (i = segment; i < cs.nr_segment; i++)
357     {
358       context->candidate_numbers[i] = 0;
359       if (i == segment + 1)
360         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
361       action = make_candidate_list (context, i);
362       mplist_add (actions, Mplist, action);
363       m17n_object_unref (action);
364     }
365   if (segment + 1 < cs.nr_segment)
366     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
367   return actions;
368 }
369
370 MPlist *
371 commit (MPlist *args)
372 {
373   MInputContext *ic = mplist_value (args);
374   AnthyContext *context = get_context (ic);
375   struct anthy_conv_stat cs;
376   int i;
377
378   if (! context)
379     return NULL;
380   anthy_get_stat (context->ac, &cs);
381   for (i = 0; i < cs.nr_segment; i++)
382     anthy_commit_segment (context->ac, i, context->candidate_numbers[i]);
383   return NULL;
384 }
385
386 #else  /* not HAVE_ANTHY */
387
388 MPlist *convert (MPlist *args) { return NULL; }
389 MPlist *change (MPlist *args) { return NULL; }
390 MPlist *resize (MPlist *args) { return NULL; }
391 MPlist *commit (MPlist *args) { return NULL; }
392
393 #endif /* not HAVE_ANTHY */
394 #endif /* not FOR_DOXYGEN */