xref: /titanic_44/usr/src/cmd/mandoc/term.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
1*698f87a4SGarrett D'Amore /*	$Id: term.c,v 1.214 2013/12/25 00:39:31 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore  * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore  *
695c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore  *
1095c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore  */
1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore #endif
2195c635efSGarrett D'Amore 
2295c635efSGarrett D'Amore #include <sys/types.h>
2395c635efSGarrett D'Amore 
2495c635efSGarrett D'Amore #include <assert.h>
2595c635efSGarrett D'Amore #include <ctype.h>
2695c635efSGarrett D'Amore #include <stdint.h>
2795c635efSGarrett D'Amore #include <stdio.h>
2895c635efSGarrett D'Amore #include <stdlib.h>
2995c635efSGarrett D'Amore #include <string.h>
3095c635efSGarrett D'Amore 
3195c635efSGarrett D'Amore #include "mandoc.h"
3295c635efSGarrett D'Amore #include "out.h"
3395c635efSGarrett D'Amore #include "term.h"
3495c635efSGarrett D'Amore #include "main.h"
3595c635efSGarrett D'Amore 
36*698f87a4SGarrett D'Amore static	size_t		 cond_width(const struct termp *, int, int *);
37*698f87a4SGarrett D'Amore static	void		 adjbuf(struct termp *p, size_t);
3895c635efSGarrett D'Amore static	void		 bufferc(struct termp *, char);
3995c635efSGarrett D'Amore static	void		 encode(struct termp *, const char *, size_t);
4095c635efSGarrett D'Amore static	void		 encode1(struct termp *, int);
4195c635efSGarrett D'Amore 
4295c635efSGarrett D'Amore void
term_free(struct termp * p)4395c635efSGarrett D'Amore term_free(struct termp *p)
4495c635efSGarrett D'Amore {
4595c635efSGarrett D'Amore 
4695c635efSGarrett D'Amore 	if (p->buf)
4795c635efSGarrett D'Amore 		free(p->buf);
4895c635efSGarrett D'Amore 	if (p->symtab)
4995c635efSGarrett D'Amore 		mchars_free(p->symtab);
5095c635efSGarrett D'Amore 
5195c635efSGarrett D'Amore 	free(p);
5295c635efSGarrett D'Amore }
5395c635efSGarrett D'Amore 
5495c635efSGarrett D'Amore 
5595c635efSGarrett D'Amore void
term_begin(struct termp * p,term_margin head,term_margin foot,const void * arg)5695c635efSGarrett D'Amore term_begin(struct termp *p, term_margin head,
5795c635efSGarrett D'Amore 		term_margin foot, const void *arg)
5895c635efSGarrett D'Amore {
5995c635efSGarrett D'Amore 
6095c635efSGarrett D'Amore 	p->headf = head;
6195c635efSGarrett D'Amore 	p->footf = foot;
6295c635efSGarrett D'Amore 	p->argf = arg;
6395c635efSGarrett D'Amore 	(*p->begin)(p);
6495c635efSGarrett D'Amore }
6595c635efSGarrett D'Amore 
6695c635efSGarrett D'Amore 
6795c635efSGarrett D'Amore void
term_end(struct termp * p)6895c635efSGarrett D'Amore term_end(struct termp *p)
6995c635efSGarrett D'Amore {
7095c635efSGarrett D'Amore 
7195c635efSGarrett D'Amore 	(*p->end)(p);
7295c635efSGarrett D'Amore }
7395c635efSGarrett D'Amore 
7495c635efSGarrett D'Amore /*
7595c635efSGarrett D'Amore  * Flush a line of text.  A "line" is loosely defined as being something
7695c635efSGarrett D'Amore  * that should be followed by a newline, regardless of whether it's
7795c635efSGarrett D'Amore  * broken apart by newlines getting there.  A line can also be a
7895c635efSGarrett D'Amore  * fragment of a columnar list (`Bl -tag' or `Bl -column'), which does
7995c635efSGarrett D'Amore  * not have a trailing newline.
8095c635efSGarrett D'Amore  *
8195c635efSGarrett D'Amore  * The following flags may be specified:
8295c635efSGarrett D'Amore  *
8395c635efSGarrett D'Amore  *  - TERMP_NOBREAK: this is the most important and is used when making
8495c635efSGarrett D'Amore  *    columns.  In short: don't print a newline and instead expect the
8595c635efSGarrett D'Amore  *    next call to do the padding up to the start of the next column.
86*698f87a4SGarrett D'Amore  *    p->trailspace may be set to 0, 1, or 2, depending on how many
87*698f87a4SGarrett D'Amore  *    space characters are required at the end of the column.
8895c635efSGarrett D'Amore  *
8995c635efSGarrett D'Amore  *  - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
9095c635efSGarrett D'Amore  *    the line is overrun, and don't pad-right if it's underrun.
9195c635efSGarrett D'Amore  *
9295c635efSGarrett D'Amore  *  - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
9395c635efSGarrett D'Amore  *    overrunning, instead save the position and continue at that point
9495c635efSGarrett D'Amore  *    when the next invocation.
9595c635efSGarrett D'Amore  *
9695c635efSGarrett D'Amore  *  In-line line breaking:
9795c635efSGarrett D'Amore  *
9895c635efSGarrett D'Amore  *  If TERMP_NOBREAK is specified and the line overruns the right
9995c635efSGarrett D'Amore  *  margin, it will break and pad-right to the right margin after
10095c635efSGarrett D'Amore  *  writing.  If maxrmargin is violated, it will break and continue
10195c635efSGarrett D'Amore  *  writing from the right-margin, which will lead to the above scenario
10295c635efSGarrett D'Amore  *  upon exit.  Otherwise, the line will break at the right margin.
10395c635efSGarrett D'Amore  */
10495c635efSGarrett D'Amore void
term_flushln(struct termp * p)10595c635efSGarrett D'Amore term_flushln(struct termp *p)
10695c635efSGarrett D'Amore {
107*698f87a4SGarrett D'Amore 	size_t		 i;     /* current input position in p->buf */
108*698f87a4SGarrett D'Amore 	int		 ntab;	/* number of tabs to prepend */
10995c635efSGarrett D'Amore 	size_t		 vis;   /* current visual position on output */
11095c635efSGarrett D'Amore 	size_t		 vbl;   /* number of blanks to prepend to output */
11195c635efSGarrett D'Amore 	size_t		 vend;	/* end of word visual position on output */
11295c635efSGarrett D'Amore 	size_t		 bp;    /* visual right border position */
11395c635efSGarrett D'Amore 	size_t		 dv;    /* temporary for visual pos calculations */
114*698f87a4SGarrett D'Amore 	size_t		 j;     /* temporary loop index for p->buf */
115*698f87a4SGarrett D'Amore 	size_t		 jhy;	/* last hyph before overflow w/r/t j */
11695c635efSGarrett D'Amore 	size_t		 maxvis; /* output position of visible boundary */
11795c635efSGarrett D'Amore 	size_t		 mmax; /* used in calculating bp */
11895c635efSGarrett D'Amore 
11995c635efSGarrett D'Amore 	/*
12095c635efSGarrett D'Amore 	 * First, establish the maximum columns of "visible" content.
12195c635efSGarrett D'Amore 	 * This is usually the difference between the right-margin and
12295c635efSGarrett D'Amore 	 * an indentation, but can be, for tagged lists or columns, a
12395c635efSGarrett D'Amore 	 * small set of values.
124*698f87a4SGarrett D'Amore 	 *
125*698f87a4SGarrett D'Amore 	 * The following unsigned-signed subtractions look strange,
126*698f87a4SGarrett D'Amore 	 * but they are actually correct.  If the int p->overstep
127*698f87a4SGarrett D'Amore 	 * is negative, it gets sign extended.  Subtracting that
128*698f87a4SGarrett D'Amore 	 * very large size_t effectively adds a small number to dv.
12995c635efSGarrett D'Amore 	 */
13095c635efSGarrett D'Amore 	assert  (p->rmargin >= p->offset);
13195c635efSGarrett D'Amore 	dv     = p->rmargin - p->offset;
13295c635efSGarrett D'Amore 	maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
13395c635efSGarrett D'Amore 	dv     = p->maxrmargin - p->offset;
13495c635efSGarrett D'Amore 	mmax   = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
13595c635efSGarrett D'Amore 
13695c635efSGarrett D'Amore 	bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
13795c635efSGarrett D'Amore 
13895c635efSGarrett D'Amore 	/*
13995c635efSGarrett D'Amore 	 * Calculate the required amount of padding.
14095c635efSGarrett D'Amore 	 */
14195c635efSGarrett D'Amore 	vbl = p->offset + p->overstep > p->viscol ?
14295c635efSGarrett D'Amore 	      p->offset + p->overstep - p->viscol : 0;
14395c635efSGarrett D'Amore 
14495c635efSGarrett D'Amore 	vis = vend = 0;
14595c635efSGarrett D'Amore 	i = 0;
14695c635efSGarrett D'Amore 
14795c635efSGarrett D'Amore 	while (i < p->col) {
14895c635efSGarrett D'Amore 		/*
14995c635efSGarrett D'Amore 		 * Handle literal tab characters: collapse all
15095c635efSGarrett D'Amore 		 * subsequent tabs into a single huge set of spaces.
15195c635efSGarrett D'Amore 		 */
152*698f87a4SGarrett D'Amore 		ntab = 0;
15395c635efSGarrett D'Amore 		while (i < p->col && '\t' == p->buf[i]) {
15495c635efSGarrett D'Amore 			vend = (vis / p->tabwidth + 1) * p->tabwidth;
15595c635efSGarrett D'Amore 			vbl += vend - vis;
15695c635efSGarrett D'Amore 			vis = vend;
157*698f87a4SGarrett D'Amore 			ntab++;
15895c635efSGarrett D'Amore 			i++;
15995c635efSGarrett D'Amore 		}
16095c635efSGarrett D'Amore 
16195c635efSGarrett D'Amore 		/*
16295c635efSGarrett D'Amore 		 * Count up visible word characters.  Control sequences
16395c635efSGarrett D'Amore 		 * (starting with the CSI) aren't counted.  A space
16495c635efSGarrett D'Amore 		 * generates a non-printing word, which is valid (the
16595c635efSGarrett D'Amore 		 * space is printed according to regular spacing rules).
16695c635efSGarrett D'Amore 		 */
16795c635efSGarrett D'Amore 
16895c635efSGarrett D'Amore 		for (j = i, jhy = 0; j < p->col; j++) {
169*698f87a4SGarrett D'Amore 			if (' ' == p->buf[j] || '\t' == p->buf[j])
17095c635efSGarrett D'Amore 				break;
17195c635efSGarrett D'Amore 
17295c635efSGarrett D'Amore 			/* Back over the the last printed character. */
17395c635efSGarrett D'Amore 			if (8 == p->buf[j]) {
17495c635efSGarrett D'Amore 				assert(j);
17595c635efSGarrett D'Amore 				vend -= (*p->width)(p, p->buf[j - 1]);
17695c635efSGarrett D'Amore 				continue;
17795c635efSGarrett D'Amore 			}
17895c635efSGarrett D'Amore 
17995c635efSGarrett D'Amore 			/* Regular word. */
18095c635efSGarrett D'Amore 			/* Break at the hyphen point if we overrun. */
18195c635efSGarrett D'Amore 			if (vend > vis && vend < bp &&
18295c635efSGarrett D'Amore 					ASCII_HYPH == p->buf[j])
18395c635efSGarrett D'Amore 				jhy = j;
18495c635efSGarrett D'Amore 
18595c635efSGarrett D'Amore 			vend += (*p->width)(p, p->buf[j]);
18695c635efSGarrett D'Amore 		}
18795c635efSGarrett D'Amore 
18895c635efSGarrett D'Amore 		/*
18995c635efSGarrett D'Amore 		 * Find out whether we would exceed the right margin.
19095c635efSGarrett D'Amore 		 * If so, break to the next line.
19195c635efSGarrett D'Amore 		 */
19295c635efSGarrett D'Amore 		if (vend > bp && 0 == jhy && vis > 0) {
19395c635efSGarrett D'Amore 			vend -= vis;
19495c635efSGarrett D'Amore 			(*p->endline)(p);
19595c635efSGarrett D'Amore 			p->viscol = 0;
19695c635efSGarrett D'Amore 			if (TERMP_NOBREAK & p->flags) {
19795c635efSGarrett D'Amore 				vbl = p->rmargin;
19895c635efSGarrett D'Amore 				vend += p->rmargin - p->offset;
19995c635efSGarrett D'Amore 			} else
20095c635efSGarrett D'Amore 				vbl = p->offset;
20195c635efSGarrett D'Amore 
202*698f87a4SGarrett D'Amore 			/* use pending tabs on the new line */
203*698f87a4SGarrett D'Amore 
204*698f87a4SGarrett D'Amore 			if (0 < ntab)
205*698f87a4SGarrett D'Amore 				vbl += ntab * p->tabwidth;
206*698f87a4SGarrett D'Amore 
207*698f87a4SGarrett D'Amore 			/*
208*698f87a4SGarrett D'Amore 			 * Remove the p->overstep width.
209*698f87a4SGarrett D'Amore 			 * Again, if p->overstep is negative,
210*698f87a4SGarrett D'Amore 			 * sign extension does the right thing.
211*698f87a4SGarrett D'Amore 			 */
21295c635efSGarrett D'Amore 
21395c635efSGarrett D'Amore 			bp += (size_t)p->overstep;
21495c635efSGarrett D'Amore 			p->overstep = 0;
21595c635efSGarrett D'Amore 		}
21695c635efSGarrett D'Amore 
21795c635efSGarrett D'Amore 		/* Write out the [remaining] word. */
21895c635efSGarrett D'Amore 		for ( ; i < p->col; i++) {
21995c635efSGarrett D'Amore 			if (vend > bp && jhy > 0 && i > jhy)
22095c635efSGarrett D'Amore 				break;
22195c635efSGarrett D'Amore 			if ('\t' == p->buf[i])
22295c635efSGarrett D'Amore 				break;
22395c635efSGarrett D'Amore 			if (' ' == p->buf[i]) {
22495c635efSGarrett D'Amore 				j = i;
22595c635efSGarrett D'Amore 				while (' ' == p->buf[i])
22695c635efSGarrett D'Amore 					i++;
227*698f87a4SGarrett D'Amore 				dv = (i - j) * (*p->width)(p, ' ');
22895c635efSGarrett D'Amore 				vbl += dv;
22995c635efSGarrett D'Amore 				vend += dv;
23095c635efSGarrett D'Amore 				break;
23195c635efSGarrett D'Amore 			}
23295c635efSGarrett D'Amore 			if (ASCII_NBRSP == p->buf[i]) {
23395c635efSGarrett D'Amore 				vbl += (*p->width)(p, ' ');
23495c635efSGarrett D'Amore 				continue;
23595c635efSGarrett D'Amore 			}
23695c635efSGarrett D'Amore 
23795c635efSGarrett D'Amore 			/*
23895c635efSGarrett D'Amore 			 * Now we definitely know there will be
23995c635efSGarrett D'Amore 			 * printable characters to output,
24095c635efSGarrett D'Amore 			 * so write preceding white space now.
24195c635efSGarrett D'Amore 			 */
24295c635efSGarrett D'Amore 			if (vbl) {
24395c635efSGarrett D'Amore 				(*p->advance)(p, vbl);
24495c635efSGarrett D'Amore 				p->viscol += vbl;
24595c635efSGarrett D'Amore 				vbl = 0;
24695c635efSGarrett D'Amore 			}
24795c635efSGarrett D'Amore 
24895c635efSGarrett D'Amore 			if (ASCII_HYPH == p->buf[i]) {
24995c635efSGarrett D'Amore 				(*p->letter)(p, '-');
25095c635efSGarrett D'Amore 				p->viscol += (*p->width)(p, '-');
25195c635efSGarrett D'Amore 				continue;
25295c635efSGarrett D'Amore 			}
25395c635efSGarrett D'Amore 
25495c635efSGarrett D'Amore 			(*p->letter)(p, p->buf[i]);
25595c635efSGarrett D'Amore 			if (8 == p->buf[i])
25695c635efSGarrett D'Amore 				p->viscol -= (*p->width)(p, p->buf[i-1]);
25795c635efSGarrett D'Amore 			else
25895c635efSGarrett D'Amore 				p->viscol += (*p->width)(p, p->buf[i]);
25995c635efSGarrett D'Amore 		}
26095c635efSGarrett D'Amore 		vis = vend;
26195c635efSGarrett D'Amore 	}
26295c635efSGarrett D'Amore 
26395c635efSGarrett D'Amore 	/*
26495c635efSGarrett D'Amore 	 * If there was trailing white space, it was not printed;
26595c635efSGarrett D'Amore 	 * so reset the cursor position accordingly.
26695c635efSGarrett D'Amore 	 */
26795c635efSGarrett D'Amore 	if (vis)
26895c635efSGarrett D'Amore 		vis -= vbl;
26995c635efSGarrett D'Amore 
27095c635efSGarrett D'Amore 	p->col = 0;
27195c635efSGarrett D'Amore 	p->overstep = 0;
27295c635efSGarrett D'Amore 
27395c635efSGarrett D'Amore 	if ( ! (TERMP_NOBREAK & p->flags)) {
27495c635efSGarrett D'Amore 		p->viscol = 0;
27595c635efSGarrett D'Amore 		(*p->endline)(p);
27695c635efSGarrett D'Amore 		return;
27795c635efSGarrett D'Amore 	}
27895c635efSGarrett D'Amore 
27995c635efSGarrett D'Amore 	if (TERMP_HANG & p->flags) {
280*698f87a4SGarrett D'Amore 		p->overstep = (int)(vis - maxvis +
281*698f87a4SGarrett D'Amore 				p->trailspace * (*p->width)(p, ' '));
28295c635efSGarrett D'Amore 
28395c635efSGarrett D'Amore 		/*
28495c635efSGarrett D'Amore 		 * If we have overstepped the margin, temporarily move
28595c635efSGarrett D'Amore 		 * it to the right and flag the rest of the line to be
28695c635efSGarrett D'Amore 		 * shorter.
287*698f87a4SGarrett D'Amore 		 * If there is a request to keep the columns together,
288*698f87a4SGarrett D'Amore 		 * allow negative overstep when the column is not full.
28995c635efSGarrett D'Amore 		 */
290*698f87a4SGarrett D'Amore 		if (p->trailspace && p->overstep < 0)
29195c635efSGarrett D'Amore 			p->overstep = 0;
29295c635efSGarrett D'Amore 		return;
29395c635efSGarrett D'Amore 
29495c635efSGarrett D'Amore 	} else if (TERMP_DANGLE & p->flags)
29595c635efSGarrett D'Amore 		return;
29695c635efSGarrett D'Amore 
29795c635efSGarrett D'Amore 	/* If the column was overrun, break the line. */
298*698f87a4SGarrett D'Amore 	if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) {
29995c635efSGarrett D'Amore 		(*p->endline)(p);
30095c635efSGarrett D'Amore 		p->viscol = 0;
30195c635efSGarrett D'Amore 	}
30295c635efSGarrett D'Amore }
30395c635efSGarrett D'Amore 
30495c635efSGarrett D'Amore 
30595c635efSGarrett D'Amore /*
30695c635efSGarrett D'Amore  * A newline only breaks an existing line; it won't assert vertical
30795c635efSGarrett D'Amore  * space.  All data in the output buffer is flushed prior to the newline
30895c635efSGarrett D'Amore  * assertion.
30995c635efSGarrett D'Amore  */
31095c635efSGarrett D'Amore void
term_newln(struct termp * p)31195c635efSGarrett D'Amore term_newln(struct termp *p)
31295c635efSGarrett D'Amore {
31395c635efSGarrett D'Amore 
31495c635efSGarrett D'Amore 	p->flags |= TERMP_NOSPACE;
31595c635efSGarrett D'Amore 	if (p->col || p->viscol)
31695c635efSGarrett D'Amore 		term_flushln(p);
31795c635efSGarrett D'Amore }
31895c635efSGarrett D'Amore 
31995c635efSGarrett D'Amore 
32095c635efSGarrett D'Amore /*
32195c635efSGarrett D'Amore  * Asserts a vertical space (a full, empty line-break between lines).
32295c635efSGarrett D'Amore  * Note that if used twice, this will cause two blank spaces and so on.
32395c635efSGarrett D'Amore  * All data in the output buffer is flushed prior to the newline
32495c635efSGarrett D'Amore  * assertion.
32595c635efSGarrett D'Amore  */
32695c635efSGarrett D'Amore void
term_vspace(struct termp * p)32795c635efSGarrett D'Amore term_vspace(struct termp *p)
32895c635efSGarrett D'Amore {
32995c635efSGarrett D'Amore 
33095c635efSGarrett D'Amore 	term_newln(p);
33195c635efSGarrett D'Amore 	p->viscol = 0;
332*698f87a4SGarrett D'Amore 	if (0 < p->skipvsp)
333*698f87a4SGarrett D'Amore 		p->skipvsp--;
334*698f87a4SGarrett D'Amore 	else
33595c635efSGarrett D'Amore 		(*p->endline)(p);
33695c635efSGarrett D'Amore }
33795c635efSGarrett D'Amore 
33895c635efSGarrett D'Amore void
term_fontlast(struct termp * p)33995c635efSGarrett D'Amore term_fontlast(struct termp *p)
34095c635efSGarrett D'Amore {
34195c635efSGarrett D'Amore 	enum termfont	 f;
34295c635efSGarrett D'Amore 
34395c635efSGarrett D'Amore 	f = p->fontl;
34495c635efSGarrett D'Amore 	p->fontl = p->fontq[p->fonti];
34595c635efSGarrett D'Amore 	p->fontq[p->fonti] = f;
34695c635efSGarrett D'Amore }
34795c635efSGarrett D'Amore 
34895c635efSGarrett D'Amore 
34995c635efSGarrett D'Amore void
term_fontrepl(struct termp * p,enum termfont f)35095c635efSGarrett D'Amore term_fontrepl(struct termp *p, enum termfont f)
35195c635efSGarrett D'Amore {
35295c635efSGarrett D'Amore 
35395c635efSGarrett D'Amore 	p->fontl = p->fontq[p->fonti];
35495c635efSGarrett D'Amore 	p->fontq[p->fonti] = f;
35595c635efSGarrett D'Amore }
35695c635efSGarrett D'Amore 
35795c635efSGarrett D'Amore 
35895c635efSGarrett D'Amore void
term_fontpush(struct termp * p,enum termfont f)35995c635efSGarrett D'Amore term_fontpush(struct termp *p, enum termfont f)
36095c635efSGarrett D'Amore {
36195c635efSGarrett D'Amore 
36295c635efSGarrett D'Amore 	assert(p->fonti + 1 < 10);
36395c635efSGarrett D'Amore 	p->fontl = p->fontq[p->fonti];
36495c635efSGarrett D'Amore 	p->fontq[++p->fonti] = f;
36595c635efSGarrett D'Amore }
36695c635efSGarrett D'Amore 
36795c635efSGarrett D'Amore 
36895c635efSGarrett D'Amore const void *
term_fontq(struct termp * p)36995c635efSGarrett D'Amore term_fontq(struct termp *p)
37095c635efSGarrett D'Amore {
37195c635efSGarrett D'Amore 
37295c635efSGarrett D'Amore 	return(&p->fontq[p->fonti]);
37395c635efSGarrett D'Amore }
37495c635efSGarrett D'Amore 
37595c635efSGarrett D'Amore 
37695c635efSGarrett D'Amore enum termfont
term_fonttop(struct termp * p)37795c635efSGarrett D'Amore term_fonttop(struct termp *p)
37895c635efSGarrett D'Amore {
37995c635efSGarrett D'Amore 
38095c635efSGarrett D'Amore 	return(p->fontq[p->fonti]);
38195c635efSGarrett D'Amore }
38295c635efSGarrett D'Amore 
38395c635efSGarrett D'Amore 
38495c635efSGarrett D'Amore void
term_fontpopq(struct termp * p,const void * key)38595c635efSGarrett D'Amore term_fontpopq(struct termp *p, const void *key)
38695c635efSGarrett D'Amore {
38795c635efSGarrett D'Amore 
388*698f87a4SGarrett D'Amore 	while (p->fonti >= 0 && key < (void *)(p->fontq + p->fonti))
38995c635efSGarrett D'Amore 		p->fonti--;
39095c635efSGarrett D'Amore 	assert(p->fonti >= 0);
39195c635efSGarrett D'Amore }
39295c635efSGarrett D'Amore 
39395c635efSGarrett D'Amore 
39495c635efSGarrett D'Amore void
term_fontpop(struct termp * p)39595c635efSGarrett D'Amore term_fontpop(struct termp *p)
39695c635efSGarrett D'Amore {
39795c635efSGarrett D'Amore 
39895c635efSGarrett D'Amore 	assert(p->fonti);
39995c635efSGarrett D'Amore 	p->fonti--;
40095c635efSGarrett D'Amore }
40195c635efSGarrett D'Amore 
40295c635efSGarrett D'Amore /*
40395c635efSGarrett D'Amore  * Handle pwords, partial words, which may be either a single word or a
40495c635efSGarrett D'Amore  * phrase that cannot be broken down (such as a literal string).  This
40595c635efSGarrett D'Amore  * handles word styling.
40695c635efSGarrett D'Amore  */
40795c635efSGarrett D'Amore void
term_word(struct termp * p,const char * word)40895c635efSGarrett D'Amore term_word(struct termp *p, const char *word)
40995c635efSGarrett D'Amore {
410*698f87a4SGarrett D'Amore 	const char	 nbrsp[2] = { ASCII_NBRSP, 0 };
41195c635efSGarrett D'Amore 	const char	*seq, *cp;
41295c635efSGarrett D'Amore 	char		 c;
41395c635efSGarrett D'Amore 	int		 sz, uc;
41495c635efSGarrett D'Amore 	size_t		 ssz;
41595c635efSGarrett D'Amore 	enum mandoc_esc	 esc;
41695c635efSGarrett D'Amore 
41795c635efSGarrett D'Amore 	if ( ! (TERMP_NOSPACE & p->flags)) {
41895c635efSGarrett D'Amore 		if ( ! (TERMP_KEEP & p->flags)) {
41995c635efSGarrett D'Amore 			bufferc(p, ' ');
42095c635efSGarrett D'Amore 			if (TERMP_SENTENCE & p->flags)
42195c635efSGarrett D'Amore 				bufferc(p, ' ');
42295c635efSGarrett D'Amore 		} else
42395c635efSGarrett D'Amore 			bufferc(p, ASCII_NBRSP);
42495c635efSGarrett D'Amore 	}
425*698f87a4SGarrett D'Amore 	if (TERMP_PREKEEP & p->flags)
426*698f87a4SGarrett D'Amore 		p->flags |= TERMP_KEEP;
42795c635efSGarrett D'Amore 
42895c635efSGarrett D'Amore 	if ( ! (p->flags & TERMP_NONOSPACE))
42995c635efSGarrett D'Amore 		p->flags &= ~TERMP_NOSPACE;
43095c635efSGarrett D'Amore 	else
43195c635efSGarrett D'Amore 		p->flags |= TERMP_NOSPACE;
43295c635efSGarrett D'Amore 
433*698f87a4SGarrett D'Amore 	p->flags &= ~TERMP_SENTENCE;
43495c635efSGarrett D'Amore 
43595c635efSGarrett D'Amore 	while ('\0' != *word) {
436*698f87a4SGarrett D'Amore 		if ('\\' != *word) {
437*698f87a4SGarrett D'Amore 			if (TERMP_SKIPCHAR & p->flags) {
438*698f87a4SGarrett D'Amore 				p->flags &= ~TERMP_SKIPCHAR;
439*698f87a4SGarrett D'Amore 				word++;
44095c635efSGarrett D'Amore 				continue;
441*698f87a4SGarrett D'Amore 			}
442*698f87a4SGarrett D'Amore 			if (TERMP_NBRWORD & p->flags) {
443*698f87a4SGarrett D'Amore 				if (' ' == *word) {
444*698f87a4SGarrett D'Amore 					encode(p, nbrsp, 1);
445*698f87a4SGarrett D'Amore 					word++;
446*698f87a4SGarrett D'Amore 					continue;
447*698f87a4SGarrett D'Amore 				}
448*698f87a4SGarrett D'Amore 				ssz = strcspn(word, "\\ ");
449*698f87a4SGarrett D'Amore 			} else
450*698f87a4SGarrett D'Amore 				ssz = strcspn(word, "\\");
451*698f87a4SGarrett D'Amore 			encode(p, word, ssz);
452*698f87a4SGarrett D'Amore 			word += (int)ssz;
453*698f87a4SGarrett D'Amore 			continue;
454*698f87a4SGarrett D'Amore 		}
45595c635efSGarrett D'Amore 
45695c635efSGarrett D'Amore 		word++;
45795c635efSGarrett D'Amore 		esc = mandoc_escape(&word, &seq, &sz);
45895c635efSGarrett D'Amore 		if (ESCAPE_ERROR == esc)
45995c635efSGarrett D'Amore 			break;
46095c635efSGarrett D'Amore 
46195c635efSGarrett D'Amore 		if (TERMENC_ASCII != p->enc)
46295c635efSGarrett D'Amore 			switch (esc) {
46395c635efSGarrett D'Amore 			case (ESCAPE_UNICODE):
46495c635efSGarrett D'Amore 				uc = mchars_num2uc(seq + 1, sz - 1);
46595c635efSGarrett D'Amore 				if ('\0' == uc)
46695c635efSGarrett D'Amore 					break;
46795c635efSGarrett D'Amore 				encode1(p, uc);
46895c635efSGarrett D'Amore 				continue;
46995c635efSGarrett D'Amore 			case (ESCAPE_SPECIAL):
47095c635efSGarrett D'Amore 				uc = mchars_spec2cp(p->symtab, seq, sz);
47195c635efSGarrett D'Amore 				if (uc <= 0)
47295c635efSGarrett D'Amore 					break;
47395c635efSGarrett D'Amore 				encode1(p, uc);
47495c635efSGarrett D'Amore 				continue;
47595c635efSGarrett D'Amore 			default:
47695c635efSGarrett D'Amore 				break;
47795c635efSGarrett D'Amore 			}
47895c635efSGarrett D'Amore 
47995c635efSGarrett D'Amore 		switch (esc) {
48095c635efSGarrett D'Amore 		case (ESCAPE_UNICODE):
48195c635efSGarrett D'Amore 			encode1(p, '?');
48295c635efSGarrett D'Amore 			break;
48395c635efSGarrett D'Amore 		case (ESCAPE_NUMBERED):
48495c635efSGarrett D'Amore 			c = mchars_num2char(seq, sz);
48595c635efSGarrett D'Amore 			if ('\0' != c)
48695c635efSGarrett D'Amore 				encode(p, &c, 1);
48795c635efSGarrett D'Amore 			break;
48895c635efSGarrett D'Amore 		case (ESCAPE_SPECIAL):
48995c635efSGarrett D'Amore 			cp = mchars_spec2str(p->symtab, seq, sz, &ssz);
49095c635efSGarrett D'Amore 			if (NULL != cp)
49195c635efSGarrett D'Amore 				encode(p, cp, ssz);
49295c635efSGarrett D'Amore 			else if (1 == ssz)
49395c635efSGarrett D'Amore 				encode(p, seq, sz);
49495c635efSGarrett D'Amore 			break;
49595c635efSGarrett D'Amore 		case (ESCAPE_FONTBOLD):
49695c635efSGarrett D'Amore 			term_fontrepl(p, TERMFONT_BOLD);
49795c635efSGarrett D'Amore 			break;
49895c635efSGarrett D'Amore 		case (ESCAPE_FONTITALIC):
49995c635efSGarrett D'Amore 			term_fontrepl(p, TERMFONT_UNDER);
50095c635efSGarrett D'Amore 			break;
501*698f87a4SGarrett D'Amore 		case (ESCAPE_FONTBI):
502*698f87a4SGarrett D'Amore 			term_fontrepl(p, TERMFONT_BI);
503*698f87a4SGarrett D'Amore 			break;
50495c635efSGarrett D'Amore 		case (ESCAPE_FONT):
50595c635efSGarrett D'Amore 			/* FALLTHROUGH */
50695c635efSGarrett D'Amore 		case (ESCAPE_FONTROMAN):
50795c635efSGarrett D'Amore 			term_fontrepl(p, TERMFONT_NONE);
50895c635efSGarrett D'Amore 			break;
50995c635efSGarrett D'Amore 		case (ESCAPE_FONTPREV):
51095c635efSGarrett D'Amore 			term_fontlast(p);
51195c635efSGarrett D'Amore 			break;
51295c635efSGarrett D'Amore 		case (ESCAPE_NOSPACE):
513*698f87a4SGarrett D'Amore 			if (TERMP_SKIPCHAR & p->flags)
514*698f87a4SGarrett D'Amore 				p->flags &= ~TERMP_SKIPCHAR;
515*698f87a4SGarrett D'Amore 			else if ('\0' == *word)
51695c635efSGarrett D'Amore 				p->flags |= TERMP_NOSPACE;
51795c635efSGarrett D'Amore 			break;
518*698f87a4SGarrett D'Amore 		case (ESCAPE_SKIPCHAR):
519*698f87a4SGarrett D'Amore 			p->flags |= TERMP_SKIPCHAR;
520*698f87a4SGarrett D'Amore 			break;
52195c635efSGarrett D'Amore 		default:
52295c635efSGarrett D'Amore 			break;
52395c635efSGarrett D'Amore 		}
52495c635efSGarrett D'Amore 	}
525*698f87a4SGarrett D'Amore 	p->flags &= ~TERMP_NBRWORD;
52695c635efSGarrett D'Amore }
52795c635efSGarrett D'Amore 
52895c635efSGarrett D'Amore static void
adjbuf(struct termp * p,size_t sz)529*698f87a4SGarrett D'Amore adjbuf(struct termp *p, size_t sz)
53095c635efSGarrett D'Amore {
53195c635efSGarrett D'Amore 
53295c635efSGarrett D'Amore 	if (0 == p->maxcols)
53395c635efSGarrett D'Amore 		p->maxcols = 1024;
53495c635efSGarrett D'Amore 	while (sz >= p->maxcols)
53595c635efSGarrett D'Amore 		p->maxcols <<= 2;
53695c635efSGarrett D'Amore 
537*698f87a4SGarrett D'Amore 	p->buf = mandoc_realloc(p->buf, sizeof(int) * p->maxcols);
53895c635efSGarrett D'Amore }
53995c635efSGarrett D'Amore 
54095c635efSGarrett D'Amore static void
bufferc(struct termp * p,char c)54195c635efSGarrett D'Amore bufferc(struct termp *p, char c)
54295c635efSGarrett D'Amore {
54395c635efSGarrett D'Amore 
54495c635efSGarrett D'Amore 	if (p->col + 1 >= p->maxcols)
54595c635efSGarrett D'Amore 		adjbuf(p, p->col + 1);
54695c635efSGarrett D'Amore 
54795c635efSGarrett D'Amore 	p->buf[p->col++] = c;
54895c635efSGarrett D'Amore }
54995c635efSGarrett D'Amore 
55095c635efSGarrett D'Amore /*
55195c635efSGarrett D'Amore  * See encode().
55295c635efSGarrett D'Amore  * Do this for a single (probably unicode) value.
55395c635efSGarrett D'Amore  * Does not check for non-decorated glyphs.
55495c635efSGarrett D'Amore  */
55595c635efSGarrett D'Amore static void
encode1(struct termp * p,int c)55695c635efSGarrett D'Amore encode1(struct termp *p, int c)
55795c635efSGarrett D'Amore {
55895c635efSGarrett D'Amore 	enum termfont	  f;
55995c635efSGarrett D'Amore 
560*698f87a4SGarrett D'Amore 	if (TERMP_SKIPCHAR & p->flags) {
561*698f87a4SGarrett D'Amore 		p->flags &= ~TERMP_SKIPCHAR;
562*698f87a4SGarrett D'Amore 		return;
563*698f87a4SGarrett D'Amore 	}
564*698f87a4SGarrett D'Amore 
565*698f87a4SGarrett D'Amore 	if (p->col + 6 >= p->maxcols)
566*698f87a4SGarrett D'Amore 		adjbuf(p, p->col + 6);
56795c635efSGarrett D'Amore 
56895c635efSGarrett D'Amore 	f = term_fonttop(p);
56995c635efSGarrett D'Amore 
570*698f87a4SGarrett D'Amore 	if (TERMFONT_UNDER == f || TERMFONT_BI == f) {
57195c635efSGarrett D'Amore 		p->buf[p->col++] = '_';
57295c635efSGarrett D'Amore 		p->buf[p->col++] = 8;
573*698f87a4SGarrett D'Amore 	}
574*698f87a4SGarrett D'Amore 	if (TERMFONT_BOLD == f || TERMFONT_BI == f) {
575*698f87a4SGarrett D'Amore 		if (ASCII_HYPH == c)
576*698f87a4SGarrett D'Amore 			p->buf[p->col++] = '-';
577*698f87a4SGarrett D'Amore 		else
578*698f87a4SGarrett D'Amore 			p->buf[p->col++] = c;
579*698f87a4SGarrett D'Amore 		p->buf[p->col++] = 8;
580*698f87a4SGarrett D'Amore 	}
58195c635efSGarrett D'Amore 	p->buf[p->col++] = c;
58295c635efSGarrett D'Amore }
58395c635efSGarrett D'Amore 
58495c635efSGarrett D'Amore static void
encode(struct termp * p,const char * word,size_t sz)58595c635efSGarrett D'Amore encode(struct termp *p, const char *word, size_t sz)
58695c635efSGarrett D'Amore {
587*698f87a4SGarrett D'Amore 	size_t		  i;
58895c635efSGarrett D'Amore 
589*698f87a4SGarrett D'Amore 	if (TERMP_SKIPCHAR & p->flags) {
590*698f87a4SGarrett D'Amore 		p->flags &= ~TERMP_SKIPCHAR;
591*698f87a4SGarrett D'Amore 		return;
592*698f87a4SGarrett D'Amore 	}
59395c635efSGarrett D'Amore 
59495c635efSGarrett D'Amore 	/*
59595c635efSGarrett D'Amore 	 * Encode and buffer a string of characters.  If the current
59695c635efSGarrett D'Amore 	 * font mode is unset, buffer directly, else encode then buffer
59795c635efSGarrett D'Amore 	 * character by character.
59895c635efSGarrett D'Amore 	 */
59995c635efSGarrett D'Amore 
600*698f87a4SGarrett D'Amore 	if (TERMFONT_NONE == term_fonttop(p)) {
601*698f87a4SGarrett D'Amore 		if (p->col + sz >= p->maxcols)
602*698f87a4SGarrett D'Amore 			adjbuf(p, p->col + sz);
603*698f87a4SGarrett D'Amore 		for (i = 0; i < sz; i++)
60495c635efSGarrett D'Amore 			p->buf[p->col++] = word[i];
60595c635efSGarrett D'Amore 		return;
60695c635efSGarrett D'Amore 	}
60795c635efSGarrett D'Amore 
60895c635efSGarrett D'Amore 	/* Pre-buffer, assuming worst-case. */
60995c635efSGarrett D'Amore 
610*698f87a4SGarrett D'Amore 	if (p->col + 1 + (sz * 5) >= p->maxcols)
611*698f87a4SGarrett D'Amore 		adjbuf(p, p->col + 1 + (sz * 5));
61295c635efSGarrett D'Amore 
613*698f87a4SGarrett D'Amore 	for (i = 0; i < sz; i++) {
614*698f87a4SGarrett D'Amore 		if (ASCII_HYPH == word[i] ||
615*698f87a4SGarrett D'Amore 		    isgraph((unsigned char)word[i]))
616*698f87a4SGarrett D'Amore 			encode1(p, word[i]);
61795c635efSGarrett D'Amore 		else
61895c635efSGarrett D'Amore 			p->buf[p->col++] = word[i];
61995c635efSGarrett D'Amore 	}
62095c635efSGarrett D'Amore }
62195c635efSGarrett D'Amore 
62295c635efSGarrett D'Amore size_t
term_len(const struct termp * p,size_t sz)62395c635efSGarrett D'Amore term_len(const struct termp *p, size_t sz)
62495c635efSGarrett D'Amore {
62595c635efSGarrett D'Amore 
62695c635efSGarrett D'Amore 	return((*p->width)(p, ' ') * sz);
62795c635efSGarrett D'Amore }
62895c635efSGarrett D'Amore 
629*698f87a4SGarrett D'Amore static size_t
cond_width(const struct termp * p,int c,int * skip)630*698f87a4SGarrett D'Amore cond_width(const struct termp *p, int c, int *skip)
631*698f87a4SGarrett D'Amore {
632*698f87a4SGarrett D'Amore 
633*698f87a4SGarrett D'Amore 	if (*skip) {
634*698f87a4SGarrett D'Amore 		(*skip) = 0;
635*698f87a4SGarrett D'Amore 		return(0);
636*698f87a4SGarrett D'Amore 	} else
637*698f87a4SGarrett D'Amore 		return((*p->width)(p, c));
638*698f87a4SGarrett D'Amore }
63995c635efSGarrett D'Amore 
64095c635efSGarrett D'Amore size_t
term_strlen(const struct termp * p,const char * cp)64195c635efSGarrett D'Amore term_strlen(const struct termp *p, const char *cp)
64295c635efSGarrett D'Amore {
64395c635efSGarrett D'Amore 	size_t		 sz, rsz, i;
644*698f87a4SGarrett D'Amore 	int		 ssz, skip, c;
64595c635efSGarrett D'Amore 	const char	*seq, *rhs;
64695c635efSGarrett D'Amore 	enum mandoc_esc	 esc;
64795c635efSGarrett D'Amore 	static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
64895c635efSGarrett D'Amore 
64995c635efSGarrett D'Amore 	/*
65095c635efSGarrett D'Amore 	 * Account for escaped sequences within string length
65195c635efSGarrett D'Amore 	 * calculations.  This follows the logic in term_word() as we
65295c635efSGarrett D'Amore 	 * must calculate the width of produced strings.
65395c635efSGarrett D'Amore 	 */
65495c635efSGarrett D'Amore 
65595c635efSGarrett D'Amore 	sz = 0;
656*698f87a4SGarrett D'Amore 	skip = 0;
65795c635efSGarrett D'Amore 	while ('\0' != *cp) {
65895c635efSGarrett D'Amore 		rsz = strcspn(cp, rej);
65995c635efSGarrett D'Amore 		for (i = 0; i < rsz; i++)
660*698f87a4SGarrett D'Amore 			sz += cond_width(p, *cp++, &skip);
66195c635efSGarrett D'Amore 
66295c635efSGarrett D'Amore 		c = 0;
66395c635efSGarrett D'Amore 		switch (*cp) {
66495c635efSGarrett D'Amore 		case ('\\'):
66595c635efSGarrett D'Amore 			cp++;
66695c635efSGarrett D'Amore 			esc = mandoc_escape(&cp, &seq, &ssz);
66795c635efSGarrett D'Amore 			if (ESCAPE_ERROR == esc)
66895c635efSGarrett D'Amore 				return(sz);
66995c635efSGarrett D'Amore 
67095c635efSGarrett D'Amore 			if (TERMENC_ASCII != p->enc)
67195c635efSGarrett D'Amore 				switch (esc) {
67295c635efSGarrett D'Amore 				case (ESCAPE_UNICODE):
67395c635efSGarrett D'Amore 					c = mchars_num2uc
67495c635efSGarrett D'Amore 						(seq + 1, ssz - 1);
67595c635efSGarrett D'Amore 					if ('\0' == c)
67695c635efSGarrett D'Amore 						break;
677*698f87a4SGarrett D'Amore 					sz += cond_width(p, c, &skip);
67895c635efSGarrett D'Amore 					continue;
67995c635efSGarrett D'Amore 				case (ESCAPE_SPECIAL):
68095c635efSGarrett D'Amore 					c = mchars_spec2cp
68195c635efSGarrett D'Amore 						(p->symtab, seq, ssz);
68295c635efSGarrett D'Amore 					if (c <= 0)
68395c635efSGarrett D'Amore 						break;
684*698f87a4SGarrett D'Amore 					sz += cond_width(p, c, &skip);
68595c635efSGarrett D'Amore 					continue;
68695c635efSGarrett D'Amore 				default:
68795c635efSGarrett D'Amore 					break;
68895c635efSGarrett D'Amore 				}
68995c635efSGarrett D'Amore 
69095c635efSGarrett D'Amore 			rhs = NULL;
69195c635efSGarrett D'Amore 
69295c635efSGarrett D'Amore 			switch (esc) {
69395c635efSGarrett D'Amore 			case (ESCAPE_UNICODE):
694*698f87a4SGarrett D'Amore 				sz += cond_width(p, '?', &skip);
69595c635efSGarrett D'Amore 				break;
69695c635efSGarrett D'Amore 			case (ESCAPE_NUMBERED):
69795c635efSGarrett D'Amore 				c = mchars_num2char(seq, ssz);
69895c635efSGarrett D'Amore 				if ('\0' != c)
699*698f87a4SGarrett D'Amore 					sz += cond_width(p, c, &skip);
70095c635efSGarrett D'Amore 				break;
70195c635efSGarrett D'Amore 			case (ESCAPE_SPECIAL):
70295c635efSGarrett D'Amore 				rhs = mchars_spec2str
70395c635efSGarrett D'Amore 					(p->symtab, seq, ssz, &rsz);
70495c635efSGarrett D'Amore 
70595c635efSGarrett D'Amore 				if (ssz != 1 || rhs)
70695c635efSGarrett D'Amore 					break;
70795c635efSGarrett D'Amore 
70895c635efSGarrett D'Amore 				rhs = seq;
70995c635efSGarrett D'Amore 				rsz = ssz;
71095c635efSGarrett D'Amore 				break;
711*698f87a4SGarrett D'Amore 			case (ESCAPE_SKIPCHAR):
712*698f87a4SGarrett D'Amore 				skip = 1;
713*698f87a4SGarrett D'Amore 				break;
71495c635efSGarrett D'Amore 			default:
71595c635efSGarrett D'Amore 				break;
71695c635efSGarrett D'Amore 			}
71795c635efSGarrett D'Amore 
71895c635efSGarrett D'Amore 			if (NULL == rhs)
71995c635efSGarrett D'Amore 				break;
72095c635efSGarrett D'Amore 
721*698f87a4SGarrett D'Amore 			if (skip) {
722*698f87a4SGarrett D'Amore 				skip = 0;
723*698f87a4SGarrett D'Amore 				break;
724*698f87a4SGarrett D'Amore 			}
725*698f87a4SGarrett D'Amore 
72695c635efSGarrett D'Amore 			for (i = 0; i < rsz; i++)
72795c635efSGarrett D'Amore 				sz += (*p->width)(p, *rhs++);
72895c635efSGarrett D'Amore 			break;
72995c635efSGarrett D'Amore 		case (ASCII_NBRSP):
730*698f87a4SGarrett D'Amore 			sz += cond_width(p, ' ', &skip);
73195c635efSGarrett D'Amore 			cp++;
73295c635efSGarrett D'Amore 			break;
73395c635efSGarrett D'Amore 		case (ASCII_HYPH):
734*698f87a4SGarrett D'Amore 			sz += cond_width(p, '-', &skip);
73595c635efSGarrett D'Amore 			cp++;
73695c635efSGarrett D'Amore 			break;
73795c635efSGarrett D'Amore 		default:
73895c635efSGarrett D'Amore 			break;
73995c635efSGarrett D'Amore 		}
74095c635efSGarrett D'Amore 	}
74195c635efSGarrett D'Amore 
74295c635efSGarrett D'Amore 	return(sz);
74395c635efSGarrett D'Amore }
74495c635efSGarrett D'Amore 
74595c635efSGarrett D'Amore /* ARGSUSED */
74695c635efSGarrett D'Amore size_t
term_vspan(const struct termp * p,const struct roffsu * su)74795c635efSGarrett D'Amore term_vspan(const struct termp *p, const struct roffsu *su)
74895c635efSGarrett D'Amore {
74995c635efSGarrett D'Amore 	double		 r;
75095c635efSGarrett D'Amore 
75195c635efSGarrett D'Amore 	switch (su->unit) {
75295c635efSGarrett D'Amore 	case (SCALE_CM):
75395c635efSGarrett D'Amore 		r = su->scale * 2;
75495c635efSGarrett D'Amore 		break;
75595c635efSGarrett D'Amore 	case (SCALE_IN):
75695c635efSGarrett D'Amore 		r = su->scale * 6;
75795c635efSGarrett D'Amore 		break;
75895c635efSGarrett D'Amore 	case (SCALE_PC):
75995c635efSGarrett D'Amore 		r = su->scale;
76095c635efSGarrett D'Amore 		break;
76195c635efSGarrett D'Amore 	case (SCALE_PT):
76295c635efSGarrett D'Amore 		r = su->scale / 8;
76395c635efSGarrett D'Amore 		break;
76495c635efSGarrett D'Amore 	case (SCALE_MM):
76595c635efSGarrett D'Amore 		r = su->scale / 1000;
76695c635efSGarrett D'Amore 		break;
76795c635efSGarrett D'Amore 	case (SCALE_VS):
76895c635efSGarrett D'Amore 		r = su->scale;
76995c635efSGarrett D'Amore 		break;
77095c635efSGarrett D'Amore 	default:
77195c635efSGarrett D'Amore 		r = su->scale - 1;
77295c635efSGarrett D'Amore 		break;
77395c635efSGarrett D'Amore 	}
77495c635efSGarrett D'Amore 
77595c635efSGarrett D'Amore 	if (r < 0.0)
77695c635efSGarrett D'Amore 		r = 0.0;
77795c635efSGarrett D'Amore 	return(/* LINTED */(size_t)
77895c635efSGarrett D'Amore 			r);
77995c635efSGarrett D'Amore }
78095c635efSGarrett D'Amore 
78195c635efSGarrett D'Amore size_t
term_hspan(const struct termp * p,const struct roffsu * su)78295c635efSGarrett D'Amore term_hspan(const struct termp *p, const struct roffsu *su)
78395c635efSGarrett D'Amore {
78495c635efSGarrett D'Amore 	double		 v;
78595c635efSGarrett D'Amore 
78695c635efSGarrett D'Amore 	v = ((*p->hspan)(p, su));
78795c635efSGarrett D'Amore 	if (v < 0.0)
78895c635efSGarrett D'Amore 		v = 0.0;
78995c635efSGarrett D'Amore 	return((size_t) /* LINTED */
79095c635efSGarrett D'Amore 			v);
79195c635efSGarrett D'Amore }
792