term.c revision 95c635efb7c3b86efc493e0447eaec7aecca3f0f
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/* $Id: term.c,v 1.201 2011/09/21 09:57:13 schwarze Exp $ */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * copyright notice and this permission notice appear in all copies.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void encode(struct termp *, const char *, size_t);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterm_begin(struct termp *p, term_margin head,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Flush a line of text. A "line" is loosely defined as being something
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * that should be followed by a newline, regardless of whether it's
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * broken apart by newlines getting there. A line can also be a
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * fragment of a columnar list (`Bl -tag' or `Bl -column'), which does
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * not have a trailing newline.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The following flags may be specified:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - TERMP_NOBREAK: this is the most important and is used when making
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * columns. In short: don't print a newline and instead expect the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * next call to do the padding up to the start of the next column.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - TERMP_TWOSPACE: make sure there is room for at least two space
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * characters of padding. Otherwise, rather break the line.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the line is overrun, and don't pad-right if it's underrun.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * overrunning, instead save the position and continue at that point
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * when the next invocation.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * In-line line breaking:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If TERMP_NOBREAK is specified and the line overruns the right
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * margin, it will break and pad-right to the right margin after
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * writing. If maxrmargin is violated, it will break and continue
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * writing from the right-margin, which will lead to the above scenario
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * upon exit. Otherwise, the line will break at the right margin.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int i; /* current input position in p->buf */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t vis; /* current visual position on output */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t vbl; /* number of blanks to prepend to output */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t vend; /* end of word visual position on output */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t bp; /* visual right border position */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t dv; /* temporary for visual pos calculations */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int j; /* temporary loop index for p->buf */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int jhy; /* last hyph before overflow w/r/t j */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore size_t maxvis; /* output position of visible boundary */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * First, establish the maximum columns of "visible" content.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * This is usually the difference between the right-margin and
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * an indentation, but can be, for tagged lists or columns, a
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * small set of values.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore mmax = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Calculate the required amount of padding.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (i < p->col) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Handle literal tab characters: collapse all
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * subsequent tabs into a single huge set of spaces.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore vend = (vis / p->tabwidth + 1) * p->tabwidth;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Count up visible word characters. Control sequences
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * (starting with the CSI) aren't counted. A space
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * generates a non-printing word, which is valid (the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * space is printed according to regular spacing rules).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j])
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Back over the the last printed character. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Regular word. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Break at the hyphen point if we overrun. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Find out whether we would exceed the right margin.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If so, break to the next line.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Remove the p->overstep width. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Write out the [remaining] word. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for ( ; i < p->col; i++) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Now we definitely know there will be
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * printable characters to output,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * so write preceding white space now.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If there was trailing white space, it was not printed;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * so reset the cursor position accordingly.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* We need one blank after the tag. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->overstep = (int)(vis - maxvis + (*p->width)(p, ' '));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Behave exactly the same way as groff:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we have overstepped the margin, temporarily move
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * it to the right and flag the rest of the line to be
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we landed right at the margin, be happy.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we are one step before the margin, temporarily
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * move it one step LEFT and flag the rest of the line
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * to be longer.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* If the column was overrun, break the line. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * A newline only breaks an existing line; it won't assert vertical
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * space. All data in the output buffer is flushed prior to the newline
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Asserts a vertical space (a full, empty line-break between lines).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Note that if used twice, this will cause two blank spaces and so on.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * All data in the output buffer is flushed prior to the newline
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterm_fontrepl(struct termp *p, enum termfont f)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterm_fontpush(struct termp *p, enum termfont f)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterm_fontpopq(struct termp *p, const void *key)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (p->fonti >= 0 && key != &p->fontq[p->fonti])
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Handle pwords, partial words, which may be either a single word or a
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * phrase that cannot be broken down (such as a literal string). This
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * handles word styling.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\0' != c)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore cp = mchars_spec2str(p->symtab, seq, sz, &ssz);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * See encode().
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Do this for a single (probably unicode) value.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Does not check for non-decorated glyphs.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore } else if (TERMFONT_UNDER == f) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreencode(struct termp *p, const char *word, size_t sz)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Encode and buffer a string of characters. If the current
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * font mode is unset, buffer directly, else encode then buffer
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * character by character.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (TERMFONT_NONE == (f = term_fonttop(p))) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < len; i++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Pre-buffer, assuming worst-case. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < len; i++) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterm_strlen(const struct termp *p, const char *cp)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Account for escaped sequences within string length
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * calculations. This follows the logic in term_word() as we
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * must calculate the width of produced strings.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < rsz; i++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\0' == c)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ('\0' != c)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for (i = 0; i < rsz; i++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/* ARGSUSED */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterm_vspan(const struct termp *p, const struct roffsu *su)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterm_hspan(const struct termp *p, const struct roffsu *su)