xref: /openbsd/usr.bin/mandoc/roff_term.c (revision e501e731)
1*e501e731Sschwarze /*	$OpenBSD: roff_term.c,v 1.16 2018/12/14 01:17:46 schwarze Exp $ */
296a5de47Sschwarze /*
39b153f25Sschwarze  * Copyright (c) 2010,2014,2015,2017,2018 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>
20*e501e731Sschwarze #include <stdio.h>
2196a5de47Sschwarze 
22f3476b07Sschwarze #include "mandoc.h"
2396a5de47Sschwarze #include "roff.h"
2496a5de47Sschwarze #include "out.h"
2596a5de47Sschwarze #include "term.h"
2696a5de47Sschwarze 
2796a5de47Sschwarze #define	ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
2896a5de47Sschwarze 
2996a5de47Sschwarze typedef	void	(*roff_term_pre_fp)(ROFF_TERM_ARGS);
3096a5de47Sschwarze 
3196a5de47Sschwarze static	void	  roff_term_pre_br(ROFF_TERM_ARGS);
32e13b4195Sschwarze static	void	  roff_term_pre_ce(ROFF_TERM_ARGS);
33c4d3fa85Sschwarze static	void	  roff_term_pre_ft(ROFF_TERM_ARGS);
34644b390bSschwarze static	void	  roff_term_pre_ll(ROFF_TERM_ARGS);
3524f1eaadSschwarze static	void	  roff_term_pre_mc(ROFF_TERM_ARGS);
36af1e8f15Sschwarze static	void	  roff_term_pre_po(ROFF_TERM_ARGS);
376561cb23Sschwarze static	void	  roff_term_pre_sp(ROFF_TERM_ARGS);
38f7242c43Sschwarze static	void	  roff_term_pre_ta(ROFF_TERM_ARGS);
3911d70615Sschwarze static	void	  roff_term_pre_ti(ROFF_TERM_ARGS);
4096a5de47Sschwarze 
4196a5de47Sschwarze static	const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
4296a5de47Sschwarze 	roff_term_pre_br,  /* br */
43e13b4195Sschwarze 	roff_term_pre_ce,  /* ce */
44c4d3fa85Sschwarze 	roff_term_pre_ft,  /* ft */
4524f1eaadSschwarze 	roff_term_pre_ll,  /* ll */
4624f1eaadSschwarze 	roff_term_pre_mc,  /* mc */
47af1e8f15Sschwarze 	roff_term_pre_po,  /* po */
486de096f4Sschwarze 	roff_term_pre_ce,  /* rj */
49f7242c43Sschwarze 	roff_term_pre_sp,  /* sp */
50f7242c43Sschwarze 	roff_term_pre_ta,  /* ta */
5111d70615Sschwarze 	roff_term_pre_ti,  /* ti */
5296a5de47Sschwarze };
5396a5de47Sschwarze 
5496a5de47Sschwarze 
5596a5de47Sschwarze void
5696a5de47Sschwarze roff_term_pre(struct termp *p, const struct roff_node *n)
5796a5de47Sschwarze {
5896a5de47Sschwarze 	assert(n->tok < ROFF_MAX);
5996a5de47Sschwarze 	(*roff_term_pre_acts[n->tok])(p, n);
6096a5de47Sschwarze }
6196a5de47Sschwarze 
6296a5de47Sschwarze static void
6396a5de47Sschwarze roff_term_pre_br(ROFF_TERM_ARGS)
6496a5de47Sschwarze {
6596a5de47Sschwarze 	term_newln(p);
6696a5de47Sschwarze 	if (p->flags & TERMP_BRIND) {
67e93ea447Sschwarze 		p->tcol->offset = p->tcol->rmargin;
68e93ea447Sschwarze 		p->tcol->rmargin = p->maxrmargin;
6996a5de47Sschwarze 		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
7096a5de47Sschwarze 	}
7196a5de47Sschwarze }
72c4d3fa85Sschwarze 
73c4d3fa85Sschwarze static void
74e13b4195Sschwarze roff_term_pre_ce(ROFF_TERM_ARGS)
75e13b4195Sschwarze {
766de096f4Sschwarze 	const struct roff_node	*nc1, *nc2;
77e13b4195Sschwarze 	size_t			 len, lm;
78e13b4195Sschwarze 
79e13b4195Sschwarze 	roff_term_pre_br(p, n);
80e93ea447Sschwarze 	lm = p->tcol->offset;
816de096f4Sschwarze 	nc1 = n->child->next;
826de096f4Sschwarze 	while (nc1 != NULL) {
836de096f4Sschwarze 		nc2 = nc1;
84e13b4195Sschwarze 		len = 0;
85e13b4195Sschwarze 		do {
866de096f4Sschwarze 			if (nc2->type == ROFFT_TEXT) {
87e13b4195Sschwarze 				if (len)
88e13b4195Sschwarze 					len++;
896de096f4Sschwarze 				len += term_strlen(p, nc2->string);
90e13b4195Sschwarze 			}
916de096f4Sschwarze 			nc2 = nc2->next;
926de096f4Sschwarze 		} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
936de096f4Sschwarze 		    (nc2->flags & NODE_LINE) == 0));
94e93ea447Sschwarze 		p->tcol->offset = len >= p->tcol->rmargin ? 0 :
95e93ea447Sschwarze 		    lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
966de096f4Sschwarze 		    n->tok == ROFF_rj ? p->tcol->rmargin - len :
97e93ea447Sschwarze 		    (lm + p->tcol->rmargin - len) / 2;
986de096f4Sschwarze 		while (nc1 != nc2) {
996de096f4Sschwarze 			if (nc1->type == ROFFT_TEXT)
1006de096f4Sschwarze 				term_word(p, nc1->string);
101e13b4195Sschwarze 			else
1026de096f4Sschwarze 				roff_term_pre(p, nc1);
1036de096f4Sschwarze 			nc1 = nc1->next;
104e13b4195Sschwarze 		}
105e13b4195Sschwarze 		p->flags |= TERMP_NOSPACE;
106e13b4195Sschwarze 		term_flushln(p);
107e13b4195Sschwarze 	}
108e93ea447Sschwarze 	p->tcol->offset = lm;
109e13b4195Sschwarze }
110e13b4195Sschwarze 
111e13b4195Sschwarze static void
112c4d3fa85Sschwarze roff_term_pre_ft(ROFF_TERM_ARGS)
113c4d3fa85Sschwarze {
1149b153f25Sschwarze 	const char	*cp;
1159b153f25Sschwarze 
1169b153f25Sschwarze 	if (*(cp = n->child->string) == 'C')
1179b153f25Sschwarze 		cp++;
1189b153f25Sschwarze 
1199b153f25Sschwarze 	switch (*cp) {
120c4d3fa85Sschwarze 	case '4':
121c4d3fa85Sschwarze 	case '3':
122c4d3fa85Sschwarze 	case 'B':
123c4d3fa85Sschwarze 		term_fontrepl(p, TERMFONT_BOLD);
124c4d3fa85Sschwarze 		break;
125c4d3fa85Sschwarze 	case '2':
126c4d3fa85Sschwarze 	case 'I':
127c4d3fa85Sschwarze 		term_fontrepl(p, TERMFONT_UNDER);
128c4d3fa85Sschwarze 		break;
129c4d3fa85Sschwarze 	case 'P':
130c4d3fa85Sschwarze 		term_fontlast(p);
131c4d3fa85Sschwarze 		break;
132c4d3fa85Sschwarze 	case '1':
133c4d3fa85Sschwarze 	case 'C':
134c4d3fa85Sschwarze 	case 'R':
135c4d3fa85Sschwarze 		term_fontrepl(p, TERMFONT_NONE);
136c4d3fa85Sschwarze 		break;
137c4d3fa85Sschwarze 	default:
138c4d3fa85Sschwarze 		break;
139c4d3fa85Sschwarze 	}
140c4d3fa85Sschwarze }
141644b390bSschwarze 
142644b390bSschwarze static void
143644b390bSschwarze roff_term_pre_ll(ROFF_TERM_ARGS)
144644b390bSschwarze {
145644b390bSschwarze 	term_setwidth(p, n->child != NULL ? n->child->string : NULL);
146644b390bSschwarze }
1476561cb23Sschwarze 
1486561cb23Sschwarze static void
14924f1eaadSschwarze roff_term_pre_mc(ROFF_TERM_ARGS)
15024f1eaadSschwarze {
15124f1eaadSschwarze 	if (p->col) {
15224f1eaadSschwarze 		p->flags |= TERMP_NOBREAK;
15324f1eaadSschwarze 		term_flushln(p);
15424f1eaadSschwarze 		p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
15524f1eaadSschwarze 	}
15624f1eaadSschwarze 	if (n->child != NULL) {
15724f1eaadSschwarze 		p->mc = n->child->string;
15824f1eaadSschwarze 		p->flags |= TERMP_NEWMC;
15924f1eaadSschwarze 	} else
16024f1eaadSschwarze 		p->flags |= TERMP_ENDMC;
16124f1eaadSschwarze }
16224f1eaadSschwarze 
16324f1eaadSschwarze static void
164af1e8f15Sschwarze roff_term_pre_po(ROFF_TERM_ARGS)
165af1e8f15Sschwarze {
166af1e8f15Sschwarze 	struct roffsu	 su;
167af1e8f15Sschwarze 	static int	 po, polast;
168af1e8f15Sschwarze 	int		 ponew;
169af1e8f15Sschwarze 
170af1e8f15Sschwarze 	if (n->child != NULL &&
171af1e8f15Sschwarze 	    a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
172af1e8f15Sschwarze 		ponew = term_hen(p, &su);
173af1e8f15Sschwarze 		if (*n->child->string == '+' ||
174af1e8f15Sschwarze 		    *n->child->string == '-')
175af1e8f15Sschwarze 			ponew += po;
176af1e8f15Sschwarze 	} else
177af1e8f15Sschwarze 		ponew = polast;
178af1e8f15Sschwarze 	polast = po;
179af1e8f15Sschwarze 	po = ponew;
180af1e8f15Sschwarze 
181af1e8f15Sschwarze 	ponew = po - polast + (int)p->tcol->offset;
182af1e8f15Sschwarze 	p->tcol->offset = ponew > 0 ? ponew : 0;
183af1e8f15Sschwarze }
184af1e8f15Sschwarze 
185af1e8f15Sschwarze static void
1866561cb23Sschwarze roff_term_pre_sp(ROFF_TERM_ARGS)
1876561cb23Sschwarze {
1886561cb23Sschwarze 	struct roffsu	 su;
1896561cb23Sschwarze 	int		 len;
1906561cb23Sschwarze 
1916561cb23Sschwarze 	if (n->child != NULL) {
192ecd22486Sschwarze 		if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
1936561cb23Sschwarze 			su.scale = 1.0;
1946561cb23Sschwarze 		len = term_vspan(p, &su);
1956561cb23Sschwarze 	} else
1966561cb23Sschwarze 		len = 1;
1976561cb23Sschwarze 
1986561cb23Sschwarze 	if (len < 0)
1996561cb23Sschwarze 		p->skipvsp -= len;
2006561cb23Sschwarze 	else
2016561cb23Sschwarze 		while (len--)
2026561cb23Sschwarze 			term_vspace(p);
2036561cb23Sschwarze 
2046561cb23Sschwarze 	roff_term_pre_br(p, n);
2056561cb23Sschwarze }
206f7242c43Sschwarze 
207f7242c43Sschwarze static void
208f7242c43Sschwarze roff_term_pre_ta(ROFF_TERM_ARGS)
209f7242c43Sschwarze {
210f7242c43Sschwarze 	term_tab_set(p, NULL);
211f7242c43Sschwarze 	for (n = n->child; n != NULL; n = n->next)
212f7242c43Sschwarze 		term_tab_set(p, n->string);
213f7242c43Sschwarze }
21411d70615Sschwarze 
21511d70615Sschwarze static void
21611d70615Sschwarze roff_term_pre_ti(ROFF_TERM_ARGS)
21711d70615Sschwarze {
21811d70615Sschwarze 	struct roffsu	 su;
21911d70615Sschwarze 	const char	*cp;
22011d70615Sschwarze 	int		 len, sign;
22111d70615Sschwarze 
22211d70615Sschwarze 	roff_term_pre_br(p, n);
22311d70615Sschwarze 
22411d70615Sschwarze 	if (n->child == NULL)
22511d70615Sschwarze 		return;
22611d70615Sschwarze 	cp = n->child->string;
22711d70615Sschwarze 	if (*cp == '+') {
22811d70615Sschwarze 		sign = 1;
22911d70615Sschwarze 		cp++;
23011d70615Sschwarze 	} else if (*cp == '-') {
23111d70615Sschwarze 		sign = -1;
23211d70615Sschwarze 		cp++;
23311d70615Sschwarze 	} else
23411d70615Sschwarze 		sign = 0;
23511d70615Sschwarze 
236ecd22486Sschwarze 	if (a2roffsu(cp, &su, SCALE_EM) == NULL)
23711d70615Sschwarze 		return;
238f4692b45Sschwarze 	len = term_hen(p, &su);
23911d70615Sschwarze 
24011d70615Sschwarze 	if (sign == 0) {
241e93ea447Sschwarze 		p->ti = len - p->tcol->offset;
242e93ea447Sschwarze 		p->tcol->offset = len;
24311d70615Sschwarze 	} else if (sign == 1) {
24411d70615Sschwarze 		p->ti = len;
245e93ea447Sschwarze 		p->tcol->offset += len;
246e93ea447Sschwarze 	} else if ((size_t)len < p->tcol->offset) {
24711d70615Sschwarze 		p->ti = -len;
248e93ea447Sschwarze 		p->tcol->offset -= len;
24911d70615Sschwarze 	} else {
250e93ea447Sschwarze 		p->ti = -p->tcol->offset;
251e93ea447Sschwarze 		p->tcol->offset = 0;
25211d70615Sschwarze 	}
25311d70615Sschwarze }
254