1*260e9a87SYuri Pankov /* $Id: term_ps.c,v 1.72 2015/01/21 19:40:54 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*260e9a87SYuri Pankov * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #include "config.h" 1995c635efSGarrett D'Amore 2095c635efSGarrett D'Amore #include <sys/types.h> 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <assert.h> 2395c635efSGarrett D'Amore #include <stdarg.h> 2495c635efSGarrett D'Amore #include <stdint.h> 2595c635efSGarrett D'Amore #include <stdio.h> 2695c635efSGarrett D'Amore #include <stdlib.h> 2795c635efSGarrett D'Amore #include <string.h> 2895c635efSGarrett D'Amore #include <unistd.h> 2995c635efSGarrett D'Amore 30*260e9a87SYuri Pankov #include "mandoc_aux.h" 3195c635efSGarrett D'Amore #include "out.h" 3295c635efSGarrett D'Amore #include "term.h" 33*260e9a87SYuri Pankov #include "main.h" 3495c635efSGarrett D'Amore 3595c635efSGarrett D'Amore /* These work the buffer used by the header and footer. */ 3695c635efSGarrett D'Amore #define PS_BUFSLOP 128 3795c635efSGarrett D'Amore 3895c635efSGarrett D'Amore /* Convert PostScript point "x" to an AFM unit. */ 39*260e9a87SYuri Pankov #define PNT2AFM(p, x) \ 4095c635efSGarrett D'Amore (size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale)) 4195c635efSGarrett D'Amore 4295c635efSGarrett D'Amore /* Convert an AFM unit "x" to a PostScript points */ 43*260e9a87SYuri Pankov #define AFM2PNT(p, x) \ 4495c635efSGarrett D'Amore ((double)(x) / (1000.0 / (double)(p)->ps->scale)) 4595c635efSGarrett D'Amore 4695c635efSGarrett D'Amore struct glyph { 4795c635efSGarrett D'Amore unsigned short wx; /* WX in AFM */ 4895c635efSGarrett D'Amore }; 4995c635efSGarrett D'Amore 5095c635efSGarrett D'Amore struct font { 5195c635efSGarrett D'Amore const char *name; /* FontName in AFM */ 5295c635efSGarrett D'Amore #define MAXCHAR 95 /* total characters we can handle */ 5395c635efSGarrett D'Amore struct glyph gly[MAXCHAR]; /* glyph metrics */ 5495c635efSGarrett D'Amore }; 5595c635efSGarrett D'Amore 5695c635efSGarrett D'Amore struct termp_ps { 5795c635efSGarrett D'Amore int flags; 5895c635efSGarrett D'Amore #define PS_INLINE (1 << 0) /* we're in a word */ 5995c635efSGarrett D'Amore #define PS_MARGINS (1 << 1) /* we're in the margins */ 6095c635efSGarrett D'Amore #define PS_NEWPAGE (1 << 2) /* new page, no words yet */ 61*260e9a87SYuri Pankov #define PS_BACKSP (1 << 3) /* last character was backspace */ 6295c635efSGarrett D'Amore size_t pscol; /* visible column (AFM units) */ 63*260e9a87SYuri Pankov size_t pscolnext; /* used for overstrike */ 6495c635efSGarrett D'Amore size_t psrow; /* visible row (AFM units) */ 6595c635efSGarrett D'Amore char *psmarg; /* margin buf */ 6695c635efSGarrett D'Amore size_t psmargsz; /* margin buf size */ 6795c635efSGarrett D'Amore size_t psmargcur; /* cur index in margin buf */ 68*260e9a87SYuri Pankov char last; /* last non-backspace seen */ 6995c635efSGarrett D'Amore enum termfont lastf; /* last set font */ 70*260e9a87SYuri Pankov enum termfont nextf; /* building next font here */ 7195c635efSGarrett D'Amore size_t scale; /* font scaling factor */ 7295c635efSGarrett D'Amore size_t pages; /* number of pages shown */ 7395c635efSGarrett D'Amore size_t lineheight; /* line height (AFM units) */ 7495c635efSGarrett D'Amore size_t top; /* body top (AFM units) */ 7595c635efSGarrett D'Amore size_t bottom; /* body bottom (AFM units) */ 7695c635efSGarrett D'Amore size_t height; /* page height (AFM units */ 7795c635efSGarrett D'Amore size_t width; /* page width (AFM units) */ 78*260e9a87SYuri Pankov size_t lastwidth; /* page width before last ll */ 7995c635efSGarrett D'Amore size_t left; /* body left (AFM units) */ 8095c635efSGarrett D'Amore size_t header; /* header pos (AFM units) */ 8195c635efSGarrett D'Amore size_t footer; /* footer pos (AFM units) */ 8295c635efSGarrett D'Amore size_t pdfbytes; /* current output byte */ 8395c635efSGarrett D'Amore size_t pdflastpg; /* byte of last page mark */ 8495c635efSGarrett D'Amore size_t pdfbody; /* start of body object */ 8595c635efSGarrett D'Amore size_t *pdfobjs; /* table of object offsets */ 8695c635efSGarrett D'Amore size_t pdfobjsz; /* size of pdfobjs */ 8795c635efSGarrett D'Amore }; 8895c635efSGarrett D'Amore 8995c635efSGarrett D'Amore static double ps_hspan(const struct termp *, 9095c635efSGarrett D'Amore const struct roffsu *); 9195c635efSGarrett D'Amore static size_t ps_width(const struct termp *, int); 9295c635efSGarrett D'Amore static void ps_advance(struct termp *, size_t); 9395c635efSGarrett D'Amore static void ps_begin(struct termp *); 9495c635efSGarrett D'Amore static void ps_closepage(struct termp *); 9595c635efSGarrett D'Amore static void ps_end(struct termp *); 9695c635efSGarrett D'Amore static void ps_endline(struct termp *); 9795c635efSGarrett D'Amore static void ps_fclose(struct termp *); 9895c635efSGarrett D'Amore static void ps_growbuf(struct termp *, size_t); 9995c635efSGarrett D'Amore static void ps_letter(struct termp *, int); 10095c635efSGarrett D'Amore static void ps_pclose(struct termp *); 10195c635efSGarrett D'Amore static void ps_pletter(struct termp *, int); 102*260e9a87SYuri Pankov #if __GNUC__ - 0 >= 4 103*260e9a87SYuri Pankov __attribute__((__format__ (__printf__, 2, 3))) 104*260e9a87SYuri Pankov #endif 10595c635efSGarrett D'Amore static void ps_printf(struct termp *, const char *, ...); 10695c635efSGarrett D'Amore static void ps_putchar(struct termp *, char); 10795c635efSGarrett D'Amore static void ps_setfont(struct termp *, enum termfont); 108*260e9a87SYuri Pankov static void ps_setwidth(struct termp *, int, size_t); 109*260e9a87SYuri Pankov static struct termp *pspdf_alloc(const struct mchars *, char *); 11095c635efSGarrett D'Amore static void pdf_obj(struct termp *, size_t); 11195c635efSGarrett D'Amore 11295c635efSGarrett D'Amore /* 11395c635efSGarrett D'Amore * We define, for the time being, three fonts: bold, oblique/italic, and 11495c635efSGarrett D'Amore * normal (roman). The following table hard-codes the font metrics for 11595c635efSGarrett D'Amore * ASCII, i.e., 32--127. 11695c635efSGarrett D'Amore */ 11795c635efSGarrett D'Amore 11895c635efSGarrett D'Amore static const struct font fonts[TERMFONT__MAX] = { 11995c635efSGarrett D'Amore { "Times-Roman", { 12095c635efSGarrett D'Amore { 250 }, 12195c635efSGarrett D'Amore { 333 }, 12295c635efSGarrett D'Amore { 408 }, 12395c635efSGarrett D'Amore { 500 }, 12495c635efSGarrett D'Amore { 500 }, 12595c635efSGarrett D'Amore { 833 }, 12695c635efSGarrett D'Amore { 778 }, 12795c635efSGarrett D'Amore { 333 }, 12895c635efSGarrett D'Amore { 333 }, 12995c635efSGarrett D'Amore { 333 }, 13095c635efSGarrett D'Amore { 500 }, 13195c635efSGarrett D'Amore { 564 }, 13295c635efSGarrett D'Amore { 250 }, 13395c635efSGarrett D'Amore { 333 }, 13495c635efSGarrett D'Amore { 250 }, 13595c635efSGarrett D'Amore { 278 }, 13695c635efSGarrett D'Amore { 500 }, 13795c635efSGarrett D'Amore { 500 }, 13895c635efSGarrett D'Amore { 500 }, 13995c635efSGarrett D'Amore { 500 }, 14095c635efSGarrett D'Amore { 500 }, 14195c635efSGarrett D'Amore { 500 }, 14295c635efSGarrett D'Amore { 500 }, 14395c635efSGarrett D'Amore { 500 }, 14495c635efSGarrett D'Amore { 500 }, 14595c635efSGarrett D'Amore { 500 }, 14695c635efSGarrett D'Amore { 278 }, 14795c635efSGarrett D'Amore { 278 }, 14895c635efSGarrett D'Amore { 564 }, 14995c635efSGarrett D'Amore { 564 }, 15095c635efSGarrett D'Amore { 564 }, 15195c635efSGarrett D'Amore { 444 }, 15295c635efSGarrett D'Amore { 921 }, 15395c635efSGarrett D'Amore { 722 }, 15495c635efSGarrett D'Amore { 667 }, 15595c635efSGarrett D'Amore { 667 }, 15695c635efSGarrett D'Amore { 722 }, 15795c635efSGarrett D'Amore { 611 }, 15895c635efSGarrett D'Amore { 556 }, 15995c635efSGarrett D'Amore { 722 }, 16095c635efSGarrett D'Amore { 722 }, 16195c635efSGarrett D'Amore { 333 }, 16295c635efSGarrett D'Amore { 389 }, 16395c635efSGarrett D'Amore { 722 }, 16495c635efSGarrett D'Amore { 611 }, 16595c635efSGarrett D'Amore { 889 }, 16695c635efSGarrett D'Amore { 722 }, 16795c635efSGarrett D'Amore { 722 }, 16895c635efSGarrett D'Amore { 556 }, 16995c635efSGarrett D'Amore { 722 }, 17095c635efSGarrett D'Amore { 667 }, 17195c635efSGarrett D'Amore { 556 }, 17295c635efSGarrett D'Amore { 611 }, 17395c635efSGarrett D'Amore { 722 }, 17495c635efSGarrett D'Amore { 722 }, 17595c635efSGarrett D'Amore { 944 }, 17695c635efSGarrett D'Amore { 722 }, 17795c635efSGarrett D'Amore { 722 }, 17895c635efSGarrett D'Amore { 611 }, 17995c635efSGarrett D'Amore { 333 }, 18095c635efSGarrett D'Amore { 278 }, 18195c635efSGarrett D'Amore { 333 }, 18295c635efSGarrett D'Amore { 469 }, 18395c635efSGarrett D'Amore { 500 }, 18495c635efSGarrett D'Amore { 333 }, 18595c635efSGarrett D'Amore { 444 }, 18695c635efSGarrett D'Amore { 500 }, 18795c635efSGarrett D'Amore { 444 }, 18895c635efSGarrett D'Amore { 500}, 18995c635efSGarrett D'Amore { 444}, 19095c635efSGarrett D'Amore { 333}, 19195c635efSGarrett D'Amore { 500}, 19295c635efSGarrett D'Amore { 500}, 19395c635efSGarrett D'Amore { 278}, 19495c635efSGarrett D'Amore { 278}, 19595c635efSGarrett D'Amore { 500}, 19695c635efSGarrett D'Amore { 278}, 19795c635efSGarrett D'Amore { 778}, 19895c635efSGarrett D'Amore { 500}, 19995c635efSGarrett D'Amore { 500}, 20095c635efSGarrett D'Amore { 500}, 20195c635efSGarrett D'Amore { 500}, 20295c635efSGarrett D'Amore { 333}, 20395c635efSGarrett D'Amore { 389}, 20495c635efSGarrett D'Amore { 278}, 20595c635efSGarrett D'Amore { 500}, 20695c635efSGarrett D'Amore { 500}, 20795c635efSGarrett D'Amore { 722}, 20895c635efSGarrett D'Amore { 500}, 20995c635efSGarrett D'Amore { 500}, 21095c635efSGarrett D'Amore { 444}, 21195c635efSGarrett D'Amore { 480}, 21295c635efSGarrett D'Amore { 200}, 21395c635efSGarrett D'Amore { 480}, 21495c635efSGarrett D'Amore { 541}, 21595c635efSGarrett D'Amore } }, 21695c635efSGarrett D'Amore { "Times-Bold", { 21795c635efSGarrett D'Amore { 250 }, 21895c635efSGarrett D'Amore { 333 }, 21995c635efSGarrett D'Amore { 555 }, 22095c635efSGarrett D'Amore { 500 }, 22195c635efSGarrett D'Amore { 500 }, 22295c635efSGarrett D'Amore { 1000 }, 22395c635efSGarrett D'Amore { 833 }, 22495c635efSGarrett D'Amore { 333 }, 22595c635efSGarrett D'Amore { 333 }, 22695c635efSGarrett D'Amore { 333 }, 22795c635efSGarrett D'Amore { 500 }, 22895c635efSGarrett D'Amore { 570 }, 22995c635efSGarrett D'Amore { 250 }, 23095c635efSGarrett D'Amore { 333 }, 23195c635efSGarrett D'Amore { 250 }, 23295c635efSGarrett D'Amore { 278 }, 23395c635efSGarrett D'Amore { 500 }, 23495c635efSGarrett D'Amore { 500 }, 23595c635efSGarrett D'Amore { 500 }, 23695c635efSGarrett D'Amore { 500 }, 23795c635efSGarrett D'Amore { 500 }, 23895c635efSGarrett D'Amore { 500 }, 23995c635efSGarrett D'Amore { 500 }, 24095c635efSGarrett D'Amore { 500 }, 24195c635efSGarrett D'Amore { 500 }, 24295c635efSGarrett D'Amore { 500 }, 24395c635efSGarrett D'Amore { 333 }, 24495c635efSGarrett D'Amore { 333 }, 24595c635efSGarrett D'Amore { 570 }, 24695c635efSGarrett D'Amore { 570 }, 24795c635efSGarrett D'Amore { 570 }, 24895c635efSGarrett D'Amore { 500 }, 24995c635efSGarrett D'Amore { 930 }, 25095c635efSGarrett D'Amore { 722 }, 25195c635efSGarrett D'Amore { 667 }, 25295c635efSGarrett D'Amore { 722 }, 25395c635efSGarrett D'Amore { 722 }, 25495c635efSGarrett D'Amore { 667 }, 25595c635efSGarrett D'Amore { 611 }, 25695c635efSGarrett D'Amore { 778 }, 25795c635efSGarrett D'Amore { 778 }, 25895c635efSGarrett D'Amore { 389 }, 25995c635efSGarrett D'Amore { 500 }, 26095c635efSGarrett D'Amore { 778 }, 26195c635efSGarrett D'Amore { 667 }, 26295c635efSGarrett D'Amore { 944 }, 26395c635efSGarrett D'Amore { 722 }, 26495c635efSGarrett D'Amore { 778 }, 26595c635efSGarrett D'Amore { 611 }, 26695c635efSGarrett D'Amore { 778 }, 26795c635efSGarrett D'Amore { 722 }, 26895c635efSGarrett D'Amore { 556 }, 26995c635efSGarrett D'Amore { 667 }, 27095c635efSGarrett D'Amore { 722 }, 27195c635efSGarrett D'Amore { 722 }, 27295c635efSGarrett D'Amore { 1000 }, 27395c635efSGarrett D'Amore { 722 }, 27495c635efSGarrett D'Amore { 722 }, 27595c635efSGarrett D'Amore { 667 }, 27695c635efSGarrett D'Amore { 333 }, 27795c635efSGarrett D'Amore { 278 }, 27895c635efSGarrett D'Amore { 333 }, 27995c635efSGarrett D'Amore { 581 }, 28095c635efSGarrett D'Amore { 500 }, 28195c635efSGarrett D'Amore { 333 }, 28295c635efSGarrett D'Amore { 500 }, 28395c635efSGarrett D'Amore { 556 }, 28495c635efSGarrett D'Amore { 444 }, 28595c635efSGarrett D'Amore { 556 }, 28695c635efSGarrett D'Amore { 444 }, 28795c635efSGarrett D'Amore { 333 }, 28895c635efSGarrett D'Amore { 500 }, 28995c635efSGarrett D'Amore { 556 }, 29095c635efSGarrett D'Amore { 278 }, 29195c635efSGarrett D'Amore { 333 }, 29295c635efSGarrett D'Amore { 556 }, 29395c635efSGarrett D'Amore { 278 }, 29495c635efSGarrett D'Amore { 833 }, 29595c635efSGarrett D'Amore { 556 }, 29695c635efSGarrett D'Amore { 500 }, 29795c635efSGarrett D'Amore { 556 }, 29895c635efSGarrett D'Amore { 556 }, 29995c635efSGarrett D'Amore { 444 }, 30095c635efSGarrett D'Amore { 389 }, 30195c635efSGarrett D'Amore { 333 }, 30295c635efSGarrett D'Amore { 556 }, 30395c635efSGarrett D'Amore { 500 }, 30495c635efSGarrett D'Amore { 722 }, 30595c635efSGarrett D'Amore { 500 }, 30695c635efSGarrett D'Amore { 500 }, 30795c635efSGarrett D'Amore { 444 }, 30895c635efSGarrett D'Amore { 394 }, 30995c635efSGarrett D'Amore { 220 }, 31095c635efSGarrett D'Amore { 394 }, 31195c635efSGarrett D'Amore { 520 }, 31295c635efSGarrett D'Amore } }, 31395c635efSGarrett D'Amore { "Times-Italic", { 31495c635efSGarrett D'Amore { 250 }, 31595c635efSGarrett D'Amore { 333 }, 31695c635efSGarrett D'Amore { 420 }, 31795c635efSGarrett D'Amore { 500 }, 31895c635efSGarrett D'Amore { 500 }, 31995c635efSGarrett D'Amore { 833 }, 32095c635efSGarrett D'Amore { 778 }, 32195c635efSGarrett D'Amore { 333 }, 32295c635efSGarrett D'Amore { 333 }, 32395c635efSGarrett D'Amore { 333 }, 32495c635efSGarrett D'Amore { 500 }, 32595c635efSGarrett D'Amore { 675 }, 32695c635efSGarrett D'Amore { 250 }, 32795c635efSGarrett D'Amore { 333 }, 32895c635efSGarrett D'Amore { 250 }, 32995c635efSGarrett D'Amore { 278 }, 33095c635efSGarrett D'Amore { 500 }, 33195c635efSGarrett D'Amore { 500 }, 33295c635efSGarrett D'Amore { 500 }, 33395c635efSGarrett D'Amore { 500 }, 33495c635efSGarrett D'Amore { 500 }, 33595c635efSGarrett D'Amore { 500 }, 33695c635efSGarrett D'Amore { 500 }, 33795c635efSGarrett D'Amore { 500 }, 33895c635efSGarrett D'Amore { 500 }, 33995c635efSGarrett D'Amore { 500 }, 34095c635efSGarrett D'Amore { 333 }, 34195c635efSGarrett D'Amore { 333 }, 34295c635efSGarrett D'Amore { 675 }, 34395c635efSGarrett D'Amore { 675 }, 34495c635efSGarrett D'Amore { 675 }, 34595c635efSGarrett D'Amore { 500 }, 34695c635efSGarrett D'Amore { 920 }, 34795c635efSGarrett D'Amore { 611 }, 34895c635efSGarrett D'Amore { 611 }, 34995c635efSGarrett D'Amore { 667 }, 35095c635efSGarrett D'Amore { 722 }, 35195c635efSGarrett D'Amore { 611 }, 35295c635efSGarrett D'Amore { 611 }, 35395c635efSGarrett D'Amore { 722 }, 35495c635efSGarrett D'Amore { 722 }, 35595c635efSGarrett D'Amore { 333 }, 35695c635efSGarrett D'Amore { 444 }, 35795c635efSGarrett D'Amore { 667 }, 35895c635efSGarrett D'Amore { 556 }, 35995c635efSGarrett D'Amore { 833 }, 36095c635efSGarrett D'Amore { 667 }, 36195c635efSGarrett D'Amore { 722 }, 36295c635efSGarrett D'Amore { 611 }, 36395c635efSGarrett D'Amore { 722 }, 36495c635efSGarrett D'Amore { 611 }, 36595c635efSGarrett D'Amore { 500 }, 36695c635efSGarrett D'Amore { 556 }, 36795c635efSGarrett D'Amore { 722 }, 36895c635efSGarrett D'Amore { 611 }, 36995c635efSGarrett D'Amore { 833 }, 37095c635efSGarrett D'Amore { 611 }, 37195c635efSGarrett D'Amore { 556 }, 37295c635efSGarrett D'Amore { 556 }, 37395c635efSGarrett D'Amore { 389 }, 37495c635efSGarrett D'Amore { 278 }, 37595c635efSGarrett D'Amore { 389 }, 37695c635efSGarrett D'Amore { 422 }, 37795c635efSGarrett D'Amore { 500 }, 37895c635efSGarrett D'Amore { 333 }, 37995c635efSGarrett D'Amore { 500 }, 38095c635efSGarrett D'Amore { 500 }, 38195c635efSGarrett D'Amore { 444 }, 38295c635efSGarrett D'Amore { 500 }, 38395c635efSGarrett D'Amore { 444 }, 38495c635efSGarrett D'Amore { 278 }, 38595c635efSGarrett D'Amore { 500 }, 38695c635efSGarrett D'Amore { 500 }, 38795c635efSGarrett D'Amore { 278 }, 38895c635efSGarrett D'Amore { 278 }, 38995c635efSGarrett D'Amore { 444 }, 39095c635efSGarrett D'Amore { 278 }, 39195c635efSGarrett D'Amore { 722 }, 39295c635efSGarrett D'Amore { 500 }, 39395c635efSGarrett D'Amore { 500 }, 39495c635efSGarrett D'Amore { 500 }, 39595c635efSGarrett D'Amore { 500 }, 39695c635efSGarrett D'Amore { 389 }, 39795c635efSGarrett D'Amore { 389 }, 39895c635efSGarrett D'Amore { 278 }, 39995c635efSGarrett D'Amore { 500 }, 40095c635efSGarrett D'Amore { 444 }, 40195c635efSGarrett D'Amore { 667 }, 40295c635efSGarrett D'Amore { 444 }, 40395c635efSGarrett D'Amore { 444 }, 40495c635efSGarrett D'Amore { 389 }, 40595c635efSGarrett D'Amore { 400 }, 40695c635efSGarrett D'Amore { 275 }, 40795c635efSGarrett D'Amore { 400 }, 40895c635efSGarrett D'Amore { 541 }, 40995c635efSGarrett D'Amore } }, 410*260e9a87SYuri Pankov { "Times-BoldItalic", { 411*260e9a87SYuri Pankov { 250 }, 412*260e9a87SYuri Pankov { 389 }, 413*260e9a87SYuri Pankov { 555 }, 414*260e9a87SYuri Pankov { 500 }, 415*260e9a87SYuri Pankov { 500 }, 416*260e9a87SYuri Pankov { 833 }, 417*260e9a87SYuri Pankov { 778 }, 418*260e9a87SYuri Pankov { 333 }, 419*260e9a87SYuri Pankov { 333 }, 420*260e9a87SYuri Pankov { 333 }, 421*260e9a87SYuri Pankov { 500 }, 422*260e9a87SYuri Pankov { 570 }, 423*260e9a87SYuri Pankov { 250 }, 424*260e9a87SYuri Pankov { 333 }, 425*260e9a87SYuri Pankov { 250 }, 426*260e9a87SYuri Pankov { 278 }, 427*260e9a87SYuri Pankov { 500 }, 428*260e9a87SYuri Pankov { 500 }, 429*260e9a87SYuri Pankov { 500 }, 430*260e9a87SYuri Pankov { 500 }, 431*260e9a87SYuri Pankov { 500 }, 432*260e9a87SYuri Pankov { 500 }, 433*260e9a87SYuri Pankov { 500 }, 434*260e9a87SYuri Pankov { 500 }, 435*260e9a87SYuri Pankov { 500 }, 436*260e9a87SYuri Pankov { 500 }, 437*260e9a87SYuri Pankov { 333 }, 438*260e9a87SYuri Pankov { 333 }, 439*260e9a87SYuri Pankov { 570 }, 440*260e9a87SYuri Pankov { 570 }, 441*260e9a87SYuri Pankov { 570 }, 442*260e9a87SYuri Pankov { 500 }, 443*260e9a87SYuri Pankov { 832 }, 444*260e9a87SYuri Pankov { 667 }, 445*260e9a87SYuri Pankov { 667 }, 446*260e9a87SYuri Pankov { 667 }, 447*260e9a87SYuri Pankov { 722 }, 448*260e9a87SYuri Pankov { 667 }, 449*260e9a87SYuri Pankov { 667 }, 450*260e9a87SYuri Pankov { 722 }, 451*260e9a87SYuri Pankov { 778 }, 452*260e9a87SYuri Pankov { 389 }, 453*260e9a87SYuri Pankov { 500 }, 454*260e9a87SYuri Pankov { 667 }, 455*260e9a87SYuri Pankov { 611 }, 456*260e9a87SYuri Pankov { 889 }, 457*260e9a87SYuri Pankov { 722 }, 458*260e9a87SYuri Pankov { 722 }, 459*260e9a87SYuri Pankov { 611 }, 460*260e9a87SYuri Pankov { 722 }, 461*260e9a87SYuri Pankov { 667 }, 462*260e9a87SYuri Pankov { 556 }, 463*260e9a87SYuri Pankov { 611 }, 464*260e9a87SYuri Pankov { 722 }, 465*260e9a87SYuri Pankov { 667 }, 466*260e9a87SYuri Pankov { 889 }, 467*260e9a87SYuri Pankov { 667 }, 468*260e9a87SYuri Pankov { 611 }, 469*260e9a87SYuri Pankov { 611 }, 470*260e9a87SYuri Pankov { 333 }, 471*260e9a87SYuri Pankov { 278 }, 472*260e9a87SYuri Pankov { 333 }, 473*260e9a87SYuri Pankov { 570 }, 474*260e9a87SYuri Pankov { 500 }, 475*260e9a87SYuri Pankov { 333 }, 476*260e9a87SYuri Pankov { 500 }, 477*260e9a87SYuri Pankov { 500 }, 478*260e9a87SYuri Pankov { 444 }, 479*260e9a87SYuri Pankov { 500 }, 480*260e9a87SYuri Pankov { 444 }, 481*260e9a87SYuri Pankov { 333 }, 482*260e9a87SYuri Pankov { 500 }, 483*260e9a87SYuri Pankov { 556 }, 484*260e9a87SYuri Pankov { 278 }, 485*260e9a87SYuri Pankov { 278 }, 486*260e9a87SYuri Pankov { 500 }, 487*260e9a87SYuri Pankov { 278 }, 488*260e9a87SYuri Pankov { 778 }, 489*260e9a87SYuri Pankov { 556 }, 490*260e9a87SYuri Pankov { 500 }, 491*260e9a87SYuri Pankov { 500 }, 492*260e9a87SYuri Pankov { 500 }, 493*260e9a87SYuri Pankov { 389 }, 494*260e9a87SYuri Pankov { 389 }, 495*260e9a87SYuri Pankov { 278 }, 496*260e9a87SYuri Pankov { 556 }, 497*260e9a87SYuri Pankov { 444 }, 498*260e9a87SYuri Pankov { 667 }, 499*260e9a87SYuri Pankov { 500 }, 500*260e9a87SYuri Pankov { 444 }, 501*260e9a87SYuri Pankov { 389 }, 502*260e9a87SYuri Pankov { 348 }, 503*260e9a87SYuri Pankov { 220 }, 504*260e9a87SYuri Pankov { 348 }, 505*260e9a87SYuri Pankov { 570 }, 506*260e9a87SYuri Pankov } }, 50795c635efSGarrett D'Amore }; 50895c635efSGarrett D'Amore 50995c635efSGarrett D'Amore void * 510*260e9a87SYuri Pankov pdf_alloc(const struct mchars *mchars, char *outopts) 51195c635efSGarrett D'Amore { 51295c635efSGarrett D'Amore struct termp *p; 51395c635efSGarrett D'Amore 514*260e9a87SYuri Pankov if (NULL != (p = pspdf_alloc(mchars, outopts))) 51595c635efSGarrett D'Amore p->type = TERMTYPE_PDF; 51695c635efSGarrett D'Amore 51795c635efSGarrett D'Amore return(p); 51895c635efSGarrett D'Amore } 51995c635efSGarrett D'Amore 52095c635efSGarrett D'Amore void * 521*260e9a87SYuri Pankov ps_alloc(const struct mchars *mchars, char *outopts) 52295c635efSGarrett D'Amore { 52395c635efSGarrett D'Amore struct termp *p; 52495c635efSGarrett D'Amore 525*260e9a87SYuri Pankov if (NULL != (p = pspdf_alloc(mchars, outopts))) 52695c635efSGarrett D'Amore p->type = TERMTYPE_PS; 52795c635efSGarrett D'Amore 52895c635efSGarrett D'Amore return(p); 52995c635efSGarrett D'Amore } 53095c635efSGarrett D'Amore 53195c635efSGarrett D'Amore static struct termp * 532*260e9a87SYuri Pankov pspdf_alloc(const struct mchars *mchars, char *outopts) 53395c635efSGarrett D'Amore { 53495c635efSGarrett D'Amore struct termp *p; 53595c635efSGarrett D'Amore unsigned int pagex, pagey; 53695c635efSGarrett D'Amore size_t marginx, marginy, lineheight; 53795c635efSGarrett D'Amore const char *toks[2]; 53895c635efSGarrett D'Amore const char *pp; 53995c635efSGarrett D'Amore char *v; 54095c635efSGarrett D'Amore 54195c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct termp)); 542*260e9a87SYuri Pankov p->symtab = mchars; 54395c635efSGarrett D'Amore p->enc = TERMENC_ASCII; 544*260e9a87SYuri Pankov p->fontq = mandoc_reallocarray(NULL, 545*260e9a87SYuri Pankov (p->fontsz = 8), sizeof(enum termfont)); 546*260e9a87SYuri Pankov p->fontq[0] = p->fontl = TERMFONT_NONE; 54795c635efSGarrett D'Amore p->ps = mandoc_calloc(1, sizeof(struct termp_ps)); 54895c635efSGarrett D'Amore 54995c635efSGarrett D'Amore p->advance = ps_advance; 55095c635efSGarrett D'Amore p->begin = ps_begin; 55195c635efSGarrett D'Amore p->end = ps_end; 55295c635efSGarrett D'Amore p->endline = ps_endline; 55395c635efSGarrett D'Amore p->hspan = ps_hspan; 55495c635efSGarrett D'Amore p->letter = ps_letter; 555*260e9a87SYuri Pankov p->setwidth = ps_setwidth; 55695c635efSGarrett D'Amore p->width = ps_width; 55795c635efSGarrett D'Amore 55895c635efSGarrett D'Amore toks[0] = "paper"; 55995c635efSGarrett D'Amore toks[1] = NULL; 56095c635efSGarrett D'Amore 56195c635efSGarrett D'Amore pp = NULL; 56295c635efSGarrett D'Amore 56395c635efSGarrett D'Amore while (outopts && *outopts) 56495c635efSGarrett D'Amore switch (getsubopt(&outopts, UNCONST(toks), &v)) { 565*260e9a87SYuri Pankov case 0: 56695c635efSGarrett D'Amore pp = v; 56795c635efSGarrett D'Amore break; 56895c635efSGarrett D'Amore default: 56995c635efSGarrett D'Amore break; 57095c635efSGarrett D'Amore } 57195c635efSGarrett D'Amore 57295c635efSGarrett D'Amore /* Default to US letter (millimetres). */ 57395c635efSGarrett D'Amore 57495c635efSGarrett D'Amore pagex = 216; 57595c635efSGarrett D'Amore pagey = 279; 57695c635efSGarrett D'Amore 57795c635efSGarrett D'Amore /* 57895c635efSGarrett D'Amore * The ISO-269 paper sizes can be calculated automatically, but 57995c635efSGarrett D'Amore * it would require bringing in -lm for pow() and I'd rather not 58095c635efSGarrett D'Amore * do that. So just do it the easy way for now. Since this 58195c635efSGarrett D'Amore * only happens once, I'm not terribly concerned. 58295c635efSGarrett D'Amore */ 58395c635efSGarrett D'Amore 58495c635efSGarrett D'Amore if (pp && strcasecmp(pp, "letter")) { 58595c635efSGarrett D'Amore if (0 == strcasecmp(pp, "a3")) { 58695c635efSGarrett D'Amore pagex = 297; 58795c635efSGarrett D'Amore pagey = 420; 58895c635efSGarrett D'Amore } else if (0 == strcasecmp(pp, "a4")) { 58995c635efSGarrett D'Amore pagex = 210; 59095c635efSGarrett D'Amore pagey = 297; 59195c635efSGarrett D'Amore } else if (0 == strcasecmp(pp, "a5")) { 59295c635efSGarrett D'Amore pagex = 148; 59395c635efSGarrett D'Amore pagey = 210; 59495c635efSGarrett D'Amore } else if (0 == strcasecmp(pp, "legal")) { 59595c635efSGarrett D'Amore pagex = 216; 59695c635efSGarrett D'Amore pagey = 356; 59795c635efSGarrett D'Amore } else if (2 != sscanf(pp, "%ux%u", &pagex, &pagey)) 59895c635efSGarrett D'Amore fprintf(stderr, "%s: Unknown paper\n", pp); 59995c635efSGarrett D'Amore } 60095c635efSGarrett D'Amore 60195c635efSGarrett D'Amore /* 60295c635efSGarrett D'Amore * This MUST be defined before any PNT2AFM or AFM2PNT 60395c635efSGarrett D'Amore * calculations occur. 60495c635efSGarrett D'Amore */ 60595c635efSGarrett D'Amore 60695c635efSGarrett D'Amore p->ps->scale = 11; 60795c635efSGarrett D'Amore 60895c635efSGarrett D'Amore /* Remember millimetres -> AFM units. */ 60995c635efSGarrett D'Amore 61095c635efSGarrett D'Amore pagex = PNT2AFM(p, ((double)pagex * 2.834)); 61195c635efSGarrett D'Amore pagey = PNT2AFM(p, ((double)pagey * 2.834)); 61295c635efSGarrett D'Amore 61395c635efSGarrett D'Amore /* Margins are 1/9 the page x and y. */ 61495c635efSGarrett D'Amore 615*260e9a87SYuri Pankov marginx = (size_t)((double)pagex / 9.0); 616*260e9a87SYuri Pankov marginy = (size_t)((double)pagey / 9.0); 61795c635efSGarrett D'Amore 61895c635efSGarrett D'Amore /* Line-height is 1.4em. */ 61995c635efSGarrett D'Amore 62095c635efSGarrett D'Amore lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4)); 62195c635efSGarrett D'Amore 622*260e9a87SYuri Pankov p->ps->width = p->ps->lastwidth = (size_t)pagex; 62395c635efSGarrett D'Amore p->ps->height = (size_t)pagey; 62495c635efSGarrett D'Amore p->ps->header = pagey - (marginy / 2) - (lineheight / 2); 62595c635efSGarrett D'Amore p->ps->top = pagey - marginy; 62695c635efSGarrett D'Amore p->ps->footer = (marginy / 2) - (lineheight / 2); 62795c635efSGarrett D'Amore p->ps->bottom = marginy; 62895c635efSGarrett D'Amore p->ps->left = marginx; 62995c635efSGarrett D'Amore p->ps->lineheight = lineheight; 63095c635efSGarrett D'Amore 63195c635efSGarrett D'Amore p->defrmargin = pagex - (marginx * 2); 63295c635efSGarrett D'Amore return(p); 63395c635efSGarrett D'Amore } 63495c635efSGarrett D'Amore 635*260e9a87SYuri Pankov static void 636*260e9a87SYuri Pankov ps_setwidth(struct termp *p, int iop, size_t width) 637*260e9a87SYuri Pankov { 638*260e9a87SYuri Pankov size_t lastwidth; 639*260e9a87SYuri Pankov 640*260e9a87SYuri Pankov lastwidth = p->ps->width; 641*260e9a87SYuri Pankov if (iop > 0) 642*260e9a87SYuri Pankov p->ps->width += width; 643*260e9a87SYuri Pankov else if (iop == 0) 644*260e9a87SYuri Pankov p->ps->width = width ? width : p->ps->lastwidth; 645*260e9a87SYuri Pankov else if (p->ps->width > width) 646*260e9a87SYuri Pankov p->ps->width -= width; 647*260e9a87SYuri Pankov else 648*260e9a87SYuri Pankov p->ps->width = 0; 649*260e9a87SYuri Pankov p->ps->lastwidth = lastwidth; 650*260e9a87SYuri Pankov } 65195c635efSGarrett D'Amore 65295c635efSGarrett D'Amore void 65395c635efSGarrett D'Amore pspdf_free(void *arg) 65495c635efSGarrett D'Amore { 65595c635efSGarrett D'Amore struct termp *p; 65695c635efSGarrett D'Amore 65795c635efSGarrett D'Amore p = (struct termp *)arg; 65895c635efSGarrett D'Amore 65995c635efSGarrett D'Amore if (p->ps->psmarg) 66095c635efSGarrett D'Amore free(p->ps->psmarg); 66195c635efSGarrett D'Amore if (p->ps->pdfobjs) 66295c635efSGarrett D'Amore free(p->ps->pdfobjs); 66395c635efSGarrett D'Amore 66495c635efSGarrett D'Amore free(p->ps); 66595c635efSGarrett D'Amore term_free(p); 66695c635efSGarrett D'Amore } 66795c635efSGarrett D'Amore 66895c635efSGarrett D'Amore static void 66995c635efSGarrett D'Amore ps_printf(struct termp *p, const char *fmt, ...) 67095c635efSGarrett D'Amore { 67195c635efSGarrett D'Amore va_list ap; 67295c635efSGarrett D'Amore int pos, len; 67395c635efSGarrett D'Amore 67495c635efSGarrett D'Amore va_start(ap, fmt); 67595c635efSGarrett D'Amore 67695c635efSGarrett D'Amore /* 67795c635efSGarrett D'Amore * If we're running in regular mode, then pipe directly into 67895c635efSGarrett D'Amore * vprintf(). If we're processing margins, then push the data 67995c635efSGarrett D'Amore * into our growable margin buffer. 68095c635efSGarrett D'Amore */ 68195c635efSGarrett D'Amore 68295c635efSGarrett D'Amore if ( ! (PS_MARGINS & p->ps->flags)) { 68395c635efSGarrett D'Amore len = vprintf(fmt, ap); 68495c635efSGarrett D'Amore va_end(ap); 685*260e9a87SYuri Pankov p->ps->pdfbytes += len < 0 ? 0 : (size_t)len; 68695c635efSGarrett D'Amore return; 68795c635efSGarrett D'Amore } 68895c635efSGarrett D'Amore 68995c635efSGarrett D'Amore /* 69095c635efSGarrett D'Amore * XXX: I assume that the in-margin print won't exceed 69195c635efSGarrett D'Amore * PS_BUFSLOP (128 bytes), which is reasonable but still an 69295c635efSGarrett D'Amore * assumption that will cause pukeage if it's not the case. 69395c635efSGarrett D'Amore */ 69495c635efSGarrett D'Amore 69595c635efSGarrett D'Amore ps_growbuf(p, PS_BUFSLOP); 69695c635efSGarrett D'Amore 69795c635efSGarrett D'Amore pos = (int)p->ps->psmargcur; 69895c635efSGarrett D'Amore vsnprintf(&p->ps->psmarg[pos], PS_BUFSLOP, fmt, ap); 69995c635efSGarrett D'Amore 70095c635efSGarrett D'Amore va_end(ap); 70195c635efSGarrett D'Amore 70295c635efSGarrett D'Amore p->ps->psmargcur = strlen(p->ps->psmarg); 70395c635efSGarrett D'Amore } 70495c635efSGarrett D'Amore 70595c635efSGarrett D'Amore static void 70695c635efSGarrett D'Amore ps_putchar(struct termp *p, char c) 70795c635efSGarrett D'Amore { 70895c635efSGarrett D'Amore int pos; 70995c635efSGarrett D'Amore 71095c635efSGarrett D'Amore /* See ps_printf(). */ 71195c635efSGarrett D'Amore 71295c635efSGarrett D'Amore if ( ! (PS_MARGINS & p->ps->flags)) { 71395c635efSGarrett D'Amore putchar(c); 71495c635efSGarrett D'Amore p->ps->pdfbytes++; 71595c635efSGarrett D'Amore return; 71695c635efSGarrett D'Amore } 71795c635efSGarrett D'Amore 71895c635efSGarrett D'Amore ps_growbuf(p, 2); 71995c635efSGarrett D'Amore 72095c635efSGarrett D'Amore pos = (int)p->ps->psmargcur++; 72195c635efSGarrett D'Amore p->ps->psmarg[pos++] = c; 72295c635efSGarrett D'Amore p->ps->psmarg[pos] = '\0'; 72395c635efSGarrett D'Amore } 72495c635efSGarrett D'Amore 72595c635efSGarrett D'Amore static void 72695c635efSGarrett D'Amore pdf_obj(struct termp *p, size_t obj) 72795c635efSGarrett D'Amore { 72895c635efSGarrett D'Amore 72995c635efSGarrett D'Amore assert(obj > 0); 73095c635efSGarrett D'Amore 73195c635efSGarrett D'Amore if ((obj - 1) >= p->ps->pdfobjsz) { 73295c635efSGarrett D'Amore p->ps->pdfobjsz = obj + 128; 733*260e9a87SYuri Pankov p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs, 734*260e9a87SYuri Pankov p->ps->pdfobjsz, sizeof(size_t)); 73595c635efSGarrett D'Amore } 73695c635efSGarrett D'Amore 73795c635efSGarrett D'Amore p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes; 73895c635efSGarrett D'Amore ps_printf(p, "%zu 0 obj\n", obj); 73995c635efSGarrett D'Amore } 74095c635efSGarrett D'Amore 74195c635efSGarrett D'Amore static void 74295c635efSGarrett D'Amore ps_closepage(struct termp *p) 74395c635efSGarrett D'Amore { 74495c635efSGarrett D'Amore int i; 74595c635efSGarrett D'Amore size_t len, base; 74695c635efSGarrett D'Amore 74795c635efSGarrett D'Amore /* 74895c635efSGarrett D'Amore * Close out a page that we've already flushed to output. In 74995c635efSGarrett D'Amore * PostScript, we simply note that the page must be showed. In 75095c635efSGarrett D'Amore * PDF, we must now create the Length, Resource, and Page node 75195c635efSGarrett D'Amore * for the page contents. 75295c635efSGarrett D'Amore */ 75395c635efSGarrett D'Amore 75495c635efSGarrett D'Amore assert(p->ps->psmarg && p->ps->psmarg[0]); 75595c635efSGarrett D'Amore ps_printf(p, "%s", p->ps->psmarg); 75695c635efSGarrett D'Amore 75795c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 75895c635efSGarrett D'Amore ps_printf(p, "ET\n"); 75995c635efSGarrett D'Amore 76095c635efSGarrett D'Amore len = p->ps->pdfbytes - p->ps->pdflastpg; 76195c635efSGarrett D'Amore base = p->ps->pages * 4 + p->ps->pdfbody; 76295c635efSGarrett D'Amore 76395c635efSGarrett D'Amore ps_printf(p, "endstream\nendobj\n"); 76495c635efSGarrett D'Amore 76595c635efSGarrett D'Amore /* Length of content. */ 76695c635efSGarrett D'Amore pdf_obj(p, base + 1); 76795c635efSGarrett D'Amore ps_printf(p, "%zu\nendobj\n", len); 76895c635efSGarrett D'Amore 76995c635efSGarrett D'Amore /* Resource for content. */ 77095c635efSGarrett D'Amore pdf_obj(p, base + 2); 77195c635efSGarrett D'Amore ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n"); 77295c635efSGarrett D'Amore ps_printf(p, "/Font <<\n"); 77395c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) 77495c635efSGarrett D'Amore ps_printf(p, "/F%d %d 0 R\n", i, 3 + i); 77595c635efSGarrett D'Amore ps_printf(p, ">>\n>>\n"); 77695c635efSGarrett D'Amore 77795c635efSGarrett D'Amore /* Page node. */ 77895c635efSGarrett D'Amore pdf_obj(p, base + 3); 77995c635efSGarrett D'Amore ps_printf(p, "<<\n"); 78095c635efSGarrett D'Amore ps_printf(p, "/Type /Page\n"); 78195c635efSGarrett D'Amore ps_printf(p, "/Parent 2 0 R\n"); 78295c635efSGarrett D'Amore ps_printf(p, "/Resources %zu 0 R\n", base + 2); 78395c635efSGarrett D'Amore ps_printf(p, "/Contents %zu 0 R\n", base); 78495c635efSGarrett D'Amore ps_printf(p, ">>\nendobj\n"); 78595c635efSGarrett D'Amore } else 78695c635efSGarrett D'Amore ps_printf(p, "showpage\n"); 78795c635efSGarrett D'Amore 78895c635efSGarrett D'Amore p->ps->pages++; 78995c635efSGarrett D'Amore p->ps->psrow = p->ps->top; 79095c635efSGarrett D'Amore assert( ! (PS_NEWPAGE & p->ps->flags)); 79195c635efSGarrett D'Amore p->ps->flags |= PS_NEWPAGE; 79295c635efSGarrett D'Amore } 79395c635efSGarrett D'Amore 79495c635efSGarrett D'Amore static void 79595c635efSGarrett D'Amore ps_end(struct termp *p) 79695c635efSGarrett D'Amore { 79795c635efSGarrett D'Amore size_t i, xref, base; 79895c635efSGarrett D'Amore 79995c635efSGarrett D'Amore /* 80095c635efSGarrett D'Amore * At the end of the file, do one last showpage. This is the 80195c635efSGarrett D'Amore * same behaviour as groff(1) and works for multiple pages as 80295c635efSGarrett D'Amore * well as just one. 80395c635efSGarrett D'Amore */ 80495c635efSGarrett D'Amore 80595c635efSGarrett D'Amore if ( ! (PS_NEWPAGE & p->ps->flags)) { 80695c635efSGarrett D'Amore assert(0 == p->ps->flags); 80795c635efSGarrett D'Amore assert('\0' == p->ps->last); 80895c635efSGarrett D'Amore ps_closepage(p); 80995c635efSGarrett D'Amore } 81095c635efSGarrett D'Amore 81195c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 81295c635efSGarrett D'Amore ps_printf(p, "%%%%Trailer\n"); 81395c635efSGarrett D'Amore ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages); 81495c635efSGarrett D'Amore ps_printf(p, "%%%%EOF\n"); 81595c635efSGarrett D'Amore return; 81695c635efSGarrett D'Amore } 81795c635efSGarrett D'Amore 81895c635efSGarrett D'Amore pdf_obj(p, 2); 81995c635efSGarrett D'Amore ps_printf(p, "<<\n/Type /Pages\n"); 82095c635efSGarrett D'Amore ps_printf(p, "/MediaBox [0 0 %zu %zu]\n", 82195c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->width), 82295c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->height)); 82395c635efSGarrett D'Amore 82495c635efSGarrett D'Amore ps_printf(p, "/Count %zu\n", p->ps->pages); 82595c635efSGarrett D'Amore ps_printf(p, "/Kids ["); 82695c635efSGarrett D'Amore 82795c635efSGarrett D'Amore for (i = 0; i < p->ps->pages; i++) 828*260e9a87SYuri Pankov ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3); 82995c635efSGarrett D'Amore 830*260e9a87SYuri Pankov base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4; 83195c635efSGarrett D'Amore 83295c635efSGarrett D'Amore ps_printf(p, "]\n>>\nendobj\n"); 83395c635efSGarrett D'Amore pdf_obj(p, base); 83495c635efSGarrett D'Amore ps_printf(p, "<<\n"); 83595c635efSGarrett D'Amore ps_printf(p, "/Type /Catalog\n"); 83695c635efSGarrett D'Amore ps_printf(p, "/Pages 2 0 R\n"); 83795c635efSGarrett D'Amore ps_printf(p, ">>\n"); 83895c635efSGarrett D'Amore xref = p->ps->pdfbytes; 83995c635efSGarrett D'Amore ps_printf(p, "xref\n"); 84095c635efSGarrett D'Amore ps_printf(p, "0 %zu\n", base + 1); 84195c635efSGarrett D'Amore ps_printf(p, "0000000000 65535 f \n"); 84295c635efSGarrett D'Amore 84395c635efSGarrett D'Amore for (i = 0; i < base; i++) 84495c635efSGarrett D'Amore ps_printf(p, "%.10zu 00000 n \n", 84595c635efSGarrett D'Amore p->ps->pdfobjs[(int)i]); 84695c635efSGarrett D'Amore 84795c635efSGarrett D'Amore ps_printf(p, "trailer\n"); 84895c635efSGarrett D'Amore ps_printf(p, "<<\n"); 84995c635efSGarrett D'Amore ps_printf(p, "/Size %zu\n", base + 1); 85095c635efSGarrett D'Amore ps_printf(p, "/Root %zu 0 R\n", base); 85195c635efSGarrett D'Amore ps_printf(p, "/Info 1 0 R\n"); 85295c635efSGarrett D'Amore ps_printf(p, ">>\n"); 85395c635efSGarrett D'Amore ps_printf(p, "startxref\n"); 85495c635efSGarrett D'Amore ps_printf(p, "%zu\n", xref); 85595c635efSGarrett D'Amore ps_printf(p, "%%%%EOF\n"); 85695c635efSGarrett D'Amore } 85795c635efSGarrett D'Amore 85895c635efSGarrett D'Amore static void 85995c635efSGarrett D'Amore ps_begin(struct termp *p) 86095c635efSGarrett D'Amore { 86195c635efSGarrett D'Amore int i; 86295c635efSGarrett D'Amore 86395c635efSGarrett D'Amore /* 86495c635efSGarrett D'Amore * Print margins into margin buffer. Nothing gets output to the 86595c635efSGarrett D'Amore * screen yet, so we don't need to initialise the primary state. 86695c635efSGarrett D'Amore */ 86795c635efSGarrett D'Amore 86895c635efSGarrett D'Amore if (p->ps->psmarg) { 86995c635efSGarrett D'Amore assert(p->ps->psmargsz); 87095c635efSGarrett D'Amore p->ps->psmarg[0] = '\0'; 87195c635efSGarrett D'Amore } 87295c635efSGarrett D'Amore 87395c635efSGarrett D'Amore /*p->ps->pdfbytes = 0;*/ 87495c635efSGarrett D'Amore p->ps->psmargcur = 0; 87595c635efSGarrett D'Amore p->ps->flags = PS_MARGINS; 87695c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 87795c635efSGarrett D'Amore p->ps->psrow = p->ps->header; 87895c635efSGarrett D'Amore 87995c635efSGarrett D'Amore ps_setfont(p, TERMFONT_NONE); 88095c635efSGarrett D'Amore 88195c635efSGarrett D'Amore (*p->headf)(p, p->argf); 88295c635efSGarrett D'Amore (*p->endline)(p); 88395c635efSGarrett D'Amore 88495c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 88595c635efSGarrett D'Amore p->ps->psrow = p->ps->footer; 88695c635efSGarrett D'Amore 88795c635efSGarrett D'Amore (*p->footf)(p, p->argf); 88895c635efSGarrett D'Amore (*p->endline)(p); 88995c635efSGarrett D'Amore 89095c635efSGarrett D'Amore p->ps->flags &= ~PS_MARGINS; 89195c635efSGarrett D'Amore 89295c635efSGarrett D'Amore assert(0 == p->ps->flags); 89395c635efSGarrett D'Amore assert(p->ps->psmarg); 89495c635efSGarrett D'Amore assert('\0' != p->ps->psmarg[0]); 89595c635efSGarrett D'Amore 89695c635efSGarrett D'Amore /* 89795c635efSGarrett D'Amore * Print header and initialise page state. Following this, 89895c635efSGarrett D'Amore * stuff gets printed to the screen, so make sure we're sane. 89995c635efSGarrett D'Amore */ 90095c635efSGarrett D'Amore 90195c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 90295c635efSGarrett D'Amore ps_printf(p, "%%!PS-Adobe-3.0\n"); 90395c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); 90495c635efSGarrett D'Amore ps_printf(p, "%%%%Orientation: Portrait\n"); 90595c635efSGarrett D'Amore ps_printf(p, "%%%%Pages: (atend)\n"); 90695c635efSGarrett D'Amore ps_printf(p, "%%%%PageOrder: Ascend\n"); 90795c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentMedia: " 90895c635efSGarrett D'Amore "Default %zu %zu 0 () ()\n", 90995c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->width), 91095c635efSGarrett D'Amore (size_t)AFM2PNT(p, p->ps->height)); 91195c635efSGarrett D'Amore ps_printf(p, "%%%%DocumentNeededResources: font"); 91295c635efSGarrett D'Amore 91395c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) 91495c635efSGarrett D'Amore ps_printf(p, " %s", fonts[i].name); 91595c635efSGarrett D'Amore 91695c635efSGarrett D'Amore ps_printf(p, "\n%%%%EndComments\n"); 91795c635efSGarrett D'Amore } else { 91895c635efSGarrett D'Amore ps_printf(p, "%%PDF-1.1\n"); 91995c635efSGarrett D'Amore pdf_obj(p, 1); 92095c635efSGarrett D'Amore ps_printf(p, "<<\n"); 92195c635efSGarrett D'Amore ps_printf(p, ">>\n"); 92295c635efSGarrett D'Amore ps_printf(p, "endobj\n"); 92395c635efSGarrett D'Amore 92495c635efSGarrett D'Amore for (i = 0; i < (int)TERMFONT__MAX; i++) { 92595c635efSGarrett D'Amore pdf_obj(p, (size_t)i + 3); 92695c635efSGarrett D'Amore ps_printf(p, "<<\n"); 92795c635efSGarrett D'Amore ps_printf(p, "/Type /Font\n"); 92895c635efSGarrett D'Amore ps_printf(p, "/Subtype /Type1\n"); 929*260e9a87SYuri Pankov ps_printf(p, "/Name /F%d\n", i); 93095c635efSGarrett D'Amore ps_printf(p, "/BaseFont /%s\n", fonts[i].name); 93195c635efSGarrett D'Amore ps_printf(p, ">>\n"); 93295c635efSGarrett D'Amore } 93395c635efSGarrett D'Amore } 93495c635efSGarrett D'Amore 93595c635efSGarrett D'Amore p->ps->pdfbody = (size_t)TERMFONT__MAX + 3; 93695c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 93795c635efSGarrett D'Amore p->ps->psrow = p->ps->top; 93895c635efSGarrett D'Amore p->ps->flags |= PS_NEWPAGE; 93995c635efSGarrett D'Amore ps_setfont(p, TERMFONT_NONE); 94095c635efSGarrett D'Amore } 94195c635efSGarrett D'Amore 94295c635efSGarrett D'Amore static void 94395c635efSGarrett D'Amore ps_pletter(struct termp *p, int c) 94495c635efSGarrett D'Amore { 94595c635efSGarrett D'Amore int f; 94695c635efSGarrett D'Amore 94795c635efSGarrett D'Amore /* 94895c635efSGarrett D'Amore * If we haven't opened a page context, then output that we're 94995c635efSGarrett D'Amore * in a new page and make sure the font is correctly set. 95095c635efSGarrett D'Amore */ 95195c635efSGarrett D'Amore 95295c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) { 95395c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) { 95495c635efSGarrett D'Amore ps_printf(p, "%%%%Page: %zu %zu\n", 955*260e9a87SYuri Pankov p->ps->pages + 1, p->ps->pages + 1); 95695c635efSGarrett D'Amore ps_printf(p, "/%s %zu selectfont\n", 95795c635efSGarrett D'Amore fonts[(int)p->ps->lastf].name, 95895c635efSGarrett D'Amore p->ps->scale); 95995c635efSGarrett D'Amore } else { 96095c635efSGarrett D'Amore pdf_obj(p, p->ps->pdfbody + 96195c635efSGarrett D'Amore p->ps->pages * 4); 96295c635efSGarrett D'Amore ps_printf(p, "<<\n"); 96395c635efSGarrett D'Amore ps_printf(p, "/Length %zu 0 R\n", 964*260e9a87SYuri Pankov p->ps->pdfbody + 1 + p->ps->pages * 4); 96595c635efSGarrett D'Amore ps_printf(p, ">>\nstream\n"); 96695c635efSGarrett D'Amore } 96795c635efSGarrett D'Amore p->ps->pdflastpg = p->ps->pdfbytes; 96895c635efSGarrett D'Amore p->ps->flags &= ~PS_NEWPAGE; 96995c635efSGarrett D'Amore } 97095c635efSGarrett D'Amore 97195c635efSGarrett D'Amore /* 97295c635efSGarrett D'Amore * If we're not in a PostScript "word" context, then open one 97395c635efSGarrett D'Amore * now at the current cursor. 97495c635efSGarrett D'Amore */ 97595c635efSGarrett D'Amore 97695c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) { 97795c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 97895c635efSGarrett D'Amore ps_printf(p, "BT\n/F%d %zu Tf\n", 979*260e9a87SYuri Pankov (int)p->ps->lastf, p->ps->scale); 98095c635efSGarrett D'Amore ps_printf(p, "%.3f %.3f Td\n(", 98195c635efSGarrett D'Amore AFM2PNT(p, p->ps->pscol), 98295c635efSGarrett D'Amore AFM2PNT(p, p->ps->psrow)); 98395c635efSGarrett D'Amore } else 98495c635efSGarrett D'Amore ps_printf(p, "%.3f %.3f moveto\n(", 98595c635efSGarrett D'Amore AFM2PNT(p, p->ps->pscol), 98695c635efSGarrett D'Amore AFM2PNT(p, p->ps->psrow)); 98795c635efSGarrett D'Amore p->ps->flags |= PS_INLINE; 98895c635efSGarrett D'Amore } 98995c635efSGarrett D'Amore 99095c635efSGarrett D'Amore assert( ! (PS_NEWPAGE & p->ps->flags)); 99195c635efSGarrett D'Amore 99295c635efSGarrett D'Amore /* 99395c635efSGarrett D'Amore * We need to escape these characters as per the PostScript 99495c635efSGarrett D'Amore * specification. We would also escape non-graphable characters 99595c635efSGarrett D'Amore * (like tabs), but none of them would get to this point and 99695c635efSGarrett D'Amore * it's superfluous to abort() on them. 99795c635efSGarrett D'Amore */ 99895c635efSGarrett D'Amore 99995c635efSGarrett D'Amore switch (c) { 1000*260e9a87SYuri Pankov case '(': 100195c635efSGarrett D'Amore /* FALLTHROUGH */ 1002*260e9a87SYuri Pankov case ')': 100395c635efSGarrett D'Amore /* FALLTHROUGH */ 1004*260e9a87SYuri Pankov case '\\': 100595c635efSGarrett D'Amore ps_putchar(p, '\\'); 100695c635efSGarrett D'Amore break; 100795c635efSGarrett D'Amore default: 100895c635efSGarrett D'Amore break; 100995c635efSGarrett D'Amore } 101095c635efSGarrett D'Amore 101195c635efSGarrett D'Amore /* Write the character and adjust where we are on the page. */ 101295c635efSGarrett D'Amore 101395c635efSGarrett D'Amore f = (int)p->ps->lastf; 101495c635efSGarrett D'Amore 1015*260e9a87SYuri Pankov if (c <= 32 || c - 32 >= MAXCHAR) 1016*260e9a87SYuri Pankov c = 32; 101795c635efSGarrett D'Amore 101895c635efSGarrett D'Amore ps_putchar(p, (char)c); 101995c635efSGarrett D'Amore c -= 32; 102095c635efSGarrett D'Amore p->ps->pscol += (size_t)fonts[f].gly[c].wx; 102195c635efSGarrett D'Amore } 102295c635efSGarrett D'Amore 102395c635efSGarrett D'Amore static void 102495c635efSGarrett D'Amore ps_pclose(struct termp *p) 102595c635efSGarrett D'Amore { 102695c635efSGarrett D'Amore 102795c635efSGarrett D'Amore /* 102895c635efSGarrett D'Amore * Spit out that we're exiting a word context (this is a 102995c635efSGarrett D'Amore * "partial close" because we don't check the last-char buffer 103095c635efSGarrett D'Amore * or anything). 103195c635efSGarrett D'Amore */ 103295c635efSGarrett D'Amore 103395c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) 103495c635efSGarrett D'Amore return; 103595c635efSGarrett D'Amore 103695c635efSGarrett D'Amore if (TERMTYPE_PS != p->type) { 103795c635efSGarrett D'Amore ps_printf(p, ") Tj\nET\n"); 103895c635efSGarrett D'Amore } else 103995c635efSGarrett D'Amore ps_printf(p, ") show\n"); 104095c635efSGarrett D'Amore 104195c635efSGarrett D'Amore p->ps->flags &= ~PS_INLINE; 104295c635efSGarrett D'Amore } 104395c635efSGarrett D'Amore 104495c635efSGarrett D'Amore static void 104595c635efSGarrett D'Amore ps_fclose(struct termp *p) 104695c635efSGarrett D'Amore { 104795c635efSGarrett D'Amore 104895c635efSGarrett D'Amore /* 104995c635efSGarrett D'Amore * Strong closure: if we have a last-char, spit it out after 105095c635efSGarrett D'Amore * checking that we're in the right font mode. This will of 105195c635efSGarrett D'Amore * course open a new scope, if applicable. 105295c635efSGarrett D'Amore * 105395c635efSGarrett D'Amore * Following this, close out any scope that's open. 105495c635efSGarrett D'Amore */ 105595c635efSGarrett D'Amore 1056*260e9a87SYuri Pankov if (p->ps->last != '\0') { 1057*260e9a87SYuri Pankov assert( ! (p->ps->flags & PS_BACKSP)); 1058*260e9a87SYuri Pankov if (p->ps->nextf != p->ps->lastf) { 105995c635efSGarrett D'Amore ps_pclose(p); 1060*260e9a87SYuri Pankov ps_setfont(p, p->ps->nextf); 106195c635efSGarrett D'Amore } 1062*260e9a87SYuri Pankov p->ps->nextf = TERMFONT_NONE; 106395c635efSGarrett D'Amore ps_pletter(p, p->ps->last); 106495c635efSGarrett D'Amore p->ps->last = '\0'; 106595c635efSGarrett D'Amore } 106695c635efSGarrett D'Amore 106795c635efSGarrett D'Amore if ( ! (PS_INLINE & p->ps->flags)) 106895c635efSGarrett D'Amore return; 106995c635efSGarrett D'Amore 107095c635efSGarrett D'Amore ps_pclose(p); 107195c635efSGarrett D'Amore } 107295c635efSGarrett D'Amore 107395c635efSGarrett D'Amore static void 107495c635efSGarrett D'Amore ps_letter(struct termp *p, int arg) 107595c635efSGarrett D'Amore { 1076*260e9a87SYuri Pankov size_t savecol, wx; 1077*260e9a87SYuri Pankov char c; 107895c635efSGarrett D'Amore 107995c635efSGarrett D'Amore c = arg >= 128 || arg <= 0 ? '?' : arg; 108095c635efSGarrett D'Amore 108195c635efSGarrett D'Amore /* 1082*260e9a87SYuri Pankov * When receiving a backspace, merely flag it. 1083*260e9a87SYuri Pankov * We don't know yet whether it is 1084*260e9a87SYuri Pankov * a font instruction or an overstrike. 108595c635efSGarrett D'Amore */ 108695c635efSGarrett D'Amore 1087*260e9a87SYuri Pankov if (c == '\b') { 1088*260e9a87SYuri Pankov assert(p->ps->last != '\0'); 1089*260e9a87SYuri Pankov assert( ! (p->ps->flags & PS_BACKSP)); 1090*260e9a87SYuri Pankov p->ps->flags |= PS_BACKSP; 109195c635efSGarrett D'Amore return; 109295c635efSGarrett D'Amore } 109395c635efSGarrett D'Amore 1094*260e9a87SYuri Pankov /* 1095*260e9a87SYuri Pankov * Decode font instructions. 1096*260e9a87SYuri Pankov */ 1097*260e9a87SYuri Pankov 1098*260e9a87SYuri Pankov if (p->ps->flags & PS_BACKSP) { 1099*260e9a87SYuri Pankov if (p->ps->last == '_') { 1100*260e9a87SYuri Pankov switch (p->ps->nextf) { 1101*260e9a87SYuri Pankov case TERMFONT_BI: 1102*260e9a87SYuri Pankov break; 1103*260e9a87SYuri Pankov case TERMFONT_BOLD: 1104*260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BI; 1105*260e9a87SYuri Pankov break; 1106*260e9a87SYuri Pankov default: 1107*260e9a87SYuri Pankov p->ps->nextf = TERMFONT_UNDER; 1108*260e9a87SYuri Pankov } 1109*260e9a87SYuri Pankov p->ps->last = c; 1110*260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1111*260e9a87SYuri Pankov return; 1112*260e9a87SYuri Pankov } 1113*260e9a87SYuri Pankov if (p->ps->last == c) { 1114*260e9a87SYuri Pankov switch (p->ps->nextf) { 1115*260e9a87SYuri Pankov case TERMFONT_BI: 1116*260e9a87SYuri Pankov break; 1117*260e9a87SYuri Pankov case TERMFONT_UNDER: 1118*260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BI; 1119*260e9a87SYuri Pankov break; 1120*260e9a87SYuri Pankov default: 1121*260e9a87SYuri Pankov p->ps->nextf = TERMFONT_BOLD; 1122*260e9a87SYuri Pankov } 1123*260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1124*260e9a87SYuri Pankov return; 112595c635efSGarrett D'Amore } 112695c635efSGarrett D'Amore 1127*260e9a87SYuri Pankov /* 1128*260e9a87SYuri Pankov * This is not a font instruction, but rather 1129*260e9a87SYuri Pankov * the next character. Prepare for overstrike. 1130*260e9a87SYuri Pankov */ 1131*260e9a87SYuri Pankov 1132*260e9a87SYuri Pankov savecol = p->ps->pscol; 1133*260e9a87SYuri Pankov } else 1134*260e9a87SYuri Pankov savecol = SIZE_MAX; 1135*260e9a87SYuri Pankov 1136*260e9a87SYuri Pankov /* 1137*260e9a87SYuri Pankov * We found the next character, so the font instructions 1138*260e9a87SYuri Pankov * for the previous one are complete. 1139*260e9a87SYuri Pankov * Use them and print it. 1140*260e9a87SYuri Pankov */ 1141*260e9a87SYuri Pankov 1142*260e9a87SYuri Pankov if (p->ps->last != '\0') { 1143*260e9a87SYuri Pankov if (p->ps->nextf != p->ps->lastf) { 1144*260e9a87SYuri Pankov ps_pclose(p); 1145*260e9a87SYuri Pankov ps_setfont(p, p->ps->nextf); 1146*260e9a87SYuri Pankov } 1147*260e9a87SYuri Pankov p->ps->nextf = TERMFONT_NONE; 1148*260e9a87SYuri Pankov 1149*260e9a87SYuri Pankov /* 1150*260e9a87SYuri Pankov * For an overstrike, if a previous character 1151*260e9a87SYuri Pankov * was wider, advance to center the new one. 1152*260e9a87SYuri Pankov */ 1153*260e9a87SYuri Pankov 1154*260e9a87SYuri Pankov if (p->ps->pscolnext) { 1155*260e9a87SYuri Pankov wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx; 1156*260e9a87SYuri Pankov if (p->ps->pscol + wx < p->ps->pscolnext) 1157*260e9a87SYuri Pankov p->ps->pscol = (p->ps->pscol + 1158*260e9a87SYuri Pankov p->ps->pscolnext - wx) / 2; 1159*260e9a87SYuri Pankov } 1160*260e9a87SYuri Pankov 1161*260e9a87SYuri Pankov ps_pletter(p, p->ps->last); 1162*260e9a87SYuri Pankov 1163*260e9a87SYuri Pankov /* 1164*260e9a87SYuri Pankov * For an overstrike, if a previous character 1165*260e9a87SYuri Pankov * was wider, advance to the end of the old one. 1166*260e9a87SYuri Pankov */ 1167*260e9a87SYuri Pankov 1168*260e9a87SYuri Pankov if (p->ps->pscol < p->ps->pscolnext) { 1169*260e9a87SYuri Pankov ps_pclose(p); 1170*260e9a87SYuri Pankov p->ps->pscol = p->ps->pscolnext; 1171*260e9a87SYuri Pankov } 1172*260e9a87SYuri Pankov } 1173*260e9a87SYuri Pankov 1174*260e9a87SYuri Pankov /* 1175*260e9a87SYuri Pankov * Do not print the current character yet because font 1176*260e9a87SYuri Pankov * instructions might follow; only remember it. 1177*260e9a87SYuri Pankov * For the first character, nothing else is done. 1178*260e9a87SYuri Pankov * The final character will get printed from ps_fclose(). 1179*260e9a87SYuri Pankov */ 1180*260e9a87SYuri Pankov 1181*260e9a87SYuri Pankov p->ps->last = c; 1182*260e9a87SYuri Pankov 1183*260e9a87SYuri Pankov /* 1184*260e9a87SYuri Pankov * For an overstrike, back up to the previous position. 1185*260e9a87SYuri Pankov * If the previous character is wider than any it overstrikes, 1186*260e9a87SYuri Pankov * remember the current position, because it might also be 1187*260e9a87SYuri Pankov * wider than all that will overstrike it. 1188*260e9a87SYuri Pankov */ 1189*260e9a87SYuri Pankov 1190*260e9a87SYuri Pankov if (savecol != SIZE_MAX) { 1191*260e9a87SYuri Pankov if (p->ps->pscolnext < p->ps->pscol) 1192*260e9a87SYuri Pankov p->ps->pscolnext = p->ps->pscol; 1193*260e9a87SYuri Pankov ps_pclose(p); 1194*260e9a87SYuri Pankov p->ps->pscol = savecol; 1195*260e9a87SYuri Pankov p->ps->flags &= ~PS_BACKSP; 1196*260e9a87SYuri Pankov } else 1197*260e9a87SYuri Pankov p->ps->pscolnext = 0; 1198*260e9a87SYuri Pankov } 119995c635efSGarrett D'Amore 120095c635efSGarrett D'Amore static void 120195c635efSGarrett D'Amore ps_advance(struct termp *p, size_t len) 120295c635efSGarrett D'Amore { 120395c635efSGarrett D'Amore 120495c635efSGarrett D'Amore /* 120595c635efSGarrett D'Amore * Advance some spaces. This can probably be made smarter, 120695c635efSGarrett D'Amore * i.e., to have multiple space-separated words in the same 120795c635efSGarrett D'Amore * scope, but this is easier: just close out the current scope 120895c635efSGarrett D'Amore * and readjust our column settings. 120995c635efSGarrett D'Amore */ 121095c635efSGarrett D'Amore 121195c635efSGarrett D'Amore ps_fclose(p); 121295c635efSGarrett D'Amore p->ps->pscol += len; 121395c635efSGarrett D'Amore } 121495c635efSGarrett D'Amore 121595c635efSGarrett D'Amore static void 121695c635efSGarrett D'Amore ps_endline(struct termp *p) 121795c635efSGarrett D'Amore { 121895c635efSGarrett D'Amore 121995c635efSGarrett D'Amore /* Close out any scopes we have open: we're at eoln. */ 122095c635efSGarrett D'Amore 122195c635efSGarrett D'Amore ps_fclose(p); 122295c635efSGarrett D'Amore 122395c635efSGarrett D'Amore /* 122495c635efSGarrett D'Amore * If we're in the margin, don't try to recalculate our current 122595c635efSGarrett D'Amore * row. XXX: if the column tries to be fancy with multiple 122695c635efSGarrett D'Amore * lines, we'll do nasty stuff. 122795c635efSGarrett D'Amore */ 122895c635efSGarrett D'Amore 122995c635efSGarrett D'Amore if (PS_MARGINS & p->ps->flags) 123095c635efSGarrett D'Amore return; 123195c635efSGarrett D'Amore 123295c635efSGarrett D'Amore /* Left-justify. */ 123395c635efSGarrett D'Amore 123495c635efSGarrett D'Amore p->ps->pscol = p->ps->left; 123595c635efSGarrett D'Amore 123695c635efSGarrett D'Amore /* If we haven't printed anything, return. */ 123795c635efSGarrett D'Amore 123895c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) 123995c635efSGarrett D'Amore return; 124095c635efSGarrett D'Amore 124195c635efSGarrett D'Amore /* 124295c635efSGarrett D'Amore * Put us down a line. If we're at the page bottom, spit out a 124395c635efSGarrett D'Amore * showpage and restart our row. 124495c635efSGarrett D'Amore */ 124595c635efSGarrett D'Amore 1246*260e9a87SYuri Pankov if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) { 124795c635efSGarrett D'Amore p->ps->psrow -= p->ps->lineheight; 124895c635efSGarrett D'Amore return; 124995c635efSGarrett D'Amore } 125095c635efSGarrett D'Amore 125195c635efSGarrett D'Amore ps_closepage(p); 125295c635efSGarrett D'Amore } 125395c635efSGarrett D'Amore 125495c635efSGarrett D'Amore static void 125595c635efSGarrett D'Amore ps_setfont(struct termp *p, enum termfont f) 125695c635efSGarrett D'Amore { 125795c635efSGarrett D'Amore 125895c635efSGarrett D'Amore assert(f < TERMFONT__MAX); 125995c635efSGarrett D'Amore p->ps->lastf = f; 126095c635efSGarrett D'Amore 126195c635efSGarrett D'Amore /* 126295c635efSGarrett D'Amore * If we're still at the top of the page, let the font-setting 126395c635efSGarrett D'Amore * be delayed until we actually have stuff to print. 126495c635efSGarrett D'Amore */ 126595c635efSGarrett D'Amore 126695c635efSGarrett D'Amore if (PS_NEWPAGE & p->ps->flags) 126795c635efSGarrett D'Amore return; 126895c635efSGarrett D'Amore 126995c635efSGarrett D'Amore if (TERMTYPE_PS == p->type) 127095c635efSGarrett D'Amore ps_printf(p, "/%s %zu selectfont\n", 1271*260e9a87SYuri Pankov fonts[(int)f].name, p->ps->scale); 127295c635efSGarrett D'Amore else 127395c635efSGarrett D'Amore ps_printf(p, "/F%d %zu Tf\n", 1274*260e9a87SYuri Pankov (int)f, p->ps->scale); 127595c635efSGarrett D'Amore } 127695c635efSGarrett D'Amore 127795c635efSGarrett D'Amore static size_t 127895c635efSGarrett D'Amore ps_width(const struct termp *p, int c) 127995c635efSGarrett D'Amore { 128095c635efSGarrett D'Amore 128195c635efSGarrett D'Amore if (c <= 32 || c - 32 >= MAXCHAR) 1282*260e9a87SYuri Pankov c = 0; 1283*260e9a87SYuri Pankov else 128495c635efSGarrett D'Amore c -= 32; 1285*260e9a87SYuri Pankov 128695c635efSGarrett D'Amore return((size_t)fonts[(int)TERMFONT_NONE].gly[c].wx); 128795c635efSGarrett D'Amore } 128895c635efSGarrett D'Amore 128995c635efSGarrett D'Amore static double 129095c635efSGarrett D'Amore ps_hspan(const struct termp *p, const struct roffsu *su) 129195c635efSGarrett D'Amore { 129295c635efSGarrett D'Amore double r; 129395c635efSGarrett D'Amore 129495c635efSGarrett D'Amore /* 129595c635efSGarrett D'Amore * All of these measurements are derived by converting from the 129695c635efSGarrett D'Amore * native measurement to AFM units. 129795c635efSGarrett D'Amore */ 129895c635efSGarrett D'Amore switch (su->unit) { 1299*260e9a87SYuri Pankov case SCALE_BU: 1300*260e9a87SYuri Pankov /* 1301*260e9a87SYuri Pankov * Traditionally, the default unit is fixed to the 1302*260e9a87SYuri Pankov * output media. So this would refer to the point. In 1303*260e9a87SYuri Pankov * mandoc(1), however, we stick to the default terminal 1304*260e9a87SYuri Pankov * scaling unit so that output is the same regardless 1305*260e9a87SYuri Pankov * the media. 1306*260e9a87SYuri Pankov */ 1307*260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0 / 240.0); 130895c635efSGarrett D'Amore break; 1309*260e9a87SYuri Pankov case SCALE_CM: 1310*260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0 / 2.54); 131195c635efSGarrett D'Amore break; 1312*260e9a87SYuri Pankov case SCALE_EM: 131395c635efSGarrett D'Amore r = su->scale * 131495c635efSGarrett D'Amore fonts[(int)TERMFONT_NONE].gly[109 - 32].wx; 131595c635efSGarrett D'Amore break; 1316*260e9a87SYuri Pankov case SCALE_EN: 131795c635efSGarrett D'Amore r = su->scale * 131895c635efSGarrett D'Amore fonts[(int)TERMFONT_NONE].gly[110 - 32].wx; 131995c635efSGarrett D'Amore break; 1320*260e9a87SYuri Pankov case SCALE_IN: 1321*260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 72.0); 1322*260e9a87SYuri Pankov break; 1323*260e9a87SYuri Pankov case SCALE_MM: 1324*260e9a87SYuri Pankov r = su->scale * 1325*260e9a87SYuri Pankov fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0; 1326*260e9a87SYuri Pankov break; 1327*260e9a87SYuri Pankov case SCALE_PC: 1328*260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 12.0); 1329*260e9a87SYuri Pankov break; 1330*260e9a87SYuri Pankov case SCALE_PT: 1331*260e9a87SYuri Pankov r = PNT2AFM(p, su->scale * 1.0); 1332*260e9a87SYuri Pankov break; 1333*260e9a87SYuri Pankov case SCALE_VS: 133495c635efSGarrett D'Amore r = su->scale * p->ps->lineheight; 133595c635efSGarrett D'Amore break; 133695c635efSGarrett D'Amore default: 133795c635efSGarrett D'Amore r = su->scale; 133895c635efSGarrett D'Amore break; 133995c635efSGarrett D'Amore } 134095c635efSGarrett D'Amore 134195c635efSGarrett D'Amore return(r); 134295c635efSGarrett D'Amore } 134395c635efSGarrett D'Amore 134495c635efSGarrett D'Amore static void 134595c635efSGarrett D'Amore ps_growbuf(struct termp *p, size_t sz) 134695c635efSGarrett D'Amore { 134795c635efSGarrett D'Amore if (p->ps->psmargcur + sz <= p->ps->psmargsz) 134895c635efSGarrett D'Amore return; 134995c635efSGarrett D'Amore 135095c635efSGarrett D'Amore if (sz < PS_BUFSLOP) 135195c635efSGarrett D'Amore sz = PS_BUFSLOP; 135295c635efSGarrett D'Amore 135395c635efSGarrett D'Amore p->ps->psmargsz += sz; 1354*260e9a87SYuri Pankov p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz); 135595c635efSGarrett D'Amore } 1356