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 void13 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 else50 windows = w;51 last = w;52 return w;53 }55 void56 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 void89 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 else99 last = w->prev;100 if(w->prev)101 w->prev->next = w->next;102 else103 windows = w->next;104 free(w);105 }107 void108 windeleteall(void)109 {110 Win *w, *next;112 for(w=windows; w; w=next){113 next = w->next;114 winctl(w, "delete");115 }116 }118 static CFid*119 wfid(Win *w, char *name)120 {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);141 }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);148 }149 return *fid;150 }152 int153 winopenfd(Win *w, char *name, int mode)154 {155 char buf[100];157 snprint(buf, sizeof buf, "%d/%s", w->id, name);158 return fsopenfd(acmefs, buf, mode);159 }161 int162 winctl(Win *w, char *fmt, ...)163 {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;177 }179 int180 winname(Win *w, char *fmt, ...)181 {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;193 }195 int196 winprint(Win *w, char *name, char *fmt, ...)197 {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;209 }211 int212 winaddr(Win *w, char *fmt, ...)213 {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;225 }227 int228 winreadaddr(Win *w, uint *q1)229 {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;242 }244 int245 winread(Win *w, char *file, void *a, int n)246 {247 return fspread(wfid(w, file), a, n, 0);248 }250 int251 winwrite(Win *w, char *file, void *a, int n)252 {253 return fswrite(wfid(w, file), a, n);254 }256 char*257 fsreadm(CFid *fid)258 {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);270 }271 }272 if(n < 0){273 free(buf);274 return nil;275 }276 buf[tot] = 0;277 return buf;278 }280 char*281 winmread(Win *w, char *file)282 {283 return fsreadm(wfid(w, file));284 }286 char*287 winindex(void)288 {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;298 }300 int301 winseek(Win *w, char *file, int n, int off)302 {303 return fsseek(wfid(w, file), n, off);304 }306 int307 winwriteevent(Win *w, Event *e)308 {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));313 }315 int316 windel(Win *w, int sure)317 {318 return winctl(w, sure ? "delete" : "del");319 }321 int322 winfd(Win *w, char *name, int mode)323 {324 char buf[100];326 snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);327 return fsopenfd(acmefs, buf, mode);328 }330 static void331 error(Win *w, char *msg)332 {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);337 }339 static int340 getec(Win *w, CFid *efd)341 {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;347 }348 --w->nbuf;349 return *w->bufp++;350 }352 static int353 geten(Win *w, CFid *efd)354 {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;363 }365 static int366 geter(Win *w, CFid *efd, char *buf, int *nb)367 {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;382 }384 static void385 gete(Win *w, CFid *efd, Event *e)386 {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;401 }402 /* e->r[e->nr] = 0; */403 e->text[e->nb] = 0;404 if(getec(w, efd) != '\n')405 error(w, "event syntax 2");406 }408 int409 winreadevent(Win *w, Event *e)410 {411 CFid *efd;412 int r;414 if((r = setjmp(w->jmp)) != 0){415 if(r == 1)416 return 0;417 return -1;418 }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;432 }433 }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);441 }443 return 1;444 }446 int447 eventfmt(Fmt *fmt)448 {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);453 }455 void*456 emalloc(uint n)457 {458 void *v;460 v = mallocz(n, 1);461 if(v == nil)462 sysfatal("out of memory");463 return v;464 }466 void*467 erealloc(void *v, uint n)468 {469 v = realloc(v, n);470 if(v == nil)471 sysfatal("out of memory");472 return v;473 }475 char*476 estrdup(char *s)477 {478 if(s == nil)479 return nil;480 s = strdup(s);481 if(s == nil)482 sysfatal("out of memory");483 return s;484 }486 char*487 evsmprint(char *s, va_list v)488 {489 s = vsmprint(s, v);490 if(s == nil)491 sysfatal("out of memory");492 return s;493 }495 int496 pipewinto(Win *w, char *name, int errto, char *cmd, ...)497 {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;511 }513 int514 pipetowin(Win *w, char *name, int errto, char *cmd, ...)515 {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 caused524 * by pipe. program might exit before final write to acme525 * happens. so we might return before the final write.526 *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 else539 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;546 }548 char*549 sysrun(int errto, char *fmt, ...)550 {551 static char buf[1024];552 char *cmd;553 va_list arg;554 int n, fd[3], p[2], tot, pid;556 #undef pipe557 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 else564 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(buf[tot-1]))583 tot--;584 buf[tot] = 0;585 if(tot == 0){586 werrstr("no output");587 return nil;588 }589 return estrdup(buf);590 }592 static void593 eventreader(void *v)594 {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 */606 }607 sendp(w->c, nil);608 threadexits(nil);609 }611 Channel*612 wineventchan(Win *w)613 {614 if(w->c == nil){615 w->c = chancreate(sizeof(Event*), 0);616 threadcreate(eventreader, w, 32*1024);617 }618 return w->c;619 }621 char*622 wingetname(Win *w)623 {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;635 }