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