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