1 /*
2 
3   Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4 
5   All rights reserved.
6 
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10 
11   1. Redistributions of source code must retain the above copyright
12      notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14      notice, this list of conditions and the following disclaimer in the
15      documentation and/or other materials provided with the distribution.
16   3. Neither the name of authors nor the names of its contributors
17      may be used to endorse or promote products derived from this software
18      without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30   SUCH DAMAGE.
31 */
32 
33 #include <config.h>
34 
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <anthy/anthy.h>
39 
40 #include "uim.h"
41 #include "uim-scm.h"
42 #include "uim-scm-abbrev.h"
43 #include "dynlib.h"
44 
45 
46 #ifdef ENABLE_ANTHY_STATIC
47 void uim_anthy_plugin_instance_init(void);
48 void uim_anthy_plugin_instance_quit(void);
49 #endif
50 
51 static uim_bool initialized;
52 static uim_lisp context_list;
53 
54 static void
validate_segment_index(anthy_context_t ac,int i)55 validate_segment_index(anthy_context_t ac, int i)
56 {
57   int err;
58   struct anthy_conv_stat cs;
59 
60   err = anthy_get_stat(ac, &cs);
61   if (err)
62     uim_fatal_error("anthy_get_stat() failed");
63   if (!(0 <= i && i < cs.nr_segment))
64     ERROR_OBJ("invalid segment index", MAKE_INT(i));
65 }
66 
67 static anthy_context_t
get_anthy_context(uim_lisp ac_)68 get_anthy_context(uim_lisp ac_)
69 {
70   anthy_context_t ac;
71 
72   ac = C_PTR(ac_);
73   if (!ac)
74     uim_fatal_error("NULL anthy_context_t");
75 
76   return ac;
77 }
78 
79 static uim_lisp
anthy_version()80 anthy_version()
81 {
82   return MAKE_STR(anthy_get_version_string());
83 }
84 
85 static uim_lisp
init_anthy_lib(void)86 init_anthy_lib(void)
87 {
88   if (!initialized) {
89     if (anthy_init() == -1)
90       uim_fatal_error("anthy_init() failed");
91 
92     initialized = UIM_TRUE;
93   }
94 
95   return uim_scm_t();
96 }
97 
98 static uim_lisp
create_context(void)99 create_context(void)
100 {
101   anthy_context_t ac;
102   uim_lisp ac_;
103 
104   ac = anthy_create_context();
105   if (!ac)
106     uim_fatal_error("anthy_create_context() failed");
107 
108   ac_ = MAKE_PTR(ac);
109   context_list = uim_scm_callf("cons", "oo", ac_, context_list);
110 
111   return ac_;
112 }
113 
114 
115 static uim_lisp
release_context(uim_lisp ac_)116 release_context(uim_lisp ac_)
117 {
118   anthy_context_t ac;
119 
120   context_list = uim_scm_callf("delete!", "oo", ac_, context_list);
121 
122   ac = get_anthy_context(ac_);
123   anthy_release_context(ac);
124   uim_scm_nullify_c_ptr(ac_);
125 
126   return uim_scm_f();
127 }
128 
129 static uim_lisp
set_string(uim_lisp ac_,uim_lisp str_)130 set_string(uim_lisp ac_, uim_lisp str_)
131 {
132   anthy_context_t ac;
133   const char *str;
134 
135   ac = get_anthy_context(ac_);
136   str = REFER_C_STR(str_);
137   anthy_set_string(ac, str);
138 
139   return uim_scm_f();
140 }
141 
142 static uim_lisp
get_nr_segments(uim_lisp ac_)143 get_nr_segments(uim_lisp ac_)
144 {
145   anthy_context_t ac;
146   struct anthy_conv_stat cs;
147   int err;
148 
149   ac = get_anthy_context(ac_);
150   err = anthy_get_stat(ac, &cs);
151   if (err)
152     uim_fatal_error("anthy_get_stat() failed");
153 
154   return MAKE_INT(cs.nr_segment);
155 }
156 
157 static uim_lisp
get_nr_candidates(uim_lisp ac_,uim_lisp seg_)158 get_nr_candidates(uim_lisp ac_, uim_lisp seg_)
159 {
160   anthy_context_t ac;
161   int seg, err;
162   struct anthy_segment_stat ss;
163 
164   ac = get_anthy_context(ac_);
165   seg = C_INT(seg_);
166 
167   validate_segment_index(ac, seg);
168 
169   err = anthy_get_segment_stat(ac, seg, &ss);
170   if (err)
171     uim_fatal_error("anthy_get_segment_stat() failed");
172 
173   return MAKE_INT(ss.nr_candidate);
174 }
175 
176 static uim_lisp
get_nth_candidate(uim_lisp ac_,uim_lisp seg_,uim_lisp nth_)177 get_nth_candidate(uim_lisp ac_, uim_lisp seg_, uim_lisp nth_)
178 {
179   anthy_context_t ac;
180   int seg, nth, buflen;
181   char *buf;
182   uim_lisp buf_;
183 
184   ac = get_anthy_context(ac_);
185   seg = C_INT(seg_);
186   nth  = C_INT(nth_);
187 
188   buflen = anthy_get_segment(ac, seg, nth, NULL, 0);
189   if (buflen == -1)
190     uim_fatal_error("anthy_get_segment() failed");
191 
192   buf = uim_malloc(buflen + 1);
193   buflen = anthy_get_segment(ac, seg, nth, buf, buflen + 1);
194   if (buflen == -1) {
195     free(buf);
196     uim_fatal_error("anthy_get_segment() failed");
197   }
198   buf_ = MAKE_STR_DIRECTLY(buf);
199 
200   return buf_;
201 }
202 
203 static uim_lisp
get_unconv_candidate(uim_lisp ac_,uim_lisp seg_)204 get_unconv_candidate(uim_lisp ac_, uim_lisp seg_)
205 {
206   uim_lisp nth_;
207 
208   nth_ = MAKE_INT(NTH_UNCONVERTED_CANDIDATE);
209   return get_nth_candidate(ac_, seg_, nth_);
210 }
211 
212 static uim_lisp
get_segment_length(uim_lisp ac_,uim_lisp seg_)213 get_segment_length(uim_lisp ac_, uim_lisp seg_)
214 {
215   anthy_context_t ac;
216   int seg, err;
217   struct anthy_segment_stat ss;
218 
219   ac = get_anthy_context(ac_);
220   seg = C_INT(seg_);
221 
222   validate_segment_index(ac, seg);
223 
224   err = anthy_get_segment_stat(ac, seg, &ss);
225   if (err)
226     uim_fatal_error("anthy_get_segment_stat() failed");
227 
228   return MAKE_INT(ss.seg_len);
229 }
230 
231 static uim_lisp
resize_segment(uim_lisp ac_,uim_lisp seg_,uim_lisp delta_)232 resize_segment(uim_lisp ac_, uim_lisp seg_, uim_lisp delta_)
233 {
234   anthy_context_t ac;
235   int seg, delta;
236 
237   ac = get_anthy_context(ac_);
238   seg = C_INT(seg_);
239   delta = C_INT(delta_);
240 
241   anthy_resize_segment(ac, seg, delta);
242   return uim_scm_f();
243 }
244 
245 static uim_lisp
commit_segment(uim_lisp ac_,uim_lisp seg_,uim_lisp nth_)246 commit_segment(uim_lisp ac_, uim_lisp seg_, uim_lisp nth_)
247 {
248   anthy_context_t ac;
249   int seg, nth;
250 
251   ac = get_anthy_context(ac_);
252   seg = C_INT(seg_);
253   nth = C_INT(nth_);
254 
255   anthy_commit_segment(ac, seg, nth);
256   return uim_scm_f();
257 }
258 
259 static uim_lisp
set_prediction_src_string(uim_lisp ac_,uim_lisp str_)260 set_prediction_src_string(uim_lisp ac_, uim_lisp str_)
261 {
262 #ifdef HAS_ANTHY_PREDICTION
263   anthy_context_t ac;
264   const char *str;
265 
266   ac = get_anthy_context(ac_);
267   str = REFER_C_STR(str_);
268 
269   anthy_set_prediction_string(ac, str);
270 #endif
271   return uim_scm_f();
272 }
273 
274 static uim_lisp
get_nr_predictions(uim_lisp ac_)275 get_nr_predictions(uim_lisp ac_)
276 {
277 #ifdef HAS_ANTHY_PREDICTION
278   anthy_context_t ac;
279   struct anthy_prediction_stat ps;
280   int err;
281 
282   ac = get_anthy_context(ac_);
283 
284   err = anthy_get_prediction_stat(ac, &ps);
285   if (err)
286     uim_fatal_error("anthy_get_prediction_stat() failed");
287   return MAKE_INT(ps.nr_prediction);
288 #else
289   return uim_scm_f();
290 #endif
291 }
292 
293 static uim_lisp
get_nth_prediction(uim_lisp ac_,uim_lisp nth_)294 get_nth_prediction(uim_lisp ac_, uim_lisp nth_)
295 {
296 #ifdef HAS_ANTHY_PREDICTION
297   anthy_context_t ac;
298   int nth, buflen;
299   char *buf;
300   uim_lisp buf_;
301 
302   ac = get_anthy_context(ac_);
303   nth = C_INT(nth_);
304 
305   buflen = anthy_get_prediction(ac, nth, NULL, 0);
306   if (buflen == -1)
307     uim_fatal_error("anthy_get_prediction() failed");
308 
309   buf = uim_malloc(buflen + 1);
310   buflen = anthy_get_prediction(ac, nth, buf, buflen + 1);
311   if (buflen == -1) {
312     free(buf);
313     uim_fatal_error("anthy_get_prediction() failed");
314   }
315   buf_ = MAKE_STR_DIRECTLY(buf);
316 
317   return buf_;
318 #else
319   return uim_scm_f();
320 #endif
321 }
322 
323 static uim_lisp
commit_nth_prediction(uim_lisp ac_,uim_lisp nth_)324 commit_nth_prediction(uim_lisp ac_, uim_lisp nth_)
325 {
326 #ifdef HAS_ANTHY_COMMIT_PREDICTION
327   anthy_context_t ac;
328   int nth, err;
329 
330   ac = get_anthy_context(ac_);
331   nth = C_INT(nth_);
332 
333   err = anthy_commit_prediction(ac, nth);
334 
335   return MAKE_BOOL(!err);
336 #else
337   return uim_scm_f();
338 #endif
339 }
340 
341 #ifndef ENABLE_ANTHY_STATIC
342 void
uim_plugin_instance_init(void)343 uim_plugin_instance_init(void)
344 #else
345 void
346 uim_anthy_plugin_instance_init(void)
347 #endif
348 {
349   context_list = uim_scm_null();
350   uim_scm_gc_protect(&context_list);
351 
352   uim_scm_eval_c_string("(require-extension (srfi 1))"); /* for delete! */
353 
354   uim_scm_init_proc0("anthy-lib-init", init_anthy_lib);
355   uim_scm_init_proc0("anthy-lib-alloc-context", create_context);
356   uim_scm_init_proc1("anthy-lib-free-context", release_context);
357   uim_scm_init_proc2("anthy-lib-set-string", set_string);
358   uim_scm_init_proc1("anthy-lib-get-nr-segments",get_nr_segments);
359   uim_scm_init_proc2("anthy-lib-get-nr-candidates", get_nr_candidates);
360   uim_scm_init_proc3("anthy-lib-get-nth-candidate", get_nth_candidate);
361   uim_scm_init_proc2("anthy-lib-get-unconv-candidate", get_unconv_candidate);
362   uim_scm_init_proc2("anthy-lib-get-segment-length", get_segment_length);
363   uim_scm_init_proc3("anthy-lib-resize-segment", resize_segment);
364   uim_scm_init_proc3("anthy-lib-commit-segment", commit_segment);
365   uim_scm_init_proc0("anthy-lib-get-anthy-version", anthy_version);
366   uim_scm_init_proc2("anthy-lib-set-prediction-src-string", set_prediction_src_string);
367   uim_scm_init_proc1("anthy-lib-get-nr-predictions", get_nr_predictions);
368   uim_scm_init_proc2("anthy-lib-get-nth-prediction", get_nth_prediction);
369   uim_scm_init_proc2("anthy-lib-commit-nth-prediction",
370 		     commit_nth_prediction);
371 }
372 
373 #ifndef ENABLE_ANTHY_STATIC
374 void
uim_plugin_instance_quit(void)375 uim_plugin_instance_quit(void)
376 #else
377 void
378 uim_anthy_plugin_instance_quit(void)
379 #endif
380 {
381   if (initialized) {
382     uim_scm_callf("for-each", "vo", "anthy-lib-free-context", context_list);
383     context_list = uim_scm_null();
384     uim_scm_gc_unprotect(&context_list);
385 
386     anthy_quit();
387     initialized = UIM_FALSE;
388   }
389 }
390