X-Git-Url: https://git.distorted.org.uk/~mdw/fwd/blobdiff_plain/e82f7154f65062d9ac8b9677862774498b331058..858a73afbf5018d74920761f7015ac2e7d3987b6:/scan.c diff --git a/scan.c b/scan.c index 808ef8f..379951d 100644 --- a/scan.c +++ b/scan.c @@ -1,126 +1,302 @@ /* -*-c-*- * - * $Id: scan.c,v 1.1 1999/07/01 08:56:23 mdw Exp $ - * * Character scanners * - * (c) 1999 Mark Wooding + * (c) 1999 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * - * This file is part of the `fw' port forwarder. + * This file is part of the `fwd' port forwarder. * - * `fw' is free software; you can redistribute it and/or modify + * `fwd' is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * `fw' is distributed in the hope that it will be useful, + * + * `fwd' is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with `fw'; if not, write to the Free Software Foundation, + * along with `fwd'; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* +#include "fwd.h" + +/*----- File scanner source -----------------------------------------------*/ + +/* --- File scanner block --- */ + +typedef struct fscan { + scansrc ss; + FILE *fp; + unsigned f; +} fscan; + +/* --- @scan@ --- */ + +static int fscan_scan(scansrc *ss) +{ + fscan *fs = (fscan *)ss; + int ch = getc(fs->fp); + if (ch == '\n') + fs->ss.line++; + return (ch); +} + +/* --- @destroy@ --- */ + +static void fscan_destroy(scansrc *ss) +{ + fscan *fs = (fscan *)ss; + if (!(fs->f & SCF_NOCLOSE)) + fclose(fs->fp); + xfree(fs->ss.src); + DESTROY(fs); +} + +/* --- File scanner operations --- */ + +static scansrc_ops fscan_ops = { fscan_scan, fscan_destroy }; + +/* --- @scan_file@ --- * + * + * Arguments: @FILE *fp@ = pointer to file descriptor + * @const char *name@ = pointer to source file name + * @unsigned f@ = flags * - * $Log: scan.c,v $ - * Revision 1.1 1999/07/01 08:56:23 mdw - * Initial revision + * Returns: A scanner source. * + * Use: Creates a new scanner source for reading from a file. */ -/*----- Header files ------------------------------------------------------*/ +scansrc *scan_file(FILE *fp, const char *name, unsigned f) +{ + fscan *fs = CREATE(fscan); + fs->ss.ops = &fscan_ops; + fs->ss.src = xstrdup(name); + fs->ss.line = 1; + fs->fp = fp; + fs->f = f; + return (&fs->ss); +} -#include "config.h" +/*---- Argv scanner source ------------------------------------------------*/ -#include -#include -#include +/* --- Argv scanner block --- */ -#include +typedef struct avscan { + scansrc ss; + char **av; + char *p; +} avscan; -#include "scan.h" +/* --- @scan@ --- */ -/*----- Main code ---------------------------------------------------------*/ +static int avscan_scan(scansrc *ss) +{ + avscan *as = (avscan *)ss; + int ch; + if (!as->p) + ch = EOF; + else if ((ch = (unsigned char)*as->p++) == 0) { + as->ss.line++; + as->p = *as->av++; + ch = '\n'; + } + return (ch); +} -/* --- Generic scanner setup --- */ +/* --- @destroy@ --- */ -static void scan_init(scanner *sc, scan_ops *ops, const char *src) +static void avscan_destroy(scansrc *ss) { - sc->ops = ops; - sc->line = 1; - sc->src = src; - dstr_create(&sc->d); + avscan *as = (avscan *)ss; + DESTROY(as); } -/* --- @argv@ scanner --- */ +/* --- Argv scanner operations --- */ + +static scansrc_ops avscan_ops = { avscan_scan, avscan_destroy }; + +/* --- @scan_argv@ --- * + * + * Arguments: @char **av@ = pointer to argument array (null terminated) + * + * Returns: A scanner source. + * + * Use: Creates a new scanner source for reading from an @argv@ + * array. + */ -static int argv_scan(void *p) +scansrc *scan_argv(char **av) { - scan_argvctx *c = p; - int ch; + avscan *as = CREATE(avscan); + as->ss.ops = &avscan_ops; + as->ss.src = ""; + as->ss.line = 1; + as->p = *av++; + as->av = av; + return (&as->ss); +} - if (c->ch != EOF) { - ch = c->ch; - c->ch = EOF; - } else if (*c->p) - ch = *c->p++; - else if (*c->pp) { - c->p = *c->pp++; - ch = '\n'; - } else - ch = EOF; +/*----- End-of-file sentinel block ----------------------------------------*/ - return (ch); +/* --- @scan@ --- */ + +static int eof_scan(scansrc *ss) +{ + return (EOF); } -static void argv_unscan(int ch, void *p) +/* --- @destroy@ --- */ + +static void eof_destroy(scansrc *ss) +{ + ; +} + +/* --- Eof scanner operations --- */ + +static scansrc_ops eof_ops = { eof_scan, eof_destroy }; + +/* --- The end of file marker --- */ + +static scansrc scan_eof = { &scan_eof, &eof_ops, "", 0, DSTR_INIT }; + +/*----- General scanner handling ------------------------------------------*/ + +/* --- @scan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * + * Returns: Character read, or end-of-file. + * + * Use: Scans a character from a source of characters. + */ + +int scan(scanner *sc) { - scan_argvctx *c = p; - c->ch = ch; + int ch; + if (sc->head->pushback.len) + ch = sc->head->pushback.buf[--sc->head->pushback.len]; + else { + scansrc *ss = sc->head; + if (ss == &scan_eof) + ch = EOF; + else if ((ch = ss->ops->scan(ss)) == EOF) { + sc->head = ss->next; + if (sc->head == &scan_eof) + sc->tail = &sc->head; + ss->ops->destroy(ss); + ch = '\n'; + } + } + return (ch); } -void scan_argvinit(scan_argvctx *c, char **pp) +/* --- @unscan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @int ch@ = character to unscan + * + * Returns: --- + * + * Use: Scans a character from a source of characters. + */ + +void unscan(scanner *sc, int ch) { - static struct scan_ops ops = { argv_scan, argv_unscan }; - c->p = *pp++; - c->pp = pp; - c->ch = EOF; - scan_init(&c->sc, &ops, ""); + DPUTC(&sc->head->pushback, ch); } -/* --- File scanner --- */ +/* --- @scan_push@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Pushes a scanner source onto the front of the queue. + */ -static int file_scan(void *p) +void scan_push(scanner *sc, scansrc *ss) { - scan_filectx *c = p; - return (getc(c->fp)); + ss->next = sc->head; + if (sc->head == &scan_eof) + sc->tail = &ss->next; + sc->head = ss; + dstr_create(&ss->pushback); + ss->tok = 0; + ss->t = 0; } -static void file_unscan(int ch, void *p) +/* --- @scan_add@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Adds a scanner source onto the end of the queue. + */ + +void scan_add(scanner *sc, scansrc *ss) { - scan_filectx *c = p; - ungetc(ch, c->fp); + ss->next = &scan_eof; + *sc->tail = ss; + sc->tail = &ss->next; + dstr_create(&ss->pushback); + ss->tok = 0; + ss->t = 0; } -void scan_fileinit(scan_filectx *c, FILE *fp, const char *file) +/* --- @scan_create@ --- * + * + * Arguments: @scanner *sc@ = scanner context to initialize + * + * Returns: --- + * + * Use: Initializes a scanner block ready for use. + */ + +void scan_create(scanner *sc) { - static struct scan_ops ops = { file_scan, file_unscan }; - c->fp = fp; - scan_init(&c->sc, &ops, file); + sc->head = &scan_eof; + sc->tail = &sc->head; + dstr_create(&sc->d); + sc->wbegin = sc->wcont = 0; } -/* --- Miscellaneous functions --- */ +/* --- @scan_destroy@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner context + * + * Returns: --- + * + * Use: Destroys a scanner and all the sources attached to it. + */ -void scan_destroy(void *p) +void scan_destroy(scanner *sc) { - scanner *sc = p; + scansrc *ss = sc->head; + while (ss != &scan_eof) { + scansrc *sss = ss; + ss = ss->next; + if (sss->tok) + xfree(sss->tok); + dstr_destroy(&sss->pushback); + sss->ops->destroy(sss); + } dstr_destroy(&sc->d); + if (scan_eof.tok) + xfree(scan_eof.tok); + scan_eof.tok = 0; + sc->head = &scan_eof; + sc->tail = &sc->head; } /*----- That's all, folks -------------------------------------------------*/