1*d9a51c35Sjmc /* $OpenBSD: roff_term.c,v 1.23 2022/12/26 19:16:02 jmc Exp $ */
296a5de47Sschwarze /*
3c5afe1d3Sschwarze * Copyright (c) 2010,2014,2015,2017-2020 Ingo Schwarze <schwarze@openbsd.org>
496a5de47Sschwarze *
596a5de47Sschwarze * Permission to use, copy, modify, and distribute this software for any
696a5de47Sschwarze * purpose with or without fee is hereby granted, provided that the above
796a5de47Sschwarze * copyright notice and this permission notice appear in all copies.
896a5de47Sschwarze *
996a5de47Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1096a5de47Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1196a5de47Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1296a5de47Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1396a5de47Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1496a5de47Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1596a5de47Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1696a5de47Sschwarze */
1796a5de47Sschwarze #include <sys/types.h>
1896a5de47Sschwarze
1996a5de47Sschwarze #include <assert.h>
20e501e731Sschwarze #include <stdio.h>
212e362670Sschwarze #include <string.h>
2296a5de47Sschwarze
23f3476b07Sschwarze #include "mandoc.h"
2496a5de47Sschwarze #include "roff.h"
2596a5de47Sschwarze #include "out.h"
2696a5de47Sschwarze #include "term.h"
2796a5de47Sschwarze
2896a5de47Sschwarze #define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
2996a5de47Sschwarze
3096a5de47Sschwarze typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS);
3196a5de47Sschwarze
3296a5de47Sschwarze static void roff_term_pre_br(ROFF_TERM_ARGS);
33e13b4195Sschwarze static void roff_term_pre_ce(ROFF_TERM_ARGS);
34c4d3fa85Sschwarze static void roff_term_pre_ft(ROFF_TERM_ARGS);
35644b390bSschwarze static void roff_term_pre_ll(ROFF_TERM_ARGS);
3624f1eaadSschwarze static void roff_term_pre_mc(ROFF_TERM_ARGS);
37af1e8f15Sschwarze static void roff_term_pre_po(ROFF_TERM_ARGS);
386561cb23Sschwarze static void roff_term_pre_sp(ROFF_TERM_ARGS);
39f7242c43Sschwarze static void roff_term_pre_ta(ROFF_TERM_ARGS);
4011d70615Sschwarze static void roff_term_pre_ti(ROFF_TERM_ARGS);
4196a5de47Sschwarze
4296a5de47Sschwarze static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
4396a5de47Sschwarze roff_term_pre_br, /* br */
44e13b4195Sschwarze roff_term_pre_ce, /* ce */
450438bfdfSschwarze roff_term_pre_br, /* fi */
46c4d3fa85Sschwarze roff_term_pre_ft, /* ft */
4724f1eaadSschwarze roff_term_pre_ll, /* ll */
4824f1eaadSschwarze roff_term_pre_mc, /* mc */
490438bfdfSschwarze roff_term_pre_br, /* nf */
50af1e8f15Sschwarze roff_term_pre_po, /* po */
516de096f4Sschwarze roff_term_pre_ce, /* rj */
52f7242c43Sschwarze roff_term_pre_sp, /* sp */
53f7242c43Sschwarze roff_term_pre_ta, /* ta */
5411d70615Sschwarze roff_term_pre_ti, /* ti */
5596a5de47Sschwarze };
5696a5de47Sschwarze
5796a5de47Sschwarze
5896a5de47Sschwarze void
roff_term_pre(struct termp * p,const struct roff_node * n)5996a5de47Sschwarze roff_term_pre(struct termp *p, const struct roff_node *n)
6096a5de47Sschwarze {
6196a5de47Sschwarze assert(n->tok < ROFF_MAX);
6296a5de47Sschwarze (*roff_term_pre_acts[n->tok])(p, n);
6396a5de47Sschwarze }
6496a5de47Sschwarze
6596a5de47Sschwarze static void
roff_term_pre_br(ROFF_TERM_ARGS)6696a5de47Sschwarze roff_term_pre_br(ROFF_TERM_ARGS)
6796a5de47Sschwarze {
6896a5de47Sschwarze term_newln(p);
6996a5de47Sschwarze if (p->flags & TERMP_BRIND) {
70e93ea447Sschwarze p->tcol->offset = p->tcol->rmargin;
71e93ea447Sschwarze p->tcol->rmargin = p->maxrmargin;
720438bfdfSschwarze p->trailspace = 0;
7396a5de47Sschwarze p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
740438bfdfSschwarze p->flags |= TERMP_NOSPACE;
7596a5de47Sschwarze }
7696a5de47Sschwarze }
77c4d3fa85Sschwarze
78c4d3fa85Sschwarze static void
roff_term_pre_ce(ROFF_TERM_ARGS)79e13b4195Sschwarze roff_term_pre_ce(ROFF_TERM_ARGS)
80e13b4195Sschwarze {
816de096f4Sschwarze const struct roff_node *nc1, *nc2;
82e13b4195Sschwarze
83e13b4195Sschwarze roff_term_pre_br(p, n);
84d44dcb43Sschwarze p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
856de096f4Sschwarze nc1 = n->child->next;
866de096f4Sschwarze while (nc1 != NULL) {
876de096f4Sschwarze nc2 = nc1;
88e13b4195Sschwarze do {
896de096f4Sschwarze nc2 = nc2->next;
906de096f4Sschwarze } while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
916de096f4Sschwarze (nc2->flags & NODE_LINE) == 0));
926de096f4Sschwarze while (nc1 != nc2) {
936de096f4Sschwarze if (nc1->type == ROFFT_TEXT)
946de096f4Sschwarze term_word(p, nc1->string);
95e13b4195Sschwarze else
966de096f4Sschwarze roff_term_pre(p, nc1);
976de096f4Sschwarze nc1 = nc1->next;
98e13b4195Sschwarze }
99e13b4195Sschwarze p->flags |= TERMP_NOSPACE;
100e13b4195Sschwarze term_flushln(p);
101e13b4195Sschwarze }
102d44dcb43Sschwarze p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
103e13b4195Sschwarze }
104e13b4195Sschwarze
105e13b4195Sschwarze static void
roff_term_pre_ft(ROFF_TERM_ARGS)106c4d3fa85Sschwarze roff_term_pre_ft(ROFF_TERM_ARGS)
107c4d3fa85Sschwarze {
1089b153f25Sschwarze const char *cp;
1099b153f25Sschwarze
1102e362670Sschwarze cp = n->child->string;
1112e362670Sschwarze switch (mandoc_font(cp, (int)strlen(cp))) {
1122e362670Sschwarze case ESCAPE_FONTBOLD:
1137d063611Sschwarze case ESCAPE_FONTCB:
114c4d3fa85Sschwarze term_fontrepl(p, TERMFONT_BOLD);
115c4d3fa85Sschwarze break;
1162e362670Sschwarze case ESCAPE_FONTITALIC:
1177d063611Sschwarze case ESCAPE_FONTCI:
118c4d3fa85Sschwarze term_fontrepl(p, TERMFONT_UNDER);
119c4d3fa85Sschwarze break;
1202e362670Sschwarze case ESCAPE_FONTBI:
1212e362670Sschwarze term_fontrepl(p, TERMFONT_BI);
1222e362670Sschwarze break;
1232e362670Sschwarze case ESCAPE_FONTPREV:
124c4d3fa85Sschwarze term_fontlast(p);
125c4d3fa85Sschwarze break;
1262e362670Sschwarze case ESCAPE_FONTROMAN:
1277d063611Sschwarze case ESCAPE_FONTCR:
128c4d3fa85Sschwarze term_fontrepl(p, TERMFONT_NONE);
129c4d3fa85Sschwarze break;
130c4d3fa85Sschwarze default:
131c4d3fa85Sschwarze break;
132c4d3fa85Sschwarze }
133c4d3fa85Sschwarze }
134644b390bSschwarze
135644b390bSschwarze static void
roff_term_pre_ll(ROFF_TERM_ARGS)136644b390bSschwarze roff_term_pre_ll(ROFF_TERM_ARGS)
137644b390bSschwarze {
138644b390bSschwarze term_setwidth(p, n->child != NULL ? n->child->string : NULL);
139644b390bSschwarze }
1406561cb23Sschwarze
1416561cb23Sschwarze static void
roff_term_pre_mc(ROFF_TERM_ARGS)14224f1eaadSschwarze roff_term_pre_mc(ROFF_TERM_ARGS)
14324f1eaadSschwarze {
14424f1eaadSschwarze if (p->col) {
14524f1eaadSschwarze p->flags |= TERMP_NOBREAK;
14624f1eaadSschwarze term_flushln(p);
14724f1eaadSschwarze p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
14824f1eaadSschwarze }
14924f1eaadSschwarze if (n->child != NULL) {
15024f1eaadSschwarze p->mc = n->child->string;
15124f1eaadSschwarze p->flags |= TERMP_NEWMC;
15224f1eaadSschwarze } else
15324f1eaadSschwarze p->flags |= TERMP_ENDMC;
15424f1eaadSschwarze }
15524f1eaadSschwarze
15624f1eaadSschwarze static void
roff_term_pre_po(ROFF_TERM_ARGS)157af1e8f15Sschwarze roff_term_pre_po(ROFF_TERM_ARGS)
158af1e8f15Sschwarze {
159af1e8f15Sschwarze struct roffsu su;
160c5afe1d3Sschwarze static int po, pouse, polast;
161af1e8f15Sschwarze int ponew;
162af1e8f15Sschwarze
163c5afe1d3Sschwarze /* Revert the currently active page offset. */
164c5afe1d3Sschwarze p->tcol->offset -= pouse;
165c5afe1d3Sschwarze
166c5afe1d3Sschwarze /* Determine the requested page offset. */
167af1e8f15Sschwarze if (n->child != NULL &&
168af1e8f15Sschwarze a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
169af1e8f15Sschwarze ponew = term_hen(p, &su);
170af1e8f15Sschwarze if (*n->child->string == '+' ||
171af1e8f15Sschwarze *n->child->string == '-')
172af1e8f15Sschwarze ponew += po;
173af1e8f15Sschwarze } else
174af1e8f15Sschwarze ponew = polast;
175c5afe1d3Sschwarze
176*d9a51c35Sjmc /* Remember both the previous and the newly requested offset. */
177af1e8f15Sschwarze polast = po;
178af1e8f15Sschwarze po = ponew;
179af1e8f15Sschwarze
180c5afe1d3Sschwarze /* Truncate to the range [-offset, 60], remember, and apply it. */
181c5afe1d3Sschwarze pouse = po >= 60 ? 60 :
182c5afe1d3Sschwarze po < -(int)p->tcol->offset ? -p->tcol->offset : po;
183c5afe1d3Sschwarze p->tcol->offset += pouse;
184af1e8f15Sschwarze }
185af1e8f15Sschwarze
186af1e8f15Sschwarze static void
roff_term_pre_sp(ROFF_TERM_ARGS)1876561cb23Sschwarze roff_term_pre_sp(ROFF_TERM_ARGS)
1886561cb23Sschwarze {
1896561cb23Sschwarze struct roffsu su;
1906561cb23Sschwarze int len;
1916561cb23Sschwarze
1926561cb23Sschwarze if (n->child != NULL) {
193ecd22486Sschwarze if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
1946561cb23Sschwarze su.scale = 1.0;
1956561cb23Sschwarze len = term_vspan(p, &su);
1966561cb23Sschwarze } else
1976561cb23Sschwarze len = 1;
1986561cb23Sschwarze
1996561cb23Sschwarze if (len < 0)
2006561cb23Sschwarze p->skipvsp -= len;
2016561cb23Sschwarze else
2026561cb23Sschwarze while (len--)
2036561cb23Sschwarze term_vspace(p);
2046561cb23Sschwarze
2056561cb23Sschwarze roff_term_pre_br(p, n);
2066561cb23Sschwarze }
207f7242c43Sschwarze
208f7242c43Sschwarze static void
roff_term_pre_ta(ROFF_TERM_ARGS)209f7242c43Sschwarze roff_term_pre_ta(ROFF_TERM_ARGS)
210f7242c43Sschwarze {
211f7242c43Sschwarze term_tab_set(p, NULL);
212f7242c43Sschwarze for (n = n->child; n != NULL; n = n->next)
213f7242c43Sschwarze term_tab_set(p, n->string);
214f7242c43Sschwarze }
21511d70615Sschwarze
21611d70615Sschwarze static void
roff_term_pre_ti(ROFF_TERM_ARGS)21711d70615Sschwarze roff_term_pre_ti(ROFF_TERM_ARGS)
21811d70615Sschwarze {
21911d70615Sschwarze struct roffsu su;
22011d70615Sschwarze const char *cp;
22197ab3ebbSschwarze const size_t maxoff = 72;
22211d70615Sschwarze int len, sign;
22311d70615Sschwarze
22411d70615Sschwarze roff_term_pre_br(p, n);
22511d70615Sschwarze
22611d70615Sschwarze if (n->child == NULL)
22711d70615Sschwarze return;
22811d70615Sschwarze cp = n->child->string;
22911d70615Sschwarze if (*cp == '+') {
23011d70615Sschwarze sign = 1;
23111d70615Sschwarze cp++;
23211d70615Sschwarze } else if (*cp == '-') {
23311d70615Sschwarze sign = -1;
23411d70615Sschwarze cp++;
23511d70615Sschwarze } else
23611d70615Sschwarze sign = 0;
23711d70615Sschwarze
238ecd22486Sschwarze if (a2roffsu(cp, &su, SCALE_EM) == NULL)
23911d70615Sschwarze return;
240f4692b45Sschwarze len = term_hen(p, &su);
24111d70615Sschwarze
24297ab3ebbSschwarze switch (sign) {
24397ab3ebbSschwarze case 1:
24497ab3ebbSschwarze if (p->tcol->offset + len <= maxoff)
24511d70615Sschwarze p->ti = len;
24697ab3ebbSschwarze else if (p->tcol->offset < maxoff)
24797ab3ebbSschwarze p->ti = maxoff - p->tcol->offset;
24897ab3ebbSschwarze else
24997ab3ebbSschwarze p->ti = 0;
25097ab3ebbSschwarze break;
25197ab3ebbSschwarze case -1:
25297ab3ebbSschwarze if ((size_t)len < p->tcol->offset)
25311d70615Sschwarze p->ti = -len;
25497ab3ebbSschwarze else
255e93ea447Sschwarze p->ti = -p->tcol->offset;
25697ab3ebbSschwarze break;
25797ab3ebbSschwarze default:
25897ab3ebbSschwarze if ((size_t)len > maxoff)
25997ab3ebbSschwarze len = maxoff;
26097ab3ebbSschwarze p->ti = len - p->tcol->offset;
26197ab3ebbSschwarze break;
26211d70615Sschwarze }
26397ab3ebbSschwarze p->tcol->offset += p->ti;
26411d70615Sschwarze }
265