Blob


2 #include <u.h>
3 #include <libc.h>
4 #include <bio.h>
5 #include "libString.h"
7 struct Sinstack{
8 int depth;
9 Biobuf *fp[32]; /* hard limit to avoid infinite recursion */
10 };
12 /* initialize */
13 extern Sinstack *
14 s_allocinstack(char *file)
15 {
16 Sinstack *sp;
17 Biobuf *fp;
19 fp = Bopen(file, OREAD);
20 if(fp == nil)
21 return nil;
23 sp = malloc(sizeof *sp);
24 sp->depth = 0;
25 sp->fp[0] = fp;
26 return sp;
27 }
29 extern void
30 s_freeinstack(Sinstack *sp)
31 {
32 while(sp->depth >= 0)
33 Bterm(sp->fp[sp->depth--]);
34 free(sp);
35 }
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;
47 c = Bgetc(fp);
49 /* eat leading white */
50 while(c==' ' || c=='\t' || c=='\n' || c=='\r')
51 c = Bgetc(fp);
53 if(c < 0)
54 return 0;
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 }
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;
99 s_terminate(to);
100 fp = sp->fp[sp->depth];
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);
112 if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){
113 to->ptr = p;
114 p += 8;
116 /* sanity (and looping) */
117 if(sp->depth >= nelem(sp->fp))
118 sysfatal("s_rdinstack: includes too deep");
120 /* skip white */
121 while(*p == ' ' || *p == '\t')
122 p++;
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);
132 /* got milk? */
133 if(*p != '#')
134 break;
136 /* take care of comments */
137 to->ptr = p;
138 s_terminate(to);
140 return p;