shithub: aplenty

ref: e173b7ee0d3c26b54531c287d68aac00ec50f199
dir: /aplenty.c/

View raw version
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include <bio.h>
#include <json.h>
#include <regexp.h>

int debug;
vlong caddr;

void
handlerideevents(int in, int out, int text){
	Biobuf *bin;
	char *b, k;   /* event buffer, kind */
	long t, n, o; /*       type, length, offset */

	bin = Bfdopen(in, OREAD);
	while(b = Brdline(bin, '\n')){
		Bseek(bin, Blinelen(bin), 1);
		k = b[0]; b++;
		t = atol(strtok(b, " \n"));
		n = atol(strtok(nil, " \n"));
		o = atol(b = strtok(nil, " \n"));
		for(; *b != '\0'; b++); b++;
		if(debug > 1)
			fprintf(stderr, "ride: %c %ld %ld %ld %s\n", k, t, n, o);

		if(k == 'p')
			write(out, b, n);

		if(k == 'o' && t != 14){ /* ignore echoed input */
			b = malloc(n);
			pread(text, b, n, o);
			write(out, b, n);
			free(b);
		}
	}
}

void
handlerootevents(int wid, int in, int out){
	Biobuf *bin, *bxdata, *btag;
	int fdevent, fdaddr, fdbody;
	char o, t;        /* event origin, type */
	long n, m, f, l;  /*       addr n, addr m, flag, len */
	Rune *r;          /*       runes */
	long c;
	char *ln, s[256];
	int i;

	/* setup files */
	snprintf(s, sizeof(s), "/mnt/acme/%i", wid);
	chdir(s);
	fdevent = open("event", OWRITE);
	fdaddr  = open("addr", ORDWR);
	fdbody  = open("body", OWRITE);
	bin     = Bfdopen(in, OREAD);
	rerrstr(s, sizeof(s));
	if(s[0] != 0)
		exits(s);

	/* initial prompt not setup by ride */
	write(fdbody, "      ", 6);

	/* event handle loop: cf acme(4):/event */
	r = malloc((2+4*12 + 256)*sizeof(*r));
	while((o = Bgetc(bin)) != EOF){
		t = Bgetc(bin);
		n = atol(Brdline(bin, ' '));
		m = atol(Brdline(bin, ' '));
		f = atol(Brdline(bin, ' '));
		l = atol(Brdline(bin, ' '));
		for(i = 0; i < l+1; i++) /* trailing LF not counted by l */
			Bgetrune(bin);
		if(debug > 1)
			fprintf(stderr, "acme: %c%c%ld %ld %ld %ld\n", o, t, n , m, f, l);

		/* Ride-triggered edits */
		if(o == 'E'){
			write(fdaddr, "$-/^/", 5);
			pread(fdaddr, s, 12, 0);
			n = atol(strtok(s, " "));
			caddr = n;
			continue;
		}

		/* trailing text may be elided; read canonical source */
		if(!strchr("Dd", t)){
			fprint(fdaddr, "#%ld,#%ld", n, m);
			if(strchr("ILX", t)){
				bxdata = Bopen("xdata", OREAD);
				for(i = 0, c = Bgetrune(bxdata); c >= 0; i++, c = Bgetrune(bxdata))
					r[i] = c;
				Bterm(bxdata);
			} else if(strchr("ilx", t)) {
				btag = Bopen("tag", OREAD);
				for(i = 0, c = Bgetrune(btag); c >= 0; i++, c = Bgetrune(btag))
					r[i] = c;
				Bterm(btag);
			}
			r[i] = t == 'X' ? '\n' : 0;
	
			/* XXX: Only execute first line if multiline input */
			if(t == 'I' && n >= caddr || t == 'X'){
				fprint(fdaddr, "#%lld,#%ld", caddr, m);
				bxdata  = Bopen("xdata", OREAD);
				ln = Brdline(bxdata, '\n');
				if(ln){
					write(out, ln, Blinelen(bxdata));
					write(fdaddr, "$-/^/", 5);
					pread(fdaddr, s, 12, 0);
					n = atol(strtok(s, " "));
					caddr = n;
				}
				Bterm(bxdata);
			}
		}

		if(strchr("ID", t))
		if((t == 'D') + m < caddr)
			caddr += t == 'D' ? n-m : m-n;

		if(f%2 == 0 && strchr("Lidlx", t))
			fprint(fdevent, "%c%c%ld %ld\n", o, t, n, m);
	}
}

char*
errmsg(char *err){
	if(err == nil){
		err = malloc(ERRMAX);
		rerrstr(err, ERRMAX);
	}
	fprintf(stderr, "%s\n", err);
	return err;
}

void
usage(void){
	fprintf(stderr, "Usage: %s [-d] addr\n", argv0);
}

void
main(int argc, char **argv){
	char *err, *addr, b[256], p[256];
	int rid, rctl, rin, rout, rtext; /* ride */
	int wid, wctl, win, wout; /* root window */

	if(argc < 1){
		usage();
		exits("requires address argument");
	}

	ARGBEGIN{
	case 'd': debug++; break;
	case 'h': usage(); exits(nil);
	}ARGEND

	if(argc == 0)
		addr = getenv("rideaddr");
	else
		addr = argv[0];
	if(addr == nil){
		usage();
		exits(errmsg("no ride address"));
	}

	err = nil;

	/* new ride connection */
	if((rctl = open("/mnt/ride/clone", ORDWR)) < 0)
		exits(errmsg(err));
	sprintf(b, "connect %s\n", addr);
	write(rctl, b, strlen(b));

	/* connection id */
	pread(rctl, b, sizeof(b), 0);
	sprintf(p, "\n");
	rid = atoi(strtok(b, p));

	/* establish connection */
	snprintf(p, sizeof(p), "/mnt/ride/%i/text", rid);
	if((rout = open(p, OWRITE)) < 0)
		exits(errmsg(err));
	if((rtext = open(p, OREAD)) < 0)
		exits(errmsg(err));

	/* ride i/o files */
	snprintf(p, sizeof(p), "/mnt/ride/%i/event", rid);
	if((rin = open(p, OREAD)) < 0)
		exits(errmsg(err));

	/* new acme window */
	if((wctl = open("/mnt/acme/new/ctl", OREAD)) < 0)
		exits(errmsg(err));
	readn(wctl, b, 12);
	wid = atoi(strtok(b, " "));

	/* window i/o files */
	snprintf(p, sizeof(p), "/mnt/acme/%i/event", wid);
	if((win = open(p, OREAD)) < 0)
		exits(errmsg(err));
	snprintf(p, sizeof(p), "/mnt/acme/%i/body", wid);
	if((wout = open(p, OWRITE)) < 0)
		exits(errmsg(err));

	JSONfmtinstall();

	rfork(RFNOTEG);

	switch(rfork(RFPROC|RFMEM)){
	case -1: err = "unable to start ride message handler"; break;
	case 0:
		handlerideevents(rin, wout, rtext);
		exits(nil);
	default: break;
	}

	switch(rfork(RFPROC|RFMEM)){
	case -1: err = "unable to start root window event handler"; break;
	case 0:
		handlerootevents(wid, win, rout);
		exits(nil);
	default: break;
	}

	wait();
	postnote(PNGROUP, getpid(), "exit");

	exits(errmsg(err));
}