]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/htmlroff/input.c
fix ref822 again: remove uniqarray(), fix case with many entries in 'n'.
[plan9front.git] / sys / src / cmd / htmlroff / input.c
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
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
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
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
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
85 pushinputfile(Rune *s)
86 {
87         return _inputfile(s, ipush);
88 }
89
90 int
91 queueinputfile(Rune *s)
92 {
93         return _inputfile(s, iqueue);
94 }
95
96 int
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
116 pushstdin(void)
117 {
118         return _inputstdin(ipush);
119 }
120
121 int
122 queuestdin(void)
123 {
124         return _inputstdin(iqueue);
125 }
126
127 void
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
140 pushinputstring(Rune *s)
141 {
142         _inputstring(s, ipush);
143 }
144
145
146 void
147 inputnotify(void (*fn)(void))
148 {
149         if(istack)
150                 istack->fn = fn;
151 }
152
153 int
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
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
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
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
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 }