Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/pptfs/pptfs.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/* pptfs.c     © Steve Simon    2007 */

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>

enum {
	PPTMAGIC	= 0xe391c05f,
	Isdir 		= 0x0f
};

typedef struct {
	vlong base;		// start of record in file
	int cont;		// is 0x0f if its a container
	int opts;		// record options
	int type;		// record type 
	int len;		// length of current record
	int got;		// remaining record data
} Hdr;

typedef struct {
	int num;		// slide number ?
	vlong off;		// file offset
} Blk;

typedef struct {
	int bullet;		// true if lines have bullets
	char allign;		// l=left, r=right, c=center
} Para;

typedef struct {
	char *type;
	int len;
	int off;
} Img;

typedef struct {
	int size;
	void *table;
	int alloc;
	int used;
} Tab;

typedef struct {
	int slide;
	int blip;
} Xref;

Tab Imgtab = { sizeof(Img) };	// Blip Images (in order found)
Tab Blktab = { sizeof(Blk) };	// edited block of slides (sorted by slide ID)
Tab Xreftab = { sizeof(Xref) };	// maps blips to slides

int Slideno = -1;		// current slide number
int Margin = 1;			// am at the margin
int Txtype = -1;		// type of current text (title, body etc)

vlong Start;			// first edited slide chunk
Fmt *Fp;
int Debug = 0;
Biobuf *Bi = nil;

int parse(vlong off, int len, int indent);

typedef struct {
	char *data;
	int len;
} Vfile;

struct {
	char *s;
	int n;
} Types[] = {
	{ "Unknown",			0 },
	{ "Document",			1000 },
	{ "Document Atom",		1001 },
	{ "End Document",		1002 },
	{ "Slide",			1006 },
	{ "Slide Atom",			1007 },
	{ "Notes",			1008 },
	{ "Notes Atom",			1009 },
	{ "Environment",		1010 },
	{ "Slide Persist Atom",		1011 },
	{ "S Slide Layout Atom",	1015 },
	{ "Main Master",		1016 },
	{ "SS Slide Info Atom",		1017 },
	{ "Slide View Info",		1018 },
	{ "Guide Atom",			1019 },
	{ "View Info",			1020 },
	{ "View Info Atom",		1021 },
	{ "Slide View Info Atom",	1022 },
	{ "VBA Info",			1023 },
	{ "VBA Info Atom",		1024 },
	{ "SS Doc Info Atom",		1025 },
	{ "Summary",			1026 },
	{ "Doc Routing Slip",		1030 },
	{ "Outline View Info",		1031 },
	{ "Sorter View Info",		1032 },
	{ "Ex Obj List",		1033 },
	{ "Ex Obj List Atom",		1034 },
	{ "PP Drawing Group",		1035 },
	{ "PP Drawing",			1036 },		// Escher container
	{ "Named Shows",		1040 },
	{ "Named Show",			1041 },
	{ "Named Show Slides",		1042 },
	{ "List",			2000 },
	{ "Font Collection",		2005 },
	{ "Bookmark Collection",	2019 },
	{ "Sound Coll Atom",		2021 },
	{ "Sound",			2022 },
	{ "Sound Data",			2023 },
	{ "Bookmark Seed Atom",		2025 },
	{ "Color Scheme Atom",		2032 },
	{ "Ex Obj Xref Atom",		3009 },
	{ "OE Shape Atom",		3009 },
	{ "OE Placeholder Atom",	3011 },
	{ "G Point Atom",		3024 },
	{ "G Ratio Atom",		3031 },
	{ "Outline Text Xref Atom",	3998 },
	{ "Text Header Atom",		3999 },
	{ "Text Chars Atom",		4000 },
	{ "Style Text Prop Atom",	4001 },
	{ "Base Text Prop Atom",	4002 },
	{ "Tx Master Style Atom",	4003 },
	{ "Tx CF Style Atom",		4004 },
	{ "Tx PF Style Atom",		4005 },
	{ "Text Ruler Atom",		4006 },
	{ "Text Bookmark Atom",		4007 },
	{ "Text Bytes Atom",		4008 },
	{ "Tx SI Style Atom",		4009 },
	{ "Text Spec Info Atom",	4010 },
	{ "Default Ruler Atom",		4011 },
	{ "Font Entity Atom",		4023 },
	{ "Font Embedded Data",		4024 },
	{ "C String",			4026 },
	{ "Meta File",			4033 },
	{ "Ex Ole Obj Atom",		4035 },
	{ "Sr Kinsoku",			4040 },
	{ "Hand Out",			4041 },
	{ "Ex Embed",			4044 },
	{ "Ex Embed Atom",		4045 },
	{ "Ex Link",			4046 },
	{ "Bookmark Entity Atom",	4048 },
	{ "Ex Link Atom",		4049 },
	{ "Sr Kinsoku Atom",		4050 },
	{ "Ex Hyperlink Atom",		4051 },
	{ "Ex Hyperlink",		4055 },
	{ "Slide Number MC Atom",	4056 },
	{ "Headers Footers",		4057 },
	{ "Headers Footers Atom",	4058 },
	{ "Tx Interactive Info Atom",	4063 },
	{ "Char Format Atom",		4066 },
	{ "Para Format Atom",		4067 },
	{ "Recolor Info Atom",		4071 },
	{ "Ex Quick Time Movie",	4074 },
	{ "Ex Quick Time Movie Data",	4075 },
	{ "Ex Control",			4078 },
	{ "Slide List With Text",	4080 },
	{ "Interactive Info",		4082 },
	{ "Interactive Info Atom",	4083 },
	{ "User Edit Atom",		4085 },
	{ "Current User Atom",		4086 },
	{ "Date Time MC Atom",		4087 },
	{ "Generic Date MC Atom",	4088 },
	{ "Footer MC Atom",		4090 },
	{ "Ex Control Atom",		4091 },
	{ "Ex Media Atom",		4100 },
	{ "Ex Video",			4101 },
	{ "Ex Avi Movie",		4102 },
	{ "Ex MCI Movie",		4103 },
	{ "Ex MIDI Audio",		4109 },
	{ "Ex CD Audio",		4110 },
	{ "Ex WAV Audio Embedded",	4111 },
	{ "Ex WAV Audio Link",		4112 },
	{ "Ex Ole Obj Stg",		4113 },
	{ "Ex CD Audio Atom",		4114 },
	{ "Ex WAV Audio Embedded Atom", 4115 },
	{ "Animation Info Atom",	4116 },
	{ "RTF Date Time MC Atom",	4117 },
	{ "Prog Tags",			5000 },
	{ "Prog String Tag",		5001 },
	{ "Prog Binary Tag",		5002 },
	{ "Binary Tag Data",		5003 },
	{ "Print Options",		6000 },
	{ "Persist Ptr Full Block",	6001 },
	{ "Persist Ptr Inc Block",	6002 },
	{ "G Scaling Atom",		10001 },
	{ "GR Color Atom",		10002 },
	{ "Escher Dgg Container",	0xf000 },
	{ "Escher Dgg",			0xf006 },
	{ "Escher CLSID",		0xf016 },
	{ "Escher OPT",			0xf00b },
	{ "Escher BStore Container",	0xf001 },
	{ "Escher BSE",			0xf007 },

	{ "Escher Blip first",		0xf018 },
	{ "Escher Blip unknown",	0xf019 },
	{ "Escher Blip EMF",		0xf01a },
	{ "Escher Blip WMF",		0xf01b },
	{ "Escher Blip PICT",		0xf01c },
	{ "Escher Blip JPEG",		0xf01d },
	{ "Escher Blip PNG",		0xf01e },
	{ "Escher Blip DIB",		0xf01f },
	{ "Escher Blip last",		0xf117 },

	{ "Escher Dg Container",	0xf002 },
	{ "Escher Dg",			0xf008 },
	{ "Escher Regroup Items",	0xf118 },
	{ "Escher Color Scheme",	0xf120 }, /* bug in docs */
	{ "Escher Spgr Container",	0xf003 },
	{ "Escher Sp Container",	0xf004 },
	{ "Escher Spgr",		0xf009 },
	{ "Escher Sp",			0xf00a },
	{ "Escher Textbox",		0xf00c },
	{ "Escher Client Textbox",	0xf00d },
	{ "Escher Anchor",		0xf00e },
	{ "Escher Child Anchor",	0xf00f },
	{ "Escher Client Anchor",	0xf010 },
	{ "Escher Client Data",		0xf011 },
	{ "Escher Solver Container",	0xf005 },
	{ "Escher Connector Rule",	0xf012 } , /* bug in docs */
	{ "Escher Align Rule",		0xf013 },
	{ "Escher Arc Rule",		0xf014 },
	{ "Escher Client Rule",		0xf015 },
	{ "Escher Callout Rule",	0xf017 },
	{ "Escher Selection",		0xf119 },
	{ "Escher Color MRU",		0xf11a },
	{ "Escher Deleted Pspl",	0xf11d } , /* bug in docs */
	{ "Escher Split Menu Colors",	0xf11e },
	{ "Escher Ole Object",		0xf11f },
	{ "Escher User Defined",	0xf122 },
};


void fsread(Req *);

Srv Fs = {
	.read = fsread,
};


void
pr(char *fmt, ...)
{
	va_list args;

	va_start(args, fmt);
	if (Debug)
		vfprint(1, fmt, args);
	fmtvprint(Fp, fmt, args);
	va_end(args);
}

void *
growtab(Tab *t)
{
	if(t->alloc >= t->used){
		t->alloc += 8;
		t->table = realloc(t->table, t->alloc * t->size);
		if(t->table == nil)
			sysfatal("no memory - %r");
	}
	return (char *)t->table + t->used++ * t->size;
}

void *
indextab(Tab *t, int idx)
{
	if (idx < 0 || idx >= t->used)
		return nil;
	return (char *)t->table + idx * t->size;
}
	
int
mkfile(char *name, char *data, int len)
{
	int seq;
	char *p;
	Vfile *vf;
	File *f, *nf;
	char s[128];

	vf = emalloc9p(sizeof(Vfile));
	vf->data = data;
	vf->len = len;

	f = Fs.tree->root;
	incref(f);
	while(f && (p = strchr(name, '/'))) {
		*p = '\0';
		if(strcmp(name, "") != 0 && strcmp(name, ".") != 0){
			/* this would be a race if we were multithreaded */
			incref(f);	/* so walk doesn't kill it immediately on failure */
			if((nf = walkfile(f, name)) == nil)
				nf = createfile(f, name, "bill", DMDIR|0755, nil);
			decref(f);
			f = nf;
		}
		*p = '/';
		name = p+1;
	}
	if(f == nil){
		free(vf->data);
		free(vf);
		return -1;
	}

	incref(f);
	seq = 0;
	snprint(s, sizeof(s), "%s", name);
	while((nf = walkfile(f, s)) != nil){
		f = walkfile(nf, "..");
		snprint(s, sizeof(s), "%s.%d", name, seq++);
	}
	nf = createfile(f, s, "bill", 0644, vf);
	decref(f);
	nf->length = len;
	return 0;
}

char *
rectype(int type)
{
	int i;
	static char buf[32];

	for (i = 0; i < nelem(Types); i++)
		if(type == Types[i].n)
			return Types[i].s;
	snprint(buf, nelem(buf), "0x%x", type);
	return buf;
}

void
sheet(int num, vlong off)
{
	int i;
	Blk *bk;

	for(i = 0; (bk = indextab(&Blktab, i)); i++)
		if(bk->num == num)
			return;
	bk = growtab(&Blktab);
	bk->num = num;
	bk->off = off;
}

int
cmp(void *a, void *b)
{
	return ((Blk *)a)->num - ((Blk *)b)->num;
}

void
xd(Hdr *h)
{
	vlong off;
	uchar buf[16];
	int addr, got, n, i, j;

	addr = 0;
	off = Boffset(Bi);
	while (addr < h->len){
		n = (h->len >= sizeof(buf))? sizeof(buf): h->len;
		got = Bread(Bi, buf, n);

		print("	%6d  ", addr);
		addr += n;

		for (i = 0; i < got; i++)
			print("%02x ", buf[i]);
		for (j = i; j < 16; j++)
			print("   ");
		print("  ");
		for (i = 0; i < got; i++)
			print("%c", isprint(buf[i])? buf[i]: '.');
		print("\n");
	}
	Bseek(Bi, off, 0);
}
	
vlong
gint(Hdr *h, int n)
{
	int i, c;
	uvlong vl, rc;

	assert(n <= h->got);

	rc = 0;
	for (i = 0; i < n; i++){
		if ((c = Bgetc(Bi)) == -1)
			sysfatal("unexpected EOF - %r\n");
		h->got--;
		vl = c;
		rc |= vl << (8*i);
	}
	return rc;
}

static int 
getrec(Hdr *h, int indent)
{
	int c;

	h->base = Boffset(Bi);
	if ((c = Bgetc(Bi)) == -1)
		return -1;		// real EOF
	h->cont = c & 0x0f;
	h->opts = (c >> 4) & 0x0f;
	if ((c = Bgetc(Bi)) == -1)
		sysfatal("unexpected EOF - %r\n");
	h->opts |= c << 4;

	if ((c = Bgetc(Bi)) == -1)
		sysfatal("unexpected EOF - %r\n");
	h->type = c;
	if ((c = Bgetc(Bi)) == -1)
		sysfatal("unexpected EOF - %r\n");
	h->type |= c << 8;

	if ((c = Bgetc(Bi)) == -1)
		sysfatal("unexpected EOF - %r\n");
	h->got = c;
	if ((c = Bgetc(Bi)) == -1)
		sysfatal("unexpected EOF - %r\n");
	h->got |= c << 8;
	if ((c = Bgetc(Bi)) == -1)
		sysfatal("unexpected EOF - %r\n");
	h->got |= c << 16;
	if ((c = Bgetc(Bi)) == -1)
		sysfatal("unexpected EOF - %r\n");
	h->got |= c << 24;
	h->len = h->got +8;

	if (Debug > 1){
		print("%*.3s%s off=%-6lld len=%-6d %d=0x%x=%s\n",
			indent, "", (h->cont == Isdir)? "cont": "atom",
			h->base, h->len+8, h->type, h->type, rectype(h->type));
		if (Debug > 2 && h->cont != Isdir)
			xd(h);
	}

	return 0;
}
	
void
skip(Hdr *h, vlong n)
{
	assert(n <= h->got);
	if (Bseek(Bi, n, 1) == -1)
		sysfatal("seek failed - %r\n");
	h->got -= n;
}

void
putrune(Rune r, int bullet)
{
	static int em = 0;

	if (Margin && bullet && r != L'\r' && r != L'\n'){
		pr("\t• ");
		Margin = 0;
	}

	switch(r){
	case L'\n':
	case L'\r':
		pr("\n");
		Margin = 1;
		break;
	case L'':
		em = 1;
		break;
	case L'':			// FIXME: guesswork
		pr(" ");
		break;
	case L'':
		pr("``");
		break;
	case L'':
		pr("''");
		break;
	case L'�':
		pr("£");
		break;
	case L'':
		if (Debug)
			print("\t");
		fmtprint(Fp, "\t");
		break;
	case L' ':
		if (em)
			pr("'");
		else
			pr(" ");
		em = 0;
		break;
	case 0:			// ignore embedded nulls
		break;
	default:
		pr("%C", r);
		break;
	}
}

void
gmem(Hdr *h, void *v, int n)
{
	assert(n <= h->got);
	if (Bread(Bi, v, n) != n)
		sysfatal("unexpected EOF - %r\n");
	h->got -= n;
}

/**********************************************/

void
textcharsatom(Hdr *h, int bullet)
{
	Rune r;

	Margin = 1;
	do {
		r = Bgetrune(Bi);
		h->got -= runelen(r);
		putrune(r, bullet);
	} while(h->got);
	pr("\n");
}

void
textbytesatom(Hdr *h, int bullet)
{
	int i;
	Rune r;
	char buf[UTFmax];

	Margin = 1;
	do {
		i = Bgetc(Bi);
		buf[0] = i;
		h->got--;
		chartorune(&r, buf);
		putrune(r, bullet);
	} while(h->got);
	pr("\n");
}

void
cstring(Hdr *h, int bullet)
{
	Rune r;

	Margin = 1;
	do {
		r = Bgetrune(Bi);
		h->got -= runelen(r);
		putrune(r, bullet);
	} while(h->got);
	pr("\n");
}

void
persistincrement(Hdr *h)
{
	uint x;
	int i, num, off, first;

	do {
		x = gint(h, 4);
		first = x & 0xfffff;
		num = (x >> 20)&0xfff;
		for(i = 0; i < num; i++){
			off = gint(h, 4);
			sheet(first+i, off);
		}
	} while(h->got);
}

void
useredit(Hdr *h, int indent)
{
	vlong was;
	int lastedit, persistdir;

	skip(h, 4);			// last slide viewed
	skip(h, 4);			// major ver of app
	lastedit  = gint(h, 4);		// previous user edit
	persistdir = gint(h, 4);	// directory
	skip(h, h->got);

 	was = Boffset(Bi);
	if(lastedit)
		parse(lastedit, 0, indent+1);
	if(persistdir)
		parse(persistdir, 0, indent+1);
	Bseek(Bi, was, 0);
}

/*
 * This record is special, it occurs only
 * in the CurrentUser OLE file where it is the sole record.
 * It gives detail of the offset to _start_ walking the UserEdit
 * records from in the main PowerPointDocument OLE file.
 */
void
currentuser(Hdr *h)
{
	int n;
	char *buf;

	skip(h, 4);		// size of this rec
	if(gint(h, 4) != PPTMAGIC)
		sysfatal("bad magic number - not a powerpoint file\n");
	Start = gint(h, 4);
	n = gint(h, 2);		// usr name len
	buf = malloc(n+2);
	skip(h, 4);		// file version
	skip(h, 1);		// app major version
	skip(h, 1);		// app minor version
	gmem(h, buf, n);	// user who edited
	buf[n] = '\n';
	buf[n+1] = 0;
	mkfile("/ppt/author", buf, n+1);
	skip(h, h->got);
}

void
textheaderatom(Hdr *h, int *type)
{
	*type = gint(h, 4);	// text block type
	if(Debug)
		print("#text-type: %d\n", *type);
}

void
blipstoreentry(Hdr *h)
{
	Img *i;
	int m, w;
	char *types[] = {
		"err", "unk", "emf.gz", "wmf.gz",
		"pict.gz", "jpeg", "png", "dbi"
	};


	i = growtab(&Imgtab);

	w = gint(h, 1);
	m = gint(h, 1);
	if (w > 1 && w < nelem(types))
		i->type = types[w];
	else
	if (m >= 0 && m < nelem(types))
		i->type = types[m];
	else
		i->type = "bad";

	skip(h, 16);		// md4 of blip
	skip(h, 2);		// tag (unused)
	i->len = gint(h, 4);
	gint(h, 4);		// ref count (unused ?)
	i->off = gint(h, 4);

	skip(h, h->got);	// don't care about the rest
}

void
slide(Hdr *h)
{
	char places[8];
	int flags, geo, master, id;

	geo = gint(h, 4);		// geometry
	gmem(h, places, sizeof(places));
	master = gint(h, 4);		// master of this slide of 0 if is a master
	id = gint(h, 4);		// id of this slide
	flags = gint(h, 2);		// master follow flags

	if (Debug)
		print("#slide: master-id=%d geo=%d flags=%x id=%d/%x\n",
			master, geo, flags, id, id);
	skip(h, h->got);		// don't care about the rest

	Slideno = id;
}

void
slidepersist(Hdr *h)
{
	int ref, shapes, ntexts, id;

	ref = gint(h, 4);	// slide ref
	shapes = gint(h, 4);	// has shapes
	ntexts = gint(h, 4);	// num texts
	id = gint(h, 4);	// slide ID

	if (Debug)
		print("#slidepersist: ref=%d shapes=%d ntexts=%d id=%d/%x\n",
			ref, shapes, ntexts, id, id);
	skip(h, h->got);	// don't care about the rest

	Slideno = id;
}

void
notes(Hdr *h)
{
	int flags, id;

	id = gint(h, 4);		// slide ID these notes relate to
	flags = gint(h, 2);		// master follow flags

	if (Debug)
		print("#notes: flags=%x id=%d/%x\n", flags, id, id);
	skip(h, h->got);		// don't care about the rest

	Slideno = id;
}

void
escheropt(Hdr *h)
{
	Xref *rf;
	int x, blip, off, val, id;

	off = 0;
	blip = -1;
	do{
		x = gint(h, 2);
		id = x & 0x3fff;
		val = gint(h, 4);
		if(id == 260)
			blip = val;
		if((x & 0x8000) != 0)		// complex value
			off += val;
	}while(h->got >= off+6);

	skip(h, h->got);	// don't care about the rest

	if (blip == -1)		// only uninteresting info
		return;

	rf = growtab(&Xreftab);
	rf->blip = blip;
	rf->slide = Slideno;

	if (Debug)
		print("#escheropt: blip=%d slide=%d\n", blip-1, Slideno);
}

void
pushimage(Hdr *h, char *ext)
{
	int n;
	char *p, buf[64];
	static int blipno = 1;

	skip(h, 16);	// md4 sum of image
	skip(h, 1);	// tag (seems always to be 0xff)

	n = h->got;
	p = emalloc9p(n);
	gmem(h, p, n);

	if (Slideno == 0)
		snprint(buf, sizeof(buf), "/ppt/master/image.%s", ext);
	else
		snprint(buf, sizeof(buf), "/ppt/slide%d/image.%s", Slideno, ext);
	mkfile(buf, p, n);

	if(Debug)
		print("#blip type=%s len=%d\n", ext, n);
}

void
pushtext(int type)
{
	int n;
	char *p, buf[64];
	char *types[] = {
		"title", "body", "notes", "unused", "other",
		"centered-body", "centered-title", "half-body",
		"quater-body"
	};

	p = fmtstrflush(Fp);
	if (p == nil || *p == 0 || type < 0 || type >= nelem(types) || Slideno < 0){
		free(p);
		fmtstrinit(Fp);
		return;
	}
	n = strlen(p);

	if (Slideno == 0)
		snprint(buf, sizeof(buf), "/ppt/master/%s", types[type]);
	else
		snprint(buf, sizeof(buf), "/ppt/slide%d/%s", Slideno, types[type]);
	mkfile(buf, p, n);
	fmtstrinit(Fp);

	if(Debug)
		print("#text name=%s len=%d\n#%s\n", buf, n, p);
}


int
decode(Hdr *h, int indent)
{
	int bullet;
	static int type;

	/*
	- Slide ID is really in the Slide Persist Atom unless the slide is from the
	Template
	- The slide sequence is listed under the latest 1000 record under 4080 and
	the sequence of 1011 shows the list slides ... There is no real Slide
	number that I can find.
	*/

	bullet = (type != 0 && type != 6);
	switch (h->type){
	case 1011:
		slidepersist(h);
		break;
	case 1007:
		slide(h);
		break;
	case 1009:
		notes(h);
		break;
	case 3999:
		textheaderatom(h, &type);
		break;
	case 4000:
		textcharsatom(h, bullet);
		pushtext(type);
		break;
	case 4008:
		textbytesatom(h, bullet);
		pushtext(type);
		break;
	case 4026:
		cstring(h, bullet);
		pushtext(type);
		break;
	case 4085:
		useredit(h, indent+1);
		break;
	case 4086:
		currentuser(h);
		break;
	case 6002:
		persistincrement(h);
		break;
	case 0xf00b:
		escheropt(h);
		break;
	case 0xf01a:
		pushimage(h, "emf.gz");
		break;
	case 0xf01b:
		pushimage(h, "wmf.gz");
		break;
	case 0xf01c:
		pushimage(h, "pict.gz");
		break;
	case 0xf01d:
		pushimage(h, "jpg");
		break;
	case 0xf01e:
		pushimage(h, "png");
		break;
	case 0xf007:
		blipstoreentry(h);
		break;
	default:
		if (h->cont == Isdir)
			return parse(-1, h->len, indent+1) +8;
		skip(h, h->got);
		break;
	}
	return h->len;
}

int
parse(vlong off, int len, int indent)
{
	Hdr h;
	int got;
	
	if (off != -1 && Bseek(Bi, off, 0) != off)
		sysfatal("seek failed");

	got = 0;
	do {
		if(getrec(&h, indent) == -1)
			return -1;
		got += decode(&h, indent);
	} while((len > 0 && got < len-9) || (len == 0 && got < h.got));

	return got;
}

void
fsread(Req *r)
{
	Vfile *vf;
	vlong offset;
	long count;

	vf = r->fid->file->aux;
	offset = r->ifcall.offset;
	count = r->ifcall.count;

	if(offset >= vf->len){
		r->ofcall.count = 0;
		respond(r, nil);
		return;
	}

	if(offset+count >= vf->len)
		count = vf->len - offset;

	memmove(r->ofcall.data, vf->data+offset, count);
	r->ofcall.count = count;
	respond(r, nil);
}


void
usage(void)
{
	fmtprint(Fp, "usage: %s [-ba] [-Dd] [-s srvname] [-m mtpt] [/mnt/doc/Current␣User "
		"/mnt/doc/PowerPoint␣Document /mnt/doc/Pictures]\n", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	Qid q;
	Img *im;
	Blk *bk;
	Xref *rf;
	Fmt fmt;
	int i, j, flags;
	char *current, *document, *pictures, *srvname, *mtpt;

	Fs.tree = alloctree("bill", "trog", DMDIR|0755, nil);
	q = Fs.tree->root->qid;

	Fp = &fmt;
	mtpt = nil;
	flags = 0;
	srvname = nil;
	current="/mnt/doc/Current␣User";
	document="/mnt/doc/PowerPoint␣Document";
	pictures="/mnt/doc/Pictures";
	ARGBEGIN{
	case 'D':
		chatty9p++;
		break;
	case 'd':
		Debug++;
		break;
	case 'b':
		flags |= MBEFORE;
		break;
	case 'a':
		flags |= MAFTER;
		break;
	case 's':
		srvname = EARGF(usage());
		break;
	case 'm':
		mtpt = EARGF(usage());
		break;
	default:
		usage();
	}ARGEND;

	if (argc != 0 && argc != 3)
		usage();

	fmtstrinit(Fp);

	if (Debug)
		print("\nfile=%s\n", current);
	if ((Bi = Bopen(current, OREAD)) == nil)
		sysfatal("%s cannot open\n", current);
	parse(0, 0, 0);
	Bterm(Bi);

	if (Debug)
		print("\nfile=%s\n", document);
	if ((Bi = Bopen(document, OREAD)) == nil)
		sysfatal("%s cannot open\n", document);
	parse(Start, 0, 0);
	qsort(Blktab.table, Blktab.used, Blktab.size, cmp);
	for(i = 0; (bk = indextab(&Blktab, i)); i++)
		parse(bk->off, 0, 0);
	Bterm(Bi);

	if (Debug)
		print("\nfile=%s\n", pictures);
	if ((Bi = Bopen(pictures, OREAD)) != nil){
		for(i = 0; (im = indextab(&Imgtab, i)) != nil; i++)
			for(j = 0; (rf = indextab(&Xreftab, j)) != nil; j++){
				if (rf->blip -1 == i){
					Slideno = rf->slide;
					parse(im->off, 0, 0);
				}
			}
		Bterm(Bi);
	}

	if (mtpt == nil)
		mtpt = "/mnt/doc/";
	if (flags == 0)
		flags = MBEFORE;
	postmountsrv(&Fs, srvname, mtpt, flags);
	exits(0);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.