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