xref: /openbsd/usr.bin/mandoc/roff_term.c (revision d9a51c35)
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