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