diff options
Diffstat (limited to 'src-diclib/ruleparser.c')
-rw-r--r-- | src-diclib/ruleparser.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/src-diclib/ruleparser.c b/src-diclib/ruleparser.c new file mode 100644 index 0000000..3aaa394 --- /dev/null +++ b/src-diclib/ruleparser.c @@ -0,0 +1,329 @@ +/* + * 設定ファイルなどのための + * 汎用のファイル読み込みモジュール + * + * Copyright (C) 2000-2006 TABATA Yusuke + * + */ +/* + 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 + */ +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <anthy/conf.h> +#include <anthy/ruleparser.h> +#include <anthy/logger.h> + +/* 文法ファイルのパーザ用の定義 */ +#define MAX_TOKEN_LEN 256 +/* 最大のインクルードの深さ */ +#define MAX_INCLUDE_DEPTH 4 + +#define PS_INIT 0 +#define PS_TOKEN 1 +#define PS_EOF 2 +#define PS_RET 3 + +static const char *NL = "NL"; + +static struct parser_stat { + FILE *fp_stack[MAX_INCLUDE_DEPTH]; + FILE *fp; + int cur_fpp;/* スタックのインデックス */ + int line_num; + char **tokens; + int nr_token; +} g_ps; + +struct line_stat{ + int stat; + char buf[MAX_TOKEN_LEN]; + int buf_index; +}; + +static FILE * +open_file_in_confdir(const char *fn) +{ + const char *dn; + char *full; + size_t dname_len; + + if (!fn) { + return stdin; + } + + if (fn[0] == '/' || + (fn[0] == '.' && fn[1] == '/')) { + /* 絶対パスもしくはカレントディレクトリなのでそのままfopen */ + return fopen(fn, "r"); + } + + dn = anthy_conf_get_str("ANTHYDIR"); + if (!dn) { + return 0; + } + dname_len = strlen(dn); + full = alloca(dname_len + strlen(fn) + 2); + sprintf(full, "%s/%s", dn, fn); + + return fopen(full, "r"); +} + +/** バックスラッシュによるエスケープも処理するgetc + * エスケープされた文字ならば返り値は1になる。 + */ +static int +mygetc (int *cc) +{ + *cc = fgetc(g_ps.fp); + if (*cc == '\\') { + int c2 = fgetc(g_ps.fp); + switch(c2) { + case '\\': + *cc = '\\'; + return 1; + case '\n': + *cc = ' '; + return 1; + case '\"': + *cc = '\"'; + return 1; + default:; + /* go through */ + } + } + return 0; +} + +#define myisblank(c) ((c) == ' ' || (c) == '\t') + +/* 行に一文字追加する */ +static void +pushchar(struct line_stat *ls, int cc) +{ + if (ls->buf_index == MAX_TOKEN_LEN - 1) { + ls->buf[MAX_TOKEN_LEN - 1] = 0; + } else { + ls->buf[ls->buf_index] = cc; + ls->buf_index ++; + } +} + +static const char * +get_token_in(struct line_stat *ls) +{ + int cc, esc; + int in_quote = 0; + if (ls->stat == PS_EOF) { + return NULL; + } + if (ls->stat == PS_RET) { + return NL; + } + /* トークンが始まるまで空白を読み飛ばす */ + do { + esc = mygetc(&cc); + } while (cc > 0 && myisblank(cc) && esc == 0); + if (cc == -1) { + return NULL; + } + if (cc == '\n'){ + return NL; + } + + /**/ + if (cc == '\"' && !esc) { + in_quote = 1; + } + /**/ + do { + pushchar(ls, cc); + esc = mygetc(&cc); + if (cc < 0){ + /* EOF */ + pushchar(ls, 0); + ls->stat = PS_EOF; + return ls->buf; + } + if (cc == '\n' && !esc) { + /* 改行 */ + pushchar(ls, 0); + ls->stat = PS_RET; + return ls->buf; + } + if (!in_quote && myisblank(cc)) { + break; + } + if (in_quote && cc == '\"' && !esc) { + pushchar(ls, '\"'); + break; + } + } while (1); + pushchar(ls, 0); + return ls->buf; +} + +/* 一行読む */ +static int +get_line_in(void) +{ + const char *t; + struct line_stat ls; + + ls.stat = PS_INIT; + do{ + ls.buf_index = 0; + t = get_token_in(&ls); + if (!t) { + return -1; + } + if (t == NL) { + return 0; + } + g_ps.nr_token++; + g_ps.tokens = realloc(g_ps.tokens, sizeof(char *)*g_ps.nr_token); + g_ps.tokens[g_ps.nr_token-1] = strdup(t); + } while(1); +} + +static void +proc_include(void) +{ + FILE *fp; + if (g_ps.nr_token != 2) { + anthy_log(0, "Syntax error in include directive.\n"); + return ; + } + if (g_ps.cur_fpp > MAX_INCLUDE_DEPTH - 1) { + anthy_log(0, "Too deep include.\n"); + return ; + } + fp = open_file_in_confdir(g_ps.tokens[1]); + if (!fp) { + anthy_log(0, "Failed to open %s.\n", g_ps.tokens[1]); + return ; + } + g_ps.cur_fpp++; + g_ps.fp_stack[g_ps.cur_fpp] = fp; + g_ps.fp = fp; +} + +/* インクルードのネストを下げる */ +static void +pop_file(void) +{ + fclose(g_ps.fp); + g_ps.cur_fpp --; + g_ps.fp = g_ps.fp_stack[g_ps.cur_fpp]; +} + +static void +get_line(void) +{ + int r; + + again: + anthy_free_line(); + g_ps.line_num ++; + + r = get_line_in(); + if (r == -1){ + /* EOF等でこれ以上読めん */ + if (g_ps.cur_fpp > 0) { + pop_file(); + goto again; + }else{ + return ; + } + } + if (g_ps.nr_token < 1) { + goto again; + } + if (!strcmp(g_ps.tokens[0], "\\include")) { + proc_include(); + goto again; + }else if (!strcmp(g_ps.tokens[0], "\\eof")) { + if (g_ps.cur_fpp > 0) { + pop_file(); + goto again; + }else{ + anthy_free_line(); + return ; + } + } + if (g_ps.tokens[0][0] == '#'){ + goto again; + } +} + +void +anthy_free_line(void) +{ + int i; + if (g_ps.tokens) { /* 不正なメモリアクセスの防止 */ + for (i = 0; i < g_ps.nr_token; i++) { + free(g_ps.tokens[i]); + } + free(g_ps.tokens); + g_ps.tokens = 0; + } + g_ps.nr_token = 0; +} + +int +anthy_open_file(const char *fn) +{ + g_ps.fp_stack[0] = open_file_in_confdir(fn); + if (!g_ps.fp_stack[0]) { + return -1; + } + /* パーザの状態を初期化する */ + g_ps.cur_fpp = 0; + g_ps.fp = g_ps.fp_stack[0]; + g_ps.line_num = 0; + g_ps.nr_token = 0; /* 初期化忘れの修正 */ + g_ps.tokens = NULL; /* 初期化忘れの修正 */ + return 0; +} + +void +anthy_close_file(void) +{ + if (g_ps.fp != stdin) { + fclose(g_ps.fp); + } + anthy_free_line(); /* 後始末忘れの防止 */ +} + +int +anthy_read_line(char ***tokens, int *nr) +{ + get_line(); + *tokens = g_ps.tokens; + *nr = g_ps.nr_token; + if (!*nr) { + return -1; + } + return 0; +} + +int +anthy_get_line_number(void) +{ + return g_ps.line_num; +} |