xref: /plan9/sys/src/libString/s_rdinstack.c (revision dc5a79c1208f0704eeb474acc990728f8b4854f5)
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