1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <9pclient.h>
5 #include <acme.h>
6 
7 static CFsys *acmefs;
8 static Win *windows;
9 static Win *last;
10 
11 static void
mountacme(void)12 mountacme(void)
13 {
14 	if(acmefs == nil){
15 		acmefs = nsmount("acme", nil);
16 		if(acmefs == nil)
17 			sysfatal("cannot mount acme: %r");
18 	}
19 }
20 
21 Win*
newwin(void)22 newwin(void)
23 {
24 	CFid *fid;
25 	char buf[100];
26 	int id, n;
27 
28 	mountacme();
29 	fid = fsopen(acmefs, "new/ctl", ORDWR);
30 	if(fid == nil)
31 		sysfatal("open new/ctl: %r");
32 	n = fsread(fid, buf, sizeof buf-1);
33 	if(n <= 0)
34 		sysfatal("read new/ctl: %r");
35 	buf[n] = 0;
36 	id = atoi(buf);
37 	if(id == 0)
38 		sysfatal("read new/ctl: malformed message: %s", buf);
39 
40 	return openwin(id, fid);
41 }
42 
43 Win*
openwin(int id,CFid * ctl)44 openwin(int id, CFid *ctl)
45 {
46 	char buf[100];
47 	Win *w;
48 
49 	mountacme();
50 	if(ctl == nil){
51 		snprint(buf, sizeof buf, "%d/ctl", id);
52 		if((ctl = fsopen(acmefs, buf, ORDWR)) == nil)
53 			sysfatal("open %s: %r", buf);
54 	}
55 	w = emalloc(sizeof *w);
56 	w->id = id;
57 	w->ctl = ctl;
58 	w->next = nil;
59 	w->prev = last;
60 	if(last)
61 		last->next = w;
62 	else
63 		windows = w;
64 	last = w;
65 	return w;
66 }
67 
68 void
winclosefiles(Win * w)69 winclosefiles(Win *w)
70 {
71 	if(w->ctl){
72 		fsclose(w->ctl);
73 		w->ctl = nil;
74 	}
75 	if(w->body){
76 		fsclose(w->body);
77 		w->body = nil;
78 	}
79 	if(w->addr){
80 		fsclose(w->addr);
81 		w->addr = nil;
82 	}
83 	if(w->tag){
84 		fsclose(w->tag);
85 		w->tag = nil;
86 	}
87 	if(w->event){
88 		fsclose(w->event);
89 		w->event = nil;
90 	}
91 	if(w->data){
92 		fsclose(w->data);
93 		w->data = nil;
94 	}
95 	if(w->xdata){
96 		fsclose(w->xdata);
97 		w->xdata = nil;
98 	}
99 }
100 
101 void
winfree(Win * w)102 winfree(Win *w)
103 {
104 	winclosefiles(w);
105 	if(w->c){
106 		chanfree(w->c);
107 		w->c = nil;
108 	}
109 	if(w->next)
110 		w->next->prev = w->prev;
111 	else
112 		last = w->prev;
113 	if(w->prev)
114 		w->prev->next = w->next;
115 	else
116 		windows = w->next;
117 	free(w);
118 }
119 
120 void
windeleteall(void)121 windeleteall(void)
122 {
123 	Win *w, *next;
124 
125 	for(w=windows; w; w=next){
126 		next = w->next;
127 		winctl(w, "delete");
128 	}
129 }
130 
131 static CFid*
wfid(Win * w,char * name)132 wfid(Win *w, char *name)
133 {
134 	char buf[100];
135 	CFid **fid;
136 
137 	if(strcmp(name, "ctl") == 0)
138 		fid = &w->ctl;
139 	else if(strcmp(name, "body") == 0)
140 		fid = &w->body;
141 	else if(strcmp(name, "addr") == 0)
142 		fid = &w->addr;
143 	else if(strcmp(name, "tag") == 0)
144 		fid = &w->tag;
145 	else if(strcmp(name, "event") == 0)
146 		fid = &w->event;
147 	else if(strcmp(name, "data") == 0)
148 		fid = &w->data;
149 	else if(strcmp(name, "xdata") == 0)
150 		fid = &w->xdata;
151 	else{
152 		fid = 0;
153 		sysfatal("bad window file name %s", name);
154 	}
155 
156 	if(*fid == nil){
157 		snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
158 		*fid = fsopen(acmefs, buf, ORDWR);
159 		if(*fid == nil)
160 			sysfatal("open %s: %r", buf);
161 	}
162 	return *fid;
163 }
164 
165 int
winopenfd(Win * w,char * name,int mode)166 winopenfd(Win *w, char *name, int mode)
167 {
168 	char buf[100];
169 
170 	snprint(buf, sizeof buf, "%d/%s", w->id, name);
171 	return fsopenfd(acmefs, buf, mode);
172 }
173 
174 int
winctl(Win * w,char * fmt,...)175 winctl(Win *w, char *fmt, ...)
176 {
177 	char *s;
178 	va_list arg;
179 	CFid *fid;
180 	int n;
181 
182 	va_start(arg, fmt);
183 	s = evsmprint(fmt, arg);
184 	va_end(arg);
185 
186 	fid = wfid(w, "ctl");
187 	n = fspwrite(fid, s, strlen(s), 0);
188 	free(s);
189 	return n;
190 }
191 
192 int
winname(Win * w,char * fmt,...)193 winname(Win *w, char *fmt, ...)
194 {
195 	char *s;
196 	va_list arg;
197 	int n;
198 
199 	va_start(arg, fmt);
200 	s = evsmprint(fmt, arg);
201 	va_end(arg);
202 
203 	n = winctl(w, "name %s\n", s);
204 	free(s);
205 	return n;
206 }
207 
208 int
winprint(Win * w,char * name,char * fmt,...)209 winprint(Win *w, char *name, char *fmt, ...)
210 {
211 	char *s;
212 	va_list arg;
213 	int n;
214 
215 	va_start(arg, fmt);
216 	s = evsmprint(fmt, arg);
217 	va_end(arg);
218 
219 	n = fswrite(wfid(w, name), s, strlen(s));
220 	free(s);
221 	return n;
222 }
223 
224 int
winaddr(Win * w,char * fmt,...)225 winaddr(Win *w, char *fmt, ...)
226 {
227 	char *s;
228 	va_list arg;
229 	int n;
230 
231 	va_start(arg, fmt);
232 	s = evsmprint(fmt, arg);
233 	va_end(arg);
234 
235 	n = fswrite(wfid(w, "addr"), s, strlen(s));
236 	free(s);
237 	return n;
238 }
239 
240 int
winreadaddr(Win * w,uint * q1)241 winreadaddr(Win *w, uint *q1)
242 {
243 	char buf[40], *p;
244 	uint q0;
245 	int n;
246 
247 	n = fspread(wfid(w, "addr"), buf, sizeof buf-1, 0);
248 	if(n <= 0)
249 		return -1;
250 	buf[n] = 0;
251 	q0 = strtoul(buf, &p, 10);
252 	if(q1)
253 		*q1 = strtoul(p, nil, 10);
254 	return q0;
255 }
256 
257 int
winread(Win * w,char * file,void * a,int n)258 winread(Win *w, char *file, void *a, int n)
259 {
260 	return fsread(wfid(w, file), a, n);
261 }
262 
263 int
winwrite(Win * w,char * file,void * a,int n)264 winwrite(Win *w, char *file, void *a, int n)
265 {
266 	return fswrite(wfid(w, file), a, n);
267 }
268 
269 char*
winmread(Win * w,char * file)270 winmread(Win *w, char *file)
271 {
272 	char *buf;
273 	int n, tot, m;
274 
275 	m = 128;
276 	buf = emalloc(m+1);
277 	tot = 0;
278 	while((n = fsread(wfid(w, file), buf+tot, m-tot)) > 0){
279 		tot += n;
280 		if(tot >= m){
281 			m += 128;
282 			buf = erealloc(buf, m+1);
283 		}
284 	}
285 	if(n < 0){
286 		free(buf);
287 		return nil;
288 	}
289 	buf[tot] = 0;
290 	return buf;
291 }
292 
293 int
winseek(Win * w,char * file,int n,int off)294 winseek(Win *w, char *file, int n, int off)
295 {
296 	return fsseek(wfid(w, file), n, off);
297 }
298 
299 int
winwriteevent(Win * w,Event * e)300 winwriteevent(Win *w, Event *e)
301 {
302 	char buf[100];
303 
304 	snprint(buf, sizeof buf, "%c%c%d %d \n", e->c1, e->c2, e->q0, e->q1);
305 	return fswrite(wfid(w, "event"), buf, strlen(buf));
306 }
307 
308 int
windel(Win * w,int sure)309 windel(Win *w, int sure)
310 {
311 	return winctl(w, sure ? "delete" : "del");
312 }
313 
314 int
winfd(Win * w,char * name,int mode)315 winfd(Win *w, char *name, int mode)
316 {
317 	char buf[100];
318 
319 	snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
320 	return fsopenfd(acmefs, buf, mode);
321 }
322 
323 static void
error(Win * w,char * msg)324 error(Win *w, char *msg)
325 {
326 	if(msg == nil)
327 		longjmp(w->jmp, 1);
328 	fprint(2, "%s: win%d: %s\n", argv0, w->id, msg);
329 	longjmp(w->jmp, 2);
330 }
331 
332 static int
getec(Win * w,CFid * efd)333 getec(Win *w, CFid *efd)
334 {
335 	if(w->nbuf <= 0){
336 		w->nbuf = fsread(efd, w->buf, sizeof w->buf);
337 		if(w->nbuf <= 0)
338 			error(w, nil);
339 		w->bufp = w->buf;
340 	}
341 	--w->nbuf;
342 	return *w->bufp++;
343 }
344 
345 static int
geten(Win * w,CFid * efd)346 geten(Win *w, CFid *efd)
347 {
348 	int n, c;
349 
350 	n = 0;
351 	while('0'<=(c=getec(w,efd)) && c<='9')
352 		n = n*10+(c-'0');
353 	if(c != ' ')
354 		error(w, "event number syntax");
355 	return n;
356 }
357 
358 static int
geter(Win * w,CFid * efd,char * buf,int * nb)359 geter(Win *w, CFid *efd, char *buf, int *nb)
360 {
361 	Rune r;
362 	int n;
363 
364 	r = getec(w, efd);
365 	buf[0] = r;
366 	n = 1;
367 	if(r < Runeself)
368 		goto Return;
369 	while(!fullrune(buf, n))
370 		buf[n++] = getec(w, efd);
371 	chartorune(&r, buf);
372     Return:
373 	*nb = n;
374 	return r;
375 }
376 
377 static void
gete(Win * w,CFid * efd,Event * e)378 gete(Win *w, CFid *efd, Event *e)
379 {
380 	int i, nb;
381 
382 	e->c1 = getec(w, efd);
383 	e->c2 = getec(w, efd);
384 	e->q0 = geten(w, efd);
385 	e->q1 = geten(w, efd);
386 	e->flag = geten(w, efd);
387 	e->nr = geten(w, efd);
388 	if(e->nr > EVENTSIZE)
389 		error(w, "event string too long");
390 	e->nb = 0;
391 	for(i=0; i<e->nr; i++){
392 		/* e->r[i] = */ geter(w, efd, e->text+e->nb, &nb);
393 		e->nb += nb;
394 	}
395 /* 	e->r[e->nr] = 0; */
396 	e->text[e->nb] = 0;
397 	if(getec(w, efd) != '\n')
398 		error(w, "event syntax 2");
399 }
400 
401 int
winreadevent(Win * w,Event * e)402 winreadevent(Win *w, Event *e)
403 {
404 	CFid *efd;
405 	int r;
406 
407 	if((r = setjmp(w->jmp)) != 0){
408 		if(r == 1)
409 			return 0;
410 		return -1;
411 	}
412 	efd = wfid(w, "event");
413 	gete(w, efd, e);
414 	e->oq0 = e->q0;
415 	e->oq1 = e->q1;
416 
417 	/* expansion */
418 	if(e->flag&2){
419 		gete(w, efd, &w->e2);
420 		if(e->q0==e->q1){
421 			w->e2.oq0 = e->q0;
422 			w->e2.oq1 = e->q1;
423 			w->e2.flag = e->flag;
424 			*e = w->e2;
425 		}
426 	}
427 
428 	/* chorded argument */
429 	if(e->flag&8){
430 		gete(w, efd, &w->e3);	/* arg */
431 		gete(w, efd, &w->e4);	/* location */
432 		strcpy(e->arg, w->e3.text);
433 		strcpy(e->loc, w->e4.text);
434 	}
435 
436 	return 1;
437 }
438 
439 int
eventfmt(Fmt * fmt)440 eventfmt(Fmt *fmt)
441 {
442 	Event *e;
443 
444 	e = va_arg(fmt->args, Event*);
445 	return fmtprint(fmt, "%c%c %d %d %d %d %q", e->c1, e->c2, e->q0, e->q1, e->flag, e->nr, e->text);
446 }
447 
448 void*
emalloc(uint n)449 emalloc(uint n)
450 {
451 	void *v;
452 
453 	v = mallocz(n, 1);
454 	if(v == nil)
455 		sysfatal("out of memory");
456 	return v;
457 }
458 
459 void*
erealloc(void * v,uint n)460 erealloc(void *v, uint n)
461 {
462 	v = realloc(v, n);
463 	if(v == nil)
464 		sysfatal("out of memory");
465 	return v;
466 }
467 
468 char*
estrdup(char * s)469 estrdup(char *s)
470 {
471 	s = strdup(s);
472 	if(s == nil)
473 		sysfatal("out of memory");
474 	return s;
475 }
476 
477 char*
evsmprint(char * s,va_list v)478 evsmprint(char *s, va_list v)
479 {
480 	s = vsmprint(s, v);
481 	if(s == nil)
482 		sysfatal("out of memory");
483 	return s;
484 }
485 
486 int
pipewinto(Win * w,char * name,int errto,char * cmd,...)487 pipewinto(Win *w, char *name, int errto, char *cmd, ...)
488 {
489 	va_list arg;
490 	char *p;
491 	int fd[3], pid;
492 
493 	va_start(arg, cmd);
494 	p = evsmprint(cmd, arg);
495 	va_end(arg);
496 	fd[0] = winfd(w, name, OREAD);
497 	fd[1] = dup(errto, -1);
498 	fd[2] = dup(errto, -1);
499 	pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
500 	free(p);
501 	return pid;
502 }
503 
504 int
pipetowin(Win * w,char * name,int errto,char * cmd,...)505 pipetowin(Win *w, char *name, int errto, char *cmd, ...)
506 {
507 	va_list arg;
508 	char *p;
509 	int fd[3], pid;
510 
511 	va_start(arg, cmd);
512 	p = evsmprint(cmd, arg);
513 	va_end(arg);
514 	fd[0] = open("/dev/null", OREAD);
515 	fd[1] = winfd(w, name, OWRITE);
516 	if(errto == 0)
517 		fd[2] = dup(fd[1], -1);
518 	else
519 		fd[2] = dup(errto, -1);
520 	pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
521 	free(p);
522 	return pid;
523 }
524 
525 char*
sysrun(char * fmt,...)526 sysrun(char *fmt, ...)
527 {
528 	static char buf[1025];
529 	char *cmd;
530 	va_list arg;
531 	int n, fd[3], p[2], tot;
532 
533 #undef pipe
534 	if(pipe(p) < 0)
535 		sysfatal("pipe: %r");
536 	fd[0] = open("/dev/null", OREAD);
537 	fd[1] = p[1];
538 	fd[2] = dup(p[1], -1);
539 
540 	va_start(arg, fmt);
541 	cmd = evsmprint(fmt, arg);
542 	va_end(arg);
543 	threadspawnl(fd, "rc", "rc", "-Ic", cmd, 0);
544 
545 	tot = 0;
546 	while((n = read(p[0], buf+tot, sizeof buf-tot)) > 0)
547 		tot += n;
548 	close(p[0]);
549 	if(n < 0)
550 		return nil;
551 	free(cmd);
552 	if(tot == sizeof buf)
553 		tot--;
554 	buf[tot] = 0;
555 	while(tot > 0 && isspace(buf[tot-1]))
556 		tot--;
557 	buf[tot] = 0;
558 	if(tot == 0){
559 		werrstr("no output");
560 		return nil;
561 	}
562 	return buf;
563 }
564 
565 static void
eventreader(void * v)566 eventreader(void *v)
567 {
568 	Event e[2];
569 	Win *w;
570 	int i;
571 
572 	w = v;
573 	i = 0;
574 	for(;;){
575 		if(winreadevent(w, &e[i]) <= 0)
576 			break;
577 		sendp(w->c, &e[i]);
578 		i = 1-i;	/* toggle */
579 	}
580 	sendp(w->c, nil);
581 	threadexits(nil);
582 }
583 
584 Channel*
wineventchan(Win * w)585 wineventchan(Win *w)
586 {
587 	if(w->c == nil){
588 		w->c = chancreate(sizeof(Event*), 0);
589 		threadcreate(eventreader, w, 32*1024);
590 	}
591 	return w->c;
592 }
593