shithub: livedoc

ref: f7c00c3c004be1ecd8d064f18b5ec065aa21e422
dir: /livedoc.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <plumb.h>

void
usage(void)
{
	fprint(2, "usage: %s [-hqp] [-t sleep] [-m mark]\n", argv0);
	exits("usage");
}

char Enoacme[] = "not in acme";
char Enofile[] = "no file";

typedef struct Winpos Winpos;
struct Winpos {
	long m;
	long n;
};

int winid;
int ctlfd, addrfd, datafd;
int sctlfd, stagfd;
char *stag = nil;
char *file, *filedir, *targetfile;
char *ldpath = "/mnt/livedoc";
char *mark = "·";

int noplumb = 0;

void
runcmd(char *cmd, char **args)
{
	int p[2];
	
	if (pipe(p) < 0)
		sysfatal("runcmd: %r");
	
	switch (fork()) {
	case -1: /* error */
		sysfatal("unable to fork for %s: %r", cmd);
	case 0: /* child */
		chdir(ldpath); /* ramfs call can silently fail */
		dup(p[1], 1);
		close(p[1]);
		close(p[0]);
		exec(cmd, args);
		sysfatal("unable to exec: %r");
	default: /* parent */
		close(p[1]);
		break;
	}
	
	wait();
}

Winpos
finddot(void)
{
	int n;
	Winpos pos;
	char data[25]; /* m[11] space[1] n[11] */
	char *e;
	
	pos.m = pos.n = -1;
	
	fprint(ctlfd, "addr=dot");
	
	n = pread(addrfd, data, 24, 0);
	if (n != 24) {
		werrstr("error reading addr file");
		return pos;
	}
	
	data[24] = 0;
	pos.m = strtol(data, &e, 10);
	pos.n = strtol(e, nil, 10);
	return pos;
}

char *dircpargs[] = {
	"dircp",
	nil,
	"/mnt/livedoc",
	nil,
};

char *cleanargs[] = {
	"rm",
	"-rf",
	"/mnt/livedoc/*",
	nil,
};

void
copydata(void)
{
	dircpargs[1] = filedir;
	
//	runcmd("/bin/rm", cleanargs);
	runcmd("/bin/dircp", dircpargs);
}

void
dumpfile(Winpos pos)
{
	int fd;
	Biobuf *bin, *bout;
	char *s;
	
	fprint(addrfd, "#0,#%ld", pos.m);
	
	fd = open(targetfile, OWRITE);
	if (fd < 0)
		sysfatal("error opening file: %r");
	
	bin = Bfdopen(datafd, OREAD);
	bout = Bfdopen(fd, OWRITE);
	
	while (s = Brdstr(bin, '\n', 0))
		if (Bprint(bout, "%s", s) == -1)
			break;
	
	Bprint(bout, "%s", mark);
	fprint(addrfd, "#%ld,$", pos.m);
	
	while (s = Brdstr(bin, '\n', 0)) {
		if (Bprint(bout, "%s", s) == -1)
			break;
	}
	Bterm(bout);
}

char *mkpdargs[] = {
	"mk",
	"tout",
	nil,
};

int
pagedot(void)
{
	int p[2];
	Biobuf *bin;
	char *s;
	int page, ignore;
	
	if (pipe(p) < 0)
		sysfatal("unable to pipe: %r");
	
	switch (fork()) {
	case -1: /* error */
		sysfatal("unable to fork for pagedot: %r");
	case 0: /* child */
		chdir(ldpath);
		dup(p[1], 1);
		close(p[1]);
		close(p[0]);
		exec("/bin/mk", mkpdargs);
		sysfatal("error: %r");
	default: /* parent */
		close(p[1]);
	}
	
	page = 1;
	ignore = 0;
	bin = Bfdopen(p[0], OREAD);
	while (s = Brdstr(bin, '\n', 1)) {
		if (ignore)
			continue;
		
		if (s[0] == 'p') {
			page = atoi(&s[1]);
		}
		if (strstr(s, mark)) {
			ignore = 1;
		}
		free(s);
	}
	Bterm(bin);
	waitpid();
	
	return ignore ? page : 1;
}

char *mkargs[] = {
	"mk",
	nil,
};

void
compile(void)
{
	runcmd("/bin/mk", mkargs);
}

int round = 0;
char *pdffile = nil;

void
copyfile(void)
{
	char *s;
	int to, from, dirfd;
	int n, l;
	long r;
	Dir *dirs;
	char buf[8192];
	
	dirfd = open(ldpath, OREAD);
	if (dirfd < 0)
		sysfatal("unable to open dir: %r");
	
	s = nil;
	while ((n = dirread(dirfd, &dirs)) > 0) {
		for (int i = 0; i < n; i++) {
			l = strlen(dirs[i].name);
			if (strcmp(&dirs[i].name[l-4], ".pdf") == 0) {
				s = strdup(dirs[i].name);
				free(dirs);
				goto Found;
			}
		}
		free(dirs);
	}
Found: /* s is pdf filename or nil */
	close(dirfd);
	if (!s) {
		fprint(2, "no pdf file found!\n");
		return;
	}
	from = open(s, OREAD);
	if (from < 0)
		sysfatal("cannot open source pdf file: %r");
	free(s);
	
	if (pdffile) {
		remove(pdffile);
		free(pdffile);
		pdffile = nil;
	}
	
	round++;
	
	pdffile = smprint("/tmp/livedoc.%d.pdf", round);
	to = create(pdffile, OWRITE, 0666);
	if (to < 0)
		sysfatal("unable to create file: %r");
	
	seek(from, 0, 0);
	while (r = read(from, buf, sizeof(buf))) {
		if (write(to, buf, r) != r)
			sysfatal("write error");
	}
	
	close(from);
	close(to);
}

void
plumbpage(int page)
{
	char *s;
	int fd;
	
	if (!pdffile)
		return;
	
	if (noplumb) {
		print("%s!%d\n", pdffile, page);
		return;
	}
	
	fd = plumbopen("send", OWRITE|OCEXEC);
	if (fd < 0) {
		fprint(2, "unable to open plumber: %r\n");
		return;
	}
	
	s = smprint("%s!%d", pdffile, page);
	plumbsendtext(fd, "Livedoc", "image", "/tmp", s);
	free(s);
	close(fd);
}

int singlerun = 0;

int
tick(void)
{
	Winpos pos;
	int p;
	int tfd;
	
	/* access(2) doesn't work in this case for some reason */
	tfd = open(stag, OREAD);
	if (tfd < 0) {
		return 0;
	}
	close(tfd);
	
	fprint(sctlfd, "dirty");
	
	copydata();
	pos = finddot();
	dumpfile(pos);
	p = pagedot();
	compile();
	copyfile();
	plumbpage(p);
	
	fprint(sctlfd, "clean");
	
	return !singlerun;
}

char *ramfsargs[] = {
	"ramfs",
	"-m",
	"/mnt/livedoc",
	nil
};

void
main(int argc, char **argv)
{
	char *s, sidstr[13];
	char *winctl, *winaddr, *windata;
	int sleeptimer = 5000;
	int n, sid;
	
	ARGBEGIN{
	case 'h':
		usage();
		return;
	case 't':
		sleeptimer = abs(atoi(EARGF(usage())));
		break;
	case 'm':
		mark = EARGF(usage());
		break;
	case 'p':
		noplumb++;
		break;
	case 'q':
		singlerun++;
		break;
	}ARGEND;
	
	s = getenv("winid");
	if (!s) {
		fprint(2, Enoacme);
		exits(Enoacme);
	}
	winid = atoi(s);
	
	file = getenv("%");
	if (!file) {
		fprint(2, Enofile);
		exits(Enofile);
	}
	
	filedir = strdup(file);
	*strrchr(filedir, '/') = 0;
	
	targetfile = strrchr(file, '/') + 1;
	targetfile = smprint("%s/%s", ldpath, targetfile);
	
	winctl = smprint("/mnt/acme/%d/ctl", winid);
	winaddr = smprint("/mnt/acme/%d/addr", winid);
	windata = smprint("/mnt/acme/%d/xdata", winid);
	
	ctlfd = open(winctl, ORDWR);
	addrfd = open(winaddr, ORDWR);
	datafd = open(windata, OREAD);
	
	free(winctl);
	free(winaddr);
	free(windata);
	
	sctlfd = open("/mnt/acme/new/ctl", ORDWR);
	if (sctlfd < 0)
		sysfatal("unable to open file: %r");
	
	read(sctlfd, sidstr, sizeof(sidstr));
	sid = atoi(sidstr);
	stag = smprint("/mnt/acme/%d/tag", sid);
	stagfd = open(stag, ORDWR);
	
	fprint(sctlfd, "scratch\n");
	fprint(sctlfd, "name %s/-Livedoc\n", filedir);
	
	if (ctlfd < 0 || addrfd < 0 || datafd < 0) {
		sysfatal("unable to open file: %r");
	}
	
	runcmd("/bin/ramfs", ramfsargs);
	
	n = 0;
	while (tick() && n != -1)
		n = sleep(sleeptimer);
	
	if (pdffile) {
		remove(pdffile);
		free(pdffile);
	}
	
	close(ctlfd);
	close(addrfd);
	close(datafd);
	free(filedir);
	free(targetfile);
	free(stag);
	exits(nil);
}