Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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