2003-12-11 18:15:57 +00:00
|
|
|
|
|
|
|
#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))
|
2005-01-04 22:19:46 +00:00
|
|
|
sysfatal("s_rdinstack: includes too deep");
|
2003-12-11 18:15:57 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|