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