1 /*
2 * Comments in this program are written in Japanese,
3 * because this program is a Japanese input method.
4 * (many Japanese gramatical terms will appear.)
5 *
6 * Kana-Kanji conversion engine Anthy.
7 * 仮名漢字変換エンジンAnthy(アンシー)
8 *
9 * Funded by IPA未踏ソフトウェア創造事業 2001 9/22
10 * Funded by IPA未踏ソフトウェア創造事業 2005
11 * Copyright (C) 2000-2007 TABATA Yusuke, UGAWA Tomoharu
12 * Copyright (C) 2004-2006 YOSHIDA Yuichi
13 * Copyright (C) 2000-2007 KMC(Kyoto University Micro Computer Club)
14 * Copyright (C) 2001-2002 TAKAI Kosuke, Nobuoka Takahiro
15 *
16 */
17 /*
18 This library is free software; you can redistribute it and/or
19 modify it under the terms of the GNU Lesser General Public
20 License as published by the Free Software Foundation; either
21 version 2 of the License, or (at your option) any later version.
22
23 This library is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 Lesser General Public License for more details.
27
28 You should have received a copy of the GNU Lesser General Public
29 License along with this library; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 */
32 /*
33 * Anthyの変換機能はライブラリとして構成されており、この
34 * ファイルにはライブラリの提供する関数(API)が記述されています。
35 *
36 * ライブラリの提供する関数は下記のようなものがあります
37 * (1)ライブラリ全体の初期化、終了、設定
38 * (2)変換コンテキストの作成、解放
39 * (3)変換コンテキストに対する文字列の設定、文節長の変更、候補の取得等
40 *
41 * インターフェイスに関しては doc/LIBを参照してください
42 * Anthyのコードを理解しようとする場合は
43 * doc/GLOSSARY で用語を把握することを勧めます
44 */
45 #include <string.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48
49 #include <anthy/dic.h>
50 #include <anthy/splitter.h>
51 #include <anthy/conf.h>
52 #include <anthy/ordering.h>
53 #include <anthy/logger.h>
54 #include <anthy/record.h>
55 #include <anthy/anthy.h>
56 #include <anthy/record.h>
57 #include <anthy/xchar.h> /* for KK_VU */
58 #include "main.h"
59 #include "config.h"
60
61
62 /** Anthyの初期化が完了したかどうかのフラグ */
63 static int is_init_ok;
64 /** コンテキスト生成時のエンコーディング */
65 static int default_encoding;
66 /***/
67 static char *history_file;
68
69 /** (API) 全体の初期化 */
70 int
anthy_init(void)71 anthy_init(void)
72 {
73 char *hfn;
74 if (is_init_ok) {
75 /* 2度初期化しないように */
76 return 0;
77 }
78
79 /* 各サブシステムを順に初期化する */
80 if (anthy_init_dic()) {
81 anthy_log(0, "Failed to initialize dictionary.\n");
82 return -1;
83 }
84
85 if (anthy_init_splitter()) {
86 anthy_log(0, "Failed to init splitter.\n");
87 return -1;
88 }
89 anthy_init_wordlist();
90 anthy_init_contexts();
91 anthy_init_personality();
92 anthy_infosort_init();
93 anthy_relation_init();
94
95 /**/
96 default_encoding = ANTHY_UTF8_ENCODING;
97 is_init_ok = 1;
98 history_file = NULL;
99 hfn = getenv("ANTHY_HISTORY_FILE");
100 if (hfn) {
101 history_file = strdup(hfn);
102 }
103
104 /**/
105 return 0;
106 }
107
108 /** (API) 全データの解放 */
109 void
anthy_quit(void)110 anthy_quit(void)
111 {
112 if (!is_init_ok) {
113 return ;
114 }
115 anthy_quit_contexts();
116 anthy_quit_personality();
117 anthy_quit_splitter();
118 /* 多くのデータ構造はここでallocatorによって解放される */
119 anthy_quit_dic();
120
121 is_init_ok = 0;
122 /**/
123 if (history_file) {
124 free(history_file);
125 }
126 history_file = NULL;
127 }
128
129 /** (API) 設定項目の上書き */
130 void
anthy_conf_override(const char * var,const char * val)131 anthy_conf_override(const char *var, const char *val)
132 {
133 anthy_do_conf_override(var, val);
134 }
135
136 /** (API) personalityの設定 */
137 int
anthy_set_personality(const char * id)138 anthy_set_personality(const char *id)
139 {
140 return anthy_do_set_personality(id);
141 }
142
143 /** (API) 変換contextの作成 */
144 struct anthy_context *
anthy_create_context(void)145 anthy_create_context(void)
146 {
147 if (!is_init_ok) {
148 return 0;
149 }
150 return anthy_do_create_context(default_encoding);
151 }
152
153 /** (API) 変換contextのリセット */
154 void
anthy_reset_context(struct anthy_context * ac)155 anthy_reset_context(struct anthy_context *ac)
156 {
157 anthy_do_reset_context(ac);
158 }
159
160 /** (API) 変換contextの解放 */
161 void
anthy_release_context(struct anthy_context * ac)162 anthy_release_context(struct anthy_context *ac)
163 {
164 anthy_do_release_context(ac);
165 }
166
167 /**
168 * 再変換が必要かどうかの判定
169 */
170 static int
need_reconvert(struct anthy_context * ac,xstr * xs)171 need_reconvert(struct anthy_context *ac, xstr *xs)
172 {
173 int i;
174
175 if (ac->reconversion_mode == ANTHY_RECONVERT_ALWAYS) {
176 return 1;
177 }
178 if (ac->reconversion_mode == ANTHY_RECONVERT_DISABLE) {
179 return 0;
180 }
181
182 for (i = 0; i < xs->len; ++i) {
183 xchar xc = xs->str[i];
184 int type = anthy_get_xchar_type(xc);
185
186 /* これらの文字種の場合は逆変換する
187 * 「ヴ」はフロントエンドが平仮名モードの文字列として送ってくるので、
188 * 逆変換の対象とはしない
189 */
190 if (!(type & (XCT_HIRA | XCT_SYMBOL | XCT_NUM |
191 XCT_WIDENUM | XCT_OPEN | XCT_CLOSE |
192 XCT_ASCII)) &&
193 xc != KK_VU) {
194 return 1;
195 }
196 }
197 return 0;
198 }
199
200
201 /** (API) 変換文字列の設定 */
202 int
anthy_set_string(struct anthy_context * ac,const char * s)203 anthy_set_string(struct anthy_context *ac, const char *s)
204 {
205 xstr *xs;
206 int retval;
207
208 if (!ac) {
209 return -1;
210 }
211
212 /*初期化*/
213 anthy_do_reset_context(ac);
214
215 /* 辞書セッションの開始 */
216 if (!ac->dic_session) {
217 ac->dic_session = anthy_dic_create_session();
218 if (!ac->dic_session) {
219 return -1;
220 }
221 }
222
223 anthy_dic_activate_session(ac->dic_session);
224 /* 変換を開始する前に個人辞書をreloadする */
225 anthy_reload_record();
226
227 xs = anthy_cstr_to_xstr(s, ac->encoding);
228 /**/
229 if (!need_reconvert(ac, xs)) {
230 /* 普通に変換する */
231 retval = anthy_do_context_set_str(ac, xs, 0);
232 } else {
233 /* 漢字やカタカナが混じっていたら再変換してみる */
234 struct anthy_conv_stat stat;
235 struct seg_ent *seg;
236 int i;
237 xstr* hira_xs;
238 /* 与えられた文字列に変換をかける */
239 retval = anthy_do_context_set_str(ac, xs, 1);
240
241 /* 各文節の第一候補を取得して平仮名列を得る */
242 anthy_get_stat(ac, &stat);
243 hira_xs = NULL;
244 for (i = 0; i < stat.nr_segment; ++i) {
245 seg = anthy_get_nth_segment(&ac->seg_list, i);
246 hira_xs = anthy_xstrcat(hira_xs, &seg->cands[0]->str);
247 }
248 /* 改めて変換を行なう */
249 anthy_release_segment_list(ac);
250 retval = anthy_do_context_set_str(ac, hira_xs, 0);
251 anthy_free_xstr(hira_xs);
252 }
253
254 anthy_free_xstr(xs);
255 return retval;
256 }
257
258 /** (API) 文節長の変更 */
259 void
anthy_resize_segment(struct anthy_context * ac,int nth,int resize)260 anthy_resize_segment(struct anthy_context *ac, int nth, int resize)
261 {
262 anthy_dic_activate_session(ac->dic_session);
263 anthy_do_resize_segment(ac, nth, resize);
264 }
265
266 /** (API) 変換の状態の取得 */
267 int
anthy_get_stat(struct anthy_context * ac,struct anthy_conv_stat * s)268 anthy_get_stat(struct anthy_context *ac, struct anthy_conv_stat *s)
269 {
270 s->nr_segment = ac->seg_list.nr_segments;
271 return 0;
272 }
273
274 /** (API) 文節の状態の取得 */
275 int
anthy_get_segment_stat(struct anthy_context * ac,int n,struct anthy_segment_stat * s)276 anthy_get_segment_stat(struct anthy_context *ac, int n,
277 struct anthy_segment_stat *s)
278 {
279 struct seg_ent *seg;
280 seg = anthy_get_nth_segment(&ac->seg_list, n);
281 if (seg) {
282 s->nr_candidate = seg->nr_cands;
283 s->seg_len = seg->str.len;
284 return 0;
285 }
286 return -1;
287 }
288
289 static int
get_special_candidate_index(int nth,struct seg_ent * seg)290 get_special_candidate_index(int nth, struct seg_ent *seg)
291 {
292 int i;
293 int mask = XCT_NONE;
294 if (nth >= 0) {
295 return nth;
296 }
297 if (nth == NTH_UNCONVERTED_CANDIDATE ||
298 nth == NTH_HALFKANA_CANDIDATE) {
299 return nth;
300 }
301 if (nth == NTH_KATAKANA_CANDIDATE) {
302 mask = XCT_KATA;
303 } else if (nth == NTH_HIRAGANA_CANDIDATE) {
304 mask = XCT_HIRA;
305 }
306 for (i = 0; i < seg->nr_cands; i++) {
307 if (anthy_get_xstr_type(&seg->cands[i]->str) & mask) {
308 return i;
309 }
310 }
311 return NTH_UNCONVERTED_CANDIDATE;
312 }
313
314 /** (API) 文節の取得 */
315 int
anthy_get_segment(struct anthy_context * ac,int nth_seg,int nth_cand,char * buf,int buflen)316 anthy_get_segment(struct anthy_context *ac, int nth_seg,
317 int nth_cand, char *buf, int buflen)
318 {
319 struct seg_ent *seg;
320 char *p;
321 int len;
322
323 /* 文節を取り出す */
324 if (nth_seg < 0 || nth_seg >= ac->seg_list.nr_segments) {
325 return -1;
326 }
327 seg = anthy_get_nth_segment(&ac->seg_list, nth_seg);
328
329 /* 文節から候補を取り出す */
330 p = NULL;
331 if (nth_cand < 0) {
332 nth_cand = get_special_candidate_index(nth_cand, seg);
333 }
334 if (nth_cand == NTH_HALFKANA_CANDIDATE) {
335 xstr *xs = anthy_xstr_hira_to_half_kata(&seg->str);
336 p = anthy_xstr_to_cstr(xs, ac->encoding);
337 anthy_free_xstr(xs);
338 } else if (nth_cand == NTH_UNCONVERTED_CANDIDATE) {
339 /* 変換前の文字列を取得する */
340 p = anthy_xstr_to_cstr(&seg->str, ac->encoding);
341 } else if (nth_cand >= 0 && nth_cand < seg->nr_cands) {
342 p = anthy_xstr_to_cstr(&seg->cands[nth_cand]->str, ac->encoding);
343 }
344 if (!p) {
345 return -1;
346 }
347
348 /* バッファに書き込む */
349 len = strlen(p);
350 if (!buf) {
351 free(p);
352 return len;
353 }
354 if (len + 1 > buflen) {
355 /* バッファが足りません */
356 free(p);
357 return -1;
358 }
359 strcpy(buf, p);
360 free(p);
361 return len;
362 }
363
364 /* すべての文節がコミットされたかcheckする */
365 static int
commit_all_segment_p(struct anthy_context * ac)366 commit_all_segment_p(struct anthy_context *ac)
367 {
368 int i;
369 struct seg_ent *se;
370 for (i = 0; i < ac->seg_list.nr_segments; i++) {
371 se = anthy_get_nth_segment(&ac->seg_list, i);
372 if (se->committed < 0) {
373 return 0;
374 }
375 }
376 return 1;
377 }
378
379 /** (API) 文節の確定 */
380 int
anthy_commit_segment(struct anthy_context * ac,int s,int c)381 anthy_commit_segment(struct anthy_context *ac, int s, int c)
382 {
383 struct seg_ent *seg;
384 if (!ac->str.str) {
385 return -1;
386 }
387 if (s < 0 || s >= ac->seg_list.nr_segments) {
388 return -1;
389 }
390 if (commit_all_segment_p(ac)) {
391 /* すでに全てのセグメントがコミットされている */
392 return -1;
393 }
394
395 anthy_dic_activate_session(ac->dic_session);
396 seg = anthy_get_nth_segment(&ac->seg_list, s);
397 if (c < 0) {
398 c = get_special_candidate_index(c, seg);
399 }
400 if (c == NTH_UNCONVERTED_CANDIDATE) {
401 /*
402 * 変換前の文字列がコミットされたので,それに対応する候補の番号を探す
403 */
404 int i;
405 for (i = 0; i < seg->nr_cands; i++) {
406 if (!anthy_xstrcmp(&seg->str, &seg->cands[i]->str)) {
407 c = i;
408 }
409 }
410 }
411 if (c < 0 || c >= seg->nr_cands) {
412 return -1;
413 }
414 seg->committed = c;
415
416 if (commit_all_segment_p(ac)) {
417 /* 今、すべてのセグメントがコミットされた */
418 anthy_proc_commit(&ac->seg_list, &ac->split_info);
419 /**/
420 anthy_save_history(history_file, ac);
421 }
422 return 0;
423 }
424
425 /** (API) 予測してほしい文字列の設定 */
426 int
anthy_set_prediction_string(struct anthy_context * ac,const char * s)427 anthy_set_prediction_string(struct anthy_context *ac, const char* s)
428 {
429 int retval;
430 xstr *xs;
431
432 anthy_dic_activate_session(ac->dic_session);
433 /* 予測を開始する前に個人辞書をreloadする */
434 anthy_reload_record();
435
436
437 xs = anthy_cstr_to_xstr(s, ac->encoding);
438
439 retval = anthy_do_set_prediction_str(ac, xs);
440
441 anthy_free_xstr(xs);
442
443 return retval;
444 }
445
446 /** (API) 予測変換の状態の取得 */
447 int
anthy_get_prediction_stat(struct anthy_context * ac,struct anthy_prediction_stat * ps)448 anthy_get_prediction_stat(struct anthy_context *ac, struct anthy_prediction_stat * ps)
449 {
450 ps->nr_prediction = ac->prediction.nr_prediction;
451 return 0;
452 }
453
454 /** (API) 予測変換の候補の取得 */
455 int
anthy_get_prediction(struct anthy_context * ac,int nth,char * buf,int buflen)456 anthy_get_prediction(struct anthy_context *ac, int nth, char* buf, int buflen)
457 {
458 struct prediction_cache* prediction = &ac->prediction;
459 int nr_prediction = prediction->nr_prediction;
460 char* p;
461 int len;
462
463 if (nth < 0 || nr_prediction <= nth) {
464 return -1;
465 }
466
467 p = anthy_xstr_to_cstr(prediction->predictions[nth].str, ac->encoding);
468
469 /* バッファに書き込む */
470 len = strlen(p);
471 if (!buf) {
472 free(p);
473 return len;
474 }
475 if (len + 1 > buflen) {
476 free(p);
477 return -1;
478 } else {
479 strcpy(buf, p);
480 free(p);
481 return len;
482 }
483 }
484
485 /** (API) 予測の結果を確定する
486 */
487 int
anthy_commit_prediction(struct anthy_context * ac,int nth)488 anthy_commit_prediction(struct anthy_context *ac, int nth)
489 {
490 struct prediction_cache* pc = &ac->prediction;
491 if (nth < 0 || nth >= pc->nr_prediction) {
492 return -1;
493 }
494 anthy_do_commit_prediction(pc->predictions[nth].src_str,
495 pc->predictions[nth].str);
496 return 0;
497 }
498
499 /** (API) 開発用 */
500 void
anthy_print_context(struct anthy_context * ac)501 anthy_print_context(struct anthy_context *ac)
502 {
503 anthy_do_print_context(ac, default_encoding);
504 }
505
506 /** (API) Anthy ライブラリのバージョンを表す文字列を返す
507 * 共有ライブラリでは外部変数のエクスポートは好ましくないので関数にしてある
508 */
509 const char *
anthy_get_version_string(void)510 anthy_get_version_string (void)
511 {
512 return VERSION;
513 }
514
515 /** (API) */
516 int
anthy_context_set_encoding(struct anthy_context * ac,int encoding)517 anthy_context_set_encoding(struct anthy_context *ac, int encoding)
518 {
519 if (!ac) {
520 return ANTHY_UTF8_ENCODING;
521 }
522 if (encoding == ANTHY_UTF8_ENCODING ||
523 encoding == ANTHY_EUC_JP_ENCODING) {
524 ac->encoding = encoding;
525 }
526 return ac->encoding;
527 }
528
529 /** (API) */
530 int
anthy_set_reconversion_mode(anthy_context_t ac,int mode)531 anthy_set_reconversion_mode(anthy_context_t ac, int mode)
532 {
533 if (!ac) {
534 return ANTHY_RECONVERT_AUTO;
535 }
536 if (mode == ANTHY_RECONVERT_AUTO ||
537 mode == ANTHY_RECONVERT_DISABLE ||
538 mode == ANTHY_RECONVERT_ALWAYS) {
539 ac->reconversion_mode = mode;
540 }
541 return ac->reconversion_mode;
542 }
543