plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

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 }