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