Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <9pclient.h>
5 #include <acme.h>
7 static CFsys *acmefs;
8 static Win *windows;
9 static Win *last;
11 static 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 }
21 Win*
22 newwin(void)
23 {
24 CFid *fid;
25 char buf[100];
26 int id, n;
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);
40 return openwin(id, fid);
41 }
43 Win*
44 openwin(int id, CFid *ctl)
45 {
46 char buf[100];
47 Win *w;
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 }
68 void
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 }
101 void
102 winfree(Win *w)
104 winclosefiles(w);
105 if(w->c){
106 chanfree(w->c);
107 w->c = nil;
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);
120 void
121 windeleteall(void)
123 Win *w, *next;
125 for(w=windows; w; w=next){
126 next = w->next;
127 winctl(w, "delete");
131 static CFid*
132 wfid(Win *w, char *name)
134 char buf[100];
135 CFid **fid;
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);
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);
162 return *fid;
165 int
166 winopenfd(Win *w, char *name, int mode)
168 char buf[100];
170 snprint(buf, sizeof buf, "%d/%s", w->id, name);
171 return fsopenfd(acmefs, buf, mode);
174 int
175 winctl(Win *w, char *fmt, ...)
177 char *s;
178 va_list arg;
179 CFid *fid;
180 int n;
182 va_start(arg, fmt);
183 s = evsmprint(fmt, arg);
184 va_end(arg);
186 fid = wfid(w, "ctl");
187 n = fspwrite(fid, s, strlen(s), 0);
188 free(s);
189 return n;
192 int
193 winname(Win *w, char *fmt, ...)
195 char *s;
196 va_list arg;
197 int n;
199 va_start(arg, fmt);
200 s = evsmprint(fmt, arg);
201 va_end(arg);
203 n = winctl(w, "name %s\n", s);
204 free(s);
205 return n;
208 int
209 winprint(Win *w, char *name, char *fmt, ...)
211 char *s;
212 va_list arg;
213 int n;
215 va_start(arg, fmt);
216 s = evsmprint(fmt, arg);
217 va_end(arg);
219 n = fswrite(wfid(w, name), s, strlen(s));
220 free(s);
221 return n;
224 int
225 winaddr(Win *w, char *fmt, ...)
227 char *s;
228 va_list arg;
229 int n;
231 va_start(arg, fmt);
232 s = evsmprint(fmt, arg);
233 va_end(arg);
235 n = fswrite(wfid(w, "addr"), s, strlen(s));
236 free(s);
237 return n;
240 int
241 winreadaddr(Win *w, uint *q1)
243 char buf[40], *p;
244 uint q0;
245 int n;
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;
257 int
258 winread(Win *w, char *file, void *a, int n)
260 return fsread(wfid(w, file), a, n);
263 int
264 winwrite(Win *w, char *file, void *a, int n)
266 return fswrite(wfid(w, file), a, n);
269 char*
270 winmread(Win *w, char *file)
272 char *buf;
273 int n, tot, m;
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);
285 if(n < 0){
286 free(buf);
287 return nil;
289 buf[tot] = 0;
290 return buf;
293 int
294 winseek(Win *w, char *file, int n, int off)
296 return fsseek(wfid(w, file), n, off);
299 int
300 winwriteevent(Win *w, Event *e)
302 char buf[100];
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));
308 int
309 windel(Win *w, int sure)
311 return winctl(w, sure ? "delete" : "del");
314 int
315 winfd(Win *w, char *name, int mode)
317 char buf[100];
319 snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
320 return fsopenfd(acmefs, buf, mode);
323 static void
324 error(Win *w, char *msg)
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);
332 static int
333 getec(Win *w, CFid *efd)
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;
341 --w->nbuf;
342 return *w->bufp++;
345 static int
346 geten(Win *w, CFid *efd)
348 int n, c;
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;
358 static int
359 geter(Win *w, CFid *efd, char *buf, int *nb)
361 Rune r;
362 int n;
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;
377 static void
378 gete(Win *w, CFid *efd, Event *e)
380 int i, nb;
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;
395 /* e->r[e->nr] = 0; */
396 e->text[e->nb] = 0;
397 if(getec(w, efd) != '\n')
398 error(w, "event syntax 2");
401 int
402 winreadevent(Win *w, Event *e)
404 CFid *efd;
405 int r;
407 if((r = setjmp(w->jmp)) != 0){
408 if(r == 1)
409 return 0;
410 return -1;
412 efd = wfid(w, "event");
413 gete(w, efd, e);
414 e->oq0 = e->q0;
415 e->oq1 = e->q1;
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;
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);
436 return 1;
439 int
440 eventfmt(Fmt *fmt)
442 Event *e;
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);
448 void*
449 emalloc(uint n)
451 void *v;
453 v = mallocz(n, 1);
454 if(v == nil)
455 sysfatal("out of memory");
456 return v;
459 void*
460 erealloc(void *v, uint n)
462 v = realloc(v, n);
463 if(v == nil)
464 sysfatal("out of memory");
465 return v;
468 char*
469 estrdup(char *s)
471 s = strdup(s);
472 if(s == nil)
473 sysfatal("out of memory");
474 return s;
477 char*
478 evsmprint(char *s, va_list v)
480 s = vsmprint(s, v);
481 if(s == nil)
482 sysfatal("out of memory");
483 return s;
486 int
487 pipewinto(Win *w, char *name, int errto, char *cmd, ...)
489 va_list arg;
490 char *p;
491 int fd[3], pid;
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;
504 int
505 pipetowin(Win *w, char *name, int errto, char *cmd, ...)
507 va_list arg;
508 char *p;
509 int fd[3], pid;
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;
525 char*
526 sysrun(char *fmt, ...)
528 static char buf[1025];
529 char *cmd;
530 va_list arg;
531 int n, fd[3], p[2], tot;
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);
540 va_start(arg, fmt);
541 cmd = evsmprint(fmt, arg);
542 va_end(arg);
543 threadspawnl(fd, "rc", "rc", "-Ic", cmd, 0);
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;
562 return buf;
565 static void
566 eventreader(void *v)
568 Event e[2];
569 Win *w;
570 int i;
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 */
580 sendp(w->c, nil);
581 threadexits(nil);
584 Channel*
585 wineventchan(Win *w)
587 if(w->c == nil){
588 w->c = chancreate(sizeof(Event*), 0);
589 threadcreate(eventreader, w, 32*1024);
591 return w->c;