diff options
Diffstat (limited to 'src-main/main.c')
-rw-r--r-- | src-main/main.c | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/src-main/main.c b/src-main/main.c new file mode 100644 index 0000000..024cb6e --- /dev/null +++ b/src-main/main.c @@ -0,0 +1,545 @@ +/* + * Comments in this program are written in Japanese, + * because this program is a Japanese input method. + * (many Japanese gramatical terms will appear.) + * + * Kana-Kanji conversion engine Anthy. + * 仮名漢字変換エンジンAnthy(アンシー) + * + * Funded by IPA未踏ソフトウェア創造事業 2001 9/22 + * Funded by IPA未踏ソフトウェア創造事業 2005 + * Copyright (C) 2000-2007 TABATA Yusuke, UGAWA Tomoharu + * Copyright (C) 2004-2006 YOSHIDA Yuichi + * Copyright (C) 2000-2007 KMC(Kyoto University Micro Computer Club) + * Copyright (C) 2001-2002 TAKAI Kosuke, Nobuoka Takahiro + * + */ +/* + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Anthyの変換機能はライブラリとして構成されており、この + * ファイルにはライブラリの提供する関数(API)が記述されています。 + * + * ライブラリの提供する関数は下記のようなものがあります + * (1)ライブラリ全体の初期化、終了、設定 + * (2)変換コンテキストの作成、解放 + * (3)変換コンテキストに対する文字列の設定、文節長の変更、候補の取得等 + * + * インターフェイスに関しては doc/LIBを参照してください + * Anthyのコードを理解しようとする場合は + * doc/GLOSSARY で用語を把握することを勧めます + */ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <anthy/dic.h> +#include <anthy/splitter.h> +#include <anthy/conf.h> +#include <anthy/ordering.h> +#include <anthy/logger.h> +#include <anthy/record.h> +#include <anthy/anthy.h> +#include <anthy/record.h> +#include <anthy/xchar.h> /* for KK_VU */ +#include "main.h" +#include "config.h" + + +/** Anthyの初期化が完了したかどうかのフラグ */ +static int is_init_ok; +/** コンテキスト生成時のエンコーディング */ +static int default_encoding; +/***/ +static char *history_file; + +/** (API) 全体の初期化 */ +int +anthy_init(void) +{ + char *hfn; + if (is_init_ok) { + /* 2度初期化しないように */ + return 0; + } + + /* 各サブシステムを順に初期化する */ + if (anthy_init_dic()) { + anthy_log(0, "Failed to initialize dictionary.\n"); + return -1; + } + + if (anthy_init_splitter()) { + anthy_log(0, "Failed to init splitter.\n"); + return -1; + } + anthy_init_contexts(); + anthy_init_personality(); + anthy_infosort_init(); + anthy_relation_init(); + + /**/ + default_encoding = ANTHY_EUC_JP_ENCODING; + is_init_ok = 1; + history_file = NULL; + hfn = getenv("ANTHY_HISTORY_FILE"); + if (hfn) { + history_file = strdup(hfn); + } + + /**/ + return 0; +} + +/** (API) 全データの解放 */ +void +anthy_quit(void) +{ + if (!is_init_ok) { + return ; + } + anthy_quit_contexts(); + anthy_quit_personality(); + anthy_quit_splitter(); + /* 多くのデータ構造はここでallocatorによって解放される */ + anthy_quit_dic(); + + is_init_ok = 0; + /**/ + if (history_file) { + free(history_file); + } + history_file = NULL; +} + +/** (API) 設定項目の上書き */ +void +anthy_conf_override(const char *var, const char *val) +{ + anthy_do_conf_override(var, val); +} + +/** (API) personalityの設定 */ +int +anthy_set_personality(const char *id) +{ + return anthy_do_set_personality(id); +} + +/** (API) 変換contextの作成 */ +struct anthy_context * +anthy_create_context(void) +{ + if (!is_init_ok) { + return 0; + } + return anthy_do_create_context(default_encoding); +} + +/** (API) 変換contextのリセット */ +void +anthy_reset_context(struct anthy_context *ac) +{ + anthy_do_reset_context(ac); +} + +/** (API) 変換contextの解放 */ +void +anthy_release_context(struct anthy_context *ac) +{ + anthy_do_release_context(ac); +} + +/** + * 再変換が必要かどうかの判定 + */ +static int +need_reconvert(struct anthy_context *ac, xstr *xs) +{ + int i; + + if (ac->reconversion_mode == ANTHY_RECONVERT_ALWAYS) { + return 1; + } + if (ac->reconversion_mode == ANTHY_RECONVERT_DISABLE) { + return 0; + } + + for (i = 0; i < xs->len; ++i) { + xchar xc = xs->str[i]; + int type = anthy_get_xchar_type(xc); + + /* これらの文字種の場合は逆変換する + * 「ヴ」はフロントエンドが平仮名モードの文字列として送ってくるので、 + * 逆変換の対象とはしない + */ + if (!(type & (XCT_HIRA | XCT_SYMBOL | XCT_NUM | + XCT_WIDENUM | XCT_OPEN | XCT_CLOSE | + XCT_ASCII)) && + xc != KK_VU) { + return 1; + } + } + return 0; +} + + +/** (API) 変換文字列の設定 */ +int +anthy_set_string(struct anthy_context *ac, const char *s) +{ + xstr *xs; + int retval; + + if (!ac) { + return -1; + } + + /*初期化*/ + anthy_do_reset_context(ac); + + /* 辞書セッションの開始 */ + if (!ac->dic_session) { + ac->dic_session = anthy_dic_create_session(); + if (!ac->dic_session) { + return -1; + } + } + + anthy_dic_activate_session(ac->dic_session); + /* 変換を開始する前に個人辞書をreloadする */ + anthy_reload_record(); + + xs = anthy_cstr_to_xstr(s, ac->encoding); + /**/ + if (!need_reconvert(ac, xs)) { + /* 普通に変換する */ + retval = anthy_do_context_set_str(ac, xs, 0); + } else { + /* 漢字やカタカナが混じっていたら再変換してみる */ + struct anthy_conv_stat stat; + struct seg_ent *seg; + int i; + xstr* hira_xs; + /* 与えられた文字列に変換をかける */ + retval = anthy_do_context_set_str(ac, xs, 1); + + /* 各文節の第一候補を取得して平仮名列を得る */ + anthy_get_stat(ac, &stat); + hira_xs = NULL; + for (i = 0; i < stat.nr_segment; ++i) { + seg = anthy_get_nth_segment(&ac->seg_list, i); + hira_xs = anthy_xstrcat(hira_xs, &seg->cands[0]->str); + } + /* 改めて変換を行なう */ + anthy_release_segment_list(ac); + retval = anthy_do_context_set_str(ac, hira_xs, 0); + anthy_free_xstr(hira_xs); + } + + anthy_free_xstr(xs); + return retval; +} + +/** (API) 文節長の変更 */ +void +anthy_resize_segment(struct anthy_context *ac, int nth, int resize) +{ + anthy_dic_activate_session(ac->dic_session); + anthy_do_resize_segment(ac, nth, resize); +} + +/** (API) 変換の状態の取得 */ +int +anthy_get_stat(struct anthy_context *ac, struct anthy_conv_stat *s) +{ + s->nr_segment = ac->seg_list.nr_segments; + return 0; +} + +/** (API) 文節の状態の取得 */ +int +anthy_get_segment_stat(struct anthy_context *ac, int n, + struct anthy_segment_stat *s) +{ + struct seg_ent *seg; + seg = anthy_get_nth_segment(&ac->seg_list, n); + if (seg) { + s->nr_candidate = seg->nr_cands; + s->seg_len = seg->str.len; + return 0; + } + return -1; +} + +static int +get_special_candidate_index(int nth, struct seg_ent *seg) +{ + int i; + int mask = XCT_NONE; + if (nth >= 0) { + return nth; + } + if (nth == NTH_UNCONVERTED_CANDIDATE || + nth == NTH_HALFKANA_CANDIDATE) { + return nth; + } + if (nth == NTH_KATAKANA_CANDIDATE) { + mask = XCT_KATA; + } else if (nth == NTH_HIRAGANA_CANDIDATE) { + mask = XCT_HIRA; + } + for (i = 0; i < seg->nr_cands; i++) { + if (anthy_get_xstr_type(&seg->cands[i]->str) & mask) { + return i; + } + } + return NTH_UNCONVERTED_CANDIDATE; +} + +/** (API) 文節の取得 */ +int +anthy_get_segment(struct anthy_context *ac, int nth_seg, + int nth_cand, char *buf, int buflen) +{ + struct seg_ent *seg; + char *p; + int len; + + /* 文節を取り出す */ + if (nth_seg < 0 || nth_seg >= ac->seg_list.nr_segments) { + return -1; + } + seg = anthy_get_nth_segment(&ac->seg_list, nth_seg); + + /* 文節から候補を取り出す */ + p = NULL; + if (nth_cand < 0) { + nth_cand = get_special_candidate_index(nth_cand, seg); + } + if (nth_cand == NTH_HALFKANA_CANDIDATE) { + xstr *xs = anthy_xstr_hira_to_half_kata(&seg->str); + p = anthy_xstr_to_cstr(xs, ac->encoding); + anthy_free_xstr(xs); + } else if (nth_cand == NTH_UNCONVERTED_CANDIDATE) { + /* 変換前の文字列を取得する */ + p = anthy_xstr_to_cstr(&seg->str, ac->encoding); + } else if (nth_cand >= 0 && nth_cand < seg->nr_cands) { + p = anthy_xstr_to_cstr(&seg->cands[nth_cand]->str, ac->encoding); + } + if (!p) { + return -1; + } + + /* バッファに書き込む */ + len = strlen(p); + if (!buf) { + free(p); + return len; + } + if (len + 1 > buflen) { + /* バッファが足りません */ + free(p); + return -1; + } + strcpy(buf, p); + free(p); + return len; +} + +/* すべての文節がコミットされたかcheckする */ +static int +commit_all_segment_p(struct anthy_context *ac) +{ + int i; + struct seg_ent *se; + for (i = 0; i < ac->seg_list.nr_segments; i++) { + se = anthy_get_nth_segment(&ac->seg_list, i); + if (se->committed < 0) { + return 0; + } + } + return 1; +} + +/** (API) 文節の確定 */ +int +anthy_commit_segment(struct anthy_context *ac, int s, int c) +{ + struct seg_ent *seg; + if (!ac->str.str) { + return -1; + } + if (s < 0 || s >= ac->seg_list.nr_segments) { + return -1; + } + if (commit_all_segment_p(ac)) { + /* すでに全てのセグメントがコミットされている */ + return -1; + } + + anthy_dic_activate_session(ac->dic_session); + seg = anthy_get_nth_segment(&ac->seg_list, s); + if (c < 0) { + c = get_special_candidate_index(c, seg); + } + if (c == NTH_UNCONVERTED_CANDIDATE) { + /* + * 変換前の文字列がコミットされたので,それに対応する候補の番号を探す + */ + int i; + for (i = 0; i < seg->nr_cands; i++) { + if (!anthy_xstrcmp(&seg->str, &seg->cands[i]->str)) { + c = i; + } + } + } + if (c < 0 || c >= seg->nr_cands) { + return -1; + } + seg->committed = c; + + if (commit_all_segment_p(ac)) { + /* 今、すべてのセグメントがコミットされた */ + anthy_proc_commit(&ac->seg_list, &ac->split_info); + /**/ + anthy_save_history(history_file, ac); + } + return 0; +} + +/** (API) 予測してほしい文字列の設定 */ +int +anthy_set_prediction_string(struct anthy_context *ac, const char* s) +{ + int retval; + xstr *xs; + + anthy_dic_activate_session(ac->dic_session); + /* 予測を開始する前に個人辞書をreloadする */ + anthy_reload_record(); + + + xs = anthy_cstr_to_xstr(s, ac->encoding); + + retval = anthy_do_set_prediction_str(ac, xs); + + anthy_free_xstr(xs); + + return retval; +} + +/** (API) 予測変換の状態の取得 */ +int +anthy_get_prediction_stat(struct anthy_context *ac, struct anthy_prediction_stat * ps) +{ + ps->nr_prediction = ac->prediction.nr_prediction; + return 0; +} + +/** (API) 予測変換の候補の取得 */ +int +anthy_get_prediction(struct anthy_context *ac, int nth, char* buf, int buflen) +{ + struct prediction_cache* prediction = &ac->prediction; + int nr_prediction = prediction->nr_prediction; + char* p; + int len; + + if (nth < 0 || nr_prediction <= nth) { + return -1; + } + + p = anthy_xstr_to_cstr(prediction->predictions[nth].str, ac->encoding); + + /* バッファに書き込む */ + len = strlen(p); + if (!buf) { + free(p); + return len; + } + if (len + 1 > buflen) { + free(p); + return -1; + } else { + strcpy(buf, p); + free(p); + return len; + } +} + +/** (API) 予測の結果を確定する + */ +int +anthy_commit_prediction(struct anthy_context *ac, int nth) +{ + struct prediction_cache* pc = &ac->prediction; + if (nth < 0 || nth >= pc->nr_prediction) { + return -1; + } + anthy_do_commit_prediction(pc->predictions[nth].src_str, + pc->predictions[nth].str); + return 0; +} + +/** (API) 開発用 */ +void +anthy_print_context(struct anthy_context *ac) +{ + anthy_do_print_context(ac, default_encoding); +} + +/** (API) Anthy ライブラリのバージョンを表す文字列を返す + * 共有ライブラリでは外部変数のエクスポートは好ましくないので関数にしてある + */ +const char * +anthy_get_version_string (void) +{ +#ifdef VERSION + return VERSION; +#else /* just in case */ + return "(unknown)"; +#endif +} + +/** (API) */ +int +anthy_context_set_encoding(struct anthy_context *ac, int encoding) +{ + if (!ac) { + return ANTHY_EUC_JP_ENCODING; + } + if (encoding == ANTHY_UTF8_ENCODING || + encoding == ANTHY_EUC_JP_ENCODING) { + ac->encoding = encoding; + } + return ac->encoding; +} + +/** (API) */ +int +anthy_set_reconversion_mode(anthy_context_t ac, int mode) +{ + if (!ac) { + return ANTHY_RECONVERT_AUTO; + } + if (mode == ANTHY_RECONVERT_AUTO || + mode == ANTHY_RECONVERT_DISABLE || + mode == ANTHY_RECONVERT_ALWAYS) { + ac->reconversion_mode = mode; + } + return ac->reconversion_mode; +} |