1 rizwank 1.1 /*
2 * Process input according to the specified rules.
3 * Copyright (c) 1997-1999 Markku Rossi.
4 *
5 * Author: Markku Rossi <mtr@iki.fi>
6 */
7
8 /*
9 * This file is part of GNU enscript.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 rizwank 1.1 * along with this program; see the file COPYING. If not, write to
23 * the Free Software Foundation, 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
25 */
26
27 #include "defs.h"
28
29 /*
30 * Prototypes for static functions.
31 */
32
33 /*
34 * Evaluate the begin rules of state <state>. The begin rules are
35 * evaluated from parent to child.
36 */
37 static Node *eval_begin_rules ___P ((State *state, int *return_seen));
38
39 /*
40 * Evaluate the end rules of state <state>. The end rules are
41 * evaluated from child to parent.
42 */
43 rizwank 1.1 static Node *eval_end_rules ___P ((State *state, int *found_return));
44
45 /*
46 * Global functions.
47 */
48
49 void
50 process_file (fname)
51 char *fname;
52 {
53 Node *result;
54 int return_seen = 0;
55
56 start_state = NULL;
57 current_fname = fname;
58 current_linenum = 1;
59
60 /* Init buffer variables. */
61 data_in_buffer = 0;
62 bufpos = 0;
63 eof_seen = 0;
64 rizwank 1.1
65 /* Enter build-in variables. */
66 enter_system_variable ("filename", fname);
67
68 /* Read in the first block of data. */
69 data_in_buffer = fread (inbuf, 1, INBUFSIZE, ifp);
70 if (data_in_buffer < INBUFSIZE)
71 eof_seen = 1;
72
73 if (start_state_arg)
74 start_state = start_state_arg;
75
76 /* Execute start block. */
77 result = eval_statement_list (start_stmts, NULL, &return_seen);
78 node_free (result);
79
80 if (start_state == NULL)
81 {
82 /* No start state found, copy our input to output. */
83 while (data_in_buffer)
84 {
85 rizwank 1.1 fwrite (inbuf, 1, data_in_buffer, ofp);
86 data_in_buffer = fread (inbuf, 1, INBUFSIZE, ifp);
87 }
88 }
89 else
90 {
91 result = execute_state (start_state);
92 node_free (result);
93 }
94 }
95
96
97 Node *
98 execute_state (name)
99 char *name;
100 {
101 State *state;
102 State *s;
103 int to_read, got;
104 ListItem *rule, *first_rule;
105 unsigned int first_idx;
106 rizwank 1.1 unsigned int match_len;
107 Node *result = nvoid;
108 Cons *r;
109 Node *exp;
110 int return_seen = 0;
111 int idx;
112
113 /* Lookup state. */
114 state = lookup_state (name);
115 if (state == NULL)
116 {
117 fprintf (stderr, _("%s: undefined state `%s'\n"), program, name);
118 exit (1);
119 }
120
121 /* Begin rules. */
122 result = eval_begin_rules (state, &return_seen);
123 if (return_seen)
124 goto out;
125
126 /* Execute this state. */
127 rizwank 1.1 while (1)
128 {
129 int eol;
130
131 /* Do we have enough data? */
132 if (bufpos >= data_in_buffer)
133 {
134 if (eof_seen)
135 /* All done. */
136 break;
137
138 /* Read more data. */
139 data_in_buffer = fread (inbuf, 1, INBUFSIZE, ifp);
140 if (data_in_buffer < INBUFSIZE)
141 eof_seen = 1;
142
143 bufpos = 0;
144 continue;
145 }
146
147 /* Check line number. */
148 rizwank 1.1 if (bufpos > 0 && inbuf[bufpos - 1] == '\n')
149 current_linenum++;
150
151 /* Find the end of the input line. */
152 for (eol = bufpos; eol < data_in_buffer && inbuf[eol] != '\n'; eol++)
153 ;
154 if (eol < data_in_buffer && inbuf[eol] == '\n')
155 eol++;
156 if (eol >= data_in_buffer && !eof_seen && bufpos > 0)
157 {
158 /* Must read more data to the buffer. */
159 memmove (inbuf, inbuf + bufpos, eol - bufpos);
160 data_in_buffer = eol - bufpos;
161 bufpos = 0;
162
163 to_read = INBUFSIZE - data_in_buffer;
164 got = fread (inbuf + data_in_buffer, 1, to_read, ifp);
165 if (got < to_read)
166 eof_seen = 1;
167
168 data_in_buffer += got;
169 rizwank 1.1 continue;
170 }
171
172 /* Evaluate state expressions. */
173 first_idx = eol;
174 match_len = 0;
175 first_rule = NULL;
176 current_match = NULL;
177
178 for (s = state; s; s = s->super)
179 {
180 for (rule = s->rules->head; rule; rule = rule->next)
181 {
182 int err;
183
184 r = (Cons *) rule->data;
185 exp = (Node *) r->car;
186 if (exp == RULE_BEGIN || exp == RULE_END)
187 continue;
188
189 if (exp->type == nSYMBOL)
190 rizwank 1.1 {
191 Node *n;
192
193 /* Lookup this variable by hand from global variables. */
194 if (!strhash_get (ns_vars, exp->u.sym, strlen (exp->u.sym),
195 (void **) &n))
196 {
197 fprintf (stderr,
198 _("%s: error: undefined variable `%s'\n"),
199 program, exp->u.sym);
200 exit (1);
201 }
202 if (n->type != nREGEXP)
203 /* Skip this rule */
204 continue;
205
206 exp = n;
207 }
208
209 err = re_search (REGEXP (exp), inbuf, eol, bufpos,
210 eol - bufpos, &exp->u.re.matches);
211 rizwank 1.1 if (err < 0)
212 /* No mach. */
213 continue;
214
215 idx = exp->u.re.matches.start[0];
216 if (idx >= 0
217 && (idx < first_idx
218 || (idx == first_idx
219 && (exp->u.re.matches.end[0]
220 - exp->u.re.matches.start[0]
221 > match_len))))
222 {
223 first_idx = idx;
224 first_rule = rule;
225 match_len = (exp->u.re.matches.end[0]
226 - exp->u.re.matches.start[0]);
227 current_match = &exp->u.re.matches;
228 current_match_buf = inbuf;
229 }
230 }
231 }
232 rizwank 1.1
233 /* Print all data before the first rule. */
234 fwrite (inbuf + bufpos, 1, first_idx - bufpos, ofp);
235
236 if (first_rule)
237 {
238 /* Execute statements. */
239 bufpos = current_match->end[0];
240
241 node_free (result);
242 result = eval_statement_list ((List *)
243 ((Cons *) first_rule->data)->cdr,
244 NULL, &return_seen);
245 if (return_seen)
246 goto out;
247 }
248 else
249 bufpos = first_idx;
250 }
251
252 out:
253 rizwank 1.1
254 /* End rules. */
255 {
256 int found = 0;
257 Node *result2;
258
259 result2 = eval_end_rules (state, &found);
260 if (found)
261 {
262 node_free (result);
263 result = result2;
264 }
265 }
266
267 return result;
268 }
269
270
271 /*
272 * Static functions.
273 */
274 rizwank 1.1
275 static Node *
276 eval_begin_rules (state, return_seen)
277 State *state;
278 int *return_seen;
279 {
280 Node *result = nvoid;
281 Cons *r;
282 ListItem *rule;
283
284 /* The begin rules are evaluated from the parent to child. */
285
286 /* Autoload the super if needed. */
287 if (state->super_name && state->super == NULL)
288 {
289 state->super = lookup_state (state->super_name);
290 if (state->super == NULL)
291 {
292 fprintf (stderr, _("%s: undefined super state `%s'\n"),
293 program, state->super_name);
294 exit (1);
295 rizwank 1.1 }
296 }
297
298 if (state->super)
299 {
300 result = eval_begin_rules (state->super, return_seen);
301 if (*return_seen)
302 return result;
303 }
304
305 /* Eval our begin rule. */
306 for (rule = state->rules->head; rule; rule = rule->next)
307 {
308 r = (Cons *) rule->data;
309 if (r->car == RULE_BEGIN)
310 {
311 node_free (result);
312 result = eval_statement_list ((List *) r->cdr, NULL, return_seen);
313 if (*return_seen)
314 break;
315 }
316 rizwank 1.1 }
317
318 return result;
319 }
320
321
322 static Node *
323 eval_end_rules (state, found_return)
324 State *state;
325 int *found_return;
326 {
327 ListItem *rule;
328 Cons *r;
329 Node *result = nvoid;
330 int return_seen;
331
332 /* The end rules are evaluated from child to parent. */
333
334 for (; state; state = state->super)
335 for (rule = state->rules->head; rule; rule = rule->next)
336 {
337 rizwank 1.1 r = (Cons *) rule->data;
338 if (r->car == RULE_END)
339 {
340 *found_return = 1;
341 node_free (result);
342 result = eval_statement_list ((List *) r->cdr, NULL, &return_seen);
343 }
344 }
345
346 return result;
347 }
|