*** empty log message ***
[m17n/m17n-lib.git] / example / mimx-anthy.c
1 /* mimx-anthy.c -- Input method external module for Anthy.
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     @page 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
63 #ifndef FOR_DOXYGEN
64
65 #include <stdio.h>
66 #include <string.h>
67 #include <config.h>
68 #include <m17n.h>
69
70 #ifdef HAVE_ANTHY
71
72 #include <anthy/anthy.h>
73
74 static int initialized;
75 static MSymbol Manthy, Msegment;
76
77 /* A structure to record in MInputContext->plist with key Manthy.  */
78
79 typedef struct {
80   anthy_context_t ac;
81   /* Which candidate is selected in each segment.  */
82   int *candidate_numbers;
83   /* Size of the above array.  */
84   int num_segments;
85   /* Converter for this context.  */
86   MConverter *converter;
87 } AnthyContext;
88
89 static AnthyContext *
90 new_context (MInputContext *ic)
91 {
92   AnthyContext *context = NULL;
93   MSymbol euc_jp = msymbol ("euc-jp");
94   /* Rebound to an actual buffer just before being used.  */
95   MConverter *converter = mconv_buffer_converter (euc_jp, NULL, 0);
96
97   if (converter)
98     {
99       context = calloc (1, sizeof (AnthyContext));
100       context->ac = anthy_create_context ();
101       context->num_segments = 0;
102       context->candidate_numbers = NULL;
103       context->converter = converter;
104     }
105   return context;
106 }
107
108 static void
109 free_context (AnthyContext *context)
110 {
111   anthy_release_context (context->ac);
112   if (context->candidate_numbers)
113     free (context->candidate_numbers);
114   mconv_free_converter (context->converter);
115   free (context);
116 }
117
118 static void
119 allocate_candidate_numbers (AnthyContext *context, int num)
120 {
121   if (context->num_segments < num)
122     {
123       if (context->num_segments == 0)
124         context->candidate_numbers = malloc (sizeof (int) * num);
125       else
126         context->candidate_numbers = realloc (context->candidate_numbers,
127                                               sizeof (int) * num);
128       context->num_segments = num;
129     }
130 }
131
132 static void
133 add_action (MPlist *actions, MSymbol name, MSymbol key, void *val)
134 {
135   MPlist *action = mplist ();
136
137   mplist_add (action, Msymbol, name);
138   mplist_add (action, key, val);
139   mplist_add (actions, Mplist, action);
140   m17n_object_unref (action);
141 }
142
143 /* Return a list of all candidates of the Nth segment.  The return
144    value is a plist whose elements are plists who contains at most 5
145    candidates.  */
146
147 static MPlist *
148 make_candidate_list (AnthyContext *context, int n)
149 {
150   MPlist *plist = mplist (), *pl;
151   int i;
152   char buf[1024];
153   struct anthy_segment_stat ss;
154   MText *mt;
155   
156   anthy_get_segment_stat (context->ac, n, &ss);
157   for (i = 0, pl = mplist (); i < ss.nr_candidate; i++)
158     {
159       anthy_get_segment (context->ac, n, i, buf, sizeof (buf));
160       mconv_rebind_buffer (context->converter,
161                            (unsigned char *) buf, strlen (buf));
162       mt = mconv_decode (context->converter, mtext ());
163       mtext_put_prop (mt, 0, mtext_len (mt), Msegment, (void *) (n + 1));
164       mplist_add (pl, Mtext, mt);
165       m17n_object_unref (mt);
166       if (i % 5 == 4)
167         {
168           mplist_add (plist, Mplist, pl);
169           m17n_object_unref (pl);
170           pl = mplist ();
171         }
172     }
173   if (mplist_key (pl) != Mnil)
174     mplist_add (plist, Mplist, pl);
175   m17n_object_unref (pl);
176   return plist;
177 }
178
179 MPlist *
180 init (MPlist *args)
181 {
182   MInputContext *ic = mplist_value (args);
183
184   if (! initialized)
185     {
186       anthy_init ();
187       Manthy = msymbol (" anthy");
188       Msegment = msymbol (" segment");
189       initialized = 1;
190     }
191   mplist_push (ic->plist, Manthy, new_context (ic));
192   return NULL;
193 }
194
195 MPlist *
196 fini (MPlist *args)
197 {
198   MInputContext *ic = mplist_value (args);
199   AnthyContext *context = mplist_get (ic->plist, Manthy);
200
201   if (context)
202     free_context (context);
203   return NULL;
204 }
205
206 MPlist *
207 convert (MPlist *args)
208 {
209   MInputContext *ic = mplist_value (args);
210   AnthyContext *context = mplist_get (ic->plist, Manthy);
211   struct anthy_conv_stat cs;
212   MPlist *action, *actions;
213   int i;
214   unsigned char buf[1024];
215
216   if (! context)
217     return NULL;
218
219   mconv_rebind_buffer (context->converter, buf, sizeof (buf));
220   mconv_encode (context->converter, ic->preedit);
221   buf[context->converter->nbytes] = '\0';
222   anthy_set_string (context->ac, (char *) buf);
223   anthy_get_stat (context->ac, &cs);
224   allocate_candidate_numbers (context, cs.nr_segment);
225
226   actions = mplist ();
227   add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
228   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
229   for (i = 0; i < cs.nr_segment; i++)
230     {
231       context->candidate_numbers[i] = 0;
232       if (i == 1)
233         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
234       action = make_candidate_list (context, i);
235       mplist_add (actions, Mplist, action);
236       m17n_object_unref (action);
237     }
238   if (cs.nr_segment > 1)
239     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
240
241   return actions;
242 }
243
244 MPlist *
245 change (MPlist *args)
246 {
247   MInputContext *ic = mplist_value (args);
248   AnthyContext *context = mplist_get (ic->plist, Manthy);
249   int segment;
250
251   if (! context)
252     return NULL;
253   if (! ic->candidate_list || ic->cursor_pos == 0)
254     return NULL;
255   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
256   if (segment == 0)
257     return NULL;
258   segment--;
259   context->candidate_numbers[segment] = ic->candidate_index;
260   return NULL;
261 }
262
263 MPlist *
264 resize (MPlist *args)
265 {
266   MInputContext *ic = mplist_value (args);
267   AnthyContext *context = mplist_get (ic->plist, Manthy);
268   struct anthy_conv_stat cs;
269   MSymbol shorten;
270   int segment;
271   MPlist *actions, *action;
272   int i;
273
274   if (! context)
275     return NULL;
276   if (! ic->candidate_list || ic->cursor_pos == 0)
277     return NULL;
278   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
279   if (segment == 0)
280     return NULL;
281   segment--;
282   args = mplist_next (args);
283   shorten = mplist_value (args);
284   anthy_resize_segment (context->ac, segment, shorten == Mt ? -1 : 1);
285   anthy_get_stat (context->ac, &cs);
286   allocate_candidate_numbers (context, cs.nr_segment);
287
288   actions = mplist ();
289   if (segment == 0)
290     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
291   else
292     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@["));
293   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
294   for (i = segment; i < cs.nr_segment; i++)
295     {
296       context->candidate_numbers[i] = 0;
297       if (i == segment + 1)
298         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
299       action = make_candidate_list (context, i);
300       mplist_add (actions, Mplist, action);
301       m17n_object_unref (action);
302     }
303   if (segment + 1 < cs.nr_segment)
304     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
305   return actions;
306 }
307
308 MPlist *
309 commit (MPlist *args)
310 {
311   MInputContext *ic = mplist_value (args);
312   AnthyContext *context = mplist_get (ic->plist, Manthy);
313   struct anthy_conv_stat cs;
314   int i;
315
316   anthy_get_stat (context->ac, &cs);
317   for (i = 0; i < cs.nr_segment; i++)
318     anthy_commit_segment (context->ac, i, context->candidate_numbers[i]);
319   return NULL;
320 }
321
322 #else  /* not HAVE_ANTHY */
323
324 MPlist *convert (MPlist *args) { return NULL; }
325 MPlist *change (MPlist *args) { return NULL; }
326 MPlist *resize (MPlist *args) { return NULL; }
327 MPlist *commit (MPlist *args) { return NULL; }
328
329 #endif /* not HAVE_ANTHY */
330 #endif /* not FOR_DOXYGEN */