#include <u.h> | |
#include <libc.h> | |
#include <bio.h> | |
#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_rdinstack: 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; | |
} |