acme.c (9641B)
1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include <9pclient.h> 5 #include "acme.h" 6 7 extern int *xxx; 8 static CFsys *acmefs; 9 Win *windows; 10 static Win *last; 11 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 } 21 22 Win* 23 newwin(void) 24 { 25 Win *w; 26 CFid *fid; 27 char buf[100]; 28 int id, n; 29 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); 41 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 } 54 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 } 87 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); 105 } 106 107 void 108 windeleteall(void) 109 { 110 Win *w, *next; 111 112 for(w=windows; w; w=next){ 113 next = w->next; 114 winctl(w, "delete"); 115 } 116 } 117 118 static CFid* 119 wfid(Win *w, char *name) 120 { 121 char buf[100]; 122 CFid **fid; 123 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 } 142 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 } 151 152 int 153 winopenfd(Win *w, char *name, int mode) 154 { 155 char buf[100]; 156 157 snprint(buf, sizeof buf, "%d/%s", w->id, name); 158 return fsopenfd(acmefs, buf, mode); 159 } 160 161 int 162 winctl(Win *w, char *fmt, ...) 163 { 164 char *s; 165 va_list arg; 166 CFid *fid; 167 int n; 168 169 va_start(arg, fmt); 170 s = evsmprint(fmt, arg); 171 va_end(arg); 172 173 fid = wfid(w, "ctl"); 174 n = fspwrite(fid, s, strlen(s), 0); 175 free(s); 176 return n; 177 } 178 179 int 180 winname(Win *w, char *fmt, ...) 181 { 182 char *s; 183 va_list arg; 184 int n; 185 186 va_start(arg, fmt); 187 s = evsmprint(fmt, arg); 188 va_end(arg); 189 190 n = winctl(w, "name %s\n", s); 191 free(s); 192 return n; 193 } 194 195 int 196 winprint(Win *w, char *name, char *fmt, ...) 197 { 198 char *s; 199 va_list arg; 200 int n; 201 202 va_start(arg, fmt); 203 s = evsmprint(fmt, arg); 204 va_end(arg); 205 206 n = fswrite(wfid(w, name), s, strlen(s)); 207 free(s); 208 return n; 209 } 210 211 int 212 winaddr(Win *w, char *fmt, ...) 213 { 214 char *s; 215 va_list arg; 216 int n; 217 218 va_start(arg, fmt); 219 s = evsmprint(fmt, arg); 220 va_end(arg); 221 222 n = fswrite(wfid(w, "addr"), s, strlen(s)); 223 free(s); 224 return n; 225 } 226 227 int 228 winreadaddr(Win *w, uint *q1) 229 { 230 char buf[40], *p; 231 uint q0; 232 int n; 233 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 } 243 244 int 245 winread(Win *w, char *file, void *a, int n) 246 { 247 return fspread(wfid(w, file), a, n, 0); 248 } 249 250 int 251 winwrite(Win *w, char *file, void *a, int n) 252 { 253 return fswrite(wfid(w, file), a, n); 254 } 255 256 char* 257 fsreadm(CFid *fid) 258 { 259 char *buf; 260 int n, tot, m; 261 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 } 279 280 char* 281 winmread(Win *w, char *file) 282 { 283 return fsreadm(wfid(w, file)); 284 } 285 286 char* 287 winindex(void) 288 { 289 CFid *fid; 290 char *s; 291 292 mountacme(); 293 if((fid = fsopen(acmefs, "index", OREAD)) == nil) 294 return nil; 295 s = fsreadm(fid); 296 fsclose(fid); 297 return s; 298 } 299 300 int 301 winseek(Win *w, char *file, int n, int off) 302 { 303 return fsseek(wfid(w, file), n, off); 304 } 305 306 int 307 winwriteevent(Win *w, Event *e) 308 { 309 char buf[100]; 310 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 } 314 315 int 316 windel(Win *w, int sure) 317 { 318 return winctl(w, sure ? "delete" : "del"); 319 } 320 321 int 322 winfd(Win *w, char *name, int mode) 323 { 324 char buf[100]; 325 326 snprint(buf, sizeof buf, "acme/%d/%s", w->id, name); 327 return fsopenfd(acmefs, buf, mode); 328 } 329 330 static void 331 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 } 338 339 static int 340 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 } 351 352 static int 353 geten(Win *w, CFid *efd) 354 { 355 int n, c; 356 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 } 364 365 static int 366 geter(Win *w, CFid *efd, char *buf, int *nb) 367 { 368 Rune r; 369 int n; 370 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 } 383 384 static void 385 gete(Win *w, CFid *efd, Event *e) 386 { 387 int i, nb; 388 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 } 407 408 int 409 winreadevent(Win *w, Event *e) 410 { 411 CFid *efd; 412 int r; 413 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; 423 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 } 434 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 } 442 443 return 1; 444 } 445 446 int 447 eventfmt(Fmt *fmt) 448 { 449 Event *e; 450 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 } 454 455 void* 456 emalloc(uint n) 457 { 458 void *v; 459 460 v = mallocz(n, 1); 461 if(v == nil) 462 sysfatal("out of memory"); 463 return v; 464 } 465 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 } 474 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 } 485 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 } 494 495 int 496 pipewinto(Win *w, char *name, int errto, char *cmd, ...) 497 { 498 va_list arg; 499 char *p; 500 int fd[3], pid; 501 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 } 512 513 int 514 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; 521 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. 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 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; 546 } 547 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; 555 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); 565 566 va_start(arg, fmt); 567 cmd = evsmprint(fmt, arg); 568 va_end(arg); 569 pid = threadspawnl(fd, "rc", "rc", "-c", cmd, 0); 570 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; 588 } 589 return estrdup(buf); 590 } 591 592 static void 593 eventreader(void *v) 594 { 595 Event e[2]; 596 Win *w; 597 int i; 598 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 } 610 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 } 620 621 char* 622 wingetname(Win *w) 623 { 624 int n; 625 char *p; 626 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 }