1 /*
2 * Read input files.
3 */
4 #include "a.h"
5
6 typedef struct Istack Istack;
7 struct Istack
8 {
9 Rune unget[3];
10 int nunget;
11 Biobuf *b;
12 Rune *p;
13 Rune *ep;
14 Rune *s;
15 int lineno;
16 Rune *name;
17 Istack *next;
18 void (*fn)(void);
19 };
20
21 Istack *istack;
22 Istack *ibottom;
23
24 static void
setname(void)25 setname(void)
26 {
27 Rune *r, *p;
28
29 if(istack == nil || istack->name == nil)
30 return;
31 _nr(L(".F"), istack->name);
32 r = erunestrdup(istack->name);
33 p = runestrchr(r, '.');
34 if(p)
35 *p = 0;
36 _nr(L(".B"), r);
37 free(r);
38 }
39
40 static void
ipush(Istack * is)41 ipush(Istack *is)
42 {
43 if(istack == nil)
44 ibottom = is;
45 else
46 is->next = istack;
47 istack = is;
48 setname();
49 }
50
51 static void
iqueue(Istack * is)52 iqueue(Istack *is)
53 {
54 if(ibottom == nil){
55 istack = is;
56 setname();
57 }else
58 ibottom->next = is;
59 ibottom = is;
60 }
61
62 int
_inputfile(Rune * s,void (* push)(Istack *))63 _inputfile(Rune *s, void (*push)(Istack*))
64 {
65 Istack *is;
66 Biobuf *b;
67 char *t;
68
69 t = esmprint("%S", s);
70 if((b = Bopen(t, OREAD)) == nil){
71 free(t);
72 fprint(2, "%s: open %S: %r\n", argv0, s);
73 return -1;
74 }
75 free(t);
76 is = emalloc(sizeof *is);
77 is->b = b;
78 is->name = erunestrdup(s);
79 is->lineno = 1;
80 push(is);
81 return 0;
82 }
83
84 int
pushinputfile(Rune * s)85 pushinputfile(Rune *s)
86 {
87 return _inputfile(s, ipush);
88 }
89
90 int
queueinputfile(Rune * s)91 queueinputfile(Rune *s)
92 {
93 return _inputfile(s, iqueue);
94 }
95
96 int
_inputstdin(void (* push)(Istack *))97 _inputstdin(void (*push)(Istack*))
98 {
99 Biobuf *b;
100 Istack *is;
101
102 if((b = Bopen("/dev/null", OREAD)) == nil){
103 fprint(2, "%s: open /dev/null: %r\n", argv0);
104 return -1;
105 }
106 dup(0, b->fid);
107 is = emalloc(sizeof *is);
108 is->b = b;
109 is->name = erunestrdup(L("stdin"));
110 is->lineno = 1;
111 push(is);
112 return 0;
113 }
114
115 int
pushstdin(void)116 pushstdin(void)
117 {
118 return _inputstdin(ipush);
119 }
120
121 int
queuestdin(void)122 queuestdin(void)
123 {
124 return _inputstdin(iqueue);
125 }
126
127 void
_inputstring(Rune * s,void (* push)(Istack *))128 _inputstring(Rune *s, void (*push)(Istack*))
129 {
130 Istack *is;
131
132 is = emalloc(sizeof *is);
133 is->s = erunestrdup(s);
134 is->p = is->s;
135 is->ep = is->p+runestrlen(is->p);
136 push(is);
137 }
138
139 void
pushinputstring(Rune * s)140 pushinputstring(Rune *s)
141 {
142 _inputstring(s, ipush);
143 }
144
145
146 void
inputnotify(void (* fn)(void))147 inputnotify(void (*fn)(void))
148 {
149 if(istack)
150 istack->fn = fn;
151 }
152
153 int
popinput(void)154 popinput(void)
155 {
156 Istack *is;
157
158 is = istack;
159 if(is == nil)
160 return 0;
161
162 istack = istack->next;
163 if(is->b)
164 Bterm(is->b);
165 free(is->s);
166 free(is->name);
167 if(is->fn)
168 is->fn();
169 free(is);
170 setname();
171 return 1;
172 }
173
174 int
getrune(void)175 getrune(void)
176 {
177 Rune r;
178 int c;
179
180 top:
181 if(istack == nil)
182 return -1;
183 if(istack->nunget)
184 return istack->unget[--istack->nunget];
185 else if(istack->p){
186 if(istack->p >= istack->ep){
187 popinput();
188 goto top;
189 }
190 r = *istack->p++;
191 }else if(istack->b){
192 if((c = Bgetrune(istack->b)) < 0){
193 popinput();
194 goto top;
195 }
196 r = c;
197 }else{
198 r = 0;
199 sysfatal("getrune - can't happen");
200 }
201 if(r == '\n')
202 istack->lineno++;
203 return r;
204 }
205
206 void
ungetrune(Rune r)207 ungetrune(Rune r)
208 {
209 if(istack == nil || istack->nunget >= nelem(istack->unget))
210 pushinputstring(L(""));
211 istack->unget[istack->nunget++] = r;
212 }
213
214 int
linefmt(Fmt * f)215 linefmt(Fmt *f)
216 {
217 Istack *is;
218
219 for(is=istack; is && !is->b; is=is->next)
220 ;
221 if(is)
222 return fmtprint(f, "%S:%d", is->name, is->lineno);
223 else
224 return fmtprint(f, "<no input>");
225 }
226
227 void
setlinenumber(Rune * s,int n)228 setlinenumber(Rune *s, int n)
229 {
230 Istack *is;
231
232 for(is=istack; is && !is->name; is=is->next)
233 ;
234 if(is){
235 if(s){
236 free(is->name);
237 is->name = erunestrdup(s);
238 }
239 is->lineno = n;
240 }
241 }
242