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 "uim-util.h"
44 #include "dynlib.h"
45 
46 
47 #ifdef ENABLE_ANTHY_STATIC
48 void uim_anthy_plugin_instance_init(void);
49 void uim_anthy_plugin_instance_quit(void);
50 #endif
51 
52 static uim_bool initialized;
53 static uim_lisp context_list;
54 
55 static void *iconv_cd_e2u;
56 static void *iconv_cd_u2e;
57 
58 static void
validate_segment_index(anthy_context_t ac,int i)59 validate_segment_index(anthy_context_t ac, int i)
60 {
61   int err;
62   struct anthy_conv_stat cs;
63 
64   err = anthy_get_stat(ac, &cs);
65   if (err)
66     uim_fatal_error("anthy_get_stat() failed");
67   if (!(0 <= i && i < cs.nr_segment))
68     ERROR_OBJ("invalid segment index", MAKE_INT(i));
69 }
70 
71 static anthy_context_t
get_anthy_context(uim_lisp ac_)72 get_anthy_context(uim_lisp ac_)
73 {
74   anthy_context_t ac;
75 
76   ac = C_PTR(ac_);
77   if (!ac)
78     uim_fatal_error("NULL anthy_context_t");
79 
80   return ac;
81 }
82 
83 static uim_lisp
anthy_version()84 anthy_version()
85 {
86   return MAKE_STR(anthy_get_version_string());
87 }
88 
89 static uim_lisp
init_anthy_lib(void)90 init_anthy_lib(void)
91 {
92   if (!initialized) {
93     if (anthy_init() == -1)
94       uim_fatal_error("anthy_init() failed");
95 
96     initialized = UIM_TRUE;
97   }
98 
99   return uim_scm_t();
100 }
101 
102 static uim_lisp
create_context(uim_lisp encoding_)103 create_context(uim_lisp encoding_)
104 {
105   anthy_context_t ac;
106   uim_lisp ac_;
107   int encoding;
108 
109   /* 0: compiled, 1: EUC-JP, 2: UTF-8 */
110   encoding = C_INT(encoding_);
111 
112   if (!iconv_cd_e2u)
113     iconv_cd_e2u = uim_iconv->create("UTF-8", "EUC-JP");
114 
115   if (!iconv_cd_u2e)
116     iconv_cd_u2e = uim_iconv->create("EUC-JP", "UTF-8");
117 
118   ac = anthy_create_context();
119   if (!ac)
120     uim_fatal_error("anthy_create_context() failed");
121 
122   anthy_context_set_encoding(ac, encoding);
123   ac_ = MAKE_PTR(ac);
124   context_list = uim_scm_callf("cons", "oo", ac_, context_list);
125 
126   return ac_;
127 }
128 
129 
130 static uim_lisp
release_context(uim_lisp ac_)131 release_context(uim_lisp ac_)
132 {
133   anthy_context_t ac;
134 
135   context_list = uim_scm_callf("delete!", "oo", ac_, context_list);
136 
137   ac = get_anthy_context(ac_);
138   anthy_release_context(ac);
139   uim_scm_nullify_c_ptr(ac_);
140 
141   return uim_scm_f();
142 }
143 
144 static uim_lisp
set_string(uim_lisp ac_,uim_lisp str_)145 set_string(uim_lisp ac_, uim_lisp str_)
146 {
147   anthy_context_t ac;
148   const char *str;
149 
150   ac = get_anthy_context(ac_);
151   str = REFER_C_STR(str_);
152   anthy_set_string(ac, str);
153 
154   return uim_scm_f();
155 }
156 
157 static uim_lisp
get_nr_segments(uim_lisp ac_)158 get_nr_segments(uim_lisp ac_)
159 {
160   anthy_context_t ac;
161   struct anthy_conv_stat cs;
162   int err;
163 
164   ac = get_anthy_context(ac_);
165   err = anthy_get_stat(ac, &cs);
166   if (err)
167     uim_fatal_error("anthy_get_stat() failed");
168 
169   return MAKE_INT(cs.nr_segment);
170 }
171 
172 static uim_lisp
get_nr_candidates(uim_lisp ac_,uim_lisp seg_)173 get_nr_candidates(uim_lisp ac_, uim_lisp seg_)
174 {
175   anthy_context_t ac;
176   int seg, err;
177   struct anthy_segment_stat ss;
178 
179   ac = get_anthy_context(ac_);
180   seg = C_INT(seg_);
181 
182   validate_segment_index(ac, seg);
183 
184   err = anthy_get_segment_stat(ac, seg, &ss);
185   if (err)
186     uim_fatal_error("anthy_get_segment_stat() failed");
187 
188   return MAKE_INT(ss.nr_candidate);
189 }
190 
191 static uim_lisp
get_nth_candidate(uim_lisp ac_,uim_lisp seg_,uim_lisp nth_)192 get_nth_candidate(uim_lisp ac_, uim_lisp seg_, uim_lisp nth_)
193 {
194   anthy_context_t ac;
195   int seg, nth, buflen;
196   char *buf;
197   uim_lisp buf_;
198 
199   ac = get_anthy_context(ac_);
200   seg = C_INT(seg_);
201   nth  = C_INT(nth_);
202 
203   buflen = anthy_get_segment(ac, seg, nth, NULL, 0);
204   if (buflen == -1)
205     uim_fatal_error("anthy_get_segment() failed");
206 
207   buf = uim_malloc(buflen + 1);
208   buflen = anthy_get_segment(ac, seg, nth, buf, buflen + 1);
209   if (buflen == -1) {
210     free(buf);
211     uim_fatal_error("anthy_get_segment() failed");
212   }
213   buf_ = MAKE_STR_DIRECTLY(buf);
214 
215   return buf_;
216 }
217 
218 static uim_lisp
get_unconv_candidate(uim_lisp ac_,uim_lisp seg_)219 get_unconv_candidate(uim_lisp ac_, uim_lisp seg_)
220 {
221   uim_lisp nth_;
222 
223   nth_ = MAKE_INT(NTH_UNCONVERTED_CANDIDATE);
224   return get_nth_candidate(ac_, seg_, nth_);
225 }
226 
227 static uim_lisp
get_segment_length(uim_lisp ac_,uim_lisp seg_)228 get_segment_length(uim_lisp ac_, uim_lisp seg_)
229 {
230   anthy_context_t ac;
231   int seg, err;
232   struct anthy_segment_stat ss;
233 
234   ac = get_anthy_context(ac_);
235   seg = C_INT(seg_);
236 
237   validate_segment_index(ac, seg);
238 
239   err = anthy_get_segment_stat(ac, seg, &ss);
240   if (err)
241     uim_fatal_error("anthy_get_segment_stat() failed");
242 
243   return MAKE_INT(ss.seg_len);
244 }
245 
246 static uim_lisp
resize_segment(uim_lisp ac_,uim_lisp seg_,uim_lisp delta_)247 resize_segment(uim_lisp ac_, uim_lisp seg_, uim_lisp delta_)
248 {
249   anthy_context_t ac;
250   int seg, delta;
251 
252   ac = get_anthy_context(ac_);
253   seg = C_INT(seg_);
254   delta = C_INT(delta_);
255 
256   anthy_resize_segment(ac, seg, delta);
257   return uim_scm_f();
258 }
259 
260 static uim_lisp
commit_segment(uim_lisp ac_,uim_lisp seg_,uim_lisp nth_)261 commit_segment(uim_lisp ac_, uim_lisp seg_, uim_lisp nth_)
262 {
263   anthy_context_t ac;
264   int seg, nth;
265 
266   ac = get_anthy_context(ac_);
267   seg = C_INT(seg_);
268   nth = C_INT(nth_);
269 
270   anthy_commit_segment(ac, seg, nth);
271   return uim_scm_f();
272 }
273 
274 static uim_lisp
set_prediction_src_string(uim_lisp ac_,uim_lisp str_)275 set_prediction_src_string(uim_lisp ac_, uim_lisp str_)
276 {
277 #ifdef HAS_ANTHY_PREDICTION
278   anthy_context_t ac;
279   const char *str;
280 
281   ac = get_anthy_context(ac_);
282   str = REFER_C_STR(str_);
283 
284   anthy_set_prediction_string(ac, str);
285 #endif
286   return uim_scm_f();
287 }
288 
289 static uim_lisp
get_nr_predictions(uim_lisp ac_)290 get_nr_predictions(uim_lisp ac_)
291 {
292 #ifdef HAS_ANTHY_PREDICTION
293   anthy_context_t ac;
294   struct anthy_prediction_stat ps;
295   int err;
296 
297   ac = get_anthy_context(ac_);
298 
299   err = anthy_get_prediction_stat(ac, &ps);
300   if (err)
301     uim_fatal_error("anthy_get_prediction_stat() failed");
302   return MAKE_INT(ps.nr_prediction);
303 #else
304   return uim_scm_f();
305 #endif
306 }
307 
308 static uim_lisp
get_nth_prediction(uim_lisp ac_,uim_lisp nth_)309 get_nth_prediction(uim_lisp ac_, uim_lisp nth_)
310 {
311 #ifdef HAS_ANTHY_PREDICTION
312   anthy_context_t ac;
313   int nth, buflen;
314   char *buf;
315   uim_lisp buf_;
316 
317   ac = get_anthy_context(ac_);
318   nth = C_INT(nth_);
319 
320   buflen = anthy_get_prediction(ac, nth, NULL, 0);
321   if (buflen == -1)
322     uim_fatal_error("anthy_get_prediction() failed");
323 
324   buf = uim_malloc(buflen + 1);
325   buflen = anthy_get_prediction(ac, nth, buf, buflen + 1);
326   if (buflen == -1) {
327     free(buf);
328     uim_fatal_error("anthy_get_prediction() failed");
329   }
330   buf_ = MAKE_STR_DIRECTLY(buf);
331 
332   return buf_;
333 #else
334   return uim_scm_f();
335 #endif
336 }
337 
338 static uim_lisp
commit_nth_prediction(uim_lisp ac_,uim_lisp nth_)339 commit_nth_prediction(uim_lisp ac_, uim_lisp nth_)
340 {
341 #ifdef HAS_ANTHY_COMMIT_PREDICTION
342   anthy_context_t ac;
343   int nth, err;
344 
345   ac = get_anthy_context(ac_);
346   nth = C_INT(nth_);
347 
348   err = anthy_commit_prediction(ac, nth);
349 
350   return MAKE_BOOL(!err);
351 #else
352   return uim_scm_f();
353 #endif
354 }
355 
356 static uim_lisp
eucjp_to_utf8(uim_lisp str_)357 eucjp_to_utf8(uim_lisp str_)
358 {
359   const char *str;
360   char *convstr;
361   uim_lisp utf8_;
362 
363   if (!iconv_cd_e2u)
364     return MAKE_STR("〓");
365 
366   str = REFER_C_STR(str_);
367   convstr = uim_iconv->convert(iconv_cd_e2u, str);
368   utf8_ = MAKE_STR(convstr);
369   free(convstr);
370 
371   return utf8_;
372 }
373 
374 static uim_lisp
utf8_to_eucjp(uim_lisp str_)375 utf8_to_eucjp(uim_lisp str_)
376 {
377   const char *str;
378   char *convstr;
379   uim_lisp eucjp_;
380 
381   if (!iconv_cd_u2e)
382     return MAKE_STR("");
383 
384   str = REFER_C_STR(str_);
385   convstr = uim_iconv->convert(iconv_cd_u2e, str);
386   eucjp_ = MAKE_STR(convstr);
387   free(convstr);
388 
389   return eucjp_;
390 }
391 
392 #ifndef ENABLE_ANTHY_STATIC
393 void
uim_plugin_instance_init(void)394 uim_plugin_instance_init(void)
395 #else
396 void
397 uim_anthy_plugin_instance_init(void)
398 #endif
399 {
400   context_list = uim_scm_null();
401   uim_scm_gc_protect(&context_list);
402 
403   uim_scm_eval_c_string("(require-extension (srfi 1))"); /* for delete! */
404 
405   uim_scm_init_proc0("anthy-lib-init", init_anthy_lib);
406   uim_scm_init_proc1("anthy-lib-alloc-context", create_context);
407   uim_scm_init_proc1("anthy-lib-free-context", release_context);
408   uim_scm_init_proc2("anthy-lib-set-string", set_string);
409   uim_scm_init_proc1("anthy-lib-get-nr-segments",get_nr_segments);
410   uim_scm_init_proc2("anthy-lib-get-nr-candidates", get_nr_candidates);
411   uim_scm_init_proc3("anthy-lib-get-nth-candidate", get_nth_candidate);
412   uim_scm_init_proc2("anthy-lib-get-unconv-candidate", get_unconv_candidate);
413   uim_scm_init_proc2("anthy-lib-get-segment-length", get_segment_length);
414   uim_scm_init_proc3("anthy-lib-resize-segment", resize_segment);
415   uim_scm_init_proc3("anthy-lib-commit-segment", commit_segment);
416   uim_scm_init_proc0("anthy-lib-get-anthy-version", anthy_version);
417   uim_scm_init_proc2("anthy-lib-set-prediction-src-string", set_prediction_src_string);
418   uim_scm_init_proc1("anthy-lib-get-nr-predictions", get_nr_predictions);
419   uim_scm_init_proc2("anthy-lib-get-nth-prediction", get_nth_prediction);
420   uim_scm_init_proc2("anthy-lib-commit-nth-prediction",
421 		     commit_nth_prediction);
422   uim_scm_init_proc1("anthy-lib-eucjp-to-utf8", eucjp_to_utf8);
423   uim_scm_init_proc1("anthy-lib-utf8-to-eucjp", utf8_to_eucjp);
424 }
425 
426 #ifndef ENABLE_ANTHY_STATIC
427 void
uim_plugin_instance_quit(void)428 uim_plugin_instance_quit(void)
429 #else
430 void
431 uim_anthy_plugin_instance_quit(void)
432 #endif
433 {
434   if (initialized) {
435     uim_scm_callf("for-each", "vo", "anthy-lib-free-context", context_list);
436     context_list = uim_scm_null();
437     uim_scm_gc_unprotect(&context_list);
438 
439     anthy_quit();
440     initialized = UIM_FALSE;
441 
442     if (iconv_cd_e2u) {
443       uim_iconv->release(iconv_cd_e2u);
444       iconv_cd_e2u = NULL;
445     }
446     if (iconv_cd_u2e) {
447       uim_iconv->release(iconv_cd_u2e);
448       iconv_cd_u2e = NULL;
449     }
450   }
451 }
452