plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }