1*dc5a79c1SDavid du Colombier
2*dc5a79c1SDavid du Colombier #include <u.h>
3*dc5a79c1SDavid du Colombier #include <libc.h>
4*dc5a79c1SDavid du Colombier #include <bio.h>
5*dc5a79c1SDavid du Colombier #include "String.h"
6*dc5a79c1SDavid du Colombier
7*dc5a79c1SDavid du Colombier struct Sinstack{
8*dc5a79c1SDavid du Colombier int depth;
9*dc5a79c1SDavid du Colombier Biobuf *fp[32]; /* hard limit to avoid infinite recursion */
10*dc5a79c1SDavid du Colombier };
11*dc5a79c1SDavid du Colombier
12*dc5a79c1SDavid du Colombier /* initialize */
13*dc5a79c1SDavid du Colombier extern Sinstack *
s_allocinstack(char * file)14*dc5a79c1SDavid du Colombier s_allocinstack(char *file)
15*dc5a79c1SDavid du Colombier {
16*dc5a79c1SDavid du Colombier Sinstack *sp;
17*dc5a79c1SDavid du Colombier Biobuf *fp;
18*dc5a79c1SDavid du Colombier
19*dc5a79c1SDavid du Colombier fp = Bopen(file, OREAD);
20*dc5a79c1SDavid du Colombier if(fp == nil)
21*dc5a79c1SDavid du Colombier return nil;
22*dc5a79c1SDavid du Colombier
23*dc5a79c1SDavid du Colombier sp = malloc(sizeof *sp);
24*dc5a79c1SDavid du Colombier sp->depth = 0;
25*dc5a79c1SDavid du Colombier sp->fp[0] = fp;
26*dc5a79c1SDavid du Colombier return sp;
27*dc5a79c1SDavid du Colombier }
28*dc5a79c1SDavid du Colombier
29*dc5a79c1SDavid du Colombier extern void
s_freeinstack(Sinstack * sp)30*dc5a79c1SDavid du Colombier s_freeinstack(Sinstack *sp)
31*dc5a79c1SDavid du Colombier {
32*dc5a79c1SDavid du Colombier while(sp->depth >= 0)
33*dc5a79c1SDavid du Colombier Bterm(sp->fp[sp->depth--]);
34*dc5a79c1SDavid du Colombier free(sp);
35*dc5a79c1SDavid du Colombier }
36*dc5a79c1SDavid du Colombier
37*dc5a79c1SDavid du Colombier /* Append an input line to a String.
38*dc5a79c1SDavid du Colombier *
39*dc5a79c1SDavid du Colombier * Empty lines and leading whitespace are removed.
40*dc5a79c1SDavid du Colombier */
41*dc5a79c1SDavid du Colombier static char *
rdline(Biobuf * fp,String * to)42*dc5a79c1SDavid du Colombier rdline(Biobuf *fp, String *to)
43*dc5a79c1SDavid du Colombier {
44*dc5a79c1SDavid du Colombier int c;
45*dc5a79c1SDavid du Colombier int len = 0;
46*dc5a79c1SDavid du Colombier
47*dc5a79c1SDavid du Colombier c = Bgetc(fp);
48*dc5a79c1SDavid du Colombier
49*dc5a79c1SDavid du Colombier /* eat leading white */
50*dc5a79c1SDavid du Colombier while(c==' ' || c=='\t' || c=='\n' || c=='\r')
51*dc5a79c1SDavid du Colombier c = Bgetc(fp);
52*dc5a79c1SDavid du Colombier
53*dc5a79c1SDavid du Colombier if(c < 0)
54*dc5a79c1SDavid du Colombier return 0;
55*dc5a79c1SDavid du Colombier
56*dc5a79c1SDavid du Colombier for(;;){
57*dc5a79c1SDavid du Colombier switch(c) {
58*dc5a79c1SDavid du Colombier case -1:
59*dc5a79c1SDavid du Colombier goto out;
60*dc5a79c1SDavid du Colombier case '\\':
61*dc5a79c1SDavid du Colombier c = Bgetc(fp);
62*dc5a79c1SDavid du Colombier if (c != '\n') {
63*dc5a79c1SDavid du Colombier s_putc(to, '\\');
64*dc5a79c1SDavid du Colombier s_putc(to, c);
65*dc5a79c1SDavid du Colombier len += 2;
66*dc5a79c1SDavid du Colombier }
67*dc5a79c1SDavid du Colombier break;
68*dc5a79c1SDavid du Colombier case '\r':
69*dc5a79c1SDavid du Colombier break;
70*dc5a79c1SDavid du Colombier case '\n':
71*dc5a79c1SDavid du Colombier if(len != 0)
72*dc5a79c1SDavid du Colombier goto out;
73*dc5a79c1SDavid du Colombier break;
74*dc5a79c1SDavid du Colombier default:
75*dc5a79c1SDavid du Colombier s_putc(to, c);
76*dc5a79c1SDavid du Colombier len++;
77*dc5a79c1SDavid du Colombier break;
78*dc5a79c1SDavid du Colombier }
79*dc5a79c1SDavid du Colombier c = Bgetc(fp);
80*dc5a79c1SDavid du Colombier }
81*dc5a79c1SDavid du Colombier out:
82*dc5a79c1SDavid du Colombier s_terminate(to);
83*dc5a79c1SDavid du Colombier return to->ptr - len;
84*dc5a79c1SDavid du Colombier }
85*dc5a79c1SDavid du Colombier
86*dc5a79c1SDavid du Colombier /* Append an input line to a String.
87*dc5a79c1SDavid du Colombier *
88*dc5a79c1SDavid du Colombier * Returns a pointer to the character string (or 0).
89*dc5a79c1SDavid du Colombier * Leading whitespace and newlines are removed.
90*dc5a79c1SDavid du Colombier * Lines starting with #include cause us to descend into the new file.
91*dc5a79c1SDavid du Colombier * Empty lines and other lines starting with '#' are ignored.
92*dc5a79c1SDavid du Colombier */
93*dc5a79c1SDavid du Colombier extern char *
s_rdinstack(Sinstack * sp,String * to)94*dc5a79c1SDavid du Colombier s_rdinstack(Sinstack *sp, String *to)
95*dc5a79c1SDavid du Colombier {
96*dc5a79c1SDavid du Colombier char *p;
97*dc5a79c1SDavid du Colombier Biobuf *fp, *nfp;
98*dc5a79c1SDavid du Colombier
99*dc5a79c1SDavid du Colombier s_terminate(to);
100*dc5a79c1SDavid du Colombier fp = sp->fp[sp->depth];
101*dc5a79c1SDavid du Colombier
102*dc5a79c1SDavid du Colombier for(;;){
103*dc5a79c1SDavid du Colombier p = rdline(fp, to);
104*dc5a79c1SDavid du Colombier if(p == nil){
105*dc5a79c1SDavid du Colombier if(sp->depth == 0)
106*dc5a79c1SDavid du Colombier break;
107*dc5a79c1SDavid du Colombier Bterm(fp);
108*dc5a79c1SDavid du Colombier sp->depth--;
109*dc5a79c1SDavid du Colombier return s_rdinstack(sp, to);
110*dc5a79c1SDavid du Colombier }
111*dc5a79c1SDavid du Colombier
112*dc5a79c1SDavid du Colombier if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){
113*dc5a79c1SDavid du Colombier to->ptr = p;
114*dc5a79c1SDavid du Colombier p += 8;
115*dc5a79c1SDavid du Colombier
116*dc5a79c1SDavid du Colombier /* sanity (and looping) */
117*dc5a79c1SDavid du Colombier if(sp->depth >= nelem(sp->fp))
118*dc5a79c1SDavid du Colombier sysfatal("s_recgetline: includes too deep");
119*dc5a79c1SDavid du Colombier
120*dc5a79c1SDavid du Colombier /* skip white */
121*dc5a79c1SDavid du Colombier while(*p == ' ' || *p == '\t')
122*dc5a79c1SDavid du Colombier p++;
123*dc5a79c1SDavid du Colombier
124*dc5a79c1SDavid du Colombier nfp = Bopen(p, OREAD);
125*dc5a79c1SDavid du Colombier if(nfp == nil)
126*dc5a79c1SDavid du Colombier continue;
127*dc5a79c1SDavid du Colombier sp->depth++;
128*dc5a79c1SDavid du Colombier sp->fp[sp->depth] = nfp;
129*dc5a79c1SDavid du Colombier return s_rdinstack(sp, to);
130*dc5a79c1SDavid du Colombier }
131*dc5a79c1SDavid du Colombier
132*dc5a79c1SDavid du Colombier /* got milk? */
133*dc5a79c1SDavid du Colombier if(*p != '#')
134*dc5a79c1SDavid du Colombier break;
135*dc5a79c1SDavid du Colombier
136*dc5a79c1SDavid du Colombier /* take care of comments */
137*dc5a79c1SDavid du Colombier to->ptr = p;
138*dc5a79c1SDavid du Colombier s_terminate(to);
139*dc5a79c1SDavid du Colombier }
140*dc5a79c1SDavid du Colombier return p;
141*dc5a79c1SDavid du Colombier }
142