diff options
Diffstat (limited to 'src-util/rkhelper.c')
-rw-r--r-- | src-util/rkhelper.c | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/src-util/rkhelper.c b/src-util/rkhelper.c new file mode 100644 index 0000000..c99bd08 --- /dev/null +++ b/src-util/rkhelper.c @@ -0,0 +1,442 @@ +/* + * ローマ字から平仮名(正確にはキーの列から文字)の表(rk_map)の + * カスタマイズを管理する + * + * Copyright (C) 2001-2002 UGAWA Tomoharu + * Copyright (C) 2002 Tabata Yusuke + * + * Funded by IPA未踏ソフトウェア創造事業 2001 + */ + +#include <string.h> +#include <stdlib.h> +#include "rkconv.h" +#include "rkhelper.h" + +static const char* rk_default_symbol[128] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + " ", "!", "”", "#", "$", "%", "&", "’", + "(", ")", "*", "+", "、", "ー", "。", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + + "@", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "「", "\", "」", "^", "_", + "‘", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "{", "|", "}", "〜", NULL +}; + +struct rk_conf_ent { + char *lhs; + char *rhs; + struct rk_conf_ent *next; +}; + +struct rk_option { + int enable_default; + char toggle; /* 英数との一時的な切替えに使うシンボル */ + /* + * 配列はそれぞれリストの先頭になる + * リストの先頭は一文字のエントリが入る + */ + struct rk_conf_ent hiragana_symbol[128]; /* ひらがなとの対応 */ + struct rk_conf_ent katakana_symbol[128]; /* カタカナとの対応 */ + struct rk_conf_ent hankaku_kana_symbol[128]; /* カタカナとの対応 */ +}; + +#include "rkmap.h" + +struct rk_option * +anthy_input_create_rk_option() +{ + struct rk_option *opt; + int i; + + opt = malloc(sizeof(struct rk_option)); + opt->enable_default = 1; + opt->toggle = '/'; + for (i = 0; i < 128; i++) { + opt->hiragana_symbol[i].rhs = NULL; + opt->hiragana_symbol[i].lhs = NULL; + opt->hiragana_symbol[i].next = NULL; + opt->katakana_symbol[i].rhs = NULL; + opt->katakana_symbol[i].lhs = NULL; + opt->katakana_symbol[i].next = NULL; + opt->hankaku_kana_symbol[i].rhs = NULL; + opt->hankaku_kana_symbol[i].lhs = NULL; + opt->hankaku_kana_symbol[i].next = NULL; + } + return opt; +} + +int +anthy_input_free_rk_option(struct rk_option *opt) +{ + int err; + + err = anthy_input_do_clear_rk_option(opt, 1); + free(opt); + + return err; +} + +static struct rk_conf_ent * +find_rk_conf_ent(struct rk_option *opt, int map, + const char *key, int force) +{ + int c = key[0]; + struct rk_conf_ent *tab = NULL; + struct rk_conf_ent *sym = NULL; + + if (c == 0) { + return NULL; + } + + if (map == RKMAP_HIRAGANA) { + tab = opt->hiragana_symbol; + } + if (map == RKMAP_KATAKANA) { + tab = opt->katakana_symbol; + } + if (map == RKMAP_HANKAKU_KANA) { + tab = opt->hankaku_kana_symbol; + } + if (!tab) { + return NULL; + } + if (strlen(key) == 1) { + sym = &tab[c]; + } else { + /* 2文字以上 */ + for (sym = tab[c].next; sym; sym = sym->next) { + if (!strcmp(sym->lhs, key)) { + break; + } + } + } + if (!sym && force) { + /* メモリ確保してつなぐ */ + sym = malloc(sizeof(struct rk_conf_ent)); + sym->rhs = NULL; + sym->lhs = NULL; + sym->next = tab[c].next; + tab[c].next = sym; + } + if (sym && !sym->lhs) { + sym->lhs = strdup(key); + } + return sym; +} + +/* + * opt 変更対象のoption + * map RKMAP_* + * from 変換もとの文字 + * to 変換先の文字列 + * follow follow集合 + */ +int +anthy_input_do_edit_rk_option(struct rk_option* opt, int map, + const char* from, const char* to, const char *follow) +{ + struct rk_conf_ent *tab; + (void)follow; + + tab = find_rk_conf_ent(opt, map, from, 1); + if (!tab) { + return -1; + } + + if (tab->rhs) { + free(tab->rhs); + } + if (to == NULL) { + tab->rhs = NULL; + } else { + tab->rhs = strdup(to); + } + return 0; +} + +static void +free_rk_conf_ent(struct rk_conf_ent *e) +{ + if (e->lhs) { + free(e->lhs); + e->lhs = NULL; + } + if (e->rhs) { + free(e->rhs); + e->rhs = NULL; + } + e->next = NULL; +} + +int +anthy_input_do_clear_rk_option(struct rk_option* opt, + int use_default) +{ + int i; + + opt->enable_default = use_default; + for (i = 0; i < 128; i++) { + /* 各文字に対して */ + struct rk_conf_ent *tab, *tmp; + /* ひらがなのリストを解放 */ + for (tab = opt->hiragana_symbol[i].next; tab;) { + tmp = tab; + tab = tab->next; + free_rk_conf_ent(tmp); + free(tmp); + } + /* カタカナのリストを解放 */ + for (tab = opt->katakana_symbol[i].next; tab;) { + tmp = tab; + tab = tab->next; + free_rk_conf_ent(tmp); + free(tmp); + } + /* 先頭の一文字のエントリも忘れずに解放 */ + free_rk_conf_ent(&opt->katakana_symbol[i]); + free_rk_conf_ent(&opt->hiragana_symbol[i]); + } + return 0; +} + +int +anthy_input_do_edit_toggle_option(struct rk_option* opt, + char toggle) +{ + opt->toggle = toggle; + return 0; +} + +static void +rkrule_set(struct rk_rule* r, + const char* lhs, const char* rhs, const char* follow) +{ + r->lhs = lhs; + r->rhs = rhs; + r->follow = follow; +} + +struct rk_map* +make_rkmap_ascii(struct rk_option* opt) +{ + struct rk_rule var_part[130]; + struct rk_rule* complete_rules; + struct rk_map* map; + struct rk_rule* p; + char work[2*128]; + char* w; + int c; + + (void)opt; + p = var_part; + w = work; + for (c = 0; c < 128; c++) { + if (rk_default_symbol[c]) { + w[0] = c; + w[1] = '\0'; + rkrule_set(p++, w, w, NULL); + w += 2; + } + } + p->lhs = NULL; + + complete_rules = rk_merge_rules(rk_rule_alphabet, var_part); + map = rk_map_create(complete_rules); + rk_rules_free(complete_rules); + + return map; +} + +struct rk_map* +make_rkmap_wascii(struct rk_option* opt) +{ + (void)opt; + return rk_map_create(rk_rule_walphabet); +} + +struct rk_map* +make_rkmap_shiftascii(struct rk_option* opt) +{ + struct rk_rule var_part[130]; + struct rk_rule* complete_rules; + struct rk_map* map; + struct rk_rule* p; + char work[2*128 + 3]; + char* w; + int c; + int toggle_char = opt->toggle; + + p = var_part; + w = work; + for (c = 0; c < 128; c++) { + if (rk_default_symbol[c]) { + if (c == toggle_char) { + /* トグルする文字の場合 */ + w[0] = c; + w[1] = '\0'; + rkrule_set(p++, w, "\xff" "o", NULL); + w[2] = c; + w[3] = c; + w[4] = '\0'; + rkrule_set(p++, w + 2, w, NULL); + w += 5; + } else { + /* 普通の文字の場合 */ + w[0] = c; + w[1] = '\0'; + rkrule_set(p++, w, w, NULL); + w += 2; + } + } + } + p->lhs = NULL; + + complete_rules = rk_merge_rules(rk_rule_alphabet, var_part); + map = rk_map_create(complete_rules); + rk_rules_free(complete_rules); + + return map; +} + +static int +count_rk_rule_ent(struct rk_option *opt, int map_no) +{ + int i , c; + struct rk_conf_ent *head; + struct rk_conf_ent *ent; + + if (map_no == RKMAP_HIRAGANA) { + head = opt->hiragana_symbol; + } else if (map_no == RKMAP_HANKAKU_KANA) { + head = opt->katakana_symbol; + } else { + head = opt->hankaku_kana_symbol; + } + + c = 128; + for (i = 0; i < 128; i++) { + for (ent = head[i].next; ent; ent = ent->next) { + if (ent->lhs) { + c++; + } + } + } + return c; +} + +/* + * デフォルトのルールとカスタマイズされたルールをマージして + * rk_mapを作る。 + */ +static struct rk_map* +make_rkmap_hirakata(const struct rk_rule* rule, + struct rk_option *opt, int map_no) +{ + struct rk_conf_ent *tab; + struct rk_rule* rk_var_part; + struct rk_rule* complete_rules; + struct rk_rule* p; + struct rk_map* map; + int toggle = opt->toggle; + char *work; + char* w; + int c; + int nr_rule; + char buf[2]; + + nr_rule = count_rk_rule_ent(opt, map_no); + + rk_var_part = alloca(sizeof(struct rk_rule) *(nr_rule + 2)); + work = alloca(2*128 + 8); + p = rk_var_part; + w = work; + + /* 一文字のものをrk_var_partに書き込んでいく */ + /* トグルの場合 */ + buf[0] = toggle; + buf[1] = 0; + w[0] = toggle; + w[1] = '\0'; + w[2] = '\xff'; + w[3] = '0' + RKMAP_SHIFT_ASCII; + w[4] = '\0'; + rkrule_set(p++, w, w + 2, NULL); + w[5] = toggle; + w[6] = toggle; + w[7] = '\0'; + tab = find_rk_conf_ent(opt, map_no, buf, 0); + if (tab && tab->rhs) { + rkrule_set(p++, w + 5, tab->rhs, NULL); + } else { + rkrule_set(p++, w + 5, rk_default_symbol[toggle], NULL); + } + w += 8; + /* トグル以外 */ + for (c = 0; c < 128; c++) { + if (c != toggle) { + buf[0] = c; + buf[1] = 0; + /* 一文字のもの */ + w[0] = c; + w[1] = '\0'; + tab = find_rk_conf_ent(opt, map_no, buf, 0); + if (tab && tab->rhs) { + /* カスタマイズ済のがある */ + rkrule_set(p++, w, tab->rhs, NULL); + } else if (rk_default_symbol[c]) { + /* 記号など */ + rkrule_set(p++, w, rk_default_symbol[c], NULL); + } + w += 2; + /* 二文字以上のもの */ + if (tab) { + for (tab = tab->next; tab; tab = tab->next) { + rkrule_set(p++, tab->lhs, tab->rhs, NULL); + } + } + } + } + p->lhs = NULL; + + if (opt->enable_default) { + complete_rules = rk_merge_rules(rule, rk_var_part); + map = rk_map_create(complete_rules); + rk_rules_free(complete_rules); + } else { + map = rk_map_create(rk_var_part); + } + + return map; +} + +struct rk_map* +make_rkmap_hiragana(struct rk_option* opt) +{ + return make_rkmap_hirakata(rk_rule_hiragana, + opt, RKMAP_HIRAGANA); +} + +struct rk_map* +make_rkmap_katakana(struct rk_option* opt) +{ + return make_rkmap_hirakata(rk_rule_katakana, + opt, RKMAP_KATAKANA); +} + +struct rk_map * +make_rkmap_hankaku_kana(struct rk_option *opt) +{ + return make_rkmap_hirakata(rk_rule_hankaku_kana, + opt, RKMAP_HANKAKU_KANA); +} |