1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
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 *
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:
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:
88:
89:
90: static int
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:
108: }
109: }
110: return 0;
111: }
112:
113: #define myisblank(c) ((c) == ' ' || (c) == '\t')
114:
115:
116: static void
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 *
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:
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
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
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
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
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:
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) {
255: return ;
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
275: anthy_free_line(void)
276: {
277: int i;
278: for (i = 0; i < g_ps.nr_token; i++) {
279: free(g_ps.tokens[i]);
280: }
281: free(g_ps.tokens);
282: g_ps.tokens = 0;
283: g_ps.nr_token = 0;
284: }
285:
286: int
287: anthy_open_file(const char *fn)
288: {
289: g_ps.fp_stack[0] = open_file_in_confdir(fn);
290: if (!g_ps.fp_stack[0]) {
291: return -1;
292: }
293:
294: g_ps.cur_fpp = 0;
295: g_ps.fp = g_ps.fp_stack[0];
296: g_ps.line_num = 0;
297: return 0;
298: }
299:
300: void
301: anthy_close_file(void)
302: {
303: if (g_ps.fp != stdin) {
304: fclose(g_ps.fp);
305: }
306: }
307:
308: int
309: anthy_read_line(char ***tokens, int *nr)
310: {
311: get_line();
312: *tokens = g_ps.tokens;
313: *nr = g_ps.nr_token;
314: if (!*nr) {
315: return -1;
316: }
317: return 0;
318: }
319:
320: int
321: anthy_get_line_number(void)
322: {
323: return g_ps.line_num;
324: }