mandoc 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/COPYING +674 -0
  4. data/README.md +117 -0
  5. data/ext/mandoc/extconf.rb +59 -0
  6. data/ext/mandoc/rb_mandoc.c +548 -0
  7. data/ext/mandoc/rb_mandoc.h +22 -0
  8. data/lib/mandoc/version.rb +19 -0
  9. data/lib/mandoc.rb +26 -0
  10. data/mandoc-1.14.6/LICENSE +55 -0
  11. data/mandoc-1.14.6/arch.c +54 -0
  12. data/mandoc-1.14.6/att.c +49 -0
  13. data/mandoc-1.14.6/catman.c +260 -0
  14. data/mandoc-1.14.6/cgi.c +1279 -0
  15. data/mandoc-1.14.6/chars.c +507 -0
  16. data/mandoc-1.14.6/compat_err.c +103 -0
  17. data/mandoc-1.14.6/compat_fts.c +696 -0
  18. data/mandoc-1.14.6/compat_fts.h +106 -0
  19. data/mandoc-1.14.6/compat_getline.c +59 -0
  20. data/mandoc-1.14.6/compat_getsubopt.c +87 -0
  21. data/mandoc-1.14.6/compat_isblank.c +23 -0
  22. data/mandoc-1.14.6/compat_mkdtemp.c +50 -0
  23. data/mandoc-1.14.6/compat_mkstemps.c +63 -0
  24. data/mandoc-1.14.6/compat_ohash.c +330 -0
  25. data/mandoc-1.14.6/compat_ohash.h +72 -0
  26. data/mandoc-1.14.6/compat_progname.c +31 -0
  27. data/mandoc-1.14.6/compat_reallocarray.c +40 -0
  28. data/mandoc-1.14.6/compat_recallocarray.c +99 -0
  29. data/mandoc-1.14.6/compat_strcasestr.c +64 -0
  30. data/mandoc-1.14.6/compat_stringlist.c +135 -0
  31. data/mandoc-1.14.6/compat_stringlist.h +48 -0
  32. data/mandoc-1.14.6/compat_strlcat.c +57 -0
  33. data/mandoc-1.14.6/compat_strlcpy.c +52 -0
  34. data/mandoc-1.14.6/compat_strndup.c +42 -0
  35. data/mandoc-1.14.6/compat_strsep.c +70 -0
  36. data/mandoc-1.14.6/compat_strtonum.c +67 -0
  37. data/mandoc-1.14.6/compat_vasprintf.c +47 -0
  38. data/mandoc-1.14.6/config.h +52 -0
  39. data/mandoc-1.14.6/dba.c +508 -0
  40. data/mandoc-1.14.6/dba.h +50 -0
  41. data/mandoc-1.14.6/dba_array.c +190 -0
  42. data/mandoc-1.14.6/dba_array.h +47 -0
  43. data/mandoc-1.14.6/dba_read.c +74 -0
  44. data/mandoc-1.14.6/dba_write.c +127 -0
  45. data/mandoc-1.14.6/dba_write.h +30 -0
  46. data/mandoc-1.14.6/dbm.c +480 -0
  47. data/mandoc-1.14.6/dbm.h +68 -0
  48. data/mandoc-1.14.6/dbm_map.c +194 -0
  49. data/mandoc-1.14.6/dbm_map.h +29 -0
  50. data/mandoc-1.14.6/demandoc.c +260 -0
  51. data/mandoc-1.14.6/eqn.c +1132 -0
  52. data/mandoc-1.14.6/eqn.h +72 -0
  53. data/mandoc-1.14.6/eqn_html.c +246 -0
  54. data/mandoc-1.14.6/eqn_parse.h +48 -0
  55. data/mandoc-1.14.6/eqn_term.c +174 -0
  56. data/mandoc-1.14.6/html.c +1102 -0
  57. data/mandoc-1.14.6/html.h +142 -0
  58. data/mandoc-1.14.6/lib.c +35 -0
  59. data/mandoc-1.14.6/libman.h +42 -0
  60. data/mandoc-1.14.6/libmandoc.h +85 -0
  61. data/mandoc-1.14.6/libmdoc.h +87 -0
  62. data/mandoc-1.14.6/main.c +1375 -0
  63. data/mandoc-1.14.6/main.h +53 -0
  64. data/mandoc-1.14.6/man.c +345 -0
  65. data/mandoc-1.14.6/man.h +21 -0
  66. data/mandoc-1.14.6/man_html.c +640 -0
  67. data/mandoc-1.14.6/man_macro.c +470 -0
  68. data/mandoc-1.14.6/man_term.c +1143 -0
  69. data/mandoc-1.14.6/man_validate.c +660 -0
  70. data/mandoc-1.14.6/manconf.h +58 -0
  71. data/mandoc-1.14.6/mandoc.c +669 -0
  72. data/mandoc-1.14.6/mandoc.h +329 -0
  73. data/mandoc-1.14.6/mandoc_aux.c +118 -0
  74. data/mandoc-1.14.6/mandoc_aux.h +27 -0
  75. data/mandoc-1.14.6/mandoc_msg.c +375 -0
  76. data/mandoc-1.14.6/mandoc_ohash.c +65 -0
  77. data/mandoc-1.14.6/mandoc_ohash.h +23 -0
  78. data/mandoc-1.14.6/mandoc_parse.h +44 -0
  79. data/mandoc-1.14.6/mandoc_xr.c +123 -0
  80. data/mandoc-1.14.6/mandoc_xr.h +31 -0
  81. data/mandoc-1.14.6/mandocd.c +282 -0
  82. data/mandoc-1.14.6/mandocdb.c +2448 -0
  83. data/mandoc-1.14.6/manpath.c +363 -0
  84. data/mandoc-1.14.6/mansearch.c +851 -0
  85. data/mandoc-1.14.6/mansearch.h +118 -0
  86. data/mandoc-1.14.6/mdoc.c +433 -0
  87. data/mandoc-1.14.6/mdoc.h +158 -0
  88. data/mandoc-1.14.6/mdoc_argv.c +682 -0
  89. data/mandoc-1.14.6/mdoc_html.c +1762 -0
  90. data/mandoc-1.14.6/mdoc_macro.c +1600 -0
  91. data/mandoc-1.14.6/mdoc_man.c +1850 -0
  92. data/mandoc-1.14.6/mdoc_markdown.c +1610 -0
  93. data/mandoc-1.14.6/mdoc_state.c +256 -0
  94. data/mandoc-1.14.6/mdoc_term.c +1964 -0
  95. data/mandoc-1.14.6/mdoc_validate.c +3062 -0
  96. data/mandoc-1.14.6/msec.c +37 -0
  97. data/mandoc-1.14.6/out.c +544 -0
  98. data/mandoc-1.14.6/out.h +70 -0
  99. data/mandoc-1.14.6/preconv.c +179 -0
  100. data/mandoc-1.14.6/read.c +732 -0
  101. data/mandoc-1.14.6/roff.c +4390 -0
  102. data/mandoc-1.14.6/roff.h +561 -0
  103. data/mandoc-1.14.6/roff_html.c +119 -0
  104. data/mandoc-1.14.6/roff_int.h +94 -0
  105. data/mandoc-1.14.6/roff_term.c +266 -0
  106. data/mandoc-1.14.6/roff_validate.c +151 -0
  107. data/mandoc-1.14.6/soelim.c +182 -0
  108. data/mandoc-1.14.6/st.c +82 -0
  109. data/mandoc-1.14.6/tag.c +327 -0
  110. data/mandoc-1.14.6/tag.h +35 -0
  111. data/mandoc-1.14.6/tbl.c +183 -0
  112. data/mandoc-1.14.6/tbl.h +121 -0
  113. data/mandoc-1.14.6/tbl_data.c +323 -0
  114. data/mandoc-1.14.6/tbl_html.c +293 -0
  115. data/mandoc-1.14.6/tbl_int.h +47 -0
  116. data/mandoc-1.14.6/tbl_layout.c +376 -0
  117. data/mandoc-1.14.6/tbl_opts.c +173 -0
  118. data/mandoc-1.14.6/tbl_parse.h +30 -0
  119. data/mandoc-1.14.6/tbl_term.c +948 -0
  120. data/mandoc-1.14.6/term.c +1113 -0
  121. data/mandoc-1.14.6/term.h +158 -0
  122. data/mandoc-1.14.6/term_ascii.c +424 -0
  123. data/mandoc-1.14.6/term_ps.c +1362 -0
  124. data/mandoc-1.14.6/term_tab.c +130 -0
  125. data/mandoc-1.14.6/term_tag.c +227 -0
  126. data/mandoc-1.14.6/term_tag.h +34 -0
  127. data/mandoc-1.14.6/tree.c +536 -0
  128. metadata +170 -0
@@ -0,0 +1,1362 @@
1
+ /* $Id: term_ps.c,v 1.92 2020/09/06 14:45:22 schwarze Exp $ */
2
+ /*
3
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4
+ * Copyright (c) 2014,2015,2016,2017,2020 Ingo Schwarze <schwarze@openbsd.org>
5
+ * Copyright (c) 2017 Marc Espie <espie@openbsd.org>
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for any
8
+ * purpose with or without fee is hereby granted, provided that the above
9
+ * copyright notice and this permission notice appear in all copies.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
12
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
14
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+ */
19
+ #include "config.h"
20
+
21
+ #include <sys/types.h>
22
+
23
+ #include <assert.h>
24
+ #if HAVE_ERR
25
+ #include <err.h>
26
+ #endif
27
+ #include <stdarg.h>
28
+ #include <stdint.h>
29
+ #include <stdio.h>
30
+ #include <stdlib.h>
31
+ #include <string.h>
32
+ #include <unistd.h>
33
+
34
+ #include "mandoc_aux.h"
35
+ #include "out.h"
36
+ #include "term.h"
37
+ #include "manconf.h"
38
+ #include "main.h"
39
+
40
+ /* These work the buffer used by the header and footer. */
41
+ #define PS_BUFSLOP 128
42
+
43
+ /* Convert PostScript point "x" to an AFM unit. */
44
+ #define PNT2AFM(p, x) \
45
+ (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale))
46
+
47
+ /* Convert an AFM unit "x" to a PostScript points */
48
+ #define AFM2PNT(p, x) \
49
+ ((double)(x) / (1000.0 / (double)(p)->ps->scale))
50
+
51
+ struct glyph {
52
+ unsigned short wx; /* WX in AFM */
53
+ };
54
+
55
+ struct font {
56
+ const char *name; /* FontName in AFM */
57
+ #define MAXCHAR 95 /* total characters we can handle */
58
+ struct glyph gly[MAXCHAR]; /* glyph metrics */
59
+ };
60
+
61
+ struct termp_ps {
62
+ int flags;
63
+ #define PS_INLINE (1 << 0) /* we're in a word */
64
+ #define PS_MARGINS (1 << 1) /* we're in the margins */
65
+ #define PS_NEWPAGE (1 << 2) /* new page, no words yet */
66
+ #define PS_BACKSP (1 << 3) /* last character was backspace */
67
+ size_t pscol; /* visible column (AFM units) */
68
+ size_t pscolnext; /* used for overstrike */
69
+ size_t psrow; /* visible row (AFM units) */
70
+ size_t lastrow; /* psrow of the previous word */
71
+ char *psmarg; /* margin buf */
72
+ size_t psmargsz; /* margin buf size */
73
+ size_t psmargcur; /* cur index in margin buf */
74
+ char last; /* last non-backspace seen */
75
+ enum termfont lastf; /* last set font */
76
+ enum termfont nextf; /* building next font here */
77
+ size_t scale; /* font scaling factor */
78
+ size_t pages; /* number of pages shown */
79
+ size_t lineheight; /* line height (AFM units) */
80
+ size_t top; /* body top (AFM units) */
81
+ size_t bottom; /* body bottom (AFM units) */
82
+ const char *medianame; /* for DocumentMedia and PageSize */
83
+ size_t height; /* page height (AFM units */
84
+ size_t width; /* page width (AFM units) */
85
+ size_t lastwidth; /* page width before last ll */
86
+ size_t left; /* body left (AFM units) */
87
+ size_t header; /* header pos (AFM units) */
88
+ size_t footer; /* footer pos (AFM units) */
89
+ size_t pdfbytes; /* current output byte */
90
+ size_t pdflastpg; /* byte of last page mark */
91
+ size_t pdfbody; /* start of body object */
92
+ size_t *pdfobjs; /* table of object offsets */
93
+ size_t pdfobjsz; /* size of pdfobjs */
94
+ };
95
+
96
+ static int ps_hspan(const struct termp *,
97
+ const struct roffsu *);
98
+ static size_t ps_width(const struct termp *, int);
99
+ static void ps_advance(struct termp *, size_t);
100
+ static void ps_begin(struct termp *);
101
+ static void ps_closepage(struct termp *);
102
+ static void ps_end(struct termp *);
103
+ static void ps_endline(struct termp *);
104
+ static void ps_growbuf(struct termp *, size_t);
105
+ static void ps_letter(struct termp *, int);
106
+ static void ps_pclose(struct termp *);
107
+ static void ps_plast(struct termp *);
108
+ static void ps_pletter(struct termp *, int);
109
+ static void ps_printf(struct termp *, const char *, ...)
110
+ __attribute__((__format__ (__printf__, 2, 3)));
111
+ static void ps_putchar(struct termp *, char);
112
+ static void ps_setfont(struct termp *, enum termfont);
113
+ static void ps_setwidth(struct termp *, int, int);
114
+ static struct termp *pspdf_alloc(const struct manoutput *, enum termtype);
115
+ static void pdf_obj(struct termp *, size_t);
116
+
117
+ /*
118
+ * We define, for the time being, three fonts: bold, oblique/italic, and
119
+ * normal (roman). The following table hard-codes the font metrics for
120
+ * ASCII, i.e., 32--127.
121
+ */
122
+
123
+ static const struct font fonts[TERMFONT__MAX] = {
124
+ { "Times-Roman", {
125
+ { 250 },
126
+ { 333 },
127
+ { 408 },
128
+ { 500 },
129
+ { 500 },
130
+ { 833 },
131
+ { 778 },
132
+ { 333 },
133
+ { 333 },
134
+ { 333 },
135
+ { 500 },
136
+ { 564 },
137
+ { 250 },
138
+ { 333 },
139
+ { 250 },
140
+ { 278 },
141
+ { 500 },
142
+ { 500 },
143
+ { 500 },
144
+ { 500 },
145
+ { 500 },
146
+ { 500 },
147
+ { 500 },
148
+ { 500 },
149
+ { 500 },
150
+ { 500 },
151
+ { 278 },
152
+ { 278 },
153
+ { 564 },
154
+ { 564 },
155
+ { 564 },
156
+ { 444 },
157
+ { 921 },
158
+ { 722 },
159
+ { 667 },
160
+ { 667 },
161
+ { 722 },
162
+ { 611 },
163
+ { 556 },
164
+ { 722 },
165
+ { 722 },
166
+ { 333 },
167
+ { 389 },
168
+ { 722 },
169
+ { 611 },
170
+ { 889 },
171
+ { 722 },
172
+ { 722 },
173
+ { 556 },
174
+ { 722 },
175
+ { 667 },
176
+ { 556 },
177
+ { 611 },
178
+ { 722 },
179
+ { 722 },
180
+ { 944 },
181
+ { 722 },
182
+ { 722 },
183
+ { 611 },
184
+ { 333 },
185
+ { 278 },
186
+ { 333 },
187
+ { 469 },
188
+ { 500 },
189
+ { 333 },
190
+ { 444 },
191
+ { 500 },
192
+ { 444 },
193
+ { 500},
194
+ { 444},
195
+ { 333},
196
+ { 500},
197
+ { 500},
198
+ { 278},
199
+ { 278},
200
+ { 500},
201
+ { 278},
202
+ { 778},
203
+ { 500},
204
+ { 500},
205
+ { 500},
206
+ { 500},
207
+ { 333},
208
+ { 389},
209
+ { 278},
210
+ { 500},
211
+ { 500},
212
+ { 722},
213
+ { 500},
214
+ { 500},
215
+ { 444},
216
+ { 480},
217
+ { 200},
218
+ { 480},
219
+ { 541},
220
+ } },
221
+ { "Times-Bold", {
222
+ { 250 },
223
+ { 333 },
224
+ { 555 },
225
+ { 500 },
226
+ { 500 },
227
+ { 1000 },
228
+ { 833 },
229
+ { 333 },
230
+ { 333 },
231
+ { 333 },
232
+ { 500 },
233
+ { 570 },
234
+ { 250 },
235
+ { 333 },
236
+ { 250 },
237
+ { 278 },
238
+ { 500 },
239
+ { 500 },
240
+ { 500 },
241
+ { 500 },
242
+ { 500 },
243
+ { 500 },
244
+ { 500 },
245
+ { 500 },
246
+ { 500 },
247
+ { 500 },
248
+ { 333 },
249
+ { 333 },
250
+ { 570 },
251
+ { 570 },
252
+ { 570 },
253
+ { 500 },
254
+ { 930 },
255
+ { 722 },
256
+ { 667 },
257
+ { 722 },
258
+ { 722 },
259
+ { 667 },
260
+ { 611 },
261
+ { 778 },
262
+ { 778 },
263
+ { 389 },
264
+ { 500 },
265
+ { 778 },
266
+ { 667 },
267
+ { 944 },
268
+ { 722 },
269
+ { 778 },
270
+ { 611 },
271
+ { 778 },
272
+ { 722 },
273
+ { 556 },
274
+ { 667 },
275
+ { 722 },
276
+ { 722 },
277
+ { 1000 },
278
+ { 722 },
279
+ { 722 },
280
+ { 667 },
281
+ { 333 },
282
+ { 278 },
283
+ { 333 },
284
+ { 581 },
285
+ { 500 },
286
+ { 333 },
287
+ { 500 },
288
+ { 556 },
289
+ { 444 },
290
+ { 556 },
291
+ { 444 },
292
+ { 333 },
293
+ { 500 },
294
+ { 556 },
295
+ { 278 },
296
+ { 333 },
297
+ { 556 },
298
+ { 278 },
299
+ { 833 },
300
+ { 556 },
301
+ { 500 },
302
+ { 556 },
303
+ { 556 },
304
+ { 444 },
305
+ { 389 },
306
+ { 333 },
307
+ { 556 },
308
+ { 500 },
309
+ { 722 },
310
+ { 500 },
311
+ { 500 },
312
+ { 444 },
313
+ { 394 },
314
+ { 220 },
315
+ { 394 },
316
+ { 520 },
317
+ } },
318
+ { "Times-Italic", {
319
+ { 250 },
320
+ { 333 },
321
+ { 420 },
322
+ { 500 },
323
+ { 500 },
324
+ { 833 },
325
+ { 778 },
326
+ { 333 },
327
+ { 333 },
328
+ { 333 },
329
+ { 500 },
330
+ { 675 },
331
+ { 250 },
332
+ { 333 },
333
+ { 250 },
334
+ { 278 },
335
+ { 500 },
336
+ { 500 },
337
+ { 500 },
338
+ { 500 },
339
+ { 500 },
340
+ { 500 },
341
+ { 500 },
342
+ { 500 },
343
+ { 500 },
344
+ { 500 },
345
+ { 333 },
346
+ { 333 },
347
+ { 675 },
348
+ { 675 },
349
+ { 675 },
350
+ { 500 },
351
+ { 920 },
352
+ { 611 },
353
+ { 611 },
354
+ { 667 },
355
+ { 722 },
356
+ { 611 },
357
+ { 611 },
358
+ { 722 },
359
+ { 722 },
360
+ { 333 },
361
+ { 444 },
362
+ { 667 },
363
+ { 556 },
364
+ { 833 },
365
+ { 667 },
366
+ { 722 },
367
+ { 611 },
368
+ { 722 },
369
+ { 611 },
370
+ { 500 },
371
+ { 556 },
372
+ { 722 },
373
+ { 611 },
374
+ { 833 },
375
+ { 611 },
376
+ { 556 },
377
+ { 556 },
378
+ { 389 },
379
+ { 278 },
380
+ { 389 },
381
+ { 422 },
382
+ { 500 },
383
+ { 333 },
384
+ { 500 },
385
+ { 500 },
386
+ { 444 },
387
+ { 500 },
388
+ { 444 },
389
+ { 278 },
390
+ { 500 },
391
+ { 500 },
392
+ { 278 },
393
+ { 278 },
394
+ { 444 },
395
+ { 278 },
396
+ { 722 },
397
+ { 500 },
398
+ { 500 },
399
+ { 500 },
400
+ { 500 },
401
+ { 389 },
402
+ { 389 },
403
+ { 278 },
404
+ { 500 },
405
+ { 444 },
406
+ { 667 },
407
+ { 444 },
408
+ { 444 },
409
+ { 389 },
410
+ { 400 },
411
+ { 275 },
412
+ { 400 },
413
+ { 541 },
414
+ } },
415
+ { "Times-BoldItalic", {
416
+ { 250 },
417
+ { 389 },
418
+ { 555 },
419
+ { 500 },
420
+ { 500 },
421
+ { 833 },
422
+ { 778 },
423
+ { 333 },
424
+ { 333 },
425
+ { 333 },
426
+ { 500 },
427
+ { 570 },
428
+ { 250 },
429
+ { 333 },
430
+ { 250 },
431
+ { 278 },
432
+ { 500 },
433
+ { 500 },
434
+ { 500 },
435
+ { 500 },
436
+ { 500 },
437
+ { 500 },
438
+ { 500 },
439
+ { 500 },
440
+ { 500 },
441
+ { 500 },
442
+ { 333 },
443
+ { 333 },
444
+ { 570 },
445
+ { 570 },
446
+ { 570 },
447
+ { 500 },
448
+ { 832 },
449
+ { 667 },
450
+ { 667 },
451
+ { 667 },
452
+ { 722 },
453
+ { 667 },
454
+ { 667 },
455
+ { 722 },
456
+ { 778 },
457
+ { 389 },
458
+ { 500 },
459
+ { 667 },
460
+ { 611 },
461
+ { 889 },
462
+ { 722 },
463
+ { 722 },
464
+ { 611 },
465
+ { 722 },
466
+ { 667 },
467
+ { 556 },
468
+ { 611 },
469
+ { 722 },
470
+ { 667 },
471
+ { 889 },
472
+ { 667 },
473
+ { 611 },
474
+ { 611 },
475
+ { 333 },
476
+ { 278 },
477
+ { 333 },
478
+ { 570 },
479
+ { 500 },
480
+ { 333 },
481
+ { 500 },
482
+ { 500 },
483
+ { 444 },
484
+ { 500 },
485
+ { 444 },
486
+ { 333 },
487
+ { 500 },
488
+ { 556 },
489
+ { 278 },
490
+ { 278 },
491
+ { 500 },
492
+ { 278 },
493
+ { 778 },
494
+ { 556 },
495
+ { 500 },
496
+ { 500 },
497
+ { 500 },
498
+ { 389 },
499
+ { 389 },
500
+ { 278 },
501
+ { 556 },
502
+ { 444 },
503
+ { 667 },
504
+ { 500 },
505
+ { 444 },
506
+ { 389 },
507
+ { 348 },
508
+ { 220 },
509
+ { 348 },
510
+ { 570 },
511
+ } },
512
+ };
513
+
514
+ void *
515
+ pdf_alloc(const struct manoutput *outopts)
516
+ {
517
+ return pspdf_alloc(outopts, TERMTYPE_PDF);
518
+ }
519
+
520
+ void *
521
+ ps_alloc(const struct manoutput *outopts)
522
+ {
523
+ return pspdf_alloc(outopts, TERMTYPE_PS);
524
+ }
525
+
526
+ static struct termp *
527
+ pspdf_alloc(const struct manoutput *outopts, enum termtype type)
528
+ {
529
+ struct termp *p;
530
+ unsigned int pagex, pagey;
531
+ size_t marginx, marginy, lineheight;
532
+ const char *pp;
533
+
534
+ p = mandoc_calloc(1, sizeof(*p));
535
+ p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
536
+ p->maxtcol = 1;
537
+ p->type = type;
538
+
539
+ p->enc = TERMENC_ASCII;
540
+ p->fontq = mandoc_reallocarray(NULL,
541
+ (p->fontsz = 8), sizeof(*p->fontq));
542
+ p->fontq[0] = p->fontl = TERMFONT_NONE;
543
+ p->ps = mandoc_calloc(1, sizeof(*p->ps));
544
+
545
+ p->advance = ps_advance;
546
+ p->begin = ps_begin;
547
+ p->end = ps_end;
548
+ p->endline = ps_endline;
549
+ p->hspan = ps_hspan;
550
+ p->letter = ps_letter;
551
+ p->setwidth = ps_setwidth;
552
+ p->width = ps_width;
553
+
554
+ /* Default to US letter (millimetres). */
555
+
556
+ p->ps->medianame = "Letter";
557
+ pagex = 216;
558
+ pagey = 279;
559
+
560
+ /*
561
+ * The ISO-269 paper sizes can be calculated automatically, but
562
+ * it would require bringing in -lm for pow() and I'd rather not
563
+ * do that. So just do it the easy way for now. Since this
564
+ * only happens once, I'm not terribly concerned.
565
+ */
566
+
567
+ pp = outopts->paper;
568
+ if (pp != NULL && strcasecmp(pp, "letter") != 0) {
569
+ if (strcasecmp(pp, "a3") == 0) {
570
+ p->ps->medianame = "A3";
571
+ pagex = 297;
572
+ pagey = 420;
573
+ } else if (strcasecmp(pp, "a4") == 0) {
574
+ p->ps->medianame = "A4";
575
+ pagex = 210;
576
+ pagey = 297;
577
+ } else if (strcasecmp(pp, "a5") == 0) {
578
+ p->ps->medianame = "A5";
579
+ pagex = 148;
580
+ pagey = 210;
581
+ } else if (strcasecmp(pp, "legal") == 0) {
582
+ p->ps->medianame = "Legal";
583
+ pagex = 216;
584
+ pagey = 356;
585
+ } else if (sscanf(pp, "%ux%u", &pagex, &pagey) == 2)
586
+ p->ps->medianame = "CustomSize";
587
+ else
588
+ warnx("%s: Unknown paper", pp);
589
+ }
590
+
591
+ /*
592
+ * This MUST be defined before any PNT2AFM or AFM2PNT
593
+ * calculations occur.
594
+ */
595
+
596
+ p->ps->scale = 11;
597
+
598
+ /* Remember millimetres -> AFM units. */
599
+
600
+ pagex = PNT2AFM(p, ((double)pagex * 72.0 / 25.4));
601
+ pagey = PNT2AFM(p, ((double)pagey * 72.0 / 25.4));
602
+
603
+ /* Margins are 1/9 the page x and y. */
604
+
605
+ marginx = (size_t)((double)pagex / 9.0);
606
+ marginy = (size_t)((double)pagey / 9.0);
607
+
608
+ /* Line-height is 1.4em. */
609
+
610
+ lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4));
611
+
612
+ p->ps->width = p->ps->lastwidth = (size_t)pagex;
613
+ p->ps->height = (size_t)pagey;
614
+ p->ps->header = pagey - (marginy / 2) - (lineheight / 2);
615
+ p->ps->top = pagey - marginy;
616
+ p->ps->footer = (marginy / 2) - (lineheight / 2);
617
+ p->ps->bottom = marginy;
618
+ p->ps->left = marginx;
619
+ p->ps->lineheight = lineheight;
620
+
621
+ p->defrmargin = pagex - (marginx * 2);
622
+ return p;
623
+ }
624
+
625
+ static void
626
+ ps_setwidth(struct termp *p, int iop, int width)
627
+ {
628
+ size_t lastwidth;
629
+
630
+ lastwidth = p->ps->width;
631
+ if (iop > 0)
632
+ p->ps->width += width;
633
+ else if (iop == 0)
634
+ p->ps->width = width ? (size_t)width : p->ps->lastwidth;
635
+ else if (p->ps->width > (size_t)width)
636
+ p->ps->width -= width;
637
+ else
638
+ p->ps->width = 0;
639
+ p->ps->lastwidth = lastwidth;
640
+ }
641
+
642
+ void
643
+ pspdf_free(void *arg)
644
+ {
645
+ struct termp *p;
646
+
647
+ p = (struct termp *)arg;
648
+
649
+ free(p->ps->psmarg);
650
+ free(p->ps->pdfobjs);
651
+
652
+ free(p->ps);
653
+ term_free(p);
654
+ }
655
+
656
+ static void
657
+ ps_printf(struct termp *p, const char *fmt, ...)
658
+ {
659
+ va_list ap;
660
+ int pos, len;
661
+
662
+ va_start(ap, fmt);
663
+
664
+ /*
665
+ * If we're running in regular mode, then pipe directly into
666
+ * vprintf(). If we're processing margins, then push the data
667
+ * into our growable margin buffer.
668
+ */
669
+
670
+ if ( ! (PS_MARGINS & p->ps->flags)) {
671
+ len = vprintf(fmt, ap);
672
+ va_end(ap);
673
+ p->ps->pdfbytes += len < 0 ? 0 : (size_t)len;
674
+ return;
675
+ }
676
+
677
+ /*
678
+ * XXX: I assume that the in-margin print won't exceed
679
+ * PS_BUFSLOP (128 bytes), which is reasonable but still an
680
+ * assumption that will cause pukeage if it's not the case.
681
+ */
682
+
683
+ ps_growbuf(p, PS_BUFSLOP);
684
+
685
+ pos = (int)p->ps->psmargcur;
686
+ vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap);
687
+
688
+ va_end(ap);
689
+
690
+ p->ps->psmargcur = strlen(p->ps->psmarg);
691
+ }
692
+
693
+ static void
694
+ ps_putchar(struct termp *p, char c)
695
+ {
696
+ int pos;
697
+
698
+ /* See ps_printf(). */
699
+
700
+ if ( ! (PS_MARGINS & p->ps->flags)) {
701
+ putchar(c);
702
+ p->ps->pdfbytes++;
703
+ return;
704
+ }
705
+
706
+ ps_growbuf(p, 2);
707
+
708
+ pos = (int)p->ps->psmargcur++;
709
+ p->ps->psmarg[pos++] = c;
710
+ p->ps->psmarg[pos] = '\0';
711
+ }
712
+
713
+ static void
714
+ pdf_obj(struct termp *p, size_t obj)
715
+ {
716
+
717
+ assert(obj > 0);
718
+
719
+ if ((obj - 1) >= p->ps->pdfobjsz) {
720
+ p->ps->pdfobjsz = obj + 128;
721
+ p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs,
722
+ p->ps->pdfobjsz, sizeof(size_t));
723
+ }
724
+
725
+ p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes;
726
+ ps_printf(p, "%zu 0 obj\n", obj);
727
+ }
728
+
729
+ static void
730
+ ps_closepage(struct termp *p)
731
+ {
732
+ int i;
733
+ size_t len, base;
734
+
735
+ /*
736
+ * Close out a page that we've already flushed to output. In
737
+ * PostScript, we simply note that the page must be shown. In
738
+ * PDF, we must now create the Length, Resource, and Page node
739
+ * for the page contents.
740
+ */
741
+
742
+ assert(p->ps->psmarg && p->ps->psmarg[0]);
743
+ ps_printf(p, "%s", p->ps->psmarg);
744
+
745
+ if (TERMTYPE_PS != p->type) {
746
+ len = p->ps->pdfbytes - p->ps->pdflastpg;
747
+ base = p->ps->pages * 4 + p->ps->pdfbody;
748
+
749
+ ps_printf(p, "endstream\nendobj\n");
750
+
751
+ /* Length of content. */
752
+ pdf_obj(p, base + 1);
753
+ ps_printf(p, "%zu\nendobj\n", len);
754
+
755
+ /* Resource for content. */
756
+ pdf_obj(p, base + 2);
757
+ ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n");
758
+ ps_printf(p, "/Font <<\n");
759
+ for (i = 0; i < (int)TERMFONT__MAX; i++)
760
+ ps_printf(p, "/F%d %d 0 R\n", i, 3 + i);
761
+ ps_printf(p, ">>\n>>\nendobj\n");
762
+
763
+ /* Page node. */
764
+ pdf_obj(p, base + 3);
765
+ ps_printf(p, "<<\n");
766
+ ps_printf(p, "/Type /Page\n");
767
+ ps_printf(p, "/Parent 2 0 R\n");
768
+ ps_printf(p, "/Resources %zu 0 R\n", base + 2);
769
+ ps_printf(p, "/Contents %zu 0 R\n", base);
770
+ ps_printf(p, ">>\nendobj\n");
771
+ } else
772
+ ps_printf(p, "showpage\n");
773
+
774
+ p->ps->pages++;
775
+ p->ps->psrow = p->ps->top;
776
+ assert( ! (PS_NEWPAGE & p->ps->flags));
777
+ p->ps->flags |= PS_NEWPAGE;
778
+ }
779
+
780
+ static void
781
+ ps_end(struct termp *p)
782
+ {
783
+ size_t i, xref, base;
784
+
785
+ ps_plast(p);
786
+ ps_pclose(p);
787
+
788
+ /*
789
+ * At the end of the file, do one last showpage. This is the
790
+ * same behaviour as groff(1) and works for multiple pages as
791
+ * well as just one.
792
+ */
793
+
794
+ if ( ! (PS_NEWPAGE & p->ps->flags)) {
795
+ assert(0 == p->ps->flags);
796
+ assert('\0' == p->ps->last);
797
+ ps_closepage(p);
798
+ }
799
+
800
+ if (TERMTYPE_PS == p->type) {
801
+ ps_printf(p, "%%%%Trailer\n");
802
+ ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages);
803
+ ps_printf(p, "%%%%EOF\n");
804
+ return;
805
+ }
806
+
807
+ pdf_obj(p, 2);
808
+ ps_printf(p, "<<\n/Type /Pages\n");
809
+ ps_printf(p, "/MediaBox [0 0 %zu %zu]\n",
810
+ (size_t)AFM2PNT(p, p->ps->width),
811
+ (size_t)AFM2PNT(p, p->ps->height));
812
+
813
+ ps_printf(p, "/Count %zu\n", p->ps->pages);
814
+ ps_printf(p, "/Kids [");
815
+
816
+ for (i = 0; i < p->ps->pages; i++)
817
+ ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3);
818
+
819
+ base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4;
820
+
821
+ ps_printf(p, "]\n>>\nendobj\n");
822
+ pdf_obj(p, base);
823
+ ps_printf(p, "<<\n");
824
+ ps_printf(p, "/Type /Catalog\n");
825
+ ps_printf(p, "/Pages 2 0 R\n");
826
+ ps_printf(p, ">>\nendobj\n");
827
+ xref = p->ps->pdfbytes;
828
+ ps_printf(p, "xref\n");
829
+ ps_printf(p, "0 %zu\n", base + 1);
830
+ ps_printf(p, "0000000000 65535 f \n");
831
+
832
+ for (i = 0; i < base; i++)
833
+ ps_printf(p, "%.10zu 00000 n \n",
834
+ p->ps->pdfobjs[(int)i]);
835
+
836
+ ps_printf(p, "trailer\n");
837
+ ps_printf(p, "<<\n");
838
+ ps_printf(p, "/Size %zu\n", base + 1);
839
+ ps_printf(p, "/Root %zu 0 R\n", base);
840
+ ps_printf(p, "/Info 1 0 R\n");
841
+ ps_printf(p, ">>\n");
842
+ ps_printf(p, "startxref\n");
843
+ ps_printf(p, "%zu\n", xref);
844
+ ps_printf(p, "%%%%EOF\n");
845
+ }
846
+
847
+ static void
848
+ ps_begin(struct termp *p)
849
+ {
850
+ size_t width, height;
851
+ int i;
852
+
853
+ /*
854
+ * Print margins into margin buffer. Nothing gets output to the
855
+ * screen yet, so we don't need to initialise the primary state.
856
+ */
857
+
858
+ if (p->ps->psmarg) {
859
+ assert(p->ps->psmargsz);
860
+ p->ps->psmarg[0] = '\0';
861
+ }
862
+
863
+ /*p->ps->pdfbytes = 0;*/
864
+ p->ps->psmargcur = 0;
865
+ p->ps->flags = PS_MARGINS;
866
+ p->ps->pscol = p->ps->left;
867
+ p->ps->psrow = p->ps->header;
868
+ p->ps->lastrow = 0; /* impossible row */
869
+
870
+ ps_setfont(p, TERMFONT_NONE);
871
+
872
+ (*p->headf)(p, p->argf);
873
+ (*p->endline)(p);
874
+
875
+ p->ps->pscol = p->ps->left;
876
+ p->ps->psrow = p->ps->footer;
877
+
878
+ (*p->footf)(p, p->argf);
879
+ (*p->endline)(p);
880
+
881
+ p->ps->flags &= ~PS_MARGINS;
882
+
883
+ assert(0 == p->ps->flags);
884
+ assert(p->ps->psmarg);
885
+ assert('\0' != p->ps->psmarg[0]);
886
+
887
+ /*
888
+ * Print header and initialise page state. Following this,
889
+ * stuff gets printed to the screen, so make sure we're sane.
890
+ */
891
+
892
+ if (TERMTYPE_PS == p->type) {
893
+ width = AFM2PNT(p, p->ps->width);
894
+ height = AFM2PNT(p, p->ps->height);
895
+
896
+ ps_printf(p, "%%!PS-Adobe-3.0\n");
897
+ ps_printf(p, "%%%%DocumentData: Clean7Bit\n");
898
+ ps_printf(p, "%%%%Orientation: Portrait\n");
899
+ ps_printf(p, "%%%%Pages: (atend)\n");
900
+ ps_printf(p, "%%%%PageOrder: Ascend\n");
901
+ ps_printf(p, "%%%%DocumentMedia: man-%s %zu %zu 0 () ()\n",
902
+ p->ps->medianame, width, height);
903
+ ps_printf(p, "%%%%DocumentNeededResources: font");
904
+
905
+ for (i = 0; i < (int)TERMFONT__MAX; i++)
906
+ ps_printf(p, " %s", fonts[i].name);
907
+
908
+ ps_printf(p, "\n%%%%DocumentSuppliedResources: "
909
+ "procset MandocProcs 1.0 0\n");
910
+ ps_printf(p, "%%%%EndComments\n");
911
+ ps_printf(p, "%%%%BeginProlog\n");
912
+ ps_printf(p, "%%%%BeginResource: procset MandocProcs "
913
+ "10170 10170\n");
914
+ /* The font size is effectively hard-coded for now. */
915
+ ps_printf(p, "/fs %zu def\n", p->ps->scale);
916
+ for (i = 0; i < (int)TERMFONT__MAX; i++)
917
+ ps_printf(p, "/f%d { /%s fs selectfont } def\n",
918
+ i, fonts[i].name);
919
+ ps_printf(p, "/s { 3 1 roll moveto show } bind def\n");
920
+ ps_printf(p, "/c { exch currentpoint exch pop "
921
+ "moveto show } bind def\n");
922
+ ps_printf(p, "%%%%EndResource\n");
923
+ ps_printf(p, "%%%%EndProlog\n");
924
+ ps_printf(p, "%%%%BeginSetup\n");
925
+ ps_printf(p, "%%%%BeginFeature: *PageSize %s\n",
926
+ p->ps->medianame);
927
+ ps_printf(p, "<</PageSize [%zu %zu]>>setpagedevice\n",
928
+ width, height);
929
+ ps_printf(p, "%%%%EndFeature\n");
930
+ ps_printf(p, "%%%%EndSetup\n");
931
+ } else {
932
+ ps_printf(p, "%%PDF-1.1\n");
933
+ pdf_obj(p, 1);
934
+ ps_printf(p, "<<\n");
935
+ ps_printf(p, ">>\n");
936
+ ps_printf(p, "endobj\n");
937
+
938
+ for (i = 0; i < (int)TERMFONT__MAX; i++) {
939
+ pdf_obj(p, (size_t)i + 3);
940
+ ps_printf(p, "<<\n");
941
+ ps_printf(p, "/Type /Font\n");
942
+ ps_printf(p, "/Subtype /Type1\n");
943
+ ps_printf(p, "/Name /F%d\n", i);
944
+ ps_printf(p, "/BaseFont /%s\n", fonts[i].name);
945
+ ps_printf(p, ">>\nendobj\n");
946
+ }
947
+ }
948
+
949
+ p->ps->pdfbody = (size_t)TERMFONT__MAX + 3;
950
+ p->ps->pscol = p->ps->left;
951
+ p->ps->psrow = p->ps->top;
952
+ p->ps->flags |= PS_NEWPAGE;
953
+ ps_setfont(p, TERMFONT_NONE);
954
+ }
955
+
956
+ static void
957
+ ps_pletter(struct termp *p, int c)
958
+ {
959
+ int f;
960
+
961
+ /*
962
+ * If we haven't opened a page context, then output that we're
963
+ * in a new page and make sure the font is correctly set.
964
+ */
965
+
966
+ if (PS_NEWPAGE & p->ps->flags) {
967
+ if (TERMTYPE_PS == p->type) {
968
+ ps_printf(p, "%%%%Page: %zu %zu\n",
969
+ p->ps->pages + 1, p->ps->pages + 1);
970
+ ps_printf(p, "f%d\n", (int)p->ps->lastf);
971
+ } else {
972
+ pdf_obj(p, p->ps->pdfbody +
973
+ p->ps->pages * 4);
974
+ ps_printf(p, "<<\n");
975
+ ps_printf(p, "/Length %zu 0 R\n",
976
+ p->ps->pdfbody + 1 + p->ps->pages * 4);
977
+ ps_printf(p, ">>\nstream\n");
978
+ }
979
+ p->ps->pdflastpg = p->ps->pdfbytes;
980
+ p->ps->flags &= ~PS_NEWPAGE;
981
+ }
982
+
983
+ /*
984
+ * If we're not in a PostScript "word" context, then open one
985
+ * now at the current cursor.
986
+ */
987
+
988
+ if ( ! (PS_INLINE & p->ps->flags)) {
989
+ if (TERMTYPE_PS != p->type) {
990
+ ps_printf(p, "BT\n/F%d %zu Tf\n",
991
+ (int)p->ps->lastf, p->ps->scale);
992
+ ps_printf(p, "%.3f %.3f Td\n(",
993
+ AFM2PNT(p, p->ps->pscol),
994
+ AFM2PNT(p, p->ps->psrow));
995
+ } else {
996
+ ps_printf(p, "%.3f", AFM2PNT(p, p->ps->pscol));
997
+ if (p->ps->psrow != p->ps->lastrow)
998
+ ps_printf(p, " %.3f",
999
+ AFM2PNT(p, p->ps->psrow));
1000
+ ps_printf(p, "(");
1001
+ }
1002
+ p->ps->flags |= PS_INLINE;
1003
+ }
1004
+
1005
+ assert( ! (PS_NEWPAGE & p->ps->flags));
1006
+
1007
+ /*
1008
+ * We need to escape these characters as per the PostScript
1009
+ * specification. We would also escape non-graphable characters
1010
+ * (like tabs), but none of them would get to this point and
1011
+ * it's superfluous to abort() on them.
1012
+ */
1013
+
1014
+ switch (c) {
1015
+ case '(':
1016
+ case ')':
1017
+ case '\\':
1018
+ ps_putchar(p, '\\');
1019
+ break;
1020
+ default:
1021
+ break;
1022
+ }
1023
+
1024
+ /* Write the character and adjust where we are on the page. */
1025
+
1026
+ f = (int)p->ps->lastf;
1027
+
1028
+ if (c <= 32 || c - 32 >= MAXCHAR)
1029
+ c = 32;
1030
+
1031
+ ps_putchar(p, (char)c);
1032
+ c -= 32;
1033
+ p->ps->pscol += (size_t)fonts[f].gly[c].wx;
1034
+ }
1035
+
1036
+ static void
1037
+ ps_pclose(struct termp *p)
1038
+ {
1039
+
1040
+ /*
1041
+ * Spit out that we're exiting a word context (this is a
1042
+ * "partial close" because we don't check the last-char buffer
1043
+ * or anything).
1044
+ */
1045
+
1046
+ if ( ! (PS_INLINE & p->ps->flags))
1047
+ return;
1048
+
1049
+ if (TERMTYPE_PS != p->type)
1050
+ ps_printf(p, ") Tj\nET\n");
1051
+ else if (p->ps->psrow == p->ps->lastrow)
1052
+ ps_printf(p, ")c\n");
1053
+ else {
1054
+ ps_printf(p, ")s\n");
1055
+ p->ps->lastrow = p->ps->psrow;
1056
+ }
1057
+
1058
+ p->ps->flags &= ~PS_INLINE;
1059
+ }
1060
+
1061
+ /* If we have a `last' char that wasn't printed yet, print it now. */
1062
+ static void
1063
+ ps_plast(struct termp *p)
1064
+ {
1065
+ size_t wx;
1066
+
1067
+ if (p->ps->last == '\0')
1068
+ return;
1069
+
1070
+ /* Check the font mode; open a new scope if it doesn't match. */
1071
+
1072
+ if (p->ps->nextf != p->ps->lastf) {
1073
+ ps_pclose(p);
1074
+ ps_setfont(p, p->ps->nextf);
1075
+ }
1076
+ p->ps->nextf = TERMFONT_NONE;
1077
+
1078
+ /*
1079
+ * For an overstrike, if a previous character
1080
+ * was wider, advance to center the new one.
1081
+ */
1082
+
1083
+ if (p->ps->pscolnext) {
1084
+ wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx;
1085
+ if (p->ps->pscol + wx < p->ps->pscolnext)
1086
+ p->ps->pscol = (p->ps->pscol +
1087
+ p->ps->pscolnext - wx) / 2;
1088
+ }
1089
+
1090
+ ps_pletter(p, p->ps->last);
1091
+ p->ps->last = '\0';
1092
+
1093
+ /*
1094
+ * For an overstrike, if a previous character
1095
+ * was wider, advance to the end of the old one.
1096
+ */
1097
+
1098
+ if (p->ps->pscol < p->ps->pscolnext) {
1099
+ ps_pclose(p);
1100
+ p->ps->pscol = p->ps->pscolnext;
1101
+ }
1102
+ }
1103
+
1104
+ static void
1105
+ ps_letter(struct termp *p, int arg)
1106
+ {
1107
+ size_t savecol;
1108
+ char c;
1109
+
1110
+ c = arg >= 128 || arg <= 0 ? '?' : arg;
1111
+
1112
+ /*
1113
+ * When receiving a backspace, merely flag it.
1114
+ * We don't know yet whether it is
1115
+ * a font instruction or an overstrike.
1116
+ */
1117
+
1118
+ if (c == '\b') {
1119
+ assert(p->ps->last != '\0');
1120
+ assert( ! (p->ps->flags & PS_BACKSP));
1121
+ p->ps->flags |= PS_BACKSP;
1122
+ return;
1123
+ }
1124
+
1125
+ /*
1126
+ * Decode font instructions.
1127
+ */
1128
+
1129
+ if (p->ps->flags & PS_BACKSP) {
1130
+ if (p->ps->last == '_') {
1131
+ switch (p->ps->nextf) {
1132
+ case TERMFONT_BI:
1133
+ break;
1134
+ case TERMFONT_BOLD:
1135
+ p->ps->nextf = TERMFONT_BI;
1136
+ break;
1137
+ default:
1138
+ p->ps->nextf = TERMFONT_UNDER;
1139
+ }
1140
+ p->ps->last = c;
1141
+ p->ps->flags &= ~PS_BACKSP;
1142
+ return;
1143
+ }
1144
+ if (p->ps->last == c) {
1145
+ switch (p->ps->nextf) {
1146
+ case TERMFONT_BI:
1147
+ break;
1148
+ case TERMFONT_UNDER:
1149
+ p->ps->nextf = TERMFONT_BI;
1150
+ break;
1151
+ default:
1152
+ p->ps->nextf = TERMFONT_BOLD;
1153
+ }
1154
+ p->ps->flags &= ~PS_BACKSP;
1155
+ return;
1156
+ }
1157
+
1158
+ /*
1159
+ * This is not a font instruction, but rather
1160
+ * the next character. Prepare for overstrike.
1161
+ */
1162
+
1163
+ savecol = p->ps->pscol;
1164
+ } else
1165
+ savecol = SIZE_MAX;
1166
+
1167
+ /*
1168
+ * We found the next character, so the font instructions
1169
+ * for the previous one are complete.
1170
+ * Use them and print it.
1171
+ */
1172
+
1173
+ ps_plast(p);
1174
+
1175
+ /*
1176
+ * Do not print the current character yet because font
1177
+ * instructions might follow; only remember the character.
1178
+ * It will get printed later from ps_plast().
1179
+ */
1180
+
1181
+ p->ps->last = c;
1182
+
1183
+ /*
1184
+ * For an overstrike, back up to the previous position.
1185
+ * If the previous character is wider than any it overstrikes,
1186
+ * remember the current position, because it might also be
1187
+ * wider than all that will overstrike it.
1188
+ */
1189
+
1190
+ if (savecol != SIZE_MAX) {
1191
+ if (p->ps->pscolnext < p->ps->pscol)
1192
+ p->ps->pscolnext = p->ps->pscol;
1193
+ ps_pclose(p);
1194
+ p->ps->pscol = savecol;
1195
+ p->ps->flags &= ~PS_BACKSP;
1196
+ } else
1197
+ p->ps->pscolnext = 0;
1198
+ }
1199
+
1200
+ static void
1201
+ ps_advance(struct termp *p, size_t len)
1202
+ {
1203
+
1204
+ /*
1205
+ * Advance some spaces. This can probably be made smarter,
1206
+ * i.e., to have multiple space-separated words in the same
1207
+ * scope, but this is easier: just close out the current scope
1208
+ * and readjust our column settings.
1209
+ */
1210
+
1211
+ ps_plast(p);
1212
+ ps_pclose(p);
1213
+ p->ps->pscol += len;
1214
+ }
1215
+
1216
+ static void
1217
+ ps_endline(struct termp *p)
1218
+ {
1219
+
1220
+ /* Close out any scopes we have open: we're at eoln. */
1221
+
1222
+ ps_plast(p);
1223
+ ps_pclose(p);
1224
+
1225
+ /*
1226
+ * If we're in the margin, don't try to recalculate our current
1227
+ * row. XXX: if the column tries to be fancy with multiple
1228
+ * lines, we'll do nasty stuff.
1229
+ */
1230
+
1231
+ if (PS_MARGINS & p->ps->flags)
1232
+ return;
1233
+
1234
+ /* Left-justify. */
1235
+
1236
+ p->ps->pscol = p->ps->left;
1237
+
1238
+ /* If we haven't printed anything, return. */
1239
+
1240
+ if (PS_NEWPAGE & p->ps->flags)
1241
+ return;
1242
+
1243
+ /*
1244
+ * Put us down a line. If we're at the page bottom, spit out a
1245
+ * showpage and restart our row.
1246
+ */
1247
+
1248
+ if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) {
1249
+ p->ps->psrow -= p->ps->lineheight;
1250
+ return;
1251
+ }
1252
+
1253
+ ps_closepage(p);
1254
+
1255
+ if ((int)p->tcol->offset > p->ti)
1256
+ p->tcol->offset -= p->ti;
1257
+ else
1258
+ p->tcol->offset = 0;
1259
+ p->ti = 0;
1260
+ }
1261
+
1262
+ static void
1263
+ ps_setfont(struct termp *p, enum termfont f)
1264
+ {
1265
+
1266
+ assert(f < TERMFONT__MAX);
1267
+ p->ps->lastf = f;
1268
+
1269
+ /*
1270
+ * If we're still at the top of the page, let the font-setting
1271
+ * be delayed until we actually have stuff to print.
1272
+ */
1273
+
1274
+ if (PS_NEWPAGE & p->ps->flags)
1275
+ return;
1276
+
1277
+ if (TERMTYPE_PS == p->type)
1278
+ ps_printf(p, "f%d\n", (int)f);
1279
+ else
1280
+ ps_printf(p, "/F%d %zu Tf\n",
1281
+ (int)f, p->ps->scale);
1282
+ }
1283
+
1284
+ static size_t
1285
+ ps_width(const struct termp *p, int c)
1286
+ {
1287
+
1288
+ if (c <= 32 || c - 32 >= MAXCHAR)
1289
+ c = 0;
1290
+ else
1291
+ c -= 32;
1292
+
1293
+ return (size_t)fonts[(int)TERMFONT_NONE].gly[c].wx;
1294
+ }
1295
+
1296
+ static int
1297
+ ps_hspan(const struct termp *p, const struct roffsu *su)
1298
+ {
1299
+ double r;
1300
+
1301
+ /*
1302
+ * All of these measurements are derived by converting from the
1303
+ * native measurement to AFM units.
1304
+ */
1305
+ switch (su->unit) {
1306
+ case SCALE_BU:
1307
+ /*
1308
+ * Traditionally, the default unit is fixed to the
1309
+ * output media. So this would refer to the point. In
1310
+ * mandoc(1), however, we stick to the default terminal
1311
+ * scaling unit so that output is the same regardless
1312
+ * the media.
1313
+ */
1314
+ r = PNT2AFM(p, su->scale * 72.0 / 240.0);
1315
+ break;
1316
+ case SCALE_CM:
1317
+ r = PNT2AFM(p, su->scale * 72.0 / 2.54);
1318
+ break;
1319
+ case SCALE_EM:
1320
+ r = su->scale *
1321
+ fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
1322
+ break;
1323
+ case SCALE_EN:
1324
+ r = su->scale *
1325
+ fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
1326
+ break;
1327
+ case SCALE_IN:
1328
+ r = PNT2AFM(p, su->scale * 72.0);
1329
+ break;
1330
+ case SCALE_MM:
1331
+ r = su->scale *
1332
+ fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0;
1333
+ break;
1334
+ case SCALE_PC:
1335
+ r = PNT2AFM(p, su->scale * 12.0);
1336
+ break;
1337
+ case SCALE_PT:
1338
+ r = PNT2AFM(p, su->scale * 1.0);
1339
+ break;
1340
+ case SCALE_VS:
1341
+ r = su->scale * p->ps->lineheight;
1342
+ break;
1343
+ default:
1344
+ r = su->scale;
1345
+ break;
1346
+ }
1347
+
1348
+ return r * 24.0;
1349
+ }
1350
+
1351
+ static void
1352
+ ps_growbuf(struct termp *p, size_t sz)
1353
+ {
1354
+ if (p->ps->psmargcur + sz <= p->ps->psmargsz)
1355
+ return;
1356
+
1357
+ if (sz < PS_BUFSLOP)
1358
+ sz = PS_BUFSLOP;
1359
+
1360
+ p->ps->psmargsz += sz;
1361
+ p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz);
1362
+ }