blob: 8904b4c20e2dc84364868ddab5e1076617cd6839 [file] [log] [blame]
rscf3b8bf72006-05-25 06:25:28 +00001#include <u.h>
2#include <libc.h>
3#include <thread.h>
4#include <9pclient.h>
5#include <acme.h>
6
7static CFsys *acmefs;
8static Win *windows;
9static Win *last;
10
11static void
12mountacme(void)
13{
14 if(acmefs == nil){
15 acmefs = nsmount("acme", nil);
16 if(acmefs == nil)
17 sysfatal("cannot mount acme: %r");
18 }
19}
20
21Win*
22newwin(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
43Win*
44openwin(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
68void
69winclosefiles(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
101void
102winfree(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
120void
121windeleteall(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
131static CFid*
132wfid(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
165int
166winopenfd(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
174int
175winctl(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
192int
193winname(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
208int
209winprint(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
224int
225winaddr(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
240int
241winreadaddr(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
257int
258winread(Win *w, char *file, void *a, int n)
259{
260 return fsread(wfid(w, file), a, n);
261}
262
263int
264winwrite(Win *w, char *file, void *a, int n)
265{
266 return fswrite(wfid(w, file), a, n);
267}
268
269char*
270winmread(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
293int
294winseek(Win *w, char *file, int n, int off)
295{
296 return fsseek(wfid(w, file), n, off);
297}
298
299int
300winwriteevent(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
308int
309windel(Win *w, int sure)
310{
311 return winctl(w, sure ? "delete" : "del");
312}
313
314int
315winfd(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
323static void
324error(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
332static int
333getec(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
345static int
346geten(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
358static int
359geter(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
377static void
378gete(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
401int
402winreadevent(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);
rsce074ed02006-06-25 23:52:41 +0000414 e->oq0 = e->q0;
415 e->oq1 = e->q1;
rscf3b8bf72006-05-25 06:25:28 +0000416
417 /* expansion */
418 if(e->flag&2){
419 gete(w, efd, &w->e2);
420 if(e->q0==e->q1){
rsce074ed02006-06-25 23:52:41 +0000421 w->e2.oq0 = e->q0;
422 w->e2.oq1 = e->q1;
rscf3b8bf72006-05-25 06:25:28 +0000423 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
439int
440eventfmt(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
448void*
449emalloc(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
459void*
460erealloc(void *v, uint n)
461{
462 v = realloc(v, n);
463 if(v == nil)
464 sysfatal("out of memory");
465 return v;
466}
467
468char*
469estrdup(char *s)
470{
471 s = strdup(s);
472 if(s == nil)
473 sysfatal("out of memory");
474 return s;
475}
476
477char*
478evsmprint(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
486int
487pipewinto(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
504int
505pipetowin(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
525char*
526sysrun(char *fmt, ...)
527{
rsce074ed02006-06-25 23:52:41 +0000528 static char buf[1025];
rscf3b8bf72006-05-25 06:25:28 +0000529 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
565static void
566eventreader(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
584Channel*
585wineventchan(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}