[BACK]Return to term.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/term.c, Revision 1.115

1.115   ! kristaps    1: /*     $Id: term.c,v 1.114 2009/10/27 08:05:39 kristaps Exp $ */
1.1       kristaps    2: /*
1.75      kristaps    3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.74      kristaps    6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    8:  *
1.74      kristaps    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.
1.1       kristaps   16:  */
                     17: #include <assert.h>
1.23      kristaps   18: #include <err.h>
1.22      kristaps   19: #include <stdio.h>
1.1       kristaps   20: #include <stdlib.h>
                     21: #include <string.h>
1.113     kristaps   22: #include <time.h>
1.1       kristaps   23:
1.101     kristaps   24: #include "chars.h"
1.107     kristaps   25: #include "out.h"
1.71      kristaps   26: #include "term.h"
                     27: #include "man.h"
                     28: #include "mdoc.h"
1.105     kristaps   29: #include "main.h"
1.1       kristaps   30:
1.103     kristaps   31: /* FIXME: accomodate non-breaking, non-collapsing white-space. */
                     32: /* FIXME: accomodate non-breaking, collapsing white-space. */
                     33:
1.71      kristaps   34: static struct termp     *term_alloc(enum termenc);
                     35: static void              term_free(struct termp *);
1.95      kristaps   36:
                     37: static void              do_escaped(struct termp *, const char **);
                     38: static void              do_special(struct termp *,
1.71      kristaps   39:                                const char *, size_t);
1.95      kristaps   40: static void              do_reserved(struct termp *,
1.94      kristaps   41:                                const char *, size_t);
1.95      kristaps   42: static void              buffer(struct termp *, char);
                     43: static void              encode(struct termp *, char);
1.1       kristaps   44:
                     45:
1.71      kristaps   46: void *
                     47: ascii_alloc(void)
1.10      kristaps   48: {
1.1       kristaps   49:
1.71      kristaps   50:        return(term_alloc(TERMENC_ASCII));
1.1       kristaps   51: }
                     52:
                     53:
1.99      kristaps   54: void
1.71      kristaps   55: terminal_free(void *arg)
1.11      kristaps   56: {
                     57:
1.71      kristaps   58:        term_free((struct termp *)arg);
1.11      kristaps   59: }
                     60:
                     61:
1.71      kristaps   62: static void
                     63: term_free(struct termp *p)
1.14      kristaps   64: {
                     65:
1.71      kristaps   66:        if (p->buf)
                     67:                free(p->buf);
1.102     kristaps   68:        if (p->symtab)
1.101     kristaps   69:                chars_free(p->symtab);
1.14      kristaps   70:
1.71      kristaps   71:        free(p);
1.14      kristaps   72: }
                     73:
                     74:
1.71      kristaps   75: static struct termp *
                     76: term_alloc(enum termenc enc)
1.14      kristaps   77: {
1.71      kristaps   78:        struct termp *p;
1.14      kristaps   79:
1.71      kristaps   80:        if (NULL == (p = malloc(sizeof(struct termp))))
1.98      kristaps   81:                return(NULL);
1.115   ! kristaps   82:        memset(p, 0, sizeof(struct termp));
1.80      kristaps   83:        p->maxrmargin = 78;
1.71      kristaps   84:        p->enc = enc;
                     85:        return(p);
1.14      kristaps   86: }
                     87:
                     88:
1.71      kristaps   89: /*
                     90:  * Flush a line of text.  A "line" is loosely defined as being something
                     91:  * that should be followed by a newline, regardless of whether it's
                     92:  * broken apart by newlines getting there.  A line can also be a
                     93:  * fragment of a columnar list.
                     94:  *
                     95:  * Specifically, a line is whatever's in p->buf of length p->col, which
                     96:  * is zeroed after this function returns.
                     97:  *
1.84      kristaps   98:  * The usage of termp:flags is as follows:
1.71      kristaps   99:  *
                    100:  *  - TERMP_NOLPAD: when beginning to write the line, don't left-pad the
                    101:  *    offset value.  This is useful when doing columnar lists where the
                    102:  *    prior column has right-padded.
                    103:  *
                    104:  *  - TERMP_NOBREAK: this is the most important and is used when making
                    105:  *    columns.  In short: don't print a newline and instead pad to the
                    106:  *    right margin.  Used in conjunction with TERMP_NOLPAD.
                    107:  *
1.91      kristaps  108:  *  - TERMP_TWOSPACE: when padding, make sure there are at least two
                    109:  *    space characters of padding.  Otherwise, rather break the line.
                    110:  *
1.84      kristaps  111:  *  - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
                    112:  *    the line is overrun, and don't pad-right if it's underrun.
                    113:  *
                    114:  *  - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
                    115:  *    overruning, instead save the position and continue at that point
                    116:  *    when the next invocation.
1.71      kristaps  117:  *
                    118:  *  In-line line breaking:
                    119:  *
                    120:  *  If TERMP_NOBREAK is specified and the line overruns the right
                    121:  *  margin, it will break and pad-right to the right margin after
                    122:  *  writing.  If maxrmargin is violated, it will break and continue
1.114     kristaps  123:  *  writing from the right-margin, which will lead to the above scenario
                    124:  *  upon exit.  Otherwise, the line will break at the right margin.
1.71      kristaps  125:  */
                    126: void
                    127: term_flushln(struct termp *p)
1.53      kristaps  128: {
1.114     kristaps  129:        int              i;     /* current input position in p->buf */
                    130:        size_t           vis;   /* current visual position on output */
                    131:        size_t           vbl;   /* number of blanks to prepend to output */
                    132:        size_t           vsz;   /* visual characters to write to output */
                    133:        size_t           bp;    /* visual right border position */
                    134:        int              j;     /* temporary loop index */
                    135:        size_t           maxvis, mmax;
1.91      kristaps  136:        static int       overstep = 0;
1.53      kristaps  137:
1.71      kristaps  138:        /*
                    139:         * First, establish the maximum columns of "visible" content.
                    140:         * This is usually the difference between the right-margin and
                    141:         * an indentation, but can be, for tagged lists or columns, a
1.115   ! kristaps  142:         * small set of values.
1.71      kristaps  143:         */
1.53      kristaps  144:
1.71      kristaps  145:        assert(p->offset < p->rmargin);
1.92      kristaps  146:
1.114     kristaps  147:        maxvis = (int)(p->rmargin - p->offset) - overstep < 0 ?
                    148:                        0 : p->rmargin - p->offset - overstep;
                    149:        mmax = (int)(p->maxrmargin - p->offset) - overstep < 0 ?
                    150:                        0 : p->maxrmargin - p->offset - overstep;
1.92      kristaps  151:
1.71      kristaps  152:        bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
1.115   ! kristaps  153:
        !           154:        /*
        !           155:         * FIXME: if bp is zero, we still output the first word before
        !           156:         * breaking the line.
        !           157:         */
        !           158:
1.71      kristaps  159:        vis = 0;
1.84      kristaps  160:
1.71      kristaps  161:        /*
                    162:         * If in the standard case (left-justified), then begin with our
                    163:         * indentation, otherwise (columns, etc.) just start spitting
                    164:         * out text.
                    165:         */
1.53      kristaps  166:
1.71      kristaps  167:        if ( ! (p->flags & TERMP_NOLPAD))
                    168:                /* LINTED */
                    169:                for (j = 0; j < (int)p->offset; j++)
                    170:                        putchar(' ');
                    171:
                    172:        for (i = 0; i < (int)p->col; i++) {
                    173:                /*
                    174:                 * Count up visible word characters.  Control sequences
                    175:                 * (starting with the CSI) aren't counted.  A space
                    176:                 * generates a non-printing word, which is valid (the
                    177:                 * space is printed according to regular spacing rules).
                    178:                 */
                    179:
                    180:                /* LINTED */
                    181:                for (j = i, vsz = 0; j < (int)p->col; j++) {
1.93      kristaps  182:                        if (j && ' ' == p->buf[j])
1.71      kristaps  183:                                break;
                    184:                        else if (8 == p->buf[j])
1.89      kristaps  185:                                vsz--;
1.71      kristaps  186:                        else
                    187:                                vsz++;
                    188:                }
1.53      kristaps  189:
1.71      kristaps  190:                /*
1.81      kristaps  191:                 * Choose the number of blanks to prepend: no blank at the
                    192:                 * beginning of a line, one between words -- but do not
                    193:                 * actually write them yet.
1.71      kristaps  194:                 */
1.81      kristaps  195:                vbl = (size_t)(0 == vis ? 0 : 1);
1.71      kristaps  196:
1.81      kristaps  197:                /*
                    198:                 * Find out whether we would exceed the right margin.
                    199:                 * If so, break to the next line.  (TODO: hyphenate)
                    200:                 * Otherwise, write the chosen number of blanks now.
                    201:                 */
                    202:                if (vis && vis + vbl + vsz > bp) {
                    203:                        putchar('\n');
                    204:                        if (TERMP_NOBREAK & p->flags) {
                    205:                                for (j = 0; j < (int)p->rmargin; j++)
                    206:                                        putchar(' ');
                    207:                                vis = p->rmargin - p->offset;
                    208:                        } else {
1.71      kristaps  209:                                for (j = 0; j < (int)p->offset; j++)
                    210:                                        putchar(' ');
                    211:                                vis = 0;
1.81      kristaps  212:                        }
1.104     kristaps  213:                        /* Remove the overstep width. */
1.112     kristaps  214:                        bp += (int)/* LINTED */
                    215:                                overstep;
1.110     kristaps  216:                        overstep = 0;
1.81      kristaps  217:                } else {
                    218:                        for (j = 0; j < (int)vbl; j++)
1.71      kristaps  219:                                putchar(' ');
1.81      kristaps  220:                        vis += vbl;
1.71      kristaps  221:                }
1.53      kristaps  222:
1.78      kristaps  223:                /*
1.81      kristaps  224:                 * Finally, write out the word.
1.71      kristaps  225:                 */
                    226:                for ( ; i < (int)p->col; i++) {
                    227:                        if (' ' == p->buf[i])
                    228:                                break;
                    229:                        putchar(p->buf[i]);
                    230:                }
                    231:                vis += vsz;
                    232:        }
1.111     kristaps  233:
1.91      kristaps  234:        p->col = 0;
1.111     kristaps  235:        overstep = 0;
1.15      kristaps  236:
1.91      kristaps  237:        if ( ! (TERMP_NOBREAK & p->flags)) {
                    238:                putchar('\n');
1.15      kristaps  239:                return;
1.71      kristaps  240:        }
1.15      kristaps  241:
1.91      kristaps  242:        if (TERMP_HANG & p->flags) {
                    243:                /* We need one blank after the tag. */
1.92      kristaps  244:                overstep = /* LINTED */
                    245:                        vis - maxvis + 1;
1.91      kristaps  246:
                    247:                /*
                    248:                 * Behave exactly the same way as groff:
1.92      kristaps  249:                 * If we have overstepped the margin, temporarily move
                    250:                 * it to the right and flag the rest of the line to be
                    251:                 * shorter.
1.91      kristaps  252:                 * If we landed right at the margin, be happy.
1.92      kristaps  253:                 * If we are one step before the margin, temporarily
                    254:                 * move it one step LEFT and flag the rest of the line
                    255:                 * to be longer.
1.91      kristaps  256:                 */
1.92      kristaps  257:                if (overstep >= -1) {
                    258:                        assert((int)maxvis + overstep >= 0);
                    259:                        /* LINTED */
1.91      kristaps  260:                        maxvis += overstep;
1.92      kristaps  261:                } else
1.91      kristaps  262:                        overstep = 0;
                    263:
                    264:        } else if (TERMP_DANGLE & p->flags)
                    265:                return;
1.15      kristaps  266:
1.92      kristaps  267:        /* Right-pad. */
                    268:        if (maxvis > vis + /* LINTED */
                    269:                        ((TERMP_TWOSPACE & p->flags) ? 1 : 0))
1.91      kristaps  270:                for ( ; vis < maxvis; vis++)
                    271:                        putchar(' ');
1.92      kristaps  272:        else {  /* ...or newline break. */
1.71      kristaps  273:                putchar('\n');
1.91      kristaps  274:                for (i = 0; i < (int)p->rmargin; i++)
                    275:                        putchar(' ');
                    276:        }
1.15      kristaps  277: }
                    278:
                    279:
1.71      kristaps  280: /*
                    281:  * A newline only breaks an existing line; it won't assert vertical
                    282:  * space.  All data in the output buffer is flushed prior to the newline
                    283:  * assertion.
                    284:  */
                    285: void
                    286: term_newln(struct termp *p)
1.15      kristaps  287: {
                    288:
1.71      kristaps  289:        p->flags |= TERMP_NOSPACE;
                    290:        if (0 == p->col) {
                    291:                p->flags &= ~TERMP_NOLPAD;
1.15      kristaps  292:                return;
1.16      kristaps  293:        }
1.71      kristaps  294:        term_flushln(p);
                    295:        p->flags &= ~TERMP_NOLPAD;
1.16      kristaps  296: }
                    297:
                    298:
1.71      kristaps  299: /*
                    300:  * Asserts a vertical space (a full, empty line-break between lines).
                    301:  * Note that if used twice, this will cause two blank spaces and so on.
                    302:  * All data in the output buffer is flushed prior to the newline
                    303:  * assertion.
                    304:  */
                    305: void
                    306: term_vspace(struct termp *p)
1.16      kristaps  307: {
                    308:
1.62      kristaps  309:        term_newln(p);
1.71      kristaps  310:        putchar('\n');
1.16      kristaps  311: }
                    312:
                    313:
1.71      kristaps  314: static void
1.95      kristaps  315: do_special(struct termp *p, const char *word, size_t len)
1.17      kristaps  316: {
1.71      kristaps  317:        const char      *rhs;
                    318:        size_t           sz;
1.79      kristaps  319:        int              i;
1.17      kristaps  320:
1.101     kristaps  321:        rhs = chars_a2ascii(p->symtab, word, len, &sz);
1.86      kristaps  322:
1.96      kristaps  323:        if (NULL == rhs) {
1.97      kristaps  324: #if 0
1.96      kristaps  325:                fputs("Unknown special character: ", stderr);
                    326:                for (i = 0; i < (int)len; i++)
                    327:                        fputc(word[i], stderr);
                    328:                fputc('\n', stderr);
                    329: #endif
1.94      kristaps  330:                return;
1.96      kristaps  331:        }
1.94      kristaps  332:        for (i = 0; i < (int)sz; i++)
1.95      kristaps  333:                encode(p, rhs[i]);
1.94      kristaps  334: }
                    335:
                    336:
                    337: static void
1.95      kristaps  338: do_reserved(struct termp *p, const char *word, size_t len)
1.94      kristaps  339: {
                    340:        const char      *rhs;
                    341:        size_t           sz;
                    342:        int              i;
                    343:
1.101     kristaps  344:        rhs = chars_a2res(p->symtab, word, len, &sz);
1.94      kristaps  345:
1.96      kristaps  346:        if (NULL == rhs) {
                    347: #if 0
                    348:                fputs("Unknown reserved word: ", stderr);
                    349:                for (i = 0; i < (int)len; i++)
                    350:                        fputc(word[i], stderr);
                    351:                fputc('\n', stderr);
                    352: #endif
1.94      kristaps  353:                return;
1.96      kristaps  354:        }
1.94      kristaps  355:        for (i = 0; i < (int)sz; i++)
1.95      kristaps  356:                encode(p, rhs[i]);
1.17      kristaps  357: }
                    358:
                    359:
1.71      kristaps  360: /*
                    361:  * Handle an escape sequence: determine its length and pass it to the
                    362:  * escape-symbol look table.  Note that we assume mdoc(3) has validated
                    363:  * the escape sequence (we assert upon badly-formed escape sequences).
                    364:  */
                    365: static void
1.95      kristaps  366: do_escaped(struct termp *p, const char **word)
1.17      kristaps  367: {
1.97      kristaps  368:        int              j, type;
1.86      kristaps  369:        const char      *wp;
                    370:
                    371:        wp = *word;
1.97      kristaps  372:        type = 1;
1.17      kristaps  373:
1.86      kristaps  374:        if (0 == *(++wp)) {
                    375:                *word = wp;
1.71      kristaps  376:                return;
1.86      kristaps  377:        }
1.17      kristaps  378:
1.86      kristaps  379:        if ('(' == *wp) {
                    380:                wp++;
                    381:                if (0 == *wp || 0 == *(wp + 1)) {
                    382:                        *word = 0 == *wp ? wp : wp + 1;
1.71      kristaps  383:                        return;
1.86      kristaps  384:                }
1.22      kristaps  385:
1.95      kristaps  386:                do_special(p, wp, 2);
1.86      kristaps  387:                *word = ++wp;
1.71      kristaps  388:                return;
1.22      kristaps  389:
1.86      kristaps  390:        } else if ('*' == *wp) {
                    391:                if (0 == *(++wp)) {
                    392:                        *word = wp;
1.71      kristaps  393:                        return;
1.86      kristaps  394:                }
1.22      kristaps  395:
1.86      kristaps  396:                switch (*wp) {
1.71      kristaps  397:                case ('('):
1.86      kristaps  398:                        wp++;
                    399:                        if (0 == *wp || 0 == *(wp + 1)) {
                    400:                                *word = 0 == *wp ? wp : wp + 1;
1.71      kristaps  401:                                return;
1.86      kristaps  402:                        }
1.65      kristaps  403:
1.95      kristaps  404:                        do_reserved(p, wp, 2);
1.86      kristaps  405:                        *word = ++wp;
1.71      kristaps  406:                        return;
                    407:                case ('['):
1.97      kristaps  408:                        type = 0;
1.71      kristaps  409:                        break;
                    410:                default:
1.95      kristaps  411:                        do_reserved(p, wp, 1);
1.86      kristaps  412:                        *word = wp;
1.71      kristaps  413:                        return;
                    414:                }
                    415:
1.86      kristaps  416:        } else if ('f' == *wp) {
                    417:                if (0 == *(++wp)) {
                    418:                        *word = wp;
1.71      kristaps  419:                        return;
1.86      kristaps  420:                }
                    421:
                    422:                switch (*wp) {
1.71      kristaps  423:                case ('B'):
1.98      kristaps  424:                        p->bold++;
1.71      kristaps  425:                        break;
                    426:                case ('I'):
1.98      kristaps  427:                        p->under++;
1.71      kristaps  428:                        break;
                    429:                case ('P'):
                    430:                        /* FALLTHROUGH */
                    431:                case ('R'):
1.98      kristaps  432:                        p->bold = p->under = 0;
1.71      kristaps  433:                        break;
                    434:                default:
                    435:                        break;
                    436:                }
1.86      kristaps  437:
                    438:                *word = wp;
1.71      kristaps  439:                return;
1.22      kristaps  440:
1.86      kristaps  441:        } else if ('[' != *wp) {
1.95      kristaps  442:                do_special(p, wp, 1);
1.86      kristaps  443:                *word = wp;
1.71      kristaps  444:                return;
                    445:        }
1.28      kristaps  446:
1.86      kristaps  447:        wp++;
                    448:        for (j = 0; *wp && ']' != *wp; wp++, j++)
1.71      kristaps  449:                /* Loop... */ ;
1.28      kristaps  450:
1.86      kristaps  451:        if (0 == *wp) {
                    452:                *word = wp;
1.71      kristaps  453:                return;
1.86      kristaps  454:        }
1.48      kristaps  455:
1.97      kristaps  456:        if (type)
                    457:                do_special(p, wp - j, (size_t)j);
                    458:        else
                    459:                do_reserved(p, wp - j, (size_t)j);
1.86      kristaps  460:        *word = wp;
1.48      kristaps  461: }
                    462:
                    463:
1.71      kristaps  464: /*
                    465:  * Handle pwords, partial words, which may be either a single word or a
                    466:  * phrase that cannot be broken down (such as a literal string).  This
                    467:  * handles word styling.
                    468:  */
1.86      kristaps  469: void
                    470: term_word(struct termp *p, const char *word)
1.65      kristaps  471: {
1.88      kristaps  472:        const char       *sv;
1.71      kristaps  473:
1.100     kristaps  474:        sv = word;
                    475:
                    476:        if (word[0] && 0 == word[1])
                    477:                switch (word[0]) {
                    478:                case('.'):
                    479:                        /* FALLTHROUGH */
                    480:                case(','):
                    481:                        /* FALLTHROUGH */
                    482:                case(';'):
                    483:                        /* FALLTHROUGH */
                    484:                case(':'):
                    485:                        /* FALLTHROUGH */
                    486:                case('?'):
                    487:                        /* FALLTHROUGH */
                    488:                case('!'):
                    489:                        /* FALLTHROUGH */
                    490:                case(')'):
                    491:                        /* FALLTHROUGH */
                    492:                case(']'):
                    493:                        /* FALLTHROUGH */
                    494:                case('}'):
                    495:                        if ( ! (TERMP_IGNDELIM & p->flags))
                    496:                                p->flags |= TERMP_NOSPACE;
                    497:                        break;
                    498:                default:
                    499:                        break;
                    500:                }
1.65      kristaps  501:
1.71      kristaps  502:        if ( ! (TERMP_NOSPACE & p->flags))
1.95      kristaps  503:                buffer(p, ' ');
1.65      kristaps  504:
1.71      kristaps  505:        if ( ! (p->flags & TERMP_NONOSPACE))
                    506:                p->flags &= ~TERMP_NOSPACE;
1.65      kristaps  507:
1.100     kristaps  508:        for ( ; *word; word++)
1.86      kristaps  509:                if ('\\' != *word)
1.95      kristaps  510:                        encode(p, *word);
1.79      kristaps  511:                else
1.95      kristaps  512:                        do_escaped(p, &word);
1.65      kristaps  513:
1.100     kristaps  514:        if (sv[0] && 0 == sv[1])
                    515:                switch (sv[0]) {
                    516:                case('('):
                    517:                        /* FALLTHROUGH */
                    518:                case('['):
                    519:                        /* FALLTHROUGH */
                    520:                case('{'):
                    521:                        p->flags |= TERMP_NOSPACE;
                    522:                        break;
                    523:                default:
                    524:                        break;
                    525:                }
1.65      kristaps  526: }
                    527:
                    528:
1.71      kristaps  529: /*
                    530:  * Insert a single character into the line-buffer.  If the buffer's
                    531:  * space is exceeded, then allocate more space by doubling the buffer
                    532:  * size.
                    533:  */
                    534: static void
1.95      kristaps  535: buffer(struct termp *p, char c)
1.51      kristaps  536: {
1.71      kristaps  537:        size_t           s;
1.51      kristaps  538:
1.71      kristaps  539:        if (p->col + 1 >= p->maxcols) {
                    540:                if (0 == p->maxcols)
                    541:                        p->maxcols = 256;
                    542:                s = p->maxcols * 2;
                    543:                p->buf = realloc(p->buf, s);
                    544:                if (NULL == p->buf)
1.98      kristaps  545:                        err(1, "realloc"); /* FIXME: shouldn't be here! */
1.71      kristaps  546:                p->maxcols = s;
                    547:        }
                    548:        p->buf[(int)(p->col)++] = c;
1.51      kristaps  549: }
                    550:
1.79      kristaps  551:
                    552: static void
1.95      kristaps  553: encode(struct termp *p, char c)
1.79      kristaps  554: {
1.89      kristaps  555:
1.98      kristaps  556:        if (' ' != c) {
1.109     kristaps  557:                if (p->under) {
                    558:                        buffer(p, '_');
                    559:                        buffer(p, 8);
                    560:                }
1.98      kristaps  561:                if (p->bold) {
1.95      kristaps  562:                        buffer(p, c);
                    563:                        buffer(p, 8);
1.79      kristaps  564:                }
                    565:        }
1.95      kristaps  566:        buffer(p, c);
1.79      kristaps  567: }
1.106     kristaps  568:
                    569:
1.107     kristaps  570: size_t
                    571: term_vspan(const struct roffsu *su)
1.106     kristaps  572: {
                    573:        double           r;
                    574:
1.107     kristaps  575:        switch (su->unit) {
1.106     kristaps  576:        case (SCALE_CM):
1.107     kristaps  577:                r = su->scale * 2;
1.106     kristaps  578:                break;
                    579:        case (SCALE_IN):
1.107     kristaps  580:                r = su->scale * 6;
1.106     kristaps  581:                break;
                    582:        case (SCALE_PC):
1.107     kristaps  583:                r = su->scale;
1.106     kristaps  584:                break;
                    585:        case (SCALE_PT):
1.107     kristaps  586:                r = su->scale / 8;
1.106     kristaps  587:                break;
                    588:        case (SCALE_MM):
1.107     kristaps  589:                r = su->scale / 1000;
1.106     kristaps  590:                break;
                    591:        case (SCALE_VS):
1.107     kristaps  592:                r = su->scale;
1.106     kristaps  593:                break;
                    594:        default:
1.107     kristaps  595:                r = su->scale - 1;
1.106     kristaps  596:                break;
                    597:        }
                    598:
                    599:        if (r < 0.0)
                    600:                r = 0.0;
1.107     kristaps  601:        return(/* LINTED */(size_t)
1.106     kristaps  602:                        r);
                    603: }
                    604:
                    605:
1.107     kristaps  606: size_t
                    607: term_hspan(const struct roffsu *su)
1.106     kristaps  608: {
                    609:        double           r;
                    610:
1.108     kristaps  611:        /* XXX: CM, IN, and PT are approximations. */
                    612:
1.107     kristaps  613:        switch (su->unit) {
1.106     kristaps  614:        case (SCALE_CM):
1.108     kristaps  615:                r = 4 * su->scale;
1.106     kristaps  616:                break;
                    617:        case (SCALE_IN):
1.108     kristaps  618:                /* XXX: this is an approximation. */
                    619:                r = 10 * su->scale;
1.106     kristaps  620:                break;
                    621:        case (SCALE_PC):
1.108     kristaps  622:                r = (10 * su->scale) / 6;
1.106     kristaps  623:                break;
                    624:        case (SCALE_PT):
1.108     kristaps  625:                r = (10 * su->scale) / 72;
1.106     kristaps  626:                break;
                    627:        case (SCALE_MM):
1.107     kristaps  628:                r = su->scale / 1000; /* FIXME: double-check. */
1.106     kristaps  629:                break;
                    630:        case (SCALE_VS):
1.107     kristaps  631:                r = su->scale * 2 - 1; /* FIXME: double-check. */
1.106     kristaps  632:                break;
                    633:        default:
1.107     kristaps  634:                r = su->scale;
1.106     kristaps  635:                break;
                    636:        }
                    637:
                    638:        if (r < 0.0)
                    639:                r = 0.0;
1.107     kristaps  640:        return((size_t)/* LINTED */
1.106     kristaps  641:                        r);
                    642: }
                    643:
                    644:

CVSweb