chiark / gitweb /
docs: Generate grammar and option summaries from manpage.
[fwd] / scan.c
1 /* -*-c-*-
2  *
3  * $Id: scan.c,v 1.7 2004/04/08 01:36:25 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 /*----- Header files ------------------------------------------------------*/
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <mLib/dstr.h>
36 #include <mLib/sub.h>
37
38 #include "scan.h"
39
40 /*----- File scanner source -----------------------------------------------*/
41
42 /* --- File scanner block --- */
43
44 typedef struct fscan {
45   scansrc ss;
46   FILE *fp;
47   unsigned f;
48 } fscan;
49
50 /* --- @scan@ --- */
51
52 static int fscan_scan(scansrc *ss)
53 {
54   fscan *fs = (fscan *)ss;
55   int ch = getc(fs->fp);
56   if (ch == '\n')
57     fs->ss.line++;
58   return (ch);
59 }
60
61 /* --- @destroy@ --- */
62
63 static void fscan_destroy(scansrc *ss)
64 {
65   fscan *fs = (fscan *)ss;
66   if (!(fs->f & SCF_NOCLOSE))
67     fclose(fs->fp);
68   xfree(fs->ss.src);
69   DESTROY(fs);
70 }
71
72 /* --- File scanner operations --- */
73
74 static scansrc_ops fscan_ops = { fscan_scan, fscan_destroy };
75
76 /* --- @scan_file@ --- *
77  *
78  * Arguments:   @FILE *fp@ = pointer to file descriptor
79  *              @const char *name@ = pointer to source file name
80  *              @unsigned f@ = flags
81  *
82  * Returns:     A scanner source.
83  *
84  * Use:         Creates a new scanner source for reading from a file.
85  */
86
87 scansrc *scan_file(FILE *fp, const char *name, unsigned f)
88 {
89   fscan *fs = CREATE(fscan);
90   fs->ss.ops = &fscan_ops;
91   fs->ss.src = xstrdup(name);
92   fs->ss.line = 1;
93   fs->fp = fp;
94   fs->f = f;
95   return (&fs->ss);
96 }
97
98 /*---- Argv scanner source ------------------------------------------------*/
99
100 /* --- Argv scanner block --- */
101
102 typedef struct avscan {
103   scansrc ss;
104   char **av;
105   char *p;
106 } avscan;
107
108 /* --- @scan@ --- */
109
110 static int avscan_scan(scansrc *ss)
111 {
112   avscan *as = (avscan *)ss;
113   int ch;
114   if (!as->p)
115     ch = EOF;
116   else if ((ch = (unsigned char)*as->p++) == 0) {
117     as->ss.line++;
118     as->p = *as->av++;
119     ch = '\n';
120   }
121   return (ch);
122 }
123
124 /* --- @destroy@ --- */
125
126 static void avscan_destroy(scansrc *ss)
127 {
128   avscan *as = (avscan *)ss;
129   DESTROY(as);
130 }
131
132 /* --- Argv scanner operations --- */
133
134 static scansrc_ops avscan_ops = { avscan_scan, avscan_destroy };
135
136 /* --- @scan_argv@ --- *
137  *
138  * Arguments:   @char **av@ = pointer to argument array (null terminated)
139  *
140  * Returns:     A scanner source.
141  *
142  * Use:         Creates a new scanner source for reading from an @argv@
143  *              array.
144  */
145
146 scansrc *scan_argv(char **av)
147 {
148   avscan *as = CREATE(avscan);
149   as->ss.ops = &avscan_ops;
150   as->ss.src = "<argv>";
151   as->ss.line = 1;
152   as->p = *av++;
153   as->av = av;
154   return (&as->ss);
155 }
156
157 /*----- End-of-file sentinel block ----------------------------------------*/
158
159 /* --- @scan@ --- */
160
161 static int eof_scan(scansrc *ss)
162 {
163   return (EOF);
164 }
165
166 /* --- @destroy@ --- */
167
168 static void eof_destroy(scansrc *ss)
169 {
170   ;
171 }
172
173 /* --- Eof scanner operations --- */
174
175 static scansrc_ops eof_ops = { eof_scan, eof_destroy };
176
177 /* --- The end of file marker --- */
178
179 static scansrc scan_eof = { &scan_eof, &eof_ops, "<eof>", 0, DSTR_INIT };
180
181 /*----- General scanner handling ------------------------------------------*/
182
183 /* --- @scan@ --- *
184  *
185  * Arguments:   @scanner *sc@ = pointer to main scanner context
186  *
187  * Returns:     Character read, or end-of-file.
188  *
189  * Use:         Scans a character from a source of characters.
190  */
191
192 int scan(scanner *sc)
193 {
194   int ch;
195   if (sc->head->pushback.len)
196     ch = sc->head->pushback.buf[--sc->head->pushback.len];
197   else {
198     scansrc *ss = sc->head;
199     if (ss == &scan_eof)
200       ch = EOF;
201     else if ((ch = ss->ops->scan(ss)) == EOF) {
202       sc->head = ss->next;
203       if (sc->head == &scan_eof)
204         sc->tail = &sc->head;
205       ss->ops->destroy(ss);
206       ch = '\n';
207     }
208   }
209   return (ch);
210 }
211
212 /* --- @unscan@ --- *
213  *
214  * Arguments:   @scanner *sc@ = pointer to main scanner context
215  *              @int ch@ = character to unscan
216  *
217  * Returns:     ---
218  *
219  * Use:         Scans a character from a source of characters.
220  */
221
222 void unscan(scanner *sc, int ch)
223 {
224   DPUTC(&sc->head->pushback, ch);
225 }
226
227 /* --- @scan_push@ --- *
228  *
229  * Arguments:   @scanner *sc@ = pointer to main scanner context
230  *              @scansrc *ss@ = souorce to push
231  *
232  * Returns:     ---
233  *
234  * Use:         Pushes a scanner source onto the front of the queue.
235  */
236
237 void scan_push(scanner *sc, scansrc *ss)
238 {
239   ss->next = sc->head;
240   if (sc->head == &scan_eof)
241     sc->tail = &ss->next;
242   sc->head = ss;
243   dstr_create(&ss->pushback);
244   ss->tok = 0;
245   ss->t = 0;
246 }
247
248 /* --- @scan_add@ --- *
249  *
250  * Arguments:   @scanner *sc@ = pointer to main scanner context
251  *              @scansrc *ss@ = souorce to push
252  *
253  * Returns:     ---
254  *
255  * Use:         Adds a scanner source onto the end of the queue.
256  */
257
258 void scan_add(scanner *sc, scansrc *ss)
259 {
260   ss->next = &scan_eof;
261   *sc->tail = ss;
262   sc->tail = &ss->next;
263   dstr_create(&ss->pushback);
264   ss->tok = 0;
265   ss->t = 0;
266 }
267
268 /* --- @scan_create@ --- *
269  *
270  * Arguments:   @scanner *sc@ = scanner context to initialize
271  *
272  * Returns:     ---
273  *
274  * Use:         Initializes a scanner block ready for use.
275  */
276
277 void scan_create(scanner *sc)
278 {
279   sc->head = &scan_eof;
280   sc->tail = &sc->head;
281   dstr_create(&sc->d);
282   sc->wbegin = sc->wcont = 0;
283 }
284
285 /* --- @scan_destroy@ --- *
286  *
287  * Arguments:   @scanner *sc@ = pointer to scanner context
288  *
289  * Returns:     ---
290  *
291  * Use:         Destroys a scanner and all the sources attached to it.
292  */
293
294 void scan_destroy(scanner *sc)
295 {
296   scansrc *ss = sc->head;
297   while (ss != &scan_eof) {
298     scansrc *sss = ss;
299     ss = ss->next;
300     if (sss->tok)
301       xfree(sss->tok);
302     dstr_destroy(&sss->pushback);
303     sss->ops->destroy(sss);
304   }
305   dstr_destroy(&sc->d);
306   if (scan_eof.tok)
307     xfree(scan_eof.tok);
308   scan_eof.tok = 0;
309   sc->head = &scan_eof;
310   sc->tail = &sc->head;
311 }
312
313 /*----- That's all, folks -------------------------------------------------*/