acme.c (8924B)
1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include <9pclient.h> 5 #include <acme.h> 6 7 static CFsys *acmefs; 8 static Win *windows; 9 static Win *last; 10 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 } 20 21 Win* 22 newwin(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 43 Win* 44 openwin(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 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 } 100 101 void 102 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 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 120 void 121 windeleteall(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 131 static CFid* 132 wfid(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 165 int 166 winopenfd(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 174 int 175 winctl(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 192 int 193 winname(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 208 int 209 winprint(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 224 int 225 winaddr(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 240 int 241 winreadaddr(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 257 int 258 winread(Win *w, char *file, void *a, int n) 259 { 260 return fsread(wfid(w, file), a, n); 261 } 262 263 int 264 winwrite(Win *w, char *file, void *a, int n) 265 { 266 return fswrite(wfid(w, file), a, n); 267 } 268 269 char* 270 winmread(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 293 int 294 winseek(Win *w, char *file, int n, int off) 295 { 296 return fsseek(wfid(w, file), n, off); 297 } 298 299 int 300 winwriteevent(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 308 int 309 windel(Win *w, int sure) 310 { 311 return winctl(w, sure ? "delete" : "del"); 312 } 313 314 int 315 winfd(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 323 static void 324 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 } 331 332 static int 333 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 } 344 345 static int 346 geten(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 358 static int 359 geter(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 377 static void 378 gete(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 401 int 402 winreadevent(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); 414 e->oq0 = e->q0; 415 e->oq1 = e->q1; 416 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 } 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 439 int 440 eventfmt(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 448 void* 449 emalloc(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 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 } 467 468 char* 469 estrdup(char *s) 470 { 471 s = strdup(s); 472 if(s == nil) 473 sysfatal("out of memory"); 474 return s; 475 } 476 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 } 485 486 int 487 pipewinto(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 504 int 505 pipetowin(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 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; 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 565 static void 566 eventreader(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 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 }