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

Annotation of mandoc/term.c, Revision 1.149

1.149   ! kristaps    1: /*     $Id: term.c,v 1.148 2010/06/19 20:46:28 kristaps Exp $ */
1.1       kristaps    2: /*
1.148     kristaps    3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
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:  */
1.128     kristaps   17: #ifdef HAVE_CONFIG_H
                     18: #include "config.h"
                     19: #endif
                     20:
1.126     kristaps   21: #include <sys/types.h>
                     22:
1.1       kristaps   23: #include <assert.h>
1.122     kristaps   24: #include <ctype.h>
1.141     kristaps   25: #include <stdint.h>
1.22      kristaps   26: #include <stdio.h>
1.1       kristaps   27: #include <stdlib.h>
                     28: #include <string.h>
                     29:
1.137     kristaps   30: #include "mandoc.h"
1.101     kristaps   31: #include "chars.h"
1.107     kristaps   32: #include "out.h"
1.71      kristaps   33: #include "term.h"
                     34: #include "man.h"
                     35: #include "mdoc.h"
1.105     kristaps   36: #include "main.h"
1.1       kristaps   37:
1.125     kristaps   38: static void              spec(struct termp *, const char *, size_t);
                     39: static void              res(struct termp *, const char *, size_t);
                     40: static void              buffera(struct termp *, const char *, size_t);
                     41: static void              bufferc(struct termp *, char);
                     42: static void              adjbuf(struct termp *p, size_t);
                     43: static void              encode(struct termp *, const char *, size_t);
1.11      kristaps   44:
                     45:
1.145     kristaps   46: void
1.71      kristaps   47: term_free(struct termp *p)
1.14      kristaps   48: {
                     49:
1.71      kristaps   50:        if (p->buf)
                     51:                free(p->buf);
1.102     kristaps   52:        if (p->symtab)
1.101     kristaps   53:                chars_free(p->symtab);
1.145     kristaps   54:
1.142     kristaps   55:        free(p);
                     56: }
                     57:
                     58:
                     59: void
                     60: term_begin(struct termp *p, term_margin head,
                     61:                term_margin foot, const void *arg)
                     62: {
                     63:
                     64:        p->headf = head;
                     65:        p->footf = foot;
                     66:        p->argf = arg;
1.146     kristaps   67:        (*p->begin)(p);
1.142     kristaps   68: }
                     69:
                     70:
                     71: void
                     72: term_end(struct termp *p)
                     73: {
                     74:
1.146     kristaps   75:        (*p->end)(p);
1.14      kristaps   76: }
                     77:
                     78:
1.145     kristaps   79: struct termp *
                     80: term_alloc(enum termenc enc)
1.14      kristaps   81: {
1.141     kristaps   82:        struct termp    *p;
1.14      kristaps   83:
1.117     kristaps   84:        p = calloc(1, sizeof(struct termp));
                     85:        if (NULL == p) {
1.120     kristaps   86:                perror(NULL);
1.117     kristaps   87:                exit(EXIT_FAILURE);
                     88:        }
1.141     kristaps   89:
1.71      kristaps   90:        p->enc = enc;
                     91:        return(p);
1.14      kristaps   92: }
                     93:
                     94:
1.71      kristaps   95: /*
                     96:  * Flush a line of text.  A "line" is loosely defined as being something
                     97:  * that should be followed by a newline, regardless of whether it's
                     98:  * broken apart by newlines getting there.  A line can also be a
1.130     kristaps   99:  * fragment of a columnar list (`Bl -tag' or `Bl -column'), which does
                    100:  * not have a trailing newline.
1.71      kristaps  101:  *
1.130     kristaps  102:  * The following flags may be specified:
1.71      kristaps  103:  *
                    104:  *  - TERMP_NOLPAD: when beginning to write the line, don't left-pad the
                    105:  *    offset value.  This is useful when doing columnar lists where the
                    106:  *    prior column has right-padded.
                    107:  *
                    108:  *  - TERMP_NOBREAK: this is the most important and is used when making
                    109:  *    columns.  In short: don't print a newline and instead pad to the
                    110:  *    right margin.  Used in conjunction with TERMP_NOLPAD.
                    111:  *
1.91      kristaps  112:  *  - TERMP_TWOSPACE: when padding, make sure there are at least two
                    113:  *    space characters of padding.  Otherwise, rather break the line.
                    114:  *
1.84      kristaps  115:  *  - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
                    116:  *    the line is overrun, and don't pad-right if it's underrun.
                    117:  *
                    118:  *  - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
                    119:  *    overruning, instead save the position and continue at that point
                    120:  *    when the next invocation.
1.71      kristaps  121:  *
                    122:  *  In-line line breaking:
                    123:  *
                    124:  *  If TERMP_NOBREAK is specified and the line overruns the right
                    125:  *  margin, it will break and pad-right to the right margin after
                    126:  *  writing.  If maxrmargin is violated, it will break and continue
1.114     kristaps  127:  *  writing from the right-margin, which will lead to the above scenario
                    128:  *  upon exit.  Otherwise, the line will break at the right margin.
1.71      kristaps  129:  */
                    130: void
                    131: term_flushln(struct termp *p)
1.53      kristaps  132: {
1.114     kristaps  133:        int              i;     /* current input position in p->buf */
                    134:        size_t           vis;   /* current visual position on output */
                    135:        size_t           vbl;   /* number of blanks to prepend to output */
1.136     schwarze  136:        size_t           vend;  /* end of word visual position on output */
1.114     kristaps  137:        size_t           bp;    /* visual right border position */
                    138:        int              j;     /* temporary loop index */
1.140     kristaps  139:        int              jhy;   /* last hyphen before line overflow */
1.114     kristaps  140:        size_t           maxvis, mmax;
1.53      kristaps  141:
1.71      kristaps  142:        /*
                    143:         * First, establish the maximum columns of "visible" content.
                    144:         * This is usually the difference between the right-margin and
                    145:         * an indentation, but can be, for tagged lists or columns, a
1.115     kristaps  146:         * small set of values.
1.71      kristaps  147:         */
1.53      kristaps  148:
1.71      kristaps  149:        assert(p->offset < p->rmargin);
1.92      kristaps  150:
1.129     kristaps  151:        maxvis = (int)(p->rmargin - p->offset) - p->overstep < 0 ?
1.119     kristaps  152:                /* LINTED */
1.129     kristaps  153:                0 : p->rmargin - p->offset - p->overstep;
                    154:        mmax = (int)(p->maxrmargin - p->offset) - p->overstep < 0 ?
1.119     kristaps  155:                /* LINTED */
1.129     kristaps  156:                0 : p->maxrmargin - p->offset - p->overstep;
1.92      kristaps  157:
1.71      kristaps  158:        bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
1.115     kristaps  159:
1.136     schwarze  160:        /*
                    161:         * Indent the first line of a paragraph.
                    162:         */
                    163:        vbl = p->flags & TERMP_NOLPAD ? 0 : p->offset;
                    164:
1.115     kristaps  165:        /*
                    166:         * FIXME: if bp is zero, we still output the first word before
                    167:         * breaking the line.
                    168:         */
                    169:
1.136     schwarze  170:        vis = vend = i = 0;
                    171:        while (i < (int)p->col) {
1.71      kristaps  172:
                    173:                /*
1.138     schwarze  174:                 * Handle literal tab characters.
                    175:                 */
                    176:                for (j = i; j < (int)p->col; j++) {
                    177:                        if ('\t' != p->buf[j])
                    178:                                break;
                    179:                        vend = (vis/p->tabwidth+1)*p->tabwidth;
                    180:                        vbl += vend - vis;
                    181:                        vis = vend;
                    182:                }
                    183:
                    184:                /*
1.71      kristaps  185:                 * Count up visible word characters.  Control sequences
                    186:                 * (starting with the CSI) aren't counted.  A space
                    187:                 * generates a non-printing word, which is valid (the
                    188:                 * space is printed according to regular spacing rules).
                    189:                 */
                    190:
                    191:                /* LINTED */
1.140     kristaps  192:                for (jhy = 0; j < (int)p->col; j++) {
1.138     schwarze  193:                        if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j])
1.71      kristaps  194:                                break;
1.140     kristaps  195:                        if (8 != p->buf[j]) {
                    196:                                if (vend > vis && vend < bp &&
                    197:                                    ASCII_HYPH == p->buf[j])
                    198:                                        jhy = j;
                    199:                                vend++;
                    200:                        } else
1.136     schwarze  201:                                vend--;
1.71      kristaps  202:                }
1.53      kristaps  203:
1.71      kristaps  204:                /*
1.81      kristaps  205:                 * Find out whether we would exceed the right margin.
1.136     schwarze  206:                 * If so, break to the next line.
1.81      kristaps  207:                 */
1.140     kristaps  208:                if (vend > bp && 0 == jhy && vis > 0) {
1.136     schwarze  209:                        vend -= vis;
1.146     kristaps  210:                        (*p->endline)(p);
1.81      kristaps  211:                        if (TERMP_NOBREAK & p->flags) {
1.139     schwarze  212:                                p->viscol = p->rmargin;
1.146     kristaps  213:                                (*p->advance)(p, p->rmargin);
1.136     schwarze  214:                                vend += p->rmargin - p->offset;
1.81      kristaps  215:                        } else {
1.139     schwarze  216:                                p->viscol = 0;
1.136     schwarze  217:                                vbl = p->offset;
1.81      kristaps  218:                        }
1.130     kristaps  219:
1.129     kristaps  220:                        /* Remove the p->overstep width. */
1.130     kristaps  221:
1.112     kristaps  222:                        bp += (int)/* LINTED */
1.129     kristaps  223:                                p->overstep;
                    224:                        p->overstep = 0;
1.71      kristaps  225:                }
1.53      kristaps  226:
1.138     schwarze  227:                /*
                    228:                 * Skip leading tabs, they were handled above.
                    229:                 */
                    230:                while (i < (int)p->col && '\t' == p->buf[i])
                    231:                        i++;
                    232:
1.130     kristaps  233:                /* Write out the [remaining] word. */
1.136     schwarze  234:                for ( ; i < (int)p->col; i++) {
1.140     kristaps  235:                        if (vend > bp && jhy > 0 && i > jhy)
                    236:                                break;
1.138     schwarze  237:                        if ('\t' == p->buf[i])
                    238:                                break;
1.136     schwarze  239:                        if (' ' == p->buf[i]) {
                    240:                                while (' ' == p->buf[i]) {
                    241:                                        vbl++;
                    242:                                        i++;
                    243:                                }
1.71      kristaps  244:                                break;
1.136     schwarze  245:                        }
                    246:                        if (ASCII_NBRSP == p->buf[i]) {
                    247:                                vbl++;
                    248:                                continue;
                    249:                        }
1.130     kristaps  250:
1.136     schwarze  251:                        /*
                    252:                         * Now we definitely know there will be
                    253:                         * printable characters to output,
                    254:                         * so write preceding white space now.
                    255:                         */
                    256:                        if (vbl) {
1.146     kristaps  257:                                (*p->advance)(p, vbl);
1.139     schwarze  258:                                p->viscol += vbl;
1.136     schwarze  259:                                vbl = 0;
                    260:                        }
1.140     kristaps  261:
                    262:                        if (ASCII_HYPH == p->buf[i])
1.146     kristaps  263:                                (*p->letter)(p, '-');
1.140     kristaps  264:                        else
1.146     kristaps  265:                                (*p->letter)(p, p->buf[i]);
1.140     kristaps  266:
1.139     schwarze  267:                        p->viscol += 1;
1.136     schwarze  268:                }
                    269:                vend += vbl;
                    270:                vis = vend;
1.71      kristaps  271:        }
1.111     kristaps  272:
1.91      kristaps  273:        p->col = 0;
1.129     kristaps  274:        p->overstep = 0;
1.15      kristaps  275:
1.91      kristaps  276:        if ( ! (TERMP_NOBREAK & p->flags)) {
1.139     schwarze  277:                p->viscol = 0;
1.146     kristaps  278:                (*p->endline)(p);
1.15      kristaps  279:                return;
1.71      kristaps  280:        }
1.15      kristaps  281:
1.91      kristaps  282:        if (TERMP_HANG & p->flags) {
                    283:                /* We need one blank after the tag. */
1.129     kristaps  284:                p->overstep = /* LINTED */
1.92      kristaps  285:                        vis - maxvis + 1;
1.91      kristaps  286:
                    287:                /*
                    288:                 * Behave exactly the same way as groff:
1.92      kristaps  289:                 * If we have overstepped the margin, temporarily move
                    290:                 * it to the right and flag the rest of the line to be
                    291:                 * shorter.
1.91      kristaps  292:                 * If we landed right at the margin, be happy.
1.92      kristaps  293:                 * If we are one step before the margin, temporarily
                    294:                 * move it one step LEFT and flag the rest of the line
                    295:                 * to be longer.
1.91      kristaps  296:                 */
1.129     kristaps  297:                if (p->overstep >= -1) {
                    298:                        assert((int)maxvis + p->overstep >= 0);
1.92      kristaps  299:                        /* LINTED */
1.129     kristaps  300:                        maxvis += p->overstep;
1.92      kristaps  301:                } else
1.129     kristaps  302:                        p->overstep = 0;
1.91      kristaps  303:
                    304:        } else if (TERMP_DANGLE & p->flags)
                    305:                return;
1.15      kristaps  306:
1.92      kristaps  307:        /* Right-pad. */
                    308:        if (maxvis > vis + /* LINTED */
1.139     schwarze  309:                        ((TERMP_TWOSPACE & p->flags) ? 1 : 0)) {
                    310:                p->viscol += maxvis - vis;
1.146     kristaps  311:                (*p->advance)(p, maxvis - vis);
1.142     kristaps  312:                vis += (maxvis - vis);
1.139     schwarze  313:        } else {        /* ...or newline break. */
1.146     kristaps  314:                (*p->endline)(p);
1.139     schwarze  315:                p->viscol = p->rmargin;
1.146     kristaps  316:                (*p->advance)(p, p->rmargin);
1.91      kristaps  317:        }
1.15      kristaps  318: }
                    319:
                    320:
1.71      kristaps  321: /*
                    322:  * A newline only breaks an existing line; it won't assert vertical
                    323:  * space.  All data in the output buffer is flushed prior to the newline
                    324:  * assertion.
                    325:  */
                    326: void
                    327: term_newln(struct termp *p)
1.15      kristaps  328: {
                    329:
1.71      kristaps  330:        p->flags |= TERMP_NOSPACE;
1.139     schwarze  331:        if (0 == p->col && 0 == p->viscol) {
1.71      kristaps  332:                p->flags &= ~TERMP_NOLPAD;
1.15      kristaps  333:                return;
1.16      kristaps  334:        }
1.71      kristaps  335:        term_flushln(p);
                    336:        p->flags &= ~TERMP_NOLPAD;
1.16      kristaps  337: }
                    338:
                    339:
1.71      kristaps  340: /*
                    341:  * Asserts a vertical space (a full, empty line-break between lines).
                    342:  * Note that if used twice, this will cause two blank spaces and so on.
                    343:  * All data in the output buffer is flushed prior to the newline
                    344:  * assertion.
                    345:  */
                    346: void
                    347: term_vspace(struct termp *p)
1.16      kristaps  348: {
                    349:
1.62      kristaps  350:        term_newln(p);
1.139     schwarze  351:        p->viscol = 0;
1.146     kristaps  352:        (*p->endline)(p);
1.16      kristaps  353: }
                    354:
                    355:
1.71      kristaps  356: static void
1.125     kristaps  357: spec(struct termp *p, const char *word, size_t len)
1.17      kristaps  358: {
1.71      kristaps  359:        const char      *rhs;
                    360:        size_t           sz;
1.17      kristaps  361:
1.101     kristaps  362:        rhs = chars_a2ascii(p->symtab, word, len, &sz);
1.125     kristaps  363:        if (rhs)
                    364:                encode(p, rhs, sz);
1.94      kristaps  365: }
                    366:
                    367:
                    368: static void
1.125     kristaps  369: res(struct termp *p, const char *word, size_t len)
1.94      kristaps  370: {
                    371:        const char      *rhs;
                    372:        size_t           sz;
                    373:
1.101     kristaps  374:        rhs = chars_a2res(p->symtab, word, len, &sz);
1.125     kristaps  375:        if (rhs)
                    376:                encode(p, rhs, sz);
                    377: }
                    378:
                    379:
                    380: void
                    381: term_fontlast(struct termp *p)
                    382: {
                    383:        enum termfont    f;
                    384:
                    385:        f = p->fontl;
                    386:        p->fontl = p->fontq[p->fonti];
                    387:        p->fontq[p->fonti] = f;
                    388: }
                    389:
                    390:
                    391: void
                    392: term_fontrepl(struct termp *p, enum termfont f)
                    393: {
                    394:
                    395:        p->fontl = p->fontq[p->fonti];
                    396:        p->fontq[p->fonti] = f;
                    397: }
                    398:
                    399:
                    400: void
                    401: term_fontpush(struct termp *p, enum termfont f)
                    402: {
                    403:
                    404:        assert(p->fonti + 1 < 10);
                    405:        p->fontl = p->fontq[p->fonti];
                    406:        p->fontq[++p->fonti] = f;
                    407: }
                    408:
                    409:
                    410: const void *
                    411: term_fontq(struct termp *p)
                    412: {
                    413:
                    414:        return(&p->fontq[p->fonti]);
                    415: }
                    416:
                    417:
                    418: enum termfont
                    419: term_fonttop(struct termp *p)
                    420: {
                    421:
                    422:        return(p->fontq[p->fonti]);
                    423: }
                    424:
                    425:
                    426: void
                    427: term_fontpopq(struct termp *p, const void *key)
                    428: {
                    429:
                    430:        while (p->fonti >= 0 && key != &p->fontq[p->fonti])
                    431:                p->fonti--;
                    432:        assert(p->fonti >= 0);
                    433: }
1.94      kristaps  434:
1.125     kristaps  435:
                    436: void
                    437: term_fontpop(struct termp *p)
                    438: {
                    439:
                    440:        assert(p->fonti);
                    441:        p->fonti--;
1.17      kristaps  442: }
                    443:
                    444:
1.71      kristaps  445: /*
                    446:  * Handle pwords, partial words, which may be either a single word or a
                    447:  * phrase that cannot be broken down (such as a literal string).  This
                    448:  * handles word styling.
                    449:  */
1.86      kristaps  450: void
                    451: term_word(struct termp *p, const char *word)
1.65      kristaps  452: {
1.124     kristaps  453:        const char      *sv, *seq;
1.125     kristaps  454:        int              sz;
1.124     kristaps  455:        size_t           ssz;
                    456:        enum roffdeco    deco;
1.71      kristaps  457:
1.100     kristaps  458:        sv = word;
                    459:
1.123     kristaps  460:        if (word[0] && '\0' == word[1])
1.100     kristaps  461:                switch (word[0]) {
                    462:                case('.'):
                    463:                        /* FALLTHROUGH */
                    464:                case(','):
                    465:                        /* FALLTHROUGH */
                    466:                case(';'):
                    467:                        /* FALLTHROUGH */
                    468:                case(':'):
                    469:                        /* FALLTHROUGH */
                    470:                case('?'):
                    471:                        /* FALLTHROUGH */
                    472:                case('!'):
                    473:                        /* FALLTHROUGH */
                    474:                case(')'):
                    475:                        /* FALLTHROUGH */
                    476:                case(']'):
                    477:                        if ( ! (TERMP_IGNDELIM & p->flags))
                    478:                                p->flags |= TERMP_NOSPACE;
                    479:                        break;
                    480:                default:
                    481:                        break;
                    482:                }
1.65      kristaps  483:
1.133     kristaps  484:        if ( ! (TERMP_NOSPACE & p->flags)) {
1.125     kristaps  485:                bufferc(p, ' ');
1.133     kristaps  486:                if (TERMP_SENTENCE & p->flags)
                    487:                        bufferc(p, ' ');
                    488:        }
1.65      kristaps  489:
1.71      kristaps  490:        if ( ! (p->flags & TERMP_NONOSPACE))
                    491:                p->flags &= ~TERMP_NOSPACE;
1.133     kristaps  492:
                    493:        p->flags &= ~TERMP_SENTENCE;
1.65      kristaps  494:
1.125     kristaps  495:        /* FIXME: use strcspn. */
1.124     kristaps  496:
                    497:        while (*word) {
                    498:                if ('\\' != *word) {
1.125     kristaps  499:                        encode(p, word, 1);
1.124     kristaps  500:                        word++;
                    501:                        continue;
                    502:                }
                    503:
                    504:                seq = ++word;
                    505:                sz = a2roffdeco(&deco, &seq, &ssz);
                    506:
                    507:                switch (deco) {
                    508:                case (DECO_RESERVED):
1.125     kristaps  509:                        res(p, seq, ssz);
1.124     kristaps  510:                        break;
                    511:                case (DECO_SPECIAL):
1.125     kristaps  512:                        spec(p, seq, ssz);
1.124     kristaps  513:                        break;
                    514:                case (DECO_BOLD):
1.125     kristaps  515:                        term_fontrepl(p, TERMFONT_BOLD);
1.124     kristaps  516:                        break;
                    517:                case (DECO_ITALIC):
1.125     kristaps  518:                        term_fontrepl(p, TERMFONT_UNDER);
1.124     kristaps  519:                        break;
                    520:                case (DECO_ROMAN):
1.125     kristaps  521:                        term_fontrepl(p, TERMFONT_NONE);
1.124     kristaps  522:                        break;
                    523:                case (DECO_PREVIOUS):
1.125     kristaps  524:                        term_fontlast(p);
1.124     kristaps  525:                        break;
                    526:                default:
                    527:                        break;
                    528:                }
1.127     kristaps  529:
1.124     kristaps  530:                word += sz;
1.127     kristaps  531:                if (DECO_NOSPACE == deco && '\0' == *word)
                    532:                        p->flags |= TERMP_NOSPACE;
1.124     kristaps  533:        }
1.65      kristaps  534:
1.131     kristaps  535:        /*
                    536:         * Note that we don't process the pipe: the parser sees it as
                    537:         * punctuation, but we don't in terms of typography.
                    538:         */
1.100     kristaps  539:        if (sv[0] && 0 == sv[1])
                    540:                switch (sv[0]) {
                    541:                case('('):
                    542:                        /* FALLTHROUGH */
                    543:                case('['):
                    544:                        p->flags |= TERMP_NOSPACE;
                    545:                        break;
                    546:                default:
                    547:                        break;
                    548:                }
1.65      kristaps  549: }
                    550:
                    551:
1.71      kristaps  552: static void
1.125     kristaps  553: adjbuf(struct termp *p, size_t sz)
1.51      kristaps  554: {
                    555:
1.125     kristaps  556:        if (0 == p->maxcols)
                    557:                p->maxcols = 1024;
                    558:        while (sz >= p->maxcols)
                    559:                p->maxcols <<= 2;
                    560:
                    561:        p->buf = realloc(p->buf, p->maxcols);
                    562:        if (NULL == p->buf) {
                    563:                perror(NULL);
                    564:                exit(EXIT_FAILURE);
1.71      kristaps  565:        }
1.51      kristaps  566: }
                    567:
1.79      kristaps  568:
                    569: static void
1.125     kristaps  570: buffera(struct termp *p, const char *word, size_t sz)
1.79      kristaps  571: {
1.125     kristaps  572:
                    573:        if (p->col + sz >= p->maxcols)
                    574:                adjbuf(p, p->col + sz);
                    575:
1.126     kristaps  576:        memcpy(&p->buf[(int)p->col], word, sz);
1.125     kristaps  577:        p->col += sz;
                    578: }
                    579:
                    580:
                    581: static void
                    582: bufferc(struct termp *p, char c)
                    583: {
                    584:
                    585:        if (p->col + 1 >= p->maxcols)
                    586:                adjbuf(p, p->col + 1);
                    587:
1.126     kristaps  588:        p->buf[(int)p->col++] = c;
1.125     kristaps  589: }
                    590:
                    591:
                    592: static void
                    593: encode(struct termp *p, const char *word, size_t sz)
                    594: {
                    595:        enum termfont     f;
                    596:        int               i;
                    597:
                    598:        /*
                    599:         * Encode and buffer a string of characters.  If the current
                    600:         * font mode is unset, buffer directly, else encode then buffer
                    601:         * character by character.
                    602:         */
                    603:
1.147     kristaps  604:        if (TERMFONT_NONE == (f = term_fonttop(p))) {
1.125     kristaps  605:                buffera(p, word, sz);
                    606:                return;
                    607:        }
                    608:
                    609:        for (i = 0; i < (int)sz; i++) {
                    610:                if ( ! isgraph((u_char)word[i])) {
                    611:                        bufferc(p, word[i]);
                    612:                        continue;
1.79      kristaps  613:                }
1.125     kristaps  614:
                    615:                if (TERMFONT_UNDER == f)
                    616:                        bufferc(p, '_');
                    617:                else
                    618:                        bufferc(p, word[i]);
                    619:
                    620:                bufferc(p, 8);
                    621:                bufferc(p, word[i]);
1.79      kristaps  622:        }
                    623: }
1.106     kristaps  624:
                    625:
1.107     kristaps  626: size_t
1.149   ! kristaps  627: term_len(const struct termp *p, size_t sz)
        !           628: {
        !           629:
        !           630:        return((*p->width)(p, ' ') * sz);
        !           631: }
        !           632:
        !           633:
        !           634: size_t
        !           635: term_strlen(const struct termp *p, const char *cp)
        !           636: {
        !           637:        size_t           sz;
        !           638:
        !           639:        for (sz = 0; *cp; cp++)
        !           640:                sz += (*p->width)(p, *cp);
        !           641:
        !           642:        return(sz);
        !           643: }
        !           644:
        !           645:
        !           646: size_t
        !           647: term_vspan(const struct termp *p, const struct roffsu *su)
1.106     kristaps  648: {
                    649:        double           r;
                    650:
1.107     kristaps  651:        switch (su->unit) {
1.106     kristaps  652:        case (SCALE_CM):
1.107     kristaps  653:                r = su->scale * 2;
1.106     kristaps  654:                break;
                    655:        case (SCALE_IN):
1.107     kristaps  656:                r = su->scale * 6;
1.106     kristaps  657:                break;
                    658:        case (SCALE_PC):
1.107     kristaps  659:                r = su->scale;
1.106     kristaps  660:                break;
                    661:        case (SCALE_PT):
1.107     kristaps  662:                r = su->scale / 8;
1.106     kristaps  663:                break;
                    664:        case (SCALE_MM):
1.107     kristaps  665:                r = su->scale / 1000;
1.106     kristaps  666:                break;
                    667:        case (SCALE_VS):
1.107     kristaps  668:                r = su->scale;
1.106     kristaps  669:                break;
                    670:        default:
1.107     kristaps  671:                r = su->scale - 1;
1.106     kristaps  672:                break;
                    673:        }
                    674:
                    675:        if (r < 0.0)
                    676:                r = 0.0;
1.107     kristaps  677:        return(/* LINTED */(size_t)
1.106     kristaps  678:                        r);
                    679: }
                    680:
                    681:
1.107     kristaps  682: size_t
1.149   ! kristaps  683: term_hspan(const struct termp *p, const struct roffsu *su)
1.106     kristaps  684: {
                    685:        double           r;
                    686:
1.108     kristaps  687:        /* XXX: CM, IN, and PT are approximations. */
                    688:
1.107     kristaps  689:        switch (su->unit) {
1.106     kristaps  690:        case (SCALE_CM):
1.108     kristaps  691:                r = 4 * su->scale;
1.106     kristaps  692:                break;
                    693:        case (SCALE_IN):
1.108     kristaps  694:                /* XXX: this is an approximation. */
                    695:                r = 10 * su->scale;
1.106     kristaps  696:                break;
                    697:        case (SCALE_PC):
1.108     kristaps  698:                r = (10 * su->scale) / 6;
1.106     kristaps  699:                break;
                    700:        case (SCALE_PT):
1.108     kristaps  701:                r = (10 * su->scale) / 72;
1.106     kristaps  702:                break;
                    703:        case (SCALE_MM):
1.107     kristaps  704:                r = su->scale / 1000; /* FIXME: double-check. */
1.106     kristaps  705:                break;
                    706:        case (SCALE_VS):
1.107     kristaps  707:                r = su->scale * 2 - 1; /* FIXME: double-check. */
1.106     kristaps  708:                break;
                    709:        default:
1.107     kristaps  710:                r = su->scale;
1.106     kristaps  711:                break;
                    712:        }
                    713:
                    714:        if (r < 0.0)
                    715:                r = 0.0;
1.107     kristaps  716:        return((size_t)/* LINTED */
1.106     kristaps  717:                        r);
                    718: }
                    719:
                    720:

CVSweb