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