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