0f0f81cdf98c8996b813038d4e6fa3f19d9eaae8
[fwd] / scan.c
1 /* -*-c-*-
2 *
3 * Character scanners
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the `fw' port forwarder.
11 *
12 * `fw' is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * `fw' is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with `fw'; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <mLib/dstr.h>
34 #include <mLib/sub.h>
35
36 #include "scan.h"
37
38 /*----- File scanner source -----------------------------------------------*/
39
40 /* --- File scanner block --- */
41
42 typedef struct fscan {
43 scansrc ss;
44 FILE *fp;
45 unsigned f;
46 } fscan;
47
48 /* --- @scan@ --- */
49
50 static int fscan_scan(scansrc *ss)
51 {
52 fscan *fs = (fscan *)ss;
53 int ch = getc(fs->fp);
54 if (ch == '\n')
55 fs->ss.line++;
56 return (ch);
57 }
58
59 /* --- @destroy@ --- */
60
61 static void fscan_destroy(scansrc *ss)
62 {
63 fscan *fs = (fscan *)ss;
64 if (!(fs->f & SCF_NOCLOSE))
65 fclose(fs->fp);
66 xfree(fs->ss.src);
67 DESTROY(fs);
68 }
69
70 /* --- File scanner operations --- */
71
72 static scansrc_ops fscan_ops = { fscan_scan, fscan_destroy };
73
74 /* --- @scan_file@ --- *
75 *
76 * Arguments: @FILE *fp@ = pointer to file descriptor
77 * @const char *name@ = pointer to source file name
78 * @unsigned f@ = flags
79 *
80 * Returns: A scanner source.
81 *
82 * Use: Creates a new scanner source for reading from a file.
83 */
84
85 scansrc *scan_file(FILE *fp, const char *name, unsigned f)
86 {
87 fscan *fs = CREATE(fscan);
88 fs->ss.ops = &fscan_ops;
89 fs->ss.src = xstrdup(name);
90 fs->ss.line = 1;
91 fs->fp = fp;
92 fs->f = f;
93 return (&fs->ss);
94 }
95
96 /*---- Argv scanner source ------------------------------------------------*/
97
98 /* --- Argv scanner block --- */
99
100 typedef struct avscan {
101 scansrc ss;
102 char **av;
103 char *p;
104 } avscan;
105
106 /* --- @scan@ --- */
107
108 static int avscan_scan(scansrc *ss)
109 {
110 avscan *as = (avscan *)ss;
111 int ch;
112 if (!as->p)
113 ch = EOF;
114 else if ((ch = (unsigned char)*as->p++) == 0) {
115 as->ss.line++;
116 as->p = *as->av++;
117 ch = '\n';
118 }
119 return (ch);
120 }
121
122 /* --- @destroy@ --- */
123
124 static void avscan_destroy(scansrc *ss)
125 {
126 avscan *as = (avscan *)ss;
127 DESTROY(as);
128 }
129
130 /* --- Argv scanner operations --- */
131
132 static scansrc_ops avscan_ops = { avscan_scan, avscan_destroy };
133
134 /* --- @scan_argv@ --- *
135 *
136 * Arguments: @char **av@ = pointer to argument array (null terminated)
137 *
138 * Returns: A scanner source.
139 *
140 * Use: Creates a new scanner source for reading from an @argv@
141 * array.
142 */
143
144 scansrc *scan_argv(char **av)
145 {
146 avscan *as = CREATE(avscan);
147 as->ss.ops = &avscan_ops;
148 as->ss.src = "<argv>";
149 as->ss.line = 1;
150 as->p = *av++;
151 as->av = av;
152 return (&as->ss);
153 }
154
155 /*----- End-of-file sentinel block ----------------------------------------*/
156
157 /* --- @scan@ --- */
158
159 static int eof_scan(scansrc *ss)
160 {
161 return (EOF);
162 }
163
164 /* --- @destroy@ --- */
165
166 static void eof_destroy(scansrc *ss)
167 {
168 ;
169 }
170
171 /* --- Eof scanner operations --- */
172
173 static scansrc_ops eof_ops = { eof_scan, eof_destroy };
174
175 /* --- The end of file marker --- */
176
177 static scansrc scan_eof = { &scan_eof, &eof_ops, "<eof>", 0, DSTR_INIT };
178
179 /*----- General scanner handling ------------------------------------------*/
180
181 /* --- @scan@ --- *
182 *
183 * Arguments: @scanner *sc@ = pointer to main scanner context
184 *
185 * Returns: Character read, or end-of-file.
186 *
187 * Use: Scans a character from a source of characters.
188 */
189
190 int scan(scanner *sc)
191 {
192 int ch;
193 if (sc->head->pushback.len)
194 ch = sc->head->pushback.buf[--sc->head->pushback.len];
195 else {
196 scansrc *ss = sc->head;
197 if (ss == &scan_eof)
198 ch = EOF;
199 else if ((ch = ss->ops->scan(ss)) == EOF) {
200 sc->head = ss->next;
201 if (sc->head == &scan_eof)
202 sc->tail = &sc->head;
203 ss->ops->destroy(ss);
204 ch = '\n';
205 }
206 }
207 return (ch);
208 }
209
210 /* --- @unscan@ --- *
211 *
212 * Arguments: @scanner *sc@ = pointer to main scanner context
213 * @int ch@ = character to unscan
214 *
215 * Returns: ---
216 *
217 * Use: Scans a character from a source of characters.
218 */
219
220 void unscan(scanner *sc, int ch)
221 {
222 DPUTC(&sc->head->pushback, ch);
223 }
224
225 /* --- @scan_push@ --- *
226 *
227 * Arguments: @scanner *sc@ = pointer to main scanner context
228 * @scansrc *ss@ = souorce to push
229 *
230 * Returns: ---
231 *
232 * Use: Pushes a scanner source onto the front of the queue.
233 */
234
235 void scan_push(scanner *sc, scansrc *ss)
236 {
237 ss->next = sc->head;
238 if (sc->head == &scan_eof)
239 sc->tail = &ss->next;
240 sc->head = ss;
241 dstr_create(&ss->pushback);
242 ss->tok = 0;
243 ss->t = 0;
244 }
245
246 /* --- @scan_add@ --- *
247 *
248 * Arguments: @scanner *sc@ = pointer to main scanner context
249 * @scansrc *ss@ = souorce to push
250 *
251 * Returns: ---
252 *
253 * Use: Adds a scanner source onto the end of the queue.
254 */
255
256 void scan_add(scanner *sc, scansrc *ss)
257 {
258 ss->next = &scan_eof;
259 *sc->tail = ss;
260 sc->tail = &ss->next;
261 dstr_create(&ss->pushback);
262 ss->tok = 0;
263 ss->t = 0;
264 }
265
266 /* --- @scan_create@ --- *
267 *
268 * Arguments: @scanner *sc@ = scanner context to initialize
269 *
270 * Returns: ---
271 *
272 * Use: Initializes a scanner block ready for use.
273 */
274
275 void scan_create(scanner *sc)
276 {
277 sc->head = &scan_eof;
278 sc->tail = &sc->head;
279 dstr_create(&sc->d);
280 sc->wbegin = sc->wcont = 0;
281 }
282
283 /* --- @scan_destroy@ --- *
284 *
285 * Arguments: @scanner *sc@ = pointer to scanner context
286 *
287 * Returns: ---
288 *
289 * Use: Destroys a scanner and all the sources attached to it.
290 */
291
292 void scan_destroy(scanner *sc)
293 {
294 scansrc *ss = sc->head;
295 while (ss != &scan_eof) {
296 scansrc *sss = ss;
297 ss = ss->next;
298 if (sss->tok)
299 xfree(sss->tok);
300 dstr_destroy(&sss->pushback);
301 sss->ops->destroy(sss);
302 }
303 dstr_destroy(&sc->d);
304 if (scan_eof.tok)
305 xfree(scan_eof.tok);
306 scan_eof.tok = 0;
307 sc->head = &scan_eof;
308 sc->tail = &sc->head;
309 }
310
311 /*----- That's all, folks -------------------------------------------------*/