identify.c: Stash a copy of the caller's description string.
[fwd] / scan.c
CommitLineData
e82f7154 1/* -*-c-*-
2 *
e82f7154 3 * Character scanners
4 *
77d0e3dc 5 * (c) 1999 Straylight/Edgeware
e82f7154 6 */
7
206212ca 8/*----- Licensing notice --------------------------------------------------*
e82f7154 9 *
9155ea97 10 * This file is part of the `fwd' port forwarder.
e82f7154 11 *
9155ea97 12 * `fwd' is free software; you can redistribute it and/or modify
e82f7154 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.
206212ca 16 *
9155ea97 17 * `fwd' is distributed in the hope that it will be useful,
e82f7154 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.
206212ca 21 *
e82f7154 22 * You should have received a copy of the GNU General Public License
9155ea97 23 * along with `fwd'; if not, write to the Free Software Foundation,
e82f7154 24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
9155ea97 27#include "fwd.h"
e82f7154 28
77d0e3dc 29/*----- File scanner source -----------------------------------------------*/
30
31/* --- File scanner block --- */
32
33typedef struct fscan {
34 scansrc ss;
35 FILE *fp;
36 unsigned f;
37} fscan;
e82f7154 38
77d0e3dc 39/* --- @scan@ --- */
e82f7154 40
77d0e3dc 41static int fscan_scan(scansrc *ss)
e82f7154 42{
77d0e3dc 43 fscan *fs = (fscan *)ss;
44 int ch = getc(fs->fp);
45 if (ch == '\n')
46 fs->ss.line++;
47 return (ch);
e82f7154 48}
49
77d0e3dc 50/* --- @destroy@ --- */
e82f7154 51
77d0e3dc 52static void fscan_destroy(scansrc *ss)
e82f7154 53{
77d0e3dc 54 fscan *fs = (fscan *)ss;
55 if (!(fs->f & SCF_NOCLOSE))
56 fclose(fs->fp);
7bb7c50b 57 xfree(fs->ss.src);
77d0e3dc 58 DESTROY(fs);
59}
e82f7154 60
77d0e3dc 61/* --- File scanner operations --- */
62
63static scansrc_ops fscan_ops = { fscan_scan, fscan_destroy };
64
65/* --- @scan_file@ --- *
66 *
67 * Arguments: @FILE *fp@ = pointer to file descriptor
7bb7c50b 68 * @const char *name@ = pointer to source file name
77d0e3dc 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
7bb7c50b 76scansrc *scan_file(FILE *fp, const char *name, unsigned f)
77d0e3dc 77{
372a98e2 78 fscan *fs = CREATE(fscan);
77d0e3dc 79 fs->ss.ops = &fscan_ops;
7bb7c50b 80 fs->ss.src = xstrdup(name);
77d0e3dc 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
91typedef struct avscan {
92 scansrc ss;
93 char **av;
94 char *p;
95} avscan;
96
97/* --- @scan@ --- */
e82f7154 98
77d0e3dc 99static int avscan_scan(scansrc *ss)
100{
101 avscan *as = (avscan *)ss;
102 int ch;
103 if (!as->p)
104 ch = EOF;
9e1c09df 105 else if ((ch = (unsigned char)*as->p++) == 0) {
77d0e3dc 106 as->ss.line++;
107 as->p = *as->av++;
108 ch = '\n';
109 }
e82f7154 110 return (ch);
111}
112
77d0e3dc 113/* --- @destroy@ --- */
114
115static void avscan_destroy(scansrc *ss)
e82f7154 116{
77d0e3dc 117 avscan *as = (avscan *)ss;
118 DESTROY(as);
e82f7154 119}
120
77d0e3dc 121/* --- Argv scanner operations --- */
122
123static 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
135scansrc *scan_argv(char **av)
e82f7154 136{
77d0e3dc 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);
e82f7154 144}
145
77d0e3dc 146/*----- End-of-file sentinel block ----------------------------------------*/
147
148/* --- @scan@ --- */
e82f7154 149
77d0e3dc 150static int eof_scan(scansrc *ss)
e82f7154 151{
77d0e3dc 152 return (EOF);
e82f7154 153}
154
77d0e3dc 155/* --- @destroy@ --- */
156
157static void eof_destroy(scansrc *ss)
e82f7154 158{
77d0e3dc 159 ;
e82f7154 160}
161
77d0e3dc 162/* --- Eof scanner operations --- */
163
164static scansrc_ops eof_ops = { eof_scan, eof_destroy };
165
166/* --- The end of file marker --- */
167
7bb7c50b 168static scansrc scan_eof = { &scan_eof, &eof_ops, "<eof>", 0, DSTR_INIT };
77d0e3dc 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
181int scan(scanner *sc)
182{
183 int ch;
7bb7c50b 184 if (sc->head->pushback.len)
185 ch = sc->head->pushback.buf[--sc->head->pushback.len];
186 else {
77d0e3dc 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
211void unscan(scanner *sc, int ch)
212{
7bb7c50b 213 DPUTC(&sc->head->pushback, ch);
77d0e3dc 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
226void scan_push(scanner *sc, scansrc *ss)
e82f7154 227{
77d0e3dc 228 ss->next = sc->head;
229 if (sc->head == &scan_eof)
230 sc->tail = &ss->next;
231 sc->head = ss;
7bb7c50b 232 dstr_create(&ss->pushback);
77d0e3dc 233 ss->tok = 0;
234 ss->t = 0;
e82f7154 235}
236
77d0e3dc 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
247void scan_add(scanner *sc, scansrc *ss)
248{
249 ss->next = &scan_eof;
250 *sc->tail = ss;
251 sc->tail = &ss->next;
7bb7c50b 252 dstr_create(&ss->pushback);
77d0e3dc 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
266void scan_create(scanner *sc)
267{
268 sc->head = &scan_eof;
269 sc->tail = &sc->head;
270 dstr_create(&sc->d);
e91b672f 271 sc->wbegin = sc->wcont = 0;
77d0e3dc 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 */
e82f7154 282
77d0e3dc 283void scan_destroy(scanner *sc)
e82f7154 284{
77d0e3dc 285 scansrc *ss = sc->head;
286 while (ss != &scan_eof) {
287 scansrc *sss = ss;
288 ss = ss->next;
289 if (sss->tok)
7bb7c50b 290 xfree(sss->tok);
291 dstr_destroy(&sss->pushback);
77d0e3dc 292 sss->ops->destroy(sss);
293 }
e82f7154 294 dstr_destroy(&sc->d);
77d0e3dc 295 if (scan_eof.tok)
7bb7c50b 296 xfree(scan_eof.tok);
77d0e3dc 297 scan_eof.tok = 0;
298 sc->head = &scan_eof;
299 sc->tail = &sc->head;
e82f7154 300}
301
302/*----- That's all, folks -------------------------------------------------*/