1 /*
2 * 設定ファイルなどのための
3 * 汎用のファイル読み込みモジュール
4 *
5 * Copyright (C) 2000-2006 TABATA Yusuke
6 *
7 */
8 /*
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27
28 #include <anthy/conf.h>
29 #include <anthy/ruleparser.h>
30 #include <anthy/logger.h>
31
32 /* 文法ファイルのパーザ用の定義 */
33 #define MAX_TOKEN_LEN 256
34 /* 最大のインクルードの深さ */
35 #define MAX_INCLUDE_DEPTH 4
36
37 #define PS_INIT 0
38 #define PS_TOKEN 1
39 #define PS_EOF 2
40 #define PS_RET 3
41
42 static const char *NL = "NL";
43
44 static struct parser_stat {
45 FILE *fp_stack[MAX_INCLUDE_DEPTH];
46 FILE *fp;
47 int cur_fpp;/* スタックのインデックス */
48 int line_num;
49 char **tokens;
50 int nr_token;
51 } g_ps;
52
53 struct line_stat{
54 int stat;
55 char buf[MAX_TOKEN_LEN];
56 int buf_index;
57 };
58
59 static FILE *
open_file_in_confdir(const char * fn)60 open_file_in_confdir(const char *fn)
61 {
62 const char *dn;
63 char *full;
64 size_t dname_len;
65
66 if (!fn) {
67 return stdin;
68 }
69
70 if (fn[0] == '/' ||
71 (fn[0] == '.' && fn[1] == '/')) {
72 /* 絶対パスもしくはカレントディレクトリなのでそのままfopen */
73 return fopen(fn, "r");
74 }
75
76 dn = anthy_conf_get_str("ANTHYDIR");
77 if (!dn) {
78 return 0;
79 }
80 dname_len = strlen(dn);
81 full = alloca(dname_len + strlen(fn) + 2);
82 sprintf(full, "%s/%s", dn, fn);
83
84 return fopen(full, "r");
85 }
86
87 /** バックスラッシュによるエスケープも処理するgetc
88 * エスケープされた文字ならば返り値は1になる。
89 */
90 static int
mygetc(int * cc)91 mygetc (int *cc)
92 {
93 *cc = fgetc(g_ps.fp);
94 if (*cc == '\\') {
95 int c2 = fgetc(g_ps.fp);
96 switch(c2) {
97 case '\\':
98 *cc = '\\';
99 return 1;
100 case '\n':
101 *cc = ' ';
102 return 1;
103 case '\"':
104 *cc = '\"';
105 return 1;
106 default:;
107 /* go through */
108 }
109 }
110 return 0;
111 }
112
113 #define myisblank(c) ((c) == ' ' || (c) == '\t')
114
115 /* 行に一文字追加する */
116 static void
pushchar(struct line_stat * ls,int cc)117 pushchar(struct line_stat *ls, int cc)
118 {
119 if (ls->buf_index == MAX_TOKEN_LEN - 1) {
120 ls->buf[MAX_TOKEN_LEN - 1] = 0;
121 } else {
122 ls->buf[ls->buf_index] = cc;
123 ls->buf_index ++;
124 }
125 }
126
127 static const char *
get_token_in(struct line_stat * ls)128 get_token_in(struct line_stat *ls)
129 {
130 int cc, esc;
131 int in_quote = 0;
132 if (ls->stat == PS_EOF) {
133 return NULL;
134 }
135 if (ls->stat == PS_RET) {
136 return NL;
137 }
138 /* トークンが始まるまで空白を読み飛ばす */
139 do {
140 esc = mygetc(&cc);
141 } while (cc > 0 && myisblank(cc) && esc == 0);
142 if (cc == -1) {
143 return NULL;
144 }
145 if (cc == '\n'){
146 return NL;
147 }
148
149 /**/
150 if (cc == '\"' && !esc) {
151 in_quote = 1;
152 }
153 /**/
154 do {
155 pushchar(ls, cc);
156 esc = mygetc(&cc);
157 if (cc < 0){
158 /* EOF */
159 pushchar(ls, 0);
160 ls->stat = PS_EOF;
161 return ls->buf;
162 }
163 if (cc == '\n' && !esc) {
164 /* 改行 */
165 pushchar(ls, 0);
166 ls->stat = PS_RET;
167 return ls->buf;
168 }
169 if (!in_quote && myisblank(cc)) {
170 break;
171 }
172 if (in_quote && cc == '\"' && !esc) {
173 pushchar(ls, '\"');
174 break;
175 }
176 } while (1);
177 pushchar(ls, 0);
178 return ls->buf;
179 }
180
181 /* 一行読む */
182 static int
get_line_in(void)183 get_line_in(void)
184 {
185 const char *t;
186 struct line_stat ls;
187
188 ls.stat = PS_INIT;
189 do{
190 ls.buf_index = 0;
191 t = get_token_in(&ls);
192 if (!t) {
193 return -1;
194 }
195 if (t == NL) {
196 return 0;
197 }
198 g_ps.nr_token++;
199 g_ps.tokens = realloc(g_ps.tokens, sizeof(char *)*g_ps.nr_token);
200 g_ps.tokens[g_ps.nr_token-1] = strdup(t);
201 } while(1);
202 }
203
204 static void
proc_include(void)205 proc_include(void)
206 {
207 FILE *fp;
208 if (g_ps.nr_token != 2) {
209 anthy_log(0, "Syntax error in include directive.\n");
210 return ;
211 }
212 if (g_ps.cur_fpp > MAX_INCLUDE_DEPTH - 1) {
213 anthy_log(0, "Too deep include.\n");
214 return ;
215 }
216 fp = open_file_in_confdir(g_ps.tokens[1]);
217 if (!fp) {
218 anthy_log(0, "Failed to open %s.\n", g_ps.tokens[1]);
219 return ;
220 }
221 g_ps.cur_fpp++;
222 g_ps.fp_stack[g_ps.cur_fpp] = fp;
223 g_ps.fp = fp;
224 }
225
226 /* インクルードのネストを下げる */
227 static void
pop_file(void)228 pop_file(void)
229 {
230 fclose(g_ps.fp);
231 g_ps.cur_fpp --;
232 g_ps.fp = g_ps.fp_stack[g_ps.cur_fpp];
233 }
234
235 static void
get_line(void)236 get_line(void)
237 {
238 int r;
239
240 again:
241 anthy_free_line();
242 g_ps.line_num ++;
243
244 r = get_line_in();
245 if (r == -1){
246 /* EOF等でこれ以上読めん */
247 if (g_ps.cur_fpp > 0) {
248 pop_file();
249 goto again;
250 }else{
251 return ;
252 }
253 }
254 if (g_ps.nr_token < 1) {
255 goto again;
256 }
257 if (!strcmp(g_ps.tokens[0], "\\include")) {
258 proc_include();
259 goto again;
260 }else if (!strcmp(g_ps.tokens[0], "\\eof")) {
261 if (g_ps.cur_fpp > 0) {
262 pop_file();
263 goto again;
264 }else{
265 anthy_free_line();
266 return ;
267 }
268 }
269 if (g_ps.tokens[0][0] == '#'){
270 goto again;
271 }
272 }
273
274 void
anthy_free_line(void)275 anthy_free_line(void)
276 {
277 int i;
278 if (g_ps.tokens) { /* 不正なメモリアクセスの防止 */
279 for (i = 0; i < g_ps.nr_token; i++) {
280 free(g_ps.tokens[i]);
281 }
282 free(g_ps.tokens);
283 g_ps.tokens = 0;
284 }
285 g_ps.nr_token = 0;
286 }
287
288 int
anthy_open_file(const char * fn)289 anthy_open_file(const char *fn)
290 {
291 g_ps.fp_stack[0] = open_file_in_confdir(fn);
292 if (!g_ps.fp_stack[0]) {
293 return -1;
294 }
295 /* パーザの状態を初期化する */
296 g_ps.cur_fpp = 0;
297 g_ps.fp = g_ps.fp_stack[0];
298 g_ps.line_num = 0;
299 g_ps.nr_token = 0; /* 初期化忘れの修正 */
300 g_ps.tokens = NULL; /* 初期化忘れの修正 */
301 return 0;
302 }
303
304 void
anthy_close_file(void)305 anthy_close_file(void)
306 {
307 if (g_ps.fp != stdin) {
308 fclose(g_ps.fp);
309 }
310 anthy_free_line(); /* 後始末忘れの防止 */
311 }
312
313 int
anthy_read_line(char *** tokens,int * nr)314 anthy_read_line(char ***tokens, int *nr)
315 {
316 get_line();
317 *tokens = g_ps.tokens;
318 *nr = g_ps.nr_token;
319 if (!*nr) {
320 return -1;
321 }
322 return 0;
323 }
324
325 int
anthy_get_line_number(void)326 anthy_get_line_number(void)
327 {
328 return g_ps.line_num;
329 }
330