xref: /plan9/acme/news/src/win.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <thread.h>
5 #include "win.h"
6 
7 Window*
newwindow(void)8 newwindow(void)
9 {
10 	char buf[12];
11 	Window *w;
12 
13 	w = emalloc(sizeof(Window));
14 	w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC);
15 	if(w->ctl<0 || read(w->ctl, buf, 12)!=12)
16 		error("can't open window ctl file: %r");
17 	ctlprint(w->ctl, "noscroll\n");
18 	w->id = atoi(buf);
19 	w->event = winopenfile(w, "event");
20 	w->addr = -1;	/* will be opened when needed */
21 	w->body = nil;
22 	w->data = -1;
23 	w->cevent = chancreate(sizeof(Event*), 0);
24 	if(w->cevent == nil)
25 		error("cevent is nil: %r");
26 	return w;
27 }
28 
29 void
winsetdump(Window * w,char * dir,char * cmd)30 winsetdump(Window *w, char *dir, char *cmd)
31 {
32 	if(dir != nil)
33 		ctlprint(w->ctl, "dumpdir %s\n", dir);
34 	if(cmd != nil)
35 		ctlprint(w->ctl, "dump %s\n", cmd);
36 }
37 
38 void
wineventproc(void * v)39 wineventproc(void *v)
40 {
41 	Window *w;
42 	int i;
43 
44 	threadsetname("wineventproc");
45 	w = v;
46 	for(i=0; ; i++){
47 		if(i >= NEVENT)
48 			i = 0;
49 		wingetevent(w, &w->e[i]);
50 		sendp(w->cevent, &w->e[i]);
51 	}
52 }
53 
54 int
winopenfile(Window * w,char * f)55 winopenfile(Window *w, char *f)
56 {
57 	char buf[64];
58 	int fd;
59 
60 	sprint(buf, "/mnt/wsys/%d/%s", w->id, f);
61 	fd = open(buf, ORDWR|OCEXEC);
62 	if(fd < 0)
63 		error("can't open window file %s: %r", f);
64 	return fd;
65 }
66 
67 void
wintagwrite(Window * w,char * s,int n)68 wintagwrite(Window *w, char *s, int n)
69 {
70 	int fd;
71 
72 	fd = winopenfile(w, "tag");
73 	if(write(fd, s, n) != n)
74 		error("tag write: %r");
75 	close(fd);
76 }
77 
78 void
winname(Window * w,char * s)79 winname(Window *w, char *s)
80 {
81 	ctlprint(w->ctl, "name %s\n", s);
82 }
83 
84 void
winopenbody(Window * w,int mode)85 winopenbody(Window *w, int mode)
86 {
87 	char buf[256];
88 
89 	sprint(buf, "/mnt/wsys/%d/body", w->id);
90 	w->body = Bopen(buf, mode|OCEXEC);
91 	if(w->body == nil)
92 		error("can't open window body file: %r");
93 }
94 
95 void
winclosebody(Window * w)96 winclosebody(Window *w)
97 {
98 	if(w->body != nil){
99 		Bterm(w->body);
100 		w->body = nil;
101 	}
102 }
103 
104 void
winwritebody(Window * w,char * s,int n)105 winwritebody(Window *w, char *s, int n)
106 {
107 	if(w->body == nil)
108 		winopenbody(w, OWRITE);
109 	if(Bwrite(w->body, s, n) != n)
110 		error("write error to window: %r");
111 }
112 
113 int
wingetec(Window * w)114 wingetec(Window *w)
115 {
116 	if(w->nbuf == 0){
117 		w->nbuf = read(w->event, w->buf, sizeof w->buf);
118 		if(w->nbuf <= 0){
119 			/* probably because window has exited, and only called by wineventproc, so just shut down */
120 			threadexits(nil);
121 		}
122 		w->bufp = w->buf;
123 	}
124 	w->nbuf--;
125 	return *w->bufp++;
126 }
127 
128 int
wingeten(Window * w)129 wingeten(Window *w)
130 {
131 	int n, c;
132 
133 	n = 0;
134 	while('0'<=(c=wingetec(w)) && c<='9')
135 		n = n*10+(c-'0');
136 	if(c != ' ')
137 		error("event number syntax");
138 	return n;
139 }
140 
141 int
wingeter(Window * w,char * buf,int * nb)142 wingeter(Window *w, char *buf, int *nb)
143 {
144 	Rune r;
145 	int n;
146 
147 	r = wingetec(w);
148 	buf[0] = r;
149 	n = 1;
150 	if(r >= Runeself) {
151 		while(!fullrune(buf, n))
152 			buf[n++] = wingetec(w);
153 		chartorune(&r, buf);
154 	}
155 	*nb = n;
156 	return r;
157 }
158 
159 void
wingetevent(Window * w,Event * e)160 wingetevent(Window *w, Event *e)
161 {
162 	int i, nb;
163 
164 	e->c1 = wingetec(w);
165 	e->c2 = wingetec(w);
166 	e->q0 = wingeten(w);
167 	e->q1 = wingeten(w);
168 	e->flag = wingeten(w);
169 	e->nr = wingeten(w);
170 	if(e->nr > EVENTSIZE)
171 		error("event string too long");
172 	e->nb = 0;
173 	for(i=0; i<e->nr; i++){
174 		e->r[i] = wingeter(w, e->b+e->nb, &nb);
175 		e->nb += nb;
176 	}
177 	e->r[e->nr] = 0;
178 	e->b[e->nb] = 0;
179 	if(wingetec(w) != '\n')
180 		error("event syntax error");
181 }
182 
183 void
winwriteevent(Window * w,Event * e)184 winwriteevent(Window *w, Event *e)
185 {
186 	fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
187 }
188 
189 static int
nrunes(char * s,int nb)190 nrunes(char *s, int nb)
191 {
192 	int i, n;
193 	Rune r;
194 
195 	n = 0;
196 	for(i=0; i<nb; n++)
197 		i += chartorune(&r, s+i);
198 	return n;
199 }
200 
201 void
winread(Window * w,uint q0,uint q1,char * data)202 winread(Window *w, uint q0, uint q1, char *data)
203 {
204 	int m, n, nr;
205 	char buf[256];
206 
207 	if(w->addr < 0)
208 		w->addr = winopenfile(w, "addr");
209 	if(w->data < 0)
210 		w->data = winopenfile(w, "data");
211 	m = q0;
212 	while(m < q1){
213 		n = sprint(buf, "#%d", m);
214 		if(write(w->addr, buf, n) != n)
215 			error("error writing addr: %r");
216 		n = read(w->data, buf, sizeof buf);
217 		if(n <= 0)
218 			error("reading data: %r");
219 		nr = nrunes(buf, n);
220 		while(m+nr >q1){
221 			do; while(n>0 && (buf[--n]&0xC0)==0x80);
222 			--nr;
223 		}
224 		if(n == 0)
225 			break;
226 		memmove(data, buf, n);
227 		data += n;
228 		*data = 0;
229 		m += nr;
230 	}
231 }
232 
233 void
windormant(Window * w)234 windormant(Window *w)
235 {
236 	if(w->addr >= 0){
237 		close(w->addr);
238 		w->addr = -1;
239 	}
240 	if(w->body != nil){
241 		Bterm(w->body);
242 		w->body = nil;
243 	}
244 	if(w->data >= 0){
245 		close(w->data);
246 		w->data = -1;
247 	}
248 }
249 
250 
251 int
windel(Window * w,int sure)252 windel(Window *w, int sure)
253 {
254 	if(sure)
255 		write(w->ctl, "delete\n", 7);
256 	else if(write(w->ctl, "del\n", 4) != 4)
257 		return 0;
258 	/* event proc will die due to read error from event file */
259 	windormant(w);
260 	close(w->ctl);
261 	w->ctl = -1;
262 	close(w->event);
263 	w->event = -1;
264 	return 1;
265 }
266 
267 void
winclean(Window * w)268 winclean(Window *w)
269 {
270 	if(w->body)
271 		Bflush(w->body);
272 	ctlprint(w->ctl, "clean\n");
273 }
274 
275 int
winsetaddr(Window * w,char * addr,int errok)276 winsetaddr(Window *w, char *addr, int errok)
277 {
278 	if(w->addr < 0)
279 		w->addr = winopenfile(w, "addr");
280 	if(write(w->addr, addr, strlen(addr)) < 0){
281 		if(!errok)
282 			error("error writing addr(%s): %r", addr);
283 		return 0;
284 	}
285 	return 1;
286 }
287 
288 int
winselect(Window * w,char * addr,int errok)289 winselect(Window *w, char *addr, int errok)
290 {
291 	if(winsetaddr(w, addr, errok)){
292 		ctlprint(w->ctl, "dot=addr\n");
293 		return 1;
294 	}
295 	return 0;
296 }
297 
298 char*
winreadbody(Window * w,int * np)299 winreadbody(Window *w, int *np)	/* can't use readfile because acme doesn't report the length */
300 {
301 	char *s;
302 	int m, na, n;
303 
304 	if(w->body != nil)
305 		winclosebody(w);
306 	winopenbody(w, OREAD);
307 	s = nil;
308 	na = 0;
309 	n = 0;
310 	for(;;){
311 		if(na < n+512){
312 			na += 1024;
313 			s = realloc(s, na+1);
314 		}
315 		m = Bread(w->body, s+n, na-n);
316 		if(m <= 0)
317 			break;
318 		n += m;
319 	}
320 	s[n] = 0;
321 	winclosebody(w);
322 	*np = n;
323 	return s;
324 }
325