roff_term.c revision 1.1.1.3 1 1.1.1.3 wiz /* $OpenBSD: roff_term.c,v 1.20 2020/09/03 17:37:06 schwarze Exp $ */
2 1.1 christos /*
3 1.1.1.3 wiz * Copyright (c) 2010,2014,2015,2017-2020 Ingo Schwarze <schwarze (at) openbsd.org>
4 1.1 christos *
5 1.1 christos * Permission to use, copy, modify, and distribute this software for any
6 1.1 christos * purpose with or without fee is hereby granted, provided that the above
7 1.1 christos * copyright notice and this permission notice appear in all copies.
8 1.1 christos *
9 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 1.1 christos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 1.1 christos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 1.1 christos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 1.1 christos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 1.1 christos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 1.1 christos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 1.1 christos */
17 1.1.1.3 wiz #include "config.h"
18 1.1.1.3 wiz
19 1.1 christos #include <sys/types.h>
20 1.1 christos
21 1.1 christos #include <assert.h>
22 1.1.1.2 christos #include <stdio.h>
23 1.1.1.2 christos #include <string.h>
24 1.1 christos
25 1.1 christos #include "mandoc.h"
26 1.1 christos #include "roff.h"
27 1.1 christos #include "out.h"
28 1.1 christos #include "term.h"
29 1.1 christos
30 1.1 christos #define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
31 1.1 christos
32 1.1 christos typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS);
33 1.1 christos
34 1.1 christos static void roff_term_pre_br(ROFF_TERM_ARGS);
35 1.1 christos static void roff_term_pre_ce(ROFF_TERM_ARGS);
36 1.1 christos static void roff_term_pre_ft(ROFF_TERM_ARGS);
37 1.1 christos static void roff_term_pre_ll(ROFF_TERM_ARGS);
38 1.1 christos static void roff_term_pre_mc(ROFF_TERM_ARGS);
39 1.1 christos static void roff_term_pre_po(ROFF_TERM_ARGS);
40 1.1 christos static void roff_term_pre_sp(ROFF_TERM_ARGS);
41 1.1 christos static void roff_term_pre_ta(ROFF_TERM_ARGS);
42 1.1 christos static void roff_term_pre_ti(ROFF_TERM_ARGS);
43 1.1 christos
44 1.1 christos static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
45 1.1 christos roff_term_pre_br, /* br */
46 1.1 christos roff_term_pre_ce, /* ce */
47 1.1.1.2 christos roff_term_pre_br, /* fi */
48 1.1 christos roff_term_pre_ft, /* ft */
49 1.1 christos roff_term_pre_ll, /* ll */
50 1.1 christos roff_term_pre_mc, /* mc */
51 1.1.1.2 christos roff_term_pre_br, /* nf */
52 1.1 christos roff_term_pre_po, /* po */
53 1.1 christos roff_term_pre_ce, /* rj */
54 1.1 christos roff_term_pre_sp, /* sp */
55 1.1 christos roff_term_pre_ta, /* ta */
56 1.1 christos roff_term_pre_ti, /* ti */
57 1.1 christos };
58 1.1 christos
59 1.1 christos
60 1.1 christos void
61 1.1 christos roff_term_pre(struct termp *p, const struct roff_node *n)
62 1.1 christos {
63 1.1 christos assert(n->tok < ROFF_MAX);
64 1.1 christos (*roff_term_pre_acts[n->tok])(p, n);
65 1.1 christos }
66 1.1 christos
67 1.1 christos static void
68 1.1 christos roff_term_pre_br(ROFF_TERM_ARGS)
69 1.1 christos {
70 1.1 christos term_newln(p);
71 1.1 christos if (p->flags & TERMP_BRIND) {
72 1.1 christos p->tcol->offset = p->tcol->rmargin;
73 1.1 christos p->tcol->rmargin = p->maxrmargin;
74 1.1.1.2 christos p->trailspace = 0;
75 1.1 christos p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
76 1.1.1.2 christos p->flags |= TERMP_NOSPACE;
77 1.1 christos }
78 1.1 christos }
79 1.1 christos
80 1.1 christos static void
81 1.1 christos roff_term_pre_ce(ROFF_TERM_ARGS)
82 1.1 christos {
83 1.1 christos const struct roff_node *nc1, *nc2;
84 1.1 christos
85 1.1 christos roff_term_pre_br(p, n);
86 1.1.1.2 christos p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
87 1.1 christos nc1 = n->child->next;
88 1.1 christos while (nc1 != NULL) {
89 1.1 christos nc2 = nc1;
90 1.1 christos do {
91 1.1 christos nc2 = nc2->next;
92 1.1 christos } while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
93 1.1 christos (nc2->flags & NODE_LINE) == 0));
94 1.1 christos while (nc1 != nc2) {
95 1.1 christos if (nc1->type == ROFFT_TEXT)
96 1.1 christos term_word(p, nc1->string);
97 1.1 christos else
98 1.1 christos roff_term_pre(p, nc1);
99 1.1 christos nc1 = nc1->next;
100 1.1 christos }
101 1.1 christos p->flags |= TERMP_NOSPACE;
102 1.1 christos term_flushln(p);
103 1.1 christos }
104 1.1.1.2 christos p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
105 1.1 christos }
106 1.1 christos
107 1.1 christos static void
108 1.1 christos roff_term_pre_ft(ROFF_TERM_ARGS)
109 1.1 christos {
110 1.1.1.2 christos const char *cp;
111 1.1.1.2 christos
112 1.1.1.2 christos cp = n->child->string;
113 1.1.1.2 christos switch (mandoc_font(cp, (int)strlen(cp))) {
114 1.1.1.2 christos case ESCAPE_FONTBOLD:
115 1.1.1.3 wiz case ESCAPE_FONTCB:
116 1.1 christos term_fontrepl(p, TERMFONT_BOLD);
117 1.1 christos break;
118 1.1.1.2 christos case ESCAPE_FONTITALIC:
119 1.1.1.3 wiz case ESCAPE_FONTCI:
120 1.1 christos term_fontrepl(p, TERMFONT_UNDER);
121 1.1 christos break;
122 1.1.1.2 christos case ESCAPE_FONTBI:
123 1.1.1.2 christos term_fontrepl(p, TERMFONT_BI);
124 1.1.1.2 christos break;
125 1.1.1.2 christos case ESCAPE_FONTPREV:
126 1.1 christos term_fontlast(p);
127 1.1 christos break;
128 1.1.1.2 christos case ESCAPE_FONTROMAN:
129 1.1.1.3 wiz case ESCAPE_FONTCR:
130 1.1 christos term_fontrepl(p, TERMFONT_NONE);
131 1.1 christos break;
132 1.1 christos default:
133 1.1 christos break;
134 1.1 christos }
135 1.1 christos }
136 1.1 christos
137 1.1 christos static void
138 1.1 christos roff_term_pre_ll(ROFF_TERM_ARGS)
139 1.1 christos {
140 1.1 christos term_setwidth(p, n->child != NULL ? n->child->string : NULL);
141 1.1 christos }
142 1.1 christos
143 1.1 christos static void
144 1.1 christos roff_term_pre_mc(ROFF_TERM_ARGS)
145 1.1 christos {
146 1.1 christos if (p->col) {
147 1.1 christos p->flags |= TERMP_NOBREAK;
148 1.1 christos term_flushln(p);
149 1.1 christos p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
150 1.1 christos }
151 1.1 christos if (n->child != NULL) {
152 1.1 christos p->mc = n->child->string;
153 1.1 christos p->flags |= TERMP_NEWMC;
154 1.1 christos } else
155 1.1 christos p->flags |= TERMP_ENDMC;
156 1.1 christos }
157 1.1 christos
158 1.1 christos static void
159 1.1 christos roff_term_pre_po(ROFF_TERM_ARGS)
160 1.1 christos {
161 1.1 christos struct roffsu su;
162 1.1.1.3 wiz static int po, pouse, polast;
163 1.1 christos int ponew;
164 1.1 christos
165 1.1.1.3 wiz /* Revert the currently active page offset. */
166 1.1.1.3 wiz p->tcol->offset -= pouse;
167 1.1.1.3 wiz
168 1.1.1.3 wiz /* Determine the requested page offset. */
169 1.1 christos if (n->child != NULL &&
170 1.1 christos a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
171 1.1 christos ponew = term_hen(p, &su);
172 1.1 christos if (*n->child->string == '+' ||
173 1.1 christos *n->child->string == '-')
174 1.1 christos ponew += po;
175 1.1 christos } else
176 1.1 christos ponew = polast;
177 1.1.1.3 wiz
178 1.1.1.3 wiz /* Remeber both the previous and the newly requested offset. */
179 1.1 christos polast = po;
180 1.1 christos po = ponew;
181 1.1 christos
182 1.1.1.3 wiz /* Truncate to the range [-offset, 60], remember, and apply it. */
183 1.1.1.3 wiz pouse = po >= 60 ? 60 :
184 1.1.1.3 wiz po < -(int)p->tcol->offset ? -(int)p->tcol->offset : po;
185 1.1.1.3 wiz p->tcol->offset += pouse;
186 1.1 christos }
187 1.1 christos
188 1.1 christos static void
189 1.1 christos roff_term_pre_sp(ROFF_TERM_ARGS)
190 1.1 christos {
191 1.1 christos struct roffsu su;
192 1.1 christos int len;
193 1.1 christos
194 1.1 christos if (n->child != NULL) {
195 1.1 christos if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
196 1.1 christos su.scale = 1.0;
197 1.1 christos len = term_vspan(p, &su);
198 1.1 christos } else
199 1.1 christos len = 1;
200 1.1 christos
201 1.1 christos if (len < 0)
202 1.1 christos p->skipvsp -= len;
203 1.1 christos else
204 1.1 christos while (len--)
205 1.1 christos term_vspace(p);
206 1.1 christos
207 1.1 christos roff_term_pre_br(p, n);
208 1.1 christos }
209 1.1 christos
210 1.1 christos static void
211 1.1 christos roff_term_pre_ta(ROFF_TERM_ARGS)
212 1.1 christos {
213 1.1 christos term_tab_set(p, NULL);
214 1.1 christos for (n = n->child; n != NULL; n = n->next)
215 1.1 christos term_tab_set(p, n->string);
216 1.1 christos }
217 1.1 christos
218 1.1 christos static void
219 1.1 christos roff_term_pre_ti(ROFF_TERM_ARGS)
220 1.1 christos {
221 1.1 christos struct roffsu su;
222 1.1 christos const char *cp;
223 1.1.1.3 wiz const size_t maxoff = 72;
224 1.1 christos int len, sign;
225 1.1 christos
226 1.1 christos roff_term_pre_br(p, n);
227 1.1 christos
228 1.1 christos if (n->child == NULL)
229 1.1 christos return;
230 1.1 christos cp = n->child->string;
231 1.1 christos if (*cp == '+') {
232 1.1 christos sign = 1;
233 1.1 christos cp++;
234 1.1 christos } else if (*cp == '-') {
235 1.1 christos sign = -1;
236 1.1 christos cp++;
237 1.1 christos } else
238 1.1 christos sign = 0;
239 1.1 christos
240 1.1 christos if (a2roffsu(cp, &su, SCALE_EM) == NULL)
241 1.1 christos return;
242 1.1 christos len = term_hen(p, &su);
243 1.1 christos
244 1.1.1.3 wiz switch (sign) {
245 1.1.1.3 wiz case 1:
246 1.1.1.3 wiz if (p->tcol->offset + len <= maxoff)
247 1.1.1.3 wiz p->ti = len;
248 1.1.1.3 wiz else if (p->tcol->offset < maxoff)
249 1.1.1.3 wiz p->ti = maxoff - p->tcol->offset;
250 1.1.1.3 wiz else
251 1.1.1.3 wiz p->ti = 0;
252 1.1.1.3 wiz break;
253 1.1.1.3 wiz case -1:
254 1.1.1.3 wiz if ((size_t)len < p->tcol->offset)
255 1.1.1.3 wiz p->ti = -len;
256 1.1.1.3 wiz else
257 1.1.1.3 wiz p->ti = -p->tcol->offset;
258 1.1.1.3 wiz break;
259 1.1.1.3 wiz default:
260 1.1.1.3 wiz if ((size_t)len > maxoff)
261 1.1.1.3 wiz len = maxoff;
262 1.1 christos p->ti = len - p->tcol->offset;
263 1.1.1.3 wiz break;
264 1.1 christos }
265 1.1.1.3 wiz p->tcol->offset += p->ti;
266 1.1 christos }
267