xref: /plan9/sys/src/cmd/htmlroff/input.c (revision 426d2b71458df9b491ba6c167f699b3f1f7b0428)
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