Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <9pclient.h>
5 #include "acme.h"
7 extern int *xxx;
8 static CFsys *acmefs;
9 Win *windows;
10 static Win *last;
12 void
13 mountacme(void)
14 {
15 if(acmefs == nil){
16 acmefs = nsmount("acme", nil);
17 if(acmefs == nil)
18 sysfatal("cannot mount acme: %r");
19 }
20 }
22 Win*
23 newwin(void)
24 {
25 Win *w;
26 CFid *fid;
27 char buf[100];
28 int id, n;
30 mountacme();
31 fid = fsopen(acmefs, "new/ctl", ORDWR);
32 if(fid == nil)
33 sysfatal("open new/ctl: %r");
34 n = fsread(fid, buf, sizeof buf-1);
35 if(n <= 0)
36 sysfatal("read new/ctl: %r");
37 buf[n] = 0;
38 id = atoi(buf);
39 if(id == 0)
40 sysfatal("read new/ctl: malformed message: %s", buf);
42 w = emalloc(sizeof *w);
43 w->id = id;
44 w->ctl = fid;
45 w->next = nil;
46 w->prev = last;
47 if(last)
48 last->next = w;
49 else
50 windows = w;
51 last = w;
52 return w;
53 }
55 void
56 winclosefiles(Win *w)
57 {
58 if(w->ctl){
59 fsclose(w->ctl);
60 w->ctl = nil;
61 }
62 if(w->body){
63 fsclose(w->body);
64 w->body = nil;
65 }
66 if(w->addr){
67 fsclose(w->addr);
68 w->addr = nil;
69 }
70 if(w->tag){
71 fsclose(w->tag);
72 w->tag = nil;
73 }
74 if(w->event){
75 fsclose(w->event);
76 w->event = nil;
77 }
78 if(w->data){
79 fsclose(w->data);
80 w->data = nil;
81 }
82 if(w->xdata){
83 fsclose(w->xdata);
84 w->xdata = nil;
85 }
86 }
88 void
89 winfree(Win *w)
90 {
91 winclosefiles(w);
92 if(w->c){
93 chanfree(w->c);
94 w->c = nil;
95 }
96 if(w->next)
97 w->next->prev = w->prev;
98 else
99 last = w->prev;
100 if(w->prev)
101 w->prev->next = w->next;
102 else
103 windows = w->next;
104 free(w);
107 void
108 windeleteall(void)
110 Win *w, *next;
112 for(w=windows; w; w=next){
113 next = w->next;
114 winctl(w, "delete");
118 static CFid*
119 wfid(Win *w, char *name)
121 char buf[100];
122 CFid **fid;
124 if(strcmp(name, "ctl") == 0)
125 fid = &w->ctl;
126 else if(strcmp(name, "body") == 0)
127 fid = &w->body;
128 else if(strcmp(name, "addr") == 0)
129 fid = &w->addr;
130 else if(strcmp(name, "tag") == 0)
131 fid = &w->tag;
132 else if(strcmp(name, "event") == 0)
133 fid = &w->event;
134 else if(strcmp(name, "data") == 0)
135 fid = &w->data;
136 else if(strcmp(name, "xdata") == 0)
137 fid = &w->xdata;
138 else{
139 fid = 0;
140 sysfatal("bad window file name %s", name);
143 if(*fid == nil){
144 snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
145 *fid = fsopen(acmefs, buf, ORDWR);
146 if(*fid == nil)
147 sysfatal("open %s: %r", buf);
149 return *fid;
152 int
153 winopenfd(Win *w, char *name, int mode)
155 char buf[100];
157 snprint(buf, sizeof buf, "%d/%s", w->id, name);
158 return fsopenfd(acmefs, buf, mode);
161 int
162 winctl(Win *w, char *fmt, ...)
164 char *s;
165 va_list arg;
166 CFid *fid;
167 int n;
169 va_start(arg, fmt);
170 s = evsmprint(fmt, arg);
171 va_end(arg);
173 fid = wfid(w, "ctl");
174 n = fspwrite(fid, s, strlen(s), 0);
175 free(s);
176 return n;
179 int
180 winname(Win *w, char *fmt, ...)
182 char *s;
183 va_list arg;
184 int n;
186 va_start(arg, fmt);
187 s = evsmprint(fmt, arg);
188 va_end(arg);
190 n = winctl(w, "name %s\n", s);
191 free(s);
192 return n;
195 int
196 winprint(Win *w, char *name, char *fmt, ...)
198 char *s;
199 va_list arg;
200 int n;
202 va_start(arg, fmt);
203 s = evsmprint(fmt, arg);
204 va_end(arg);
206 n = fswrite(wfid(w, name), s, strlen(s));
207 free(s);
208 return n;
211 int
212 winaddr(Win *w, char *fmt, ...)
214 char *s;
215 va_list arg;
216 int n;
218 va_start(arg, fmt);
219 s = evsmprint(fmt, arg);
220 va_end(arg);
222 n = fswrite(wfid(w, "addr"), s, strlen(s));
223 free(s);
224 return n;
227 int
228 winreadaddr(Win *w, uint *q1)
230 char buf[40], *p;
231 uint q0;
232 int n;
234 n = fspread(wfid(w, "addr"), buf, sizeof buf-1, 0);
235 if(n <= 0)
236 return -1;
237 buf[n] = 0;
238 q0 = strtoul(buf, &p, 10);
239 if(q1)
240 *q1 = strtoul(p, nil, 10);
241 return q0;
244 int
245 winread(Win *w, char *file, void *a, int n)
247 return fspread(wfid(w, file), a, n, 0);
250 int
251 winwrite(Win *w, char *file, void *a, int n)
253 return fswrite(wfid(w, file), a, n);
256 char*
257 fsreadm(CFid *fid)
259 char *buf;
260 int n, tot, m;
262 m = 128;
263 buf = emalloc(m+1);
264 tot = 0;
265 while((n = fspread(fid, buf+tot, m-tot, tot)) > 0){
266 tot += n;
267 if(tot >= m){
268 m += 128;
269 buf = erealloc(buf, m+1);
272 if(n < 0){
273 free(buf);
274 return nil;
276 buf[tot] = 0;
277 return buf;
280 char*
281 winmread(Win *w, char *file)
283 return fsreadm(wfid(w, file));
286 char*
287 winindex(void)
289 CFid *fid;
290 char *s;
292 mountacme();
293 if((fid = fsopen(acmefs, "index", OREAD)) == nil)
294 return nil;
295 s = fsreadm(fid);
296 fsclose(fid);
297 return s;
300 int
301 winseek(Win *w, char *file, int n, int off)
303 return fsseek(wfid(w, file), n, off);
306 int
307 winwriteevent(Win *w, Event *e)
309 char buf[100];
311 snprint(buf, sizeof buf, "%c%c%d %d \n", e->c1, e->c2, e->q0, e->q1);
312 return fswrite(wfid(w, "event"), buf, strlen(buf));
315 int
316 windel(Win *w, int sure)
318 return winctl(w, sure ? "delete" : "del");
321 int
322 winfd(Win *w, char *name, int mode)
324 char buf[100];
326 snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
327 return fsopenfd(acmefs, buf, mode);
330 static void
331 error(Win *w, char *msg)
333 if(msg == nil)
334 longjmp(w->jmp, 1);
335 fprint(2, "%s: win%d: %s\n", argv0, w->id, msg);
336 longjmp(w->jmp, 2);
339 static int
340 getec(Win *w, CFid *efd)
342 if(w->nbuf <= 0){
343 w->nbuf = fsread(efd, w->buf, sizeof w->buf);
344 if(w->nbuf <= 0)
345 error(w, nil);
346 w->bufp = w->buf;
348 --w->nbuf;
349 return *w->bufp++;
352 static int
353 geten(Win *w, CFid *efd)
355 int n, c;
357 n = 0;
358 while('0'<=(c=getec(w,efd)) && c<='9')
359 n = n*10+(c-'0');
360 if(c != ' ')
361 error(w, "event number syntax");
362 return n;
365 static int
366 geter(Win *w, CFid *efd, char *buf, int *nb)
368 Rune r;
369 int n;
371 r = getec(w, efd);
372 buf[0] = r;
373 n = 1;
374 if(r < Runeself)
375 goto Return;
376 while(!fullrune(buf, n))
377 buf[n++] = getec(w, efd);
378 chartorune(&r, buf);
379 Return:
380 *nb = n;
381 return r;
384 static void
385 gete(Win *w, CFid *efd, Event *e)
387 int i, nb;
389 e->c1 = getec(w, efd);
390 e->c2 = getec(w, efd);
391 e->q0 = geten(w, efd);
392 e->q1 = geten(w, efd);
393 e->flag = geten(w, efd);
394 e->nr = geten(w, efd);
395 if(e->nr > EVENTSIZE)
396 error(w, "event string too long");
397 e->nb = 0;
398 for(i=0; i<e->nr; i++){
399 /* e->r[i] = */ geter(w, efd, e->text+e->nb, &nb);
400 e->nb += nb;
402 /* e->r[e->nr] = 0; */
403 e->text[e->nb] = 0;
404 if(getec(w, efd) != '\n')
405 error(w, "event syntax 2");
408 int
409 winreadevent(Win *w, Event *e)
411 CFid *efd;
412 int r;
414 if((r = setjmp(w->jmp)) != 0){
415 if(r == 1)
416 return 0;
417 return -1;
419 efd = wfid(w, "event");
420 gete(w, efd, e);
421 e->oq0 = e->q0;
422 e->oq1 = e->q1;
424 /* expansion */
425 if(e->flag&2){
426 gete(w, efd, &w->e2);
427 if(e->q0==e->q1){
428 w->e2.oq0 = e->q0;
429 w->e2.oq1 = e->q1;
430 w->e2.flag = e->flag;
431 *e = w->e2;
435 /* chorded argument */
436 if(e->flag&8){
437 gete(w, efd, &w->e3); /* arg */
438 gete(w, efd, &w->e4); /* location */
439 strcpy(e->arg, w->e3.text);
440 strcpy(e->loc, w->e4.text);
443 return 1;
446 int
447 eventfmt(Fmt *fmt)
449 Event *e;
451 e = va_arg(fmt->args, Event*);
452 return fmtprint(fmt, "%c%c %d %d %d %d %q", e->c1, e->c2, e->q0, e->q1, e->flag, e->nr, e->text);
455 void*
456 emalloc(uint n)
458 void *v;
460 v = mallocz(n, 1);
461 if(v == nil)
462 sysfatal("out of memory");
463 return v;
466 void*
467 erealloc(void *v, uint n)
469 v = realloc(v, n);
470 if(v == nil)
471 sysfatal("out of memory");
472 return v;
475 char*
476 estrdup(char *s)
478 if(s == nil)
479 return nil;
480 s = strdup(s);
481 if(s == nil)
482 sysfatal("out of memory");
483 return s;
486 char*
487 evsmprint(char *s, va_list v)
489 s = vsmprint(s, v);
490 if(s == nil)
491 sysfatal("out of memory");
492 return s;
495 int
496 pipewinto(Win *w, char *name, int errto, char *cmd, ...)
498 va_list arg;
499 char *p;
500 int fd[3], pid;
502 va_start(arg, cmd);
503 p = evsmprint(cmd, arg);
504 va_end(arg);
505 fd[0] = winfd(w, name, OREAD);
506 fd[1] = dup(errto, -1);
507 fd[2] = dup(errto, -1);
508 pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
509 free(p);
510 return pid;
513 int
514 pipetowin(Win *w, char *name, int errto, char *cmd, ...)
516 va_list arg;
517 char *p;
518 int fd[3], pid, pfd[2];
519 char buf[1024];
520 int n;
522 /*
523 * cannot use winfd here because of buffering caused
524 * by pipe. program might exit before final write to acme
525 * happens. so we might return before the final write.
527 * to avoid this, we tend the pipe ourselves.
528 */
529 if(pipe(pfd) < 0)
530 sysfatal("pipe: %r");
531 va_start(arg, cmd);
532 p = evsmprint(cmd, arg);
533 va_end(arg);
534 fd[0] = open("/dev/null", OREAD);
535 fd[1] = pfd[1];
536 if(errto == 0)
537 fd[2] = dup(fd[1], -1);
538 else
539 fd[2] = dup(errto, -1);
540 pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
541 free(p);
542 while((n = read(pfd[0], buf, sizeof buf)) > 0)
543 winwrite(w, name, buf, n);
544 close(pfd[0]);
545 return pid;
548 char*
549 sysrun(int errto, char *fmt, ...)
551 static char buf[1024];
552 char *cmd;
553 va_list arg;
554 int n, fd[3], p[2], tot, pid;
556 #undef pipe
557 if(pipe(p) < 0)
558 sysfatal("pipe: %r");
559 fd[0] = open("/dev/null", OREAD);
560 fd[1] = p[1];
561 if(errto == 0)
562 fd[2] = dup(fd[1], -1);
563 else
564 fd[2] = dup(errto, -1);
566 va_start(arg, fmt);
567 cmd = evsmprint(fmt, arg);
568 va_end(arg);
569 pid = threadspawnl(fd, "rc", "rc", "-c", cmd, 0);
571 tot = 0;
572 while((n = read(p[0], buf+tot, sizeof buf-tot)) > 0)
573 tot += n;
574 close(p[0]);
575 twait(pid);
576 if(n < 0)
577 return nil;
578 free(cmd);
579 if(tot == sizeof buf)
580 tot--;
581 buf[tot] = 0;
582 while(tot > 0 && isspace((uchar)buf[tot-1]))
583 tot--;
584 buf[tot] = 0;
585 if(tot == 0){
586 werrstr("no output");
587 return nil;
589 return estrdup(buf);
592 static void
593 eventreader(void *v)
595 Event e[2];
596 Win *w;
597 int i;
599 w = v;
600 i = 0;
601 for(;;){
602 if(winreadevent(w, &e[i]) <= 0)
603 break;
604 sendp(w->c, &e[i]);
605 i = 1-i; /* toggle */
607 sendp(w->c, nil);
608 threadexits(nil);
611 Channel*
612 wineventchan(Win *w)
614 if(w->c == nil){
615 w->c = chancreate(sizeof(Event*), 0);
616 threadcreate(eventreader, w, 32*1024);
618 return w->c;
621 char*
622 wingetname(Win *w)
624 int n;
625 char *p;
627 n = winread(w, "tag", w->name, sizeof w->name-1);
628 if(n <= 0)
629 return nil;
630 w->name[n] = 0;
631 p = strchr(w->name, ' ');
632 if(p)
633 *p = 0;
634 return w->name;