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 void12 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 else63 windows = w;64 last = w;65 return w;66 }68 void69 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 void102 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 else112 last = w->prev;113 if(w->prev)114 w->prev->next = w->next;115 else116 windows = w->next;117 free(w);118 }120 void121 windeleteall(void)122 {123 Win *w, *next;125 for(w=windows; w; w=next){126 next = w->next;127 winctl(w, "delete");128 }129 }131 static CFid*132 wfid(Win *w, char *name)133 {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);154 }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 }165 int166 winopenfd(Win *w, char *name, int mode)167 {168 char buf[100];170 snprint(buf, sizeof buf, "%d/%s", w->id, name);171 return fsopenfd(acmefs, buf, mode);172 }174 int175 winctl(Win *w, char *fmt, ...)176 {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;190 }192 int193 winname(Win *w, char *fmt, ...)194 {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;206 }208 int209 winprint(Win *w, char *name, char *fmt, ...)210 {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;222 }224 int225 winaddr(Win *w, char *fmt, ...)226 {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;238 }240 int241 winreadaddr(Win *w, uint *q1)242 {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;255 }257 int258 winread(Win *w, char *file, void *a, int n)259 {260 return fsread(wfid(w, file), a, n);261 }263 int264 winwrite(Win *w, char *file, void *a, int n)265 {266 return fswrite(wfid(w, file), a, n);267 }269 char*270 winmread(Win *w, char *file)271 {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);283 }284 }285 if(n < 0){286 free(buf);287 return nil;288 }289 buf[tot] = 0;290 return buf;291 }293 int294 winseek(Win *w, char *file, int n, int off)295 {296 return fsseek(wfid(w, file), n, off);297 }299 int300 winwriteevent(Win *w, Event *e)301 {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));306 }308 int309 windel(Win *w, int sure)310 {311 return winctl(w, sure ? "delete" : "del");312 }314 int315 winfd(Win *w, char *name, int mode)316 {317 char buf[100];319 snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);320 return fsopenfd(acmefs, buf, mode);321 }323 static void324 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 }332 static int333 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 }345 static int346 geten(Win *w, CFid *efd)347 {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;356 }358 static int359 geter(Win *w, CFid *efd, char *buf, int *nb)360 {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;375 }377 static void378 gete(Win *w, CFid *efd, Event *e)379 {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;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 }401 int402 winreadevent(Win *w, Event *e)403 {404 CFid *efd;405 int r;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;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 }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 }436 return 1;437 }439 int440 eventfmt(Fmt *fmt)441 {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);446 }448 void*449 emalloc(uint n)450 {451 void *v;453 v = mallocz(n, 1);454 if(v == nil)455 sysfatal("out of memory");456 return v;457 }459 void*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 }468 char*469 estrdup(char *s)470 {471 s = strdup(s);472 if(s == nil)473 sysfatal("out of memory");474 return s;475 }477 char*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 }486 int487 pipewinto(Win *w, char *name, int errto, char *cmd, ...)488 {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;502 }504 int505 pipetowin(Win *w, char *name, int errto, char *cmd, ...)506 {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 else519 fd[2] = dup(errto, -1);520 pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);521 free(p);522 return pid;523 }525 char*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;533 #undef pipe534 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;561 }562 return buf;563 }565 static void566 eventreader(void *v)567 {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 */579 }580 sendp(w->c, nil);581 threadexits(nil);582 }584 Channel*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 }