xref: /openbsd-src/usr.bin/mandoc/roff_term.c (revision d1df930ffab53da22f3324c32bed7ac5709915e6)
1 /*	$OpenBSD: roff_term.c,v 1.15 2018/08/10 20:40:43 schwarze Exp $ */
2 /*
3  * Copyright (c) 2010,2014,2015,2017,2018 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 	const char	*cp;
115 
116 	if (*(cp = n->child->string) == 'C')
117 		cp++;
118 
119 	switch (*cp) {
120 	case '4':
121 	case '3':
122 	case 'B':
123 		term_fontrepl(p, TERMFONT_BOLD);
124 		break;
125 	case '2':
126 	case 'I':
127 		term_fontrepl(p, TERMFONT_UNDER);
128 		break;
129 	case 'P':
130 		term_fontlast(p);
131 		break;
132 	case '1':
133 	case 'C':
134 	case 'R':
135 		term_fontrepl(p, TERMFONT_NONE);
136 		break;
137 	default:
138 		break;
139 	}
140 }
141 
142 static void
143 roff_term_pre_ll(ROFF_TERM_ARGS)
144 {
145 	term_setwidth(p, n->child != NULL ? n->child->string : NULL);
146 }
147 
148 static void
149 roff_term_pre_mc(ROFF_TERM_ARGS)
150 {
151 	if (p->col) {
152 		p->flags |= TERMP_NOBREAK;
153 		term_flushln(p);
154 		p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
155 	}
156 	if (n->child != NULL) {
157 		p->mc = n->child->string;
158 		p->flags |= TERMP_NEWMC;
159 	} else
160 		p->flags |= TERMP_ENDMC;
161 }
162 
163 static void
164 roff_term_pre_po(ROFF_TERM_ARGS)
165 {
166 	struct roffsu	 su;
167 	static int	 po, polast;
168 	int		 ponew;
169 
170 	if (n->child != NULL &&
171 	    a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
172 		ponew = term_hen(p, &su);
173 		if (*n->child->string == '+' ||
174 		    *n->child->string == '-')
175 			ponew += po;
176 	} else
177 		ponew = polast;
178 	polast = po;
179 	po = ponew;
180 
181 	ponew = po - polast + (int)p->tcol->offset;
182 	p->tcol->offset = ponew > 0 ? ponew : 0;
183 }
184 
185 static void
186 roff_term_pre_sp(ROFF_TERM_ARGS)
187 {
188 	struct roffsu	 su;
189 	int		 len;
190 
191 	if (n->child != NULL) {
192 		if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
193 			su.scale = 1.0;
194 		len = term_vspan(p, &su);
195 	} else
196 		len = 1;
197 
198 	if (len < 0)
199 		p->skipvsp -= len;
200 	else
201 		while (len--)
202 			term_vspace(p);
203 
204 	roff_term_pre_br(p, n);
205 }
206 
207 static void
208 roff_term_pre_ta(ROFF_TERM_ARGS)
209 {
210 	term_tab_set(p, NULL);
211 	for (n = n->child; n != NULL; n = n->next)
212 		term_tab_set(p, n->string);
213 }
214 
215 static void
216 roff_term_pre_ti(ROFF_TERM_ARGS)
217 {
218 	struct roffsu	 su;
219 	const char	*cp;
220 	int		 len, sign;
221 
222 	roff_term_pre_br(p, n);
223 
224 	if (n->child == NULL)
225 		return;
226 	cp = n->child->string;
227 	if (*cp == '+') {
228 		sign = 1;
229 		cp++;
230 	} else if (*cp == '-') {
231 		sign = -1;
232 		cp++;
233 	} else
234 		sign = 0;
235 
236 	if (a2roffsu(cp, &su, SCALE_EM) == NULL)
237 		return;
238 	len = term_hen(p, &su);
239 
240 	if (sign == 0) {
241 		p->ti = len - p->tcol->offset;
242 		p->tcol->offset = len;
243 	} else if (sign == 1) {
244 		p->ti = len;
245 		p->tcol->offset += len;
246 	} else if ((size_t)len < p->tcol->offset) {
247 		p->ti = -len;
248 		p->tcol->offset -= len;
249 	} else {
250 		p->ti = -p->tcol->offset;
251 		p->tcol->offset = 0;
252 	}
253 }
254