roff_term.c revision 1.1 1 1.1 christos /* Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp */
2 1.1 christos /*
3 1.1 christos * Copyright (c) 2010, 2014, 2015, 2017 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 christos #include <sys/types.h>
18 1.1 christos
19 1.1 christos #include <assert.h>
20 1.1 christos #include <stddef.h>
21 1.1 christos
22 1.1 christos #include "mandoc.h"
23 1.1 christos #include "roff.h"
24 1.1 christos #include "out.h"
25 1.1 christos #include "term.h"
26 1.1 christos
27 1.1 christos #define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
28 1.1 christos
29 1.1 christos typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS);
30 1.1 christos
31 1.1 christos static void roff_term_pre_br(ROFF_TERM_ARGS);
32 1.1 christos static void roff_term_pre_ce(ROFF_TERM_ARGS);
33 1.1 christos static void roff_term_pre_ft(ROFF_TERM_ARGS);
34 1.1 christos static void roff_term_pre_ll(ROFF_TERM_ARGS);
35 1.1 christos static void roff_term_pre_mc(ROFF_TERM_ARGS);
36 1.1 christos static void roff_term_pre_po(ROFF_TERM_ARGS);
37 1.1 christos static void roff_term_pre_sp(ROFF_TERM_ARGS);
38 1.1 christos static void roff_term_pre_ta(ROFF_TERM_ARGS);
39 1.1 christos static void roff_term_pre_ti(ROFF_TERM_ARGS);
40 1.1 christos
41 1.1 christos static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
42 1.1 christos roff_term_pre_br, /* br */
43 1.1 christos roff_term_pre_ce, /* ce */
44 1.1 christos roff_term_pre_ft, /* ft */
45 1.1 christos roff_term_pre_ll, /* ll */
46 1.1 christos roff_term_pre_mc, /* mc */
47 1.1 christos roff_term_pre_po, /* po */
48 1.1 christos roff_term_pre_ce, /* rj */
49 1.1 christos roff_term_pre_sp, /* sp */
50 1.1 christos roff_term_pre_ta, /* ta */
51 1.1 christos roff_term_pre_ti, /* ti */
52 1.1 christos };
53 1.1 christos
54 1.1 christos
55 1.1 christos void
56 1.1 christos roff_term_pre(struct termp *p, const struct roff_node *n)
57 1.1 christos {
58 1.1 christos assert(n->tok < ROFF_MAX);
59 1.1 christos (*roff_term_pre_acts[n->tok])(p, n);
60 1.1 christos }
61 1.1 christos
62 1.1 christos static void
63 1.1 christos roff_term_pre_br(ROFF_TERM_ARGS)
64 1.1 christos {
65 1.1 christos term_newln(p);
66 1.1 christos if (p->flags & TERMP_BRIND) {
67 1.1 christos p->tcol->offset = p->tcol->rmargin;
68 1.1 christos p->tcol->rmargin = p->maxrmargin;
69 1.1 christos p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
70 1.1 christos }
71 1.1 christos }
72 1.1 christos
73 1.1 christos static void
74 1.1 christos roff_term_pre_ce(ROFF_TERM_ARGS)
75 1.1 christos {
76 1.1 christos const struct roff_node *nc1, *nc2;
77 1.1 christos size_t len, lm;
78 1.1 christos
79 1.1 christos roff_term_pre_br(p, n);
80 1.1 christos lm = p->tcol->offset;
81 1.1 christos nc1 = n->child->next;
82 1.1 christos while (nc1 != NULL) {
83 1.1 christos nc2 = nc1;
84 1.1 christos len = 0;
85 1.1 christos do {
86 1.1 christos if (nc2->type == ROFFT_TEXT) {
87 1.1 christos if (len)
88 1.1 christos len++;
89 1.1 christos len += term_strlen(p, nc2->string);
90 1.1 christos }
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 p->tcol->offset = len >= p->tcol->rmargin ? 0 :
95 1.1 christos lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
96 1.1 christos n->tok == ROFF_rj ? p->tcol->rmargin - len :
97 1.1 christos (lm + p->tcol->rmargin - len) / 2;
98 1.1 christos while (nc1 != nc2) {
99 1.1 christos if (nc1->type == ROFFT_TEXT)
100 1.1 christos term_word(p, nc1->string);
101 1.1 christos else
102 1.1 christos roff_term_pre(p, nc1);
103 1.1 christos nc1 = nc1->next;
104 1.1 christos }
105 1.1 christos p->flags |= TERMP_NOSPACE;
106 1.1 christos term_flushln(p);
107 1.1 christos }
108 1.1 christos p->tcol->offset = lm;
109 1.1 christos }
110 1.1 christos
111 1.1 christos static void
112 1.1 christos roff_term_pre_ft(ROFF_TERM_ARGS)
113 1.1 christos {
114 1.1 christos switch (*n->child->string) {
115 1.1 christos case '4':
116 1.1 christos case '3':
117 1.1 christos case 'B':
118 1.1 christos term_fontrepl(p, TERMFONT_BOLD);
119 1.1 christos break;
120 1.1 christos case '2':
121 1.1 christos case 'I':
122 1.1 christos term_fontrepl(p, TERMFONT_UNDER);
123 1.1 christos break;
124 1.1 christos case 'P':
125 1.1 christos term_fontlast(p);
126 1.1 christos break;
127 1.1 christos case '1':
128 1.1 christos case 'C':
129 1.1 christos case 'R':
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 christos static int po, polast;
163 1.1 christos int ponew;
164 1.1 christos
165 1.1 christos if (n->child != NULL &&
166 1.1 christos a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
167 1.1 christos ponew = term_hen(p, &su);
168 1.1 christos if (*n->child->string == '+' ||
169 1.1 christos *n->child->string == '-')
170 1.1 christos ponew += po;
171 1.1 christos } else
172 1.1 christos ponew = polast;
173 1.1 christos polast = po;
174 1.1 christos po = ponew;
175 1.1 christos
176 1.1 christos ponew = po - polast + (int)p->tcol->offset;
177 1.1 christos p->tcol->offset = ponew > 0 ? ponew : 0;
178 1.1 christos }
179 1.1 christos
180 1.1 christos static void
181 1.1 christos roff_term_pre_sp(ROFF_TERM_ARGS)
182 1.1 christos {
183 1.1 christos struct roffsu su;
184 1.1 christos int len;
185 1.1 christos
186 1.1 christos if (n->child != NULL) {
187 1.1 christos if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
188 1.1 christos su.scale = 1.0;
189 1.1 christos len = term_vspan(p, &su);
190 1.1 christos } else
191 1.1 christos len = 1;
192 1.1 christos
193 1.1 christos if (len < 0)
194 1.1 christos p->skipvsp -= len;
195 1.1 christos else
196 1.1 christos while (len--)
197 1.1 christos term_vspace(p);
198 1.1 christos
199 1.1 christos roff_term_pre_br(p, n);
200 1.1 christos }
201 1.1 christos
202 1.1 christos static void
203 1.1 christos roff_term_pre_ta(ROFF_TERM_ARGS)
204 1.1 christos {
205 1.1 christos term_tab_set(p, NULL);
206 1.1 christos for (n = n->child; n != NULL; n = n->next)
207 1.1 christos term_tab_set(p, n->string);
208 1.1 christos }
209 1.1 christos
210 1.1 christos static void
211 1.1 christos roff_term_pre_ti(ROFF_TERM_ARGS)
212 1.1 christos {
213 1.1 christos struct roffsu su;
214 1.1 christos const char *cp;
215 1.1 christos int len, sign;
216 1.1 christos
217 1.1 christos roff_term_pre_br(p, n);
218 1.1 christos
219 1.1 christos if (n->child == NULL)
220 1.1 christos return;
221 1.1 christos cp = n->child->string;
222 1.1 christos if (*cp == '+') {
223 1.1 christos sign = 1;
224 1.1 christos cp++;
225 1.1 christos } else if (*cp == '-') {
226 1.1 christos sign = -1;
227 1.1 christos cp++;
228 1.1 christos } else
229 1.1 christos sign = 0;
230 1.1 christos
231 1.1 christos if (a2roffsu(cp, &su, SCALE_EM) == NULL)
232 1.1 christos return;
233 1.1 christos len = term_hen(p, &su);
234 1.1 christos
235 1.1 christos if (sign == 0) {
236 1.1 christos p->ti = len - p->tcol->offset;
237 1.1 christos p->tcol->offset = len;
238 1.1 christos } else if (sign == 1) {
239 1.1 christos p->ti = len;
240 1.1 christos p->tcol->offset += len;
241 1.1 christos } else if ((size_t)len < p->tcol->offset) {
242 1.1 christos p->ti = -len;
243 1.1 christos p->tcol->offset -= len;
244 1.1 christos } else {
245 1.1 christos p->ti = -p->tcol->offset;
246 1.1 christos p->tcol->offset = 0;
247 1.1 christos }
248 1.1 christos }
249