blob: 520f16a68749966fb3490d9f6bd8e51da1b2fefb [file] [log] [blame]
rsc7f111042003-12-11 18:15:57 +00001
2#include <u.h>
3#include <libc.h>
4#include <bio.h>
5#include "libString.h"
6
7struct Sinstack{
8 int depth;
9 Biobuf *fp[32]; /* hard limit to avoid infinite recursion */
10};
11
12/* initialize */
13extern Sinstack *
14s_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
29extern void
30s_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 */
41static char *
42rdline(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 }
81out:
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 */
93extern char *
94s_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))
rsc834469a2005-01-04 22:19:46 +0000118 sysfatal("s_rdinstack: includes too deep");
rsc7f111042003-12-11 18:15:57 +0000119
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}