summaryrefslogtreecommitdiff
path: root/src-diclib/ruleparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src-diclib/ruleparser.c')
-rw-r--r--src-diclib/ruleparser.c329
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;
+}