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