Use "$(MAKE)" for sub-makes, so as to handle systems whose default "make"
[sgt/halibut] / bk_ps.c
CommitLineData
43341922 1/*
2 * PostScript backend for Halibut
3 */
4
5#include <assert.h>
6#include "halibut.h"
7#include "paper.h"
8
09358aa7 9static void ps_versionid(FILE *fp, word *words);
10
43341922 11paragraph *ps_config_filename(char *filename)
12{
e4ea58f8 13 return cmdline_cfg_simple("ps-filename", filename, NULL);
43341922 14}
15
16void ps_backend(paragraph *sourceform, keywordlist *keywords,
17 indexdata *idx, void *vdoc) {
18 document *doc = (document *)vdoc;
19 int font_index;
20 font_encoding *fe;
21 page_data *page;
22 int pageno;
23 FILE *fp;
24 char *filename;
25 paragraph *p;
26
27 IGNORE(keywords);
28 IGNORE(idx);
29
30 filename = dupstr("output.ps");
31 for (p = sourceform; p; p = p->next) {
7738a2fb 32 if (p->type == para_Config) {
43341922 33 if (!ustricmp(p->keyword, L"ps-filename")) {
34 sfree(filename);
e4ea58f8 35 filename = dupstr(adv(p->origkeyword));
43341922 36 }
37 }
38 }
39
40 fp = fopen(filename, "w");
41 if (!fp) {
42 error(err_cantopenw, filename);
43 return;
44 }
45
46 fprintf(fp, "%%!PS-Adobe-1.0\n");
47 for (pageno = 0, page = doc->pages; page; page = page->next)
48 pageno++;
49 fprintf(fp, "%%%%Pages: %d\n", pageno);
50 fprintf(fp, "%%%%EndComments\n");
51
52 fprintf(fp, "%%%%BeginProlog\n");
7c8c4239 53 /*
54 * Supply a prologue function which allows a reasonably
55 * compressed representation of the text on the pages.
56 *
57 * Expects two arguments: a y-coordinate, and then an array.
58 * Elements of the array are processed sequentially as follows:
59 *
60 * - a number is treated as an x-coordinate
61 * - an array is treated as a (font, size) pair
62 * - a string is shown
63 */
64 fprintf(fp,
65 "/t {\n"
66 " exch /y exch def {\n"
67 " /x exch def\n"
68 " x type [] type eq {x aload pop scalefont setfont} if\n"
69 " x type dup 1 type eq exch 1.0 type eq or {x y moveto} if\n"
70 " x type () type eq {x show} if\n"
71 " } forall\n"
72 "} def\n");
73
43341922 74 fprintf(fp, "%%%%EndProlog\n");
75
76 fprintf(fp, "%%%%BeginSetup\n");
09358aa7 77
78 /*
79 * This is as good a place as any to put version IDs.
80 */
81 for (p = sourceform; p; p = p->next)
82 if (p->type == para_VersionID)
83 ps_versionid(fp, p->words);
84
43341922 85 /*
86 * Re-encode and re-metric the fonts.
87 */
88 font_index = 0;
89 for (fe = doc->fonts->head; fe; fe = fe->next) {
90 char fname[40];
91 int i;
92
93 sprintf(fname, "f%d", font_index++);
94 fe->name = dupstr(fname);
95
96 fprintf(fp, "/%s findfont dup length dict begin\n", fe->font->name);
97 fprintf(fp, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
98 fprintf(fp, "/Encoding [\n");
99 for (i = 0; i < 256; i++)
100 fprintf(fp, "/%s\n", fe->vector[i] ? fe->vector[i] : ".notdef");
101 fprintf(fp, "] def /Metrics 256 dict dup begin\n");
102 for (i = 0; i < 256; i++) {
103 if (fe->indices[i] >= 0) {
104 double width = fe->font->widths[fe->indices[i]];
105 fprintf(fp, "/%s %g def\n", fe->vector[i],
106 1000.0 * width / 4096.0);
107 }
108 }
109 fprintf(fp, "end def currentdict end\n");
110 fprintf(fp, "/fontname-%s exch definefont /%s exch def\n\n",
111 fe->name, fe->name);
112 }
113 fprintf(fp, "%%%%EndSetup\n");
114
115 /*
23765aeb 116 * Output the text and graphics.
43341922 117 */
118 pageno = 0;
119 for (page = doc->pages; page; page = page->next) {
7c8c4239 120 text_fragment *frag, *frag_end;
23765aeb 121 rect *r;
43341922 122
123 pageno++;
124 fprintf(fp, "%%%%Page: %d %d\n", pageno, pageno);
125 fprintf(fp, "%%%%BeginPageSetup\n");
126 fprintf(fp, "%%%%EndPageSetup\n");
127
138d7ffb 128#if 0
129 {
130 xref *xr;
131 /*
132 * I used this diagnostic briefly to ensure that
133 * cross-reference rectangles were being put where they
134 * should be.
135 */
136 for (xr = page->first_xref; xr; xr = xr->next) {
137 fprintf(fp, "gsave 0.7 setgray %g %g moveto",
138 xr->lx/4096.0, xr->ty/4096.0);
139 fprintf(fp, " %g %g lineto %g %g lineto",
140 xr->lx/4096.0, xr->by/4096.0,
141 xr->rx/4096.0, xr->by/4096.0);
142 fprintf(fp, " %g %g lineto closepath fill grestore\n",
143 xr->rx/4096.0, xr->ty/4096.0);
144 }
145 }
146#endif
147
23765aeb 148 for (r = page->first_rect; r; r = r->next) {
149 fprintf(fp, "%g %g moveto %g 0 rlineto 0 %g rlineto "
150 "-%g 0 rlineto closepath fill\n",
151 r->x / 4096.0, r->y / 4096.0, r->w / 4096.0,
152 r->h / 4096.0, r->w / 4096.0);
153 }
154
7c8c4239 155 frag = page->first_text;
156 while (frag) {
157 font_encoding *fe;
158 int fs;
43341922 159 char *c;
160
7c8c4239 161 /*
162 * Collect all the adjacent text fragments with the
163 * same y-coordinate.
164 */
165 for (frag_end = frag;
166 frag_end && frag_end->y == frag->y;
167 frag_end = frag_end->next);
168
169 fprintf(fp, "%g[", frag->y / 4096.0);
170
171 fe = NULL;
172 fs = -1;
173
174 while (frag && frag != frag_end) {
175
176 if (frag->fe != fe || frag->fontsize != fs)
177 fprintf(fp, "[%s %d]", frag->fe->name, frag->fontsize);
178 fe = frag->fe;
179 fs = frag->fontsize;
180
181 fprintf(fp, "%g(", frag->x/4096.0);
182 for (c = frag->text; *c; c++) {
183 if (*c == '(' || *c == ')' || *c == '\\')
184 fputc('\\', fp);
185 fputc(*c, fp);
186 }
187 fprintf(fp, ")");
43341922 188
7c8c4239 189 frag = frag->next;
43341922 190 }
191
7c8c4239 192 fprintf(fp, "]t\n");
43341922 193 }
194
195 fprintf(fp, "showpage\n");
196 }
197
198 fprintf(fp, "%%%%EOF\n");
199
200 fclose(fp);
201
202 sfree(filename);
203}
09358aa7 204
205static void ps_versionid(FILE *fp, word *words)
206{
207 fprintf(fp, "%% ");
208
209 for (; words; words = words->next) {
210 char *text;
211 int type;
212
213 switch (words->type) {
214 case word_HyperLink:
215 case word_HyperEnd:
216 case word_UpperXref:
217 case word_LowerXref:
218 case word_XrefEnd:
219 case word_IndexRef:
220 continue;
221 }
222
223 type = removeattr(words->type);
224
225 switch (type) {
226 case word_Normal:
e4ea58f8 227 text = utoa_dup(words->text, CS_ASCII);
09358aa7 228 break;
229 case word_WhiteSpace:
230 text = dupstr(" ");
231 break;
232 case word_Quote:
233 text = dupstr("'");
234 break;
235 }
236
237 fputs(text, fp);
238 sfree(text);
239 }
240
241 fprintf(fp, "\n");
242}