aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/postscript/tr2post/ps_include.c
blob: 8ab840fea35da9d0e8e339837e1988c3cecfb1da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <stdio.h>
#include "../common/common.h"
#include "ps_include.h"

extern int curpostfontid;
extern int curfontsize;

typedef struct {long start, end;} Section;
static char *buf;

static void
copy(Biobuf *fin, Biobuf *fout, Section *s) {
	if (s->end <= s->start)
		return;
	Bseek(fin, s->start, 0);
	while (Bseek(fin, 0L, 1) < s->end && (buf=Brdline(fin, '\n')) != NULL){
		/*
		 * We have to be careful here, because % can legitimately appear
		 * in Ascii85 encodings, and must not be elided.
		 * The goal here is to make any DSC comments impotent without
		 * actually changing the behavior of the Postscript.
		 * Since stripping ``comments'' breaks Ascii85, we can instead just
		 * indent comments a space, which turns DSC comments into non-DSC comments
		 * and has no effect on binary encodings, which are whitespace-blind.
		 */
		if(buf[0] == '%')
			Bputc(fout, ' ');
		Bwrite(fout, buf, Blinelen(fin));
	}
}

/*
 *
 * Reads a PostScript file (*fin), and uses structuring comments to locate the
 * prologue, trailer, global definitions, and the requested page. After the whole
 * file is scanned, the  special ps_include PostScript definitions are copied to
 * *fout, followed by the prologue, global definitions, the requested page, and
 * the trailer. Before returning the initial environment (saved in PS_head) is
 * restored.
 *
 * By default we assume the picture is 8.5 by 11 inches, but the BoundingBox
 * comment, if found, takes precedence.
 *
 */
/*	*fin, *fout;		/* input and output files */
/*	page_no;		/* physical page number from *fin */
/*	whiteout;		/* erase picture area */
/*	outline;		/* draw a box around it and */
/*	scaleboth;		/* scale both dimensions - if not zero */
/*	cx, cy;			/* center of the picture and */
/*	sx, sy;			/* its size - in current coordinates */
/*	ax, ay;			/* left-right, up-down adjustment */
/*	rot;			/* rotation - in clockwise degrees */

void
ps_include(Biobuf *fin, Biobuf *fout, int page_no, int whiteout,
	int outline, int scaleboth, double cx, double cy, double sx, double sy,
	double ax, double ay, double rot) {
	char		**strp;
	int		foundpage = 0;		/* found the page when non zero */
	int		foundpbox = 0;		/* found the page bounding box */
	int		nglobal = 0;		/* number of global defs so far */
	int		maxglobal = 0;		/* and the number we've got room for */
	Section	prolog, page, trailer;	/* prologue, page, and trailer offsets */
	Section	*global = 0;		/* offsets for all global definitions */
	double	llx, lly;		/* lower left and */
	double	urx, ury;		/* upper right corners - default coords */
	double	w = whiteout != 0;	/* mostly for the var() macro */
	double	o = outline != 0;
	double	s = scaleboth != 0;
	int		i;		/* loop index */

#define has(word)	(strncmp(buf, word, strlen(word)) == 0)
#define grab(n)		((Section *)(nglobal \
			? realloc((char *)global, n*sizeof(Section)) \
			: calloc(n, sizeof(Section))))

	llx = lly = 0;		/* default BoundingBox - 8.5x11 inches */
	urx = 72 * 8.5;
	ury = 72 * 11.0;

	/* section boundaries and bounding box */

	prolog.start = prolog.end = 0;
	page.start = page.end = 0;
	trailer.start = 0;
	Bseek(fin, 0L, 0);

	while ((buf=Brdline(fin, '\n')) != NULL) {
		buf[Blinelen(fin)-1] = '\0';
		if (!has("%%"))
			continue;
		else if (has("%%Page: ")) {
			if (!foundpage)
				page.start = Bseek(fin, 0L, 1);
			sscanf(buf, "%*s %*s %d", &i);
			if (i == page_no)
				foundpage = 1;
			else if (foundpage && page.end <= page.start)
				page.end = Bseek(fin, 0L, 1);
		} else if (has("%%EndPage: ")) {
			sscanf(buf, "%*s %*s %d", &i);
			if (i == page_no) {
				foundpage = 1;
				page.end = Bseek(fin, 0L, 1);
			}
			if (!foundpage)
				page.start = Bseek(fin, 0L, 1);
		} else if (has("%%PageBoundingBox: ")) {
			if (i == page_no) {
				foundpbox = 1;
				sscanf(buf, "%*s %lf %lf %lf %lf",
						&llx, &lly, &urx, &ury);
			}
		} else if (has("%%BoundingBox: ")) {
			if (!foundpbox)
				sscanf(buf,"%*s %lf %lf %lf %lf",
						&llx, &lly, &urx, &ury);
		} else if (has("%%EndProlog") || has("%%EndSetup") || has("%%EndDocumentSetup"))
			prolog.end = page.start = Bseek(fin, 0L, 1);
		else if (has("%%Trailer"))
			trailer.start = Bseek(fin, 0L, 1);
		else if (has("%%BeginGlobal")) {
			if (page.end <= page.start) {
				if (nglobal >= maxglobal) {
					maxglobal += 20;
					global = grab(maxglobal);
				}
				global[nglobal].start = Bseek(fin, 0L, 1);
			}
		} else if (has("%%EndGlobal"))
			if (page.end <= page.start)
				global[nglobal++].end = Bseek(fin, 0L, 1);
	}
	Bseek(fin, 0L, 2);
	if (trailer.start == 0)
		trailer.start = Bseek(fin, 0L, 1);
	trailer.end = Bseek(fin, 0L, 1);

	if (page.end <= page.start)
		page.end = trailer.start;

/*
fprint(2, "prolog=(%d,%d)\n", prolog.start, prolog.end);
fprint(2, "page=(%d,%d)\n", page.start, page.end);
for(i = 0; i < nglobal; i++)
	fprint(2, "global[%d]=(%d,%d)\n", i, global[i].start, global[i].end);
fprint(2, "trailer=(%d,%d)\n", trailer.start, trailer.end);
*/

	/* all output here */
	for (strp = PS_head; *strp != NULL; strp++)
		Bwrite(fout, *strp, strlen(*strp));

	Bprint(fout, "/llx %g def\n", llx);
	Bprint(fout, "/lly %g def\n", lly);
	Bprint(fout, "/urx %g def\n", urx);
	Bprint(fout, "/ury %g def\n", ury);
	Bprint(fout, "/w %g def\n", w);
	Bprint(fout, "/o %g def\n", o);
	Bprint(fout, "/s %g def\n", s);
	Bprint(fout, "/cx %g def\n", cx);
	Bprint(fout, "/cy %g def\n", cy);
	Bprint(fout, "/sx %g def\n", sx);
	Bprint(fout, "/sy %g def\n", sy);
	Bprint(fout, "/ax %g def\n", ax);
	Bprint(fout, "/ay %g def\n", ay);
	Bprint(fout, "/rot %g def\n", rot);

	for (strp = PS_setup; *strp != NULL; strp++)
		Bwrite(fout, *strp, strlen(*strp));

	copy(fin, fout, &prolog);
	for(i = 0; i < nglobal; i++)
		copy(fin, fout, &global[i]);
	copy(fin, fout, &page);
	copy(fin, fout, &trailer);
	for (strp = PS_tail; *strp != NULL; strp++)
		Bwrite(fout, *strp, strlen(*strp));

	if(nglobal)
		free(global);

	/* force the program to reestablish its state */
	curpostfontid = -1;
	curfontsize = -1;
}