From 7f11104a5737adf261d10bc1a7b85e740f2eb491 Mon Sep 17 00:00:00 2001 From: rsc Date: Thu, 11 Dec 2003 18:15:57 +0000 Subject: Add libString. --- src/libString/s_rdinstack.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/libString/s_rdinstack.c (limited to 'src/libString/s_rdinstack.c') diff --git a/src/libString/s_rdinstack.c b/src/libString/s_rdinstack.c new file mode 100644 index 00000000..de12d219 --- /dev/null +++ b/src/libString/s_rdinstack.c @@ -0,0 +1,141 @@ + +#include +#include +#include +#include "libString.h" + +struct Sinstack{ + int depth; + Biobuf *fp[32]; /* hard limit to avoid infinite recursion */ +}; + +/* initialize */ +extern Sinstack * +s_allocinstack(char *file) +{ + Sinstack *sp; + Biobuf *fp; + + fp = Bopen(file, OREAD); + if(fp == nil) + return nil; + + sp = malloc(sizeof *sp); + sp->depth = 0; + sp->fp[0] = fp; + return sp; +} + +extern void +s_freeinstack(Sinstack *sp) +{ + while(sp->depth >= 0) + Bterm(sp->fp[sp->depth--]); + free(sp); +} + +/* Append an input line to a String. + * + * Empty lines and leading whitespace are removed. + */ +static char * +rdline(Biobuf *fp, String *to) +{ + int c; + int len = 0; + + c = Bgetc(fp); + + /* eat leading white */ + while(c==' ' || c=='\t' || c=='\n' || c=='\r') + c = Bgetc(fp); + + if(c < 0) + return 0; + + for(;;){ + switch(c) { + case -1: + goto out; + case '\\': + c = Bgetc(fp); + if (c != '\n') { + s_putc(to, '\\'); + s_putc(to, c); + len += 2; + } + break; + case '\r': + break; + case '\n': + if(len != 0) + goto out; + break; + default: + s_putc(to, c); + len++; + break; + } + c = Bgetc(fp); + } +out: + s_terminate(to); + return to->ptr - len; +} + +/* Append an input line to a String. + * + * Returns a pointer to the character string (or 0). + * Leading whitespace and newlines are removed. + * Lines starting with #include cause us to descend into the new file. + * Empty lines and other lines starting with '#' are ignored. + */ +extern char * +s_rdinstack(Sinstack *sp, String *to) +{ + char *p; + Biobuf *fp, *nfp; + + s_terminate(to); + fp = sp->fp[sp->depth]; + + for(;;){ + p = rdline(fp, to); + if(p == nil){ + if(sp->depth == 0) + break; + Bterm(fp); + sp->depth--; + return s_rdinstack(sp, to); + } + + if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){ + to->ptr = p; + p += 8; + + /* sanity (and looping) */ + if(sp->depth >= nelem(sp->fp)) + sysfatal("s_recgetline: includes too deep"); + + /* skip white */ + while(*p == ' ' || *p == '\t') + p++; + + nfp = Bopen(p, OREAD); + if(nfp == nil) + continue; + sp->depth++; + sp->fp[sp->depth] = nfp; + return s_rdinstack(sp, to); + } + + /* got milk? */ + if(*p != '#') + break; + + /* take care of comments */ + to->ptr = p; + s_terminate(to); + } + return p; +} -- cgit v1.2.3