ref: f7c00c3c004be1ecd8d064f18b5ec065aa21e422
dir: /livedoc.c/
#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);
}