Standardise on using double quotes in HTML attributes. It turns out
[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{
13 paragraph *p;
14 wchar_t *ufilename, *up;
15 int len;
16
17 p = mknew(paragraph);
18 memset(p, 0, sizeof(*p));
19 p->type = para_Config;
20 p->next = NULL;
21 p->fpos.filename = "<command line>";
22 p->fpos.line = p->fpos.col = -1;
23
24 ufilename = ufroma_dup(filename);
25 len = ustrlen(ufilename) + 2 + lenof(L"ps-filename");
26 p->keyword = mknewa(wchar_t, len);
27 up = p->keyword;
28 ustrcpy(up, L"ps-filename");
29 up = uadv(up);
30 ustrcpy(up, ufilename);
31 up = uadv(up);
32 *up = L'\0';
33 assert(up - p->keyword < len);
34 sfree(ufilename);
35
36 return p;
37}
38
39void ps_backend(paragraph *sourceform, keywordlist *keywords,
40 indexdata *idx, void *vdoc) {
41 document *doc = (document *)vdoc;
42 int font_index;
43 font_encoding *fe;
44 page_data *page;
45 int pageno;
46 FILE *fp;
47 char *filename;
48 paragraph *p;
49
50 IGNORE(keywords);
51 IGNORE(idx);
52
53 filename = dupstr("output.ps");
54 for (p = sourceform; p; p = p->next) {
43341922 55 if (p->type == para_Config && p->parent) {
56 if (!ustricmp(p->keyword, L"ps-filename")) {
57 sfree(filename);
58 filename = utoa_dup(uadv(p->keyword));
59 }
60 }
61 }
62
63 fp = fopen(filename, "w");
64 if (!fp) {
65 error(err_cantopenw, filename);
66 return;
67 }
68
69 fprintf(fp, "%%!PS-Adobe-1.0\n");
70 for (pageno = 0, page = doc->pages; page; page = page->next)
71 pageno++;
72 fprintf(fp, "%%%%Pages: %d\n", pageno);
73 fprintf(fp, "%%%%EndComments\n");
74
75 fprintf(fp, "%%%%BeginProlog\n");
76 fprintf(fp, "%%%%EndProlog\n");
77
78 fprintf(fp, "%%%%BeginSetup\n");
09358aa7 79
80 /*
81 * This is as good a place as any to put version IDs.
82 */
83 for (p = sourceform; p; p = p->next)
84 if (p->type == para_VersionID)
85 ps_versionid(fp, p->words);
86
43341922 87 /*
88 * Re-encode and re-metric the fonts.
89 */
90 font_index = 0;
91 for (fe = doc->fonts->head; fe; fe = fe->next) {
92 char fname[40];
93 int i;
94
95 sprintf(fname, "f%d", font_index++);
96 fe->name = dupstr(fname);
97
98 fprintf(fp, "/%s findfont dup length dict begin\n", fe->font->name);
99 fprintf(fp, "{1 index /FID ne {def} {pop pop} ifelse} forall\n");
100 fprintf(fp, "/Encoding [\n");
101 for (i = 0; i < 256; i++)
102 fprintf(fp, "/%s\n", fe->vector[i] ? fe->vector[i] : ".notdef");
103 fprintf(fp, "] def /Metrics 256 dict dup begin\n");
104 for (i = 0; i < 256; i++) {
105 if (fe->indices[i] >= 0) {
106 double width = fe->font->widths[fe->indices[i]];
107 fprintf(fp, "/%s %g def\n", fe->vector[i],
108 1000.0 * width / 4096.0);
109 }
110 }
111 fprintf(fp, "end def currentdict end\n");
112 fprintf(fp, "/fontname-%s exch definefont /%s exch def\n\n",
113 fe->name, fe->name);
114 }
115 fprintf(fp, "%%%%EndSetup\n");
116
117 /*
23765aeb 118 * Output the text and graphics.
43341922 119 */
120 pageno = 0;
121 for (page = doc->pages; page; page = page->next) {
122 text_fragment *frag;
23765aeb 123 rect *r;
43341922 124
125 pageno++;
126 fprintf(fp, "%%%%Page: %d %d\n", pageno, pageno);
127 fprintf(fp, "%%%%BeginPageSetup\n");
128 fprintf(fp, "%%%%EndPageSetup\n");
129
138d7ffb 130#if 0
131 {
132 xref *xr;
133 /*
134 * I used this diagnostic briefly to ensure that
135 * cross-reference rectangles were being put where they
136 * should be.
137 */
138 for (xr = page->first_xref; xr; xr = xr->next) {
139 fprintf(fp, "gsave 0.7 setgray %g %g moveto",
140 xr->lx/4096.0, xr->ty/4096.0);
141 fprintf(fp, " %g %g lineto %g %g lineto",
142 xr->lx/4096.0, xr->by/4096.0,
143 xr->rx/4096.0, xr->by/4096.0);
144 fprintf(fp, " %g %g lineto closepath fill grestore\n",
145 xr->rx/4096.0, xr->ty/4096.0);
146 }
147 }
148#endif
149
23765aeb 150 for (r = page->first_rect; r; r = r->next) {
151 fprintf(fp, "%g %g moveto %g 0 rlineto 0 %g rlineto "
152 "-%g 0 rlineto closepath fill\n",
153 r->x / 4096.0, r->y / 4096.0, r->w / 4096.0,
154 r->h / 4096.0, r->w / 4096.0);
155 }
156
43341922 157 for (frag = page->first_text; frag; frag = frag->next) {
158 char *c;
159
160 fprintf(fp, "%s %d scalefont setfont %g %g moveto (",
161 frag->fe->name, frag->fontsize,
162 frag->x/4096.0, frag->y/4096.0);
163
164 for (c = frag->text; *c; c++) {
165 if (*c == '(' || *c == ')' || *c == '\\')
166 fputc('\\', fp);
167 fputc(*c, fp);
168 }
169
170 fprintf(fp, ") show\n");
171 }
172
173 fprintf(fp, "showpage\n");
174 }
175
176 fprintf(fp, "%%%%EOF\n");
177
178 fclose(fp);
179
180 sfree(filename);
181}
09358aa7 182
183static void ps_versionid(FILE *fp, word *words)
184{
185 fprintf(fp, "%% ");
186
187 for (; words; words = words->next) {
188 char *text;
189 int type;
190
191 switch (words->type) {
192 case word_HyperLink:
193 case word_HyperEnd:
194 case word_UpperXref:
195 case word_LowerXref:
196 case word_XrefEnd:
197 case word_IndexRef:
198 continue;
199 }
200
201 type = removeattr(words->type);
202
203 switch (type) {
204 case word_Normal:
205 text = utoa_dup(words->text);
206 break;
207 case word_WhiteSpace:
208 text = dupstr(" ");
209 break;
210 case word_Quote:
211 text = dupstr("'");
212 break;
213 }
214
215 fputs(text, fp);
216 sfree(text);
217 }
218
219 fprintf(fp, "\n");
220}