chiark / gitweb /
Remove crufty CVS $Id$ tags.
[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 -------------------------------------------------*/