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