1*6d38604fSBaptiste Daroussin /* $OpenBSD: roff_term.c,v 1.20 2020/09/03 17:37:06 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
3*6d38604fSBaptiste Daroussin * Copyright (c) 2010,2014,2015,2017-2020 Ingo Schwarze <schwarze@openbsd.org>
461d06d6bSBaptiste Daroussin *
561d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any
661d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above
761d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies.
861d06d6bSBaptiste Daroussin *
961d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1061d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1161d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1261d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1361d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1461d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1561d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1661d06d6bSBaptiste Daroussin */
17*6d38604fSBaptiste Daroussin #include "config.h"
18*6d38604fSBaptiste Daroussin
1961d06d6bSBaptiste Daroussin #include <sys/types.h>
2061d06d6bSBaptiste Daroussin
2161d06d6bSBaptiste Daroussin #include <assert.h>
227295610fSBaptiste Daroussin #include <stdio.h>
237295610fSBaptiste Daroussin #include <string.h>
2461d06d6bSBaptiste Daroussin
2561d06d6bSBaptiste Daroussin #include "mandoc.h"
2661d06d6bSBaptiste Daroussin #include "roff.h"
2761d06d6bSBaptiste Daroussin #include "out.h"
2861d06d6bSBaptiste Daroussin #include "term.h"
2961d06d6bSBaptiste Daroussin
3061d06d6bSBaptiste Daroussin #define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
3161d06d6bSBaptiste Daroussin
3261d06d6bSBaptiste Daroussin typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS);
3361d06d6bSBaptiste Daroussin
3461d06d6bSBaptiste Daroussin static void roff_term_pre_br(ROFF_TERM_ARGS);
3561d06d6bSBaptiste Daroussin static void roff_term_pre_ce(ROFF_TERM_ARGS);
3661d06d6bSBaptiste Daroussin static void roff_term_pre_ft(ROFF_TERM_ARGS);
3761d06d6bSBaptiste Daroussin static void roff_term_pre_ll(ROFF_TERM_ARGS);
3861d06d6bSBaptiste Daroussin static void roff_term_pre_mc(ROFF_TERM_ARGS);
3961d06d6bSBaptiste Daroussin static void roff_term_pre_po(ROFF_TERM_ARGS);
4061d06d6bSBaptiste Daroussin static void roff_term_pre_sp(ROFF_TERM_ARGS);
4161d06d6bSBaptiste Daroussin static void roff_term_pre_ta(ROFF_TERM_ARGS);
4261d06d6bSBaptiste Daroussin static void roff_term_pre_ti(ROFF_TERM_ARGS);
4361d06d6bSBaptiste Daroussin
4461d06d6bSBaptiste Daroussin static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
4561d06d6bSBaptiste Daroussin roff_term_pre_br, /* br */
4661d06d6bSBaptiste Daroussin roff_term_pre_ce, /* ce */
477295610fSBaptiste Daroussin roff_term_pre_br, /* fi */
4861d06d6bSBaptiste Daroussin roff_term_pre_ft, /* ft */
4961d06d6bSBaptiste Daroussin roff_term_pre_ll, /* ll */
5061d06d6bSBaptiste Daroussin roff_term_pre_mc, /* mc */
517295610fSBaptiste Daroussin roff_term_pre_br, /* nf */
5261d06d6bSBaptiste Daroussin roff_term_pre_po, /* po */
5361d06d6bSBaptiste Daroussin roff_term_pre_ce, /* rj */
5461d06d6bSBaptiste Daroussin roff_term_pre_sp, /* sp */
5561d06d6bSBaptiste Daroussin roff_term_pre_ta, /* ta */
5661d06d6bSBaptiste Daroussin roff_term_pre_ti, /* ti */
5761d06d6bSBaptiste Daroussin };
5861d06d6bSBaptiste Daroussin
5961d06d6bSBaptiste Daroussin
6061d06d6bSBaptiste Daroussin void
roff_term_pre(struct termp * p,const struct roff_node * n)6161d06d6bSBaptiste Daroussin roff_term_pre(struct termp *p, const struct roff_node *n)
6261d06d6bSBaptiste Daroussin {
6361d06d6bSBaptiste Daroussin assert(n->tok < ROFF_MAX);
6461d06d6bSBaptiste Daroussin (*roff_term_pre_acts[n->tok])(p, n);
6561d06d6bSBaptiste Daroussin }
6661d06d6bSBaptiste Daroussin
6761d06d6bSBaptiste Daroussin static void
roff_term_pre_br(ROFF_TERM_ARGS)6861d06d6bSBaptiste Daroussin roff_term_pre_br(ROFF_TERM_ARGS)
6961d06d6bSBaptiste Daroussin {
7061d06d6bSBaptiste Daroussin term_newln(p);
7161d06d6bSBaptiste Daroussin if (p->flags & TERMP_BRIND) {
7261d06d6bSBaptiste Daroussin p->tcol->offset = p->tcol->rmargin;
7361d06d6bSBaptiste Daroussin p->tcol->rmargin = p->maxrmargin;
747295610fSBaptiste Daroussin p->trailspace = 0;
7561d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
767295610fSBaptiste Daroussin p->flags |= TERMP_NOSPACE;
7761d06d6bSBaptiste Daroussin }
7861d06d6bSBaptiste Daroussin }
7961d06d6bSBaptiste Daroussin
8061d06d6bSBaptiste Daroussin static void
roff_term_pre_ce(ROFF_TERM_ARGS)8161d06d6bSBaptiste Daroussin roff_term_pre_ce(ROFF_TERM_ARGS)
8261d06d6bSBaptiste Daroussin {
8361d06d6bSBaptiste Daroussin const struct roff_node *nc1, *nc2;
8461d06d6bSBaptiste Daroussin
8561d06d6bSBaptiste Daroussin roff_term_pre_br(p, n);
867295610fSBaptiste Daroussin p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
8761d06d6bSBaptiste Daroussin nc1 = n->child->next;
8861d06d6bSBaptiste Daroussin while (nc1 != NULL) {
8961d06d6bSBaptiste Daroussin nc2 = nc1;
9061d06d6bSBaptiste Daroussin do {
9161d06d6bSBaptiste Daroussin nc2 = nc2->next;
9261d06d6bSBaptiste Daroussin } while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
9361d06d6bSBaptiste Daroussin (nc2->flags & NODE_LINE) == 0));
9461d06d6bSBaptiste Daroussin while (nc1 != nc2) {
9561d06d6bSBaptiste Daroussin if (nc1->type == ROFFT_TEXT)
9661d06d6bSBaptiste Daroussin term_word(p, nc1->string);
9761d06d6bSBaptiste Daroussin else
9861d06d6bSBaptiste Daroussin roff_term_pre(p, nc1);
9961d06d6bSBaptiste Daroussin nc1 = nc1->next;
10061d06d6bSBaptiste Daroussin }
10161d06d6bSBaptiste Daroussin p->flags |= TERMP_NOSPACE;
10261d06d6bSBaptiste Daroussin term_flushln(p);
10361d06d6bSBaptiste Daroussin }
1047295610fSBaptiste Daroussin p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
10561d06d6bSBaptiste Daroussin }
10661d06d6bSBaptiste Daroussin
10761d06d6bSBaptiste Daroussin static void
roff_term_pre_ft(ROFF_TERM_ARGS)10861d06d6bSBaptiste Daroussin roff_term_pre_ft(ROFF_TERM_ARGS)
10961d06d6bSBaptiste Daroussin {
1107295610fSBaptiste Daroussin const char *cp;
1117295610fSBaptiste Daroussin
1127295610fSBaptiste Daroussin cp = n->child->string;
1137295610fSBaptiste Daroussin switch (mandoc_font(cp, (int)strlen(cp))) {
1147295610fSBaptiste Daroussin case ESCAPE_FONTBOLD:
115*6d38604fSBaptiste Daroussin case ESCAPE_FONTCB:
11661d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_BOLD);
11761d06d6bSBaptiste Daroussin break;
1187295610fSBaptiste Daroussin case ESCAPE_FONTITALIC:
119*6d38604fSBaptiste Daroussin case ESCAPE_FONTCI:
12061d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_UNDER);
12161d06d6bSBaptiste Daroussin break;
1227295610fSBaptiste Daroussin case ESCAPE_FONTBI:
1237295610fSBaptiste Daroussin term_fontrepl(p, TERMFONT_BI);
1247295610fSBaptiste Daroussin break;
1257295610fSBaptiste Daroussin case ESCAPE_FONTPREV:
12661d06d6bSBaptiste Daroussin term_fontlast(p);
12761d06d6bSBaptiste Daroussin break;
1287295610fSBaptiste Daroussin case ESCAPE_FONTROMAN:
129*6d38604fSBaptiste Daroussin case ESCAPE_FONTCR:
13061d06d6bSBaptiste Daroussin term_fontrepl(p, TERMFONT_NONE);
13161d06d6bSBaptiste Daroussin break;
13261d06d6bSBaptiste Daroussin default:
13361d06d6bSBaptiste Daroussin break;
13461d06d6bSBaptiste Daroussin }
13561d06d6bSBaptiste Daroussin }
13661d06d6bSBaptiste Daroussin
13761d06d6bSBaptiste Daroussin static void
roff_term_pre_ll(ROFF_TERM_ARGS)13861d06d6bSBaptiste Daroussin roff_term_pre_ll(ROFF_TERM_ARGS)
13961d06d6bSBaptiste Daroussin {
14061d06d6bSBaptiste Daroussin term_setwidth(p, n->child != NULL ? n->child->string : NULL);
14161d06d6bSBaptiste Daroussin }
14261d06d6bSBaptiste Daroussin
14361d06d6bSBaptiste Daroussin static void
roff_term_pre_mc(ROFF_TERM_ARGS)14461d06d6bSBaptiste Daroussin roff_term_pre_mc(ROFF_TERM_ARGS)
14561d06d6bSBaptiste Daroussin {
14661d06d6bSBaptiste Daroussin if (p->col) {
14761d06d6bSBaptiste Daroussin p->flags |= TERMP_NOBREAK;
14861d06d6bSBaptiste Daroussin term_flushln(p);
14961d06d6bSBaptiste Daroussin p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
15061d06d6bSBaptiste Daroussin }
15161d06d6bSBaptiste Daroussin if (n->child != NULL) {
15261d06d6bSBaptiste Daroussin p->mc = n->child->string;
15361d06d6bSBaptiste Daroussin p->flags |= TERMP_NEWMC;
15461d06d6bSBaptiste Daroussin } else
15561d06d6bSBaptiste Daroussin p->flags |= TERMP_ENDMC;
15661d06d6bSBaptiste Daroussin }
15761d06d6bSBaptiste Daroussin
15861d06d6bSBaptiste Daroussin static void
roff_term_pre_po(ROFF_TERM_ARGS)15961d06d6bSBaptiste Daroussin roff_term_pre_po(ROFF_TERM_ARGS)
16061d06d6bSBaptiste Daroussin {
16161d06d6bSBaptiste Daroussin struct roffsu su;
162*6d38604fSBaptiste Daroussin static int po, pouse, polast;
16361d06d6bSBaptiste Daroussin int ponew;
16461d06d6bSBaptiste Daroussin
165*6d38604fSBaptiste Daroussin /* Revert the currently active page offset. */
166*6d38604fSBaptiste Daroussin p->tcol->offset -= pouse;
167*6d38604fSBaptiste Daroussin
168*6d38604fSBaptiste Daroussin /* Determine the requested page offset. */
16961d06d6bSBaptiste Daroussin if (n->child != NULL &&
17061d06d6bSBaptiste Daroussin a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
17161d06d6bSBaptiste Daroussin ponew = term_hen(p, &su);
17261d06d6bSBaptiste Daroussin if (*n->child->string == '+' ||
17361d06d6bSBaptiste Daroussin *n->child->string == '-')
17461d06d6bSBaptiste Daroussin ponew += po;
17561d06d6bSBaptiste Daroussin } else
17661d06d6bSBaptiste Daroussin ponew = polast;
177*6d38604fSBaptiste Daroussin
178*6d38604fSBaptiste Daroussin /* Remeber both the previous and the newly requested offset. */
17961d06d6bSBaptiste Daroussin polast = po;
18061d06d6bSBaptiste Daroussin po = ponew;
18161d06d6bSBaptiste Daroussin
182*6d38604fSBaptiste Daroussin /* Truncate to the range [-offset, 60], remember, and apply it. */
183*6d38604fSBaptiste Daroussin pouse = po >= 60 ? 60 :
184*6d38604fSBaptiste Daroussin po < -(int)p->tcol->offset ? -(int)p->tcol->offset : po;
185*6d38604fSBaptiste Daroussin p->tcol->offset += pouse;
18661d06d6bSBaptiste Daroussin }
18761d06d6bSBaptiste Daroussin
18861d06d6bSBaptiste Daroussin static void
roff_term_pre_sp(ROFF_TERM_ARGS)18961d06d6bSBaptiste Daroussin roff_term_pre_sp(ROFF_TERM_ARGS)
19061d06d6bSBaptiste Daroussin {
19161d06d6bSBaptiste Daroussin struct roffsu su;
19261d06d6bSBaptiste Daroussin int len;
19361d06d6bSBaptiste Daroussin
19461d06d6bSBaptiste Daroussin if (n->child != NULL) {
19561d06d6bSBaptiste Daroussin if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
19661d06d6bSBaptiste Daroussin su.scale = 1.0;
19761d06d6bSBaptiste Daroussin len = term_vspan(p, &su);
19861d06d6bSBaptiste Daroussin } else
19961d06d6bSBaptiste Daroussin len = 1;
20061d06d6bSBaptiste Daroussin
20161d06d6bSBaptiste Daroussin if (len < 0)
20261d06d6bSBaptiste Daroussin p->skipvsp -= len;
20361d06d6bSBaptiste Daroussin else
20461d06d6bSBaptiste Daroussin while (len--)
20561d06d6bSBaptiste Daroussin term_vspace(p);
20661d06d6bSBaptiste Daroussin
20761d06d6bSBaptiste Daroussin roff_term_pre_br(p, n);
20861d06d6bSBaptiste Daroussin }
20961d06d6bSBaptiste Daroussin
21061d06d6bSBaptiste Daroussin static void
roff_term_pre_ta(ROFF_TERM_ARGS)21161d06d6bSBaptiste Daroussin roff_term_pre_ta(ROFF_TERM_ARGS)
21261d06d6bSBaptiste Daroussin {
21361d06d6bSBaptiste Daroussin term_tab_set(p, NULL);
21461d06d6bSBaptiste Daroussin for (n = n->child; n != NULL; n = n->next)
21561d06d6bSBaptiste Daroussin term_tab_set(p, n->string);
21661d06d6bSBaptiste Daroussin }
21761d06d6bSBaptiste Daroussin
21861d06d6bSBaptiste Daroussin static void
roff_term_pre_ti(ROFF_TERM_ARGS)21961d06d6bSBaptiste Daroussin roff_term_pre_ti(ROFF_TERM_ARGS)
22061d06d6bSBaptiste Daroussin {
22161d06d6bSBaptiste Daroussin struct roffsu su;
22261d06d6bSBaptiste Daroussin const char *cp;
223*6d38604fSBaptiste Daroussin const size_t maxoff = 72;
22461d06d6bSBaptiste Daroussin int len, sign;
22561d06d6bSBaptiste Daroussin
22661d06d6bSBaptiste Daroussin roff_term_pre_br(p, n);
22761d06d6bSBaptiste Daroussin
22861d06d6bSBaptiste Daroussin if (n->child == NULL)
22961d06d6bSBaptiste Daroussin return;
23061d06d6bSBaptiste Daroussin cp = n->child->string;
23161d06d6bSBaptiste Daroussin if (*cp == '+') {
23261d06d6bSBaptiste Daroussin sign = 1;
23361d06d6bSBaptiste Daroussin cp++;
23461d06d6bSBaptiste Daroussin } else if (*cp == '-') {
23561d06d6bSBaptiste Daroussin sign = -1;
23661d06d6bSBaptiste Daroussin cp++;
23761d06d6bSBaptiste Daroussin } else
23861d06d6bSBaptiste Daroussin sign = 0;
23961d06d6bSBaptiste Daroussin
24061d06d6bSBaptiste Daroussin if (a2roffsu(cp, &su, SCALE_EM) == NULL)
24161d06d6bSBaptiste Daroussin return;
24261d06d6bSBaptiste Daroussin len = term_hen(p, &su);
24361d06d6bSBaptiste Daroussin
244*6d38604fSBaptiste Daroussin switch (sign) {
245*6d38604fSBaptiste Daroussin case 1:
246*6d38604fSBaptiste Daroussin if (p->tcol->offset + len <= maxoff)
24761d06d6bSBaptiste Daroussin p->ti = len;
248*6d38604fSBaptiste Daroussin else if (p->tcol->offset < maxoff)
249*6d38604fSBaptiste Daroussin p->ti = maxoff - p->tcol->offset;
250*6d38604fSBaptiste Daroussin else
251*6d38604fSBaptiste Daroussin p->ti = 0;
252*6d38604fSBaptiste Daroussin break;
253*6d38604fSBaptiste Daroussin case -1:
254*6d38604fSBaptiste Daroussin if ((size_t)len < p->tcol->offset)
25561d06d6bSBaptiste Daroussin p->ti = -len;
256*6d38604fSBaptiste Daroussin else
25761d06d6bSBaptiste Daroussin p->ti = -p->tcol->offset;
258*6d38604fSBaptiste Daroussin break;
259*6d38604fSBaptiste Daroussin default:
260*6d38604fSBaptiste Daroussin if ((size_t)len > maxoff)
261*6d38604fSBaptiste Daroussin len = maxoff;
262*6d38604fSBaptiste Daroussin p->ti = len - p->tcol->offset;
263*6d38604fSBaptiste Daroussin break;
26461d06d6bSBaptiste Daroussin }
265*6d38604fSBaptiste Daroussin p->tcol->offset += p->ti;
26661d06d6bSBaptiste Daroussin }
267