]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libString/s_rdinstack.c
kernel: implement portable userinit() and simplify process creation
[plan9front.git] / sys / src / libString / s_rdinstack.c
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 }