xref: /plan9/sys/src/cmd/page/ps.c (revision 493edcedd7000948aab1393fdf0d530e0e0f539e)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * ps.c
37dd7cddfSDavid du Colombier  *
47dd7cddfSDavid du Colombier  * provide postscript file reading support for page
57dd7cddfSDavid du Colombier  */
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier #include <u.h>
87dd7cddfSDavid du Colombier #include <libc.h>
97dd7cddfSDavid du Colombier #include <draw.h>
107dd7cddfSDavid du Colombier #include <event.h>
117dd7cddfSDavid du Colombier #include <bio.h>
127dd7cddfSDavid du Colombier #include <ctype.h>
137dd7cddfSDavid du Colombier #include "page.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier typedef struct PSInfo	PSInfo;
167dd7cddfSDavid du Colombier typedef struct Page	Page;
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier struct Page {
199a747e4fSDavid du Colombier 	char *name;
207dd7cddfSDavid du Colombier 	int offset;			/* offset of page beginning within file */
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier struct PSInfo {
247dd7cddfSDavid du Colombier 	GSInfo;
257dd7cddfSDavid du Colombier 	Rectangle bbox;	/* default bounding box */
267dd7cddfSDavid du Colombier 	Page *page;
277dd7cddfSDavid du Colombier 	int npage;
287dd7cddfSDavid du Colombier 	int clueless;	/* don't know where page boundaries are */
2980ee5cbfSDavid du Colombier 	long psoff;	/* location of %! in file */
307dd7cddfSDavid du Colombier 	char ctm[256];
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier static int	pswritepage(Document *d, int fd, int page);
347dd7cddfSDavid du Colombier static Image*	psdrawpage(Document *d, int page);
357dd7cddfSDavid du Colombier static char*	pspagename(Document*, int);
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier #define R(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y
387dd7cddfSDavid du Colombier Rectangle
rdbbox(char * p)397dd7cddfSDavid du Colombier rdbbox(char *p)
407dd7cddfSDavid du Colombier {
417dd7cddfSDavid du Colombier 	Rectangle r;
427dd7cddfSDavid du Colombier 	int a;
437dd7cddfSDavid du Colombier 	char *f[4];
447dd7cddfSDavid du Colombier 	while(*p == ':' || *p == ' ' || *p == '\t')
457dd7cddfSDavid du Colombier 		p++;
467dd7cddfSDavid du Colombier 	if(tokenize(p, f, 4) != 4)
477dd7cddfSDavid du Colombier 		return Rect(0,0,0,0);
487dd7cddfSDavid du Colombier 	r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3]));
497dd7cddfSDavid du Colombier 	r = canonrect(r);
507dd7cddfSDavid du Colombier 	if(Dx(r) <= 0 || Dy(r) <= 0)
517dd7cddfSDavid du Colombier 		return Rect(0,0,0,0);
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier 	if(truetoboundingbox)
547dd7cddfSDavid du Colombier 		return r;
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier 	/* initdraw not called yet, can't use %R */
577dd7cddfSDavid du Colombier 	if(chatty) fprint(2, "[%d %d %d %d] -> ", R(r));
587dd7cddfSDavid du Colombier 	/*
597dd7cddfSDavid du Colombier 	 * attempt to sniff out A4, 8½×11, others
607dd7cddfSDavid du Colombier 	 * A4 is 596×842
617dd7cddfSDavid du Colombier 	 * 8½×11 is 612×792
627dd7cddfSDavid du Colombier 	 */
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier 	a = Dx(r)*Dy(r);
659a747e4fSDavid du Colombier 	if(a < 300*300){	/* really small, probably supposed to be */
669a747e4fSDavid du Colombier 		/* empty */
679a747e4fSDavid du Colombier 	} else if(Dx(r) <= 596 && r.max.x <= 596 && Dy(r) > 792 && Dy(r) <= 842 && r.max.y <= 842)	/* A4 */
687dd7cddfSDavid du Colombier 		r = Rect(0, 0, 596, 842);
697dd7cddfSDavid du Colombier 	else {	/* cast up to 8½×11 */
707dd7cddfSDavid du Colombier 		if(Dx(r) <= 612 && r.max.x <= 612){
717dd7cddfSDavid du Colombier 			r.min.x = 0;
727dd7cddfSDavid du Colombier 			r.max.x = 612;
737dd7cddfSDavid du Colombier 		}
747dd7cddfSDavid du Colombier 		if(Dy(r) <= 792 && r.max.y <= 792){
757dd7cddfSDavid du Colombier 			r.min.y = 0;
767dd7cddfSDavid du Colombier 			r.max.y = 792;
777dd7cddfSDavid du Colombier 		}
787dd7cddfSDavid du Colombier 	}
797dd7cddfSDavid du Colombier 	if(chatty) fprint(2, "[%d %d %d %d]\n", R(r));
807dd7cddfSDavid du Colombier 	return r;
817dd7cddfSDavid du Colombier }
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier #define RECT(X) X.min.x, X.min.y, X.max.x, X.max.y
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier int
prefix(char * x,char * y)867dd7cddfSDavid du Colombier prefix(char *x, char *y)
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier 	return strncmp(x, y, strlen(y)) == 0;
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier /*
927dd7cddfSDavid du Colombier  * document ps is really being printed as n-up pages.
937dd7cddfSDavid du Colombier  * we need to treat every n pages as 1.
947dd7cddfSDavid du Colombier  */
957dd7cddfSDavid du Colombier void
repaginate(PSInfo * ps,int n)967dd7cddfSDavid du Colombier repaginate(PSInfo *ps, int n)
977dd7cddfSDavid du Colombier {
987dd7cddfSDavid du Colombier 	int i, np, onp;
997dd7cddfSDavid du Colombier 	Page *page;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 	page = ps->page;
1027dd7cddfSDavid du Colombier 	onp = ps->npage;
1037dd7cddfSDavid du Colombier 	np = (ps->npage+n-1)/n;
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier 	if(chatty) {
1067dd7cddfSDavid du Colombier 		for(i=0; i<=onp+1; i++)
1077dd7cddfSDavid du Colombier 			print("page %d: %d\n", i, page[i].offset);
1087dd7cddfSDavid du Colombier 	}
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier 	for(i=0; i<np; i++)
1117dd7cddfSDavid du Colombier 		page[i] = page[n*i];
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier 	/* trailer */
1147dd7cddfSDavid du Colombier 	page[np] = page[onp];
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 	/* EOF */
1177dd7cddfSDavid du Colombier 	page[np+1] = page[onp+1];
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier 	ps->npage = np;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	if(chatty) {
1227dd7cddfSDavid du Colombier 		for(i=0; i<=np+1; i++)
1237dd7cddfSDavid du Colombier 			print("page %d: %d\n", i, page[i].offset);
1247dd7cddfSDavid du Colombier 	}
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier }
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier Document*
initps(Biobuf * b,int argc,char ** argv,uchar * buf,int nbuf)1297dd7cddfSDavid du Colombier initps(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
1307dd7cddfSDavid du Colombier {
1317dd7cddfSDavid du Colombier 	Document *d;
1327dd7cddfSDavid du Colombier 	PSInfo *ps;
1339a747e4fSDavid du Colombier 	char *p;
1347dd7cddfSDavid du Colombier 	char *q, *r;
1357dd7cddfSDavid du Colombier 	char eol;
1367dd7cddfSDavid du Colombier 	char *nargv[1];
1377dd7cddfSDavid du Colombier 	char fdbuf[20];
1389a747e4fSDavid du Colombier 	char tmp[32];
1397dd7cddfSDavid du Colombier 	int fd;
14080ee5cbfSDavid du Colombier 	int i;
1417dd7cddfSDavid du Colombier 	int incomments;
1427dd7cddfSDavid du Colombier 	int cantranslate;
1437dd7cddfSDavid du Colombier 	int trailer=0;
1447dd7cddfSDavid du Colombier 	int nesting=0;
1457dd7cddfSDavid du Colombier 	int dumb=0;
146d9306527SDavid du Colombier 	int landscape=0;
14780ee5cbfSDavid du Colombier 	long psoff;
1487dd7cddfSDavid du Colombier 	long npage, mpage;
1497dd7cddfSDavid du Colombier 	Page *page;
1507dd7cddfSDavid du Colombier 	Rectangle bbox = Rect(0,0,0,0);
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	if(argc > 1) {
1537dd7cddfSDavid du Colombier 		fprint(2, "can only view one ps file at a time\n");
1547dd7cddfSDavid du Colombier 		return nil;
1557dd7cddfSDavid du Colombier 	}
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	fprint(2, "reading through postscript...\n");
1587dd7cddfSDavid du Colombier 	if(b == nil){	/* standard input; spool to disk (ouch) */
1597dd7cddfSDavid du Colombier 		fd = spooltodisk(buf, nbuf, nil);
1607dd7cddfSDavid du Colombier 		sprint(fdbuf, "/fd/%d", fd);
1617dd7cddfSDavid du Colombier 		b = Bopen(fdbuf, OREAD);
1627dd7cddfSDavid du Colombier 		if(b == nil){
1637dd7cddfSDavid du Colombier 			fprint(2, "cannot open disk spool file\n");
1647dd7cddfSDavid du Colombier 			wexits("Bopen temp");
1657dd7cddfSDavid du Colombier 		}
1667dd7cddfSDavid du Colombier 		nargv[0] = fdbuf;
1677dd7cddfSDavid du Colombier 		argv = nargv;
1687dd7cddfSDavid du Colombier 	}
1697dd7cddfSDavid du Colombier 
17080ee5cbfSDavid du Colombier 	/* find %!, perhaps after PCL nonsense */
1717dd7cddfSDavid du Colombier 	Bseek(b, 0, 0);
17280ee5cbfSDavid du Colombier 	psoff = 0;
17380ee5cbfSDavid du Colombier 	eol = 0;
17480ee5cbfSDavid du Colombier 	for(i=0; i<16; i++){
17580ee5cbfSDavid du Colombier 		psoff = Boffset(b);
1767dd7cddfSDavid du Colombier 		if(!(p = Brdline(b, eol='\n')) && !(p = Brdline(b, eol='\r'))) {
1777dd7cddfSDavid du Colombier 			fprint(2, "cannot find end of first line\n");
1787dd7cddfSDavid du Colombier 			wexits("initps");
1797dd7cddfSDavid du Colombier 		}
18080ee5cbfSDavid du Colombier 		if(p[0]=='\x1B')
18180ee5cbfSDavid du Colombier 			p++, psoff++;
18280ee5cbfSDavid du Colombier 		if(p[0] == '%' && p[1] == '!')
18380ee5cbfSDavid du Colombier 			break;
18480ee5cbfSDavid du Colombier 	}
18580ee5cbfSDavid du Colombier 	if(i == 16){
1867dd7cddfSDavid du Colombier 		werrstr("not ps");
1877dd7cddfSDavid du Colombier 		return nil;
1887dd7cddfSDavid du Colombier 	}
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	/* page counting */
1917dd7cddfSDavid du Colombier 	npage = 0;
1927dd7cddfSDavid du Colombier 	mpage = 16;
1937dd7cddfSDavid du Colombier 	page = emalloc(mpage*sizeof(*page));
1947dd7cddfSDavid du Colombier 	memset(page, 0, mpage*sizeof(*page));
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 	cantranslate = goodps;
1977dd7cddfSDavid du Colombier 	incomments = 1;
1987dd7cddfSDavid du Colombier Keepreading:
1997dd7cddfSDavid du Colombier 	while(p = Brdline(b, eol)) {
2007dd7cddfSDavid du Colombier 		if(p[0] == '%')
201*493edcedSDavid du Colombier 			if(chatty > 1) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p);
2027dd7cddfSDavid du Colombier 		if(npage == mpage) {
2037dd7cddfSDavid du Colombier 			mpage *= 2;
2047dd7cddfSDavid du Colombier 			page = erealloc(page, mpage*sizeof(*page));
2057dd7cddfSDavid du Colombier 			memset(&page[npage], 0, npage*sizeof(*page));
2067dd7cddfSDavid du Colombier 		}
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 		if(p[0] != '%' || p[1] != '%')
2097dd7cddfSDavid du Colombier 			continue;
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 		if(prefix(p, "%%BeginDocument")) {
2127dd7cddfSDavid du Colombier 			nesting++;
2137dd7cddfSDavid du Colombier 			continue;
2147dd7cddfSDavid du Colombier 		}
2157dd7cddfSDavid du Colombier 		if(nesting > 0 && prefix(p, "%%EndDocument")) {
2167dd7cddfSDavid du Colombier 			nesting--;
2177dd7cddfSDavid du Colombier 			continue;
2187dd7cddfSDavid du Colombier 		}
2197dd7cddfSDavid du Colombier 		if(nesting)
2207dd7cddfSDavid du Colombier 			continue;
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 		if(prefix(p, "%%EndComment")) {
2237dd7cddfSDavid du Colombier 			incomments = 0;
2247dd7cddfSDavid du Colombier 			continue;
2257dd7cddfSDavid du Colombier 		}
2267dd7cddfSDavid du Colombier 		if(reverse == -1 && prefix(p, "%%PageOrder")) {
2277dd7cddfSDavid du Colombier 			/* glean whether we should reverse the viewing order */
2287dd7cddfSDavid du Colombier 			p[Blinelen(b)-1] = 0;
2297dd7cddfSDavid du Colombier 			if(strstr(p, "Ascend"))
2307dd7cddfSDavid du Colombier 				reverse = 0;
2317dd7cddfSDavid du Colombier 			else if(strstr(p, "Descend"))
2327dd7cddfSDavid du Colombier 				reverse = 1;
2337dd7cddfSDavid du Colombier 			else if(strstr(p, "Special"))
2347dd7cddfSDavid du Colombier 				dumb = 1;
2357dd7cddfSDavid du Colombier 			p[Blinelen(b)-1] = '\n';
2367dd7cddfSDavid du Colombier 			continue;
2377dd7cddfSDavid du Colombier 		} else if(prefix(p, "%%Trailer")) {
2387dd7cddfSDavid du Colombier 			incomments = 1;
2397dd7cddfSDavid du Colombier 			page[npage].offset = Boffset(b)-Blinelen(b);
2407dd7cddfSDavid du Colombier 			trailer = 1;
2417dd7cddfSDavid du Colombier 			continue;
242d9306527SDavid du Colombier 		} else if(incomments && prefix(p, "%%Orientation")) {
243d9306527SDavid du Colombier 			if(strstr(p, "Landscape"))
244d9306527SDavid du Colombier 				landscape = 1;
2457dd7cddfSDavid du Colombier 		} else if(incomments && Dx(bbox)==0 && prefix(p, q="%%BoundingBox")) {
2467dd7cddfSDavid du Colombier 			bbox = rdbbox(p+strlen(q)+1);
2477dd7cddfSDavid du Colombier 			if(chatty)
2487dd7cddfSDavid du Colombier 				/* can't use %R because haven't initdraw() */
2497dd7cddfSDavid du Colombier 				fprint(2, "document bbox [%d %d %d %d]\n",
2507dd7cddfSDavid du Colombier 					RECT(bbox));
2517dd7cddfSDavid du Colombier 			continue;
2527dd7cddfSDavid du Colombier 		}
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 		/*
2557dd7cddfSDavid du Colombier 		 * If they use the initgraphics command, we can't play our translation tricks.
2567dd7cddfSDavid du Colombier 		 */
2577dd7cddfSDavid du Colombier 		p[Blinelen(b)-1] = 0;
2587dd7cddfSDavid du Colombier 		if((q=strstr(p, "initgraphics")) && ((r=strchr(p, '%'))==nil || r > q))
2597dd7cddfSDavid du Colombier 			cantranslate = 0;
2607dd7cddfSDavid du Colombier 		p[Blinelen(b)-1] = eol;
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier 		if(!prefix(p, "%%Page:"))
2637dd7cddfSDavid du Colombier 			continue;
2647dd7cddfSDavid du Colombier 
2657dd7cddfSDavid du Colombier 		/*
2667dd7cddfSDavid du Colombier 		 * figure out of the %%Page: line contains a page number
2677dd7cddfSDavid du Colombier 		 * or some other page description to use in the menu bar.
2687dd7cddfSDavid du Colombier 		 *
2697dd7cddfSDavid du Colombier 		 * lines look like %%Page: x y or %%Page: x
2707dd7cddfSDavid du Colombier 		 * we prefer just x, and will generate our
2717dd7cddfSDavid du Colombier 		 * own if necessary.
2727dd7cddfSDavid du Colombier 		 */
2737dd7cddfSDavid du Colombier 		p[Blinelen(b)-1] = 0;
2747dd7cddfSDavid du Colombier 		if(chatty) fprint(2, "page %s\n", p);
2757dd7cddfSDavid du Colombier 		r = p+7;
2767dd7cddfSDavid du Colombier 		while(*r == ' ' || *r == '\t')
2777dd7cddfSDavid du Colombier 			r++;
2787dd7cddfSDavid du Colombier 		q = r;
2797dd7cddfSDavid du Colombier 		while(*q && *q != ' ' && *q != '\t')
2807dd7cddfSDavid du Colombier 			q++;
2819a747e4fSDavid du Colombier 		free(page[npage].name);
2827dd7cddfSDavid du Colombier 		if(*r) {
2837dd7cddfSDavid du Colombier 			if(*r == '"' && *q == '"')
2847dd7cddfSDavid du Colombier 				r++, q--;
2857dd7cddfSDavid du Colombier 			if(*q)
2867dd7cddfSDavid du Colombier 				*q = 0;
2879a747e4fSDavid du Colombier 			page[npage].name = estrdup(r);
2887dd7cddfSDavid du Colombier 			*q = 'x';
2899a747e4fSDavid du Colombier 		} else {
2909a747e4fSDavid du Colombier 			snprint(tmp, sizeof tmp, "p %ld", npage+1);
2919a747e4fSDavid du Colombier 			page[npage].name = estrdup(tmp);
2929a747e4fSDavid du Colombier 		}
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier 		/*
2957dd7cddfSDavid du Colombier 		 * store the offset info for later viewing
2967dd7cddfSDavid du Colombier 		 */
2977dd7cddfSDavid du Colombier 		trailer = 0;
2987dd7cddfSDavid du Colombier 		p[Blinelen(b)-1] = eol;
2997dd7cddfSDavid du Colombier 		page[npage++].offset = Boffset(b)-Blinelen(b);
3007dd7cddfSDavid du Colombier 	}
3017dd7cddfSDavid du Colombier 	if(Blinelen(b) > 0){
3027dd7cddfSDavid du Colombier 		fprint(2, "page: linelen %d\n", Blinelen(b));
3037dd7cddfSDavid du Colombier 		Bseek(b, Blinelen(b), 1);
3047dd7cddfSDavid du Colombier 		goto Keepreading;
3057dd7cddfSDavid du Colombier 	}
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier 	if(Dx(bbox) == 0 || Dy(bbox) == 0)
3087dd7cddfSDavid du Colombier 		bbox = Rect(0,0,612,792);	/* 8½×11 */
3097dd7cddfSDavid du Colombier 	/*
3107dd7cddfSDavid du Colombier 	 * if we didn't find any pages, assume the document
3117dd7cddfSDavid du Colombier 	 * is one big page
3127dd7cddfSDavid du Colombier 	 */
3137dd7cddfSDavid du Colombier 	if(npage == 0) {
3147dd7cddfSDavid du Colombier 		dumb = 1;
3157dd7cddfSDavid du Colombier 		if(chatty) fprint(2, "don't know where pages are\n");
3167dd7cddfSDavid du Colombier 		reverse = 0;
3177dd7cddfSDavid du Colombier 		goodps = 0;
3187dd7cddfSDavid du Colombier 		trailer = 0;
3199a747e4fSDavid du Colombier 		page[npage].name = "p 1";
3207dd7cddfSDavid du Colombier 		page[npage++].offset = 0;
3217dd7cddfSDavid du Colombier 	}
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier 	if(npage+2 > mpage) {
3247dd7cddfSDavid du Colombier 		mpage += 2;
3257dd7cddfSDavid du Colombier 		page = erealloc(page, mpage*sizeof(*page));
3267dd7cddfSDavid du Colombier 		memset(&page[mpage-2], 0, 2*sizeof(*page));
3277dd7cddfSDavid du Colombier 	}
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier 	if(!trailer)
3307dd7cddfSDavid du Colombier 		page[npage].offset = Boffset(b);
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	Bseek(b, 0, 2); /* EOF */
3337dd7cddfSDavid du Colombier 	page[npage+1].offset = Boffset(b);
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier 	d = emalloc(sizeof(*d));
3367dd7cddfSDavid du Colombier 	ps = emalloc(sizeof(*ps));
3377dd7cddfSDavid du Colombier 	ps->page = page;
3387dd7cddfSDavid du Colombier 	ps->npage = npage;
3397dd7cddfSDavid du Colombier 	ps->bbox = bbox;
34080ee5cbfSDavid du Colombier 	ps->psoff = psoff;
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 	d->extra = ps;
3437dd7cddfSDavid du Colombier 	d->npage = ps->npage;
3447dd7cddfSDavid du Colombier 	d->b = b;
3457dd7cddfSDavid du Colombier 	d->drawpage = psdrawpage;
3467dd7cddfSDavid du Colombier 	d->pagename = pspagename;
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier 	d->fwdonly = ps->clueless = dumb;
3497dd7cddfSDavid du Colombier 	d->docname = argv[0];
3507dd7cddfSDavid du Colombier 
351593dc095SDavid du Colombier 	if(spawngs(ps, "-dSAFER") < 0)
3527dd7cddfSDavid du Colombier 		return nil;
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 	if(!cantranslate)
3557dd7cddfSDavid du Colombier 		bbox.min = ZP;
356d9306527SDavid du Colombier 	setdim(ps, bbox, ppi, landscape);
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 	if(goodps){
3597dd7cddfSDavid du Colombier 		/*
3607dd7cddfSDavid du Colombier 		 * We want to only send the page (i.e. not header and trailer) information
3617dd7cddfSDavid du Colombier 	 	 * for each page, so initialize the device by sending the header now.
3627dd7cddfSDavid du Colombier 		 */
3637dd7cddfSDavid du Colombier 		pswritepage(d, ps->gsfd, -1);
3647dd7cddfSDavid du Colombier 		waitgs(ps);
3657dd7cddfSDavid du Colombier 	}
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier 	if(dumb) {
3687dd7cddfSDavid du Colombier 		fprint(ps->gsfd, "(%s) run\n", argv[0]);
36980ee5cbfSDavid du Colombier 		fprint(ps->gsfd, "(/fd/3) (w) file dup (THIS IS NOT A PLAN9 BITMAP 01234567890123456789012345678901234567890123456789\\n) writestring flushfile\n");
3707dd7cddfSDavid du Colombier 	}
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	ps->bbox = bbox;
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier 	return d;
3757dd7cddfSDavid du Colombier }
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier static int
pswritepage(Document * d,int fd,int page)3787dd7cddfSDavid du Colombier pswritepage(Document *d, int fd, int page)
3797dd7cddfSDavid du Colombier {
3807dd7cddfSDavid du Colombier 	Biobuf *b = d->b;
3817dd7cddfSDavid du Colombier 	PSInfo *ps = d->extra;
3827dd7cddfSDavid du Colombier 	int t, n, i;
3837dd7cddfSDavid du Colombier 	long begin, end;
3847dd7cddfSDavid du Colombier 	char buf[8192];
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier 	if(page == -1)
38780ee5cbfSDavid du Colombier 		begin = ps->psoff;
3887dd7cddfSDavid du Colombier 	else
3897dd7cddfSDavid du Colombier 		begin = ps->page[page].offset;
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 	end = ps->page[page+1].offset;
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier 	if(chatty) {
3947dd7cddfSDavid du Colombier 		fprint(2, "writepage(%d)... from #%ld to #%ld...\n",
3957dd7cddfSDavid du Colombier 			page, begin, end);
3967dd7cddfSDavid du Colombier 	}
3977dd7cddfSDavid du Colombier 	Bseek(b, begin, 0);
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier 	t = end-begin;
4007dd7cddfSDavid du Colombier 	n = sizeof(buf);
4017dd7cddfSDavid du Colombier 	if(n > t) n = t;
4027dd7cddfSDavid du Colombier 	while(t > 0 && (i=Bread(b, buf, n)) > 0) {
4037dd7cddfSDavid du Colombier 		if(write(fd, buf, i) != i)
4047dd7cddfSDavid du Colombier 			return -1;
4057dd7cddfSDavid du Colombier 		t -= i;
4067dd7cddfSDavid du Colombier 		if(n > t)
4077dd7cddfSDavid du Colombier 			n = t;
4087dd7cddfSDavid du Colombier 	}
4097dd7cddfSDavid du Colombier 	return end-begin;
4107dd7cddfSDavid du Colombier }
4117dd7cddfSDavid du Colombier 
4127dd7cddfSDavid du Colombier static Image*
psdrawpage(Document * d,int page)4137dd7cddfSDavid du Colombier psdrawpage(Document *d, int page)
4147dd7cddfSDavid du Colombier {
4157dd7cddfSDavid du Colombier 	PSInfo *ps = d->extra;
4167dd7cddfSDavid du Colombier 	Image *im;
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 	if(ps->clueless)
4197dd7cddfSDavid du Colombier 		return readimage(display, ps->gsdfd, 0);
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier 	waitgs(ps);
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier 	if(goodps)
4247dd7cddfSDavid du Colombier 		pswritepage(d, ps->gsfd, page);
4257dd7cddfSDavid du Colombier 	else {
4267dd7cddfSDavid du Colombier 		pswritepage(d, ps->gsfd, -1);
4277dd7cddfSDavid du Colombier 		pswritepage(d, ps->gsfd, page);
4287dd7cddfSDavid du Colombier 		pswritepage(d, ps->gsfd, d->npage);
4297dd7cddfSDavid du Colombier 	}
4306b6b9ac8SDavid du Colombier 	/*
4316b6b9ac8SDavid du Colombier 	 * If last line terminator is \r, gs will read ahead to check for \n
4326b6b9ac8SDavid du Colombier 	 * so send one to avoid deadlock.
4336b6b9ac8SDavid du Colombier 	 */
4346b6b9ac8SDavid du Colombier 	write(ps->gsfd, "\n", 1);
4357dd7cddfSDavid du Colombier 	im = readimage(display, ps->gsdfd, 0);
4367dd7cddfSDavid du Colombier 	if(im == nil) {
4377dd7cddfSDavid du Colombier 		fprint(2, "fatal: readimage error %r\n");
4387dd7cddfSDavid du Colombier 		wexits("readimage");
4397dd7cddfSDavid du Colombier 	}
4407dd7cddfSDavid du Colombier 	waitgs(ps);
4417dd7cddfSDavid du Colombier 
4427dd7cddfSDavid du Colombier 	return im;
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier static char*
pspagename(Document * d,int page)4467dd7cddfSDavid du Colombier pspagename(Document *d, int page)
4477dd7cddfSDavid du Colombier {
4487dd7cddfSDavid du Colombier 	PSInfo *ps = (PSInfo *) d->extra;
4497dd7cddfSDavid du Colombier 	return ps->page[page].name;
4507dd7cddfSDavid du Colombier }
451