[BACK]Return to man_term.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/man_term.c, Revision 1.18

1.18    ! schwarze    1: /*     $Id: man_term.c,v 1.17 2009/10/19 21:43:16 schwarze Exp $ */
1.1       kristaps    2: /*
1.2       schwarze    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.2       schwarze    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.2       schwarze    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.13      schwarze   17: #include <sys/types.h>
                     18:
1.1       kristaps   19: #include <assert.h>
1.11      schwarze   20: #include <ctype.h>
1.1       kristaps   21: #include <err.h>
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25:
1.18    ! schwarze   26: #include "out.h"
        !            27: #include "man.h"
1.1       kristaps   28: #include "term.h"
1.18    ! schwarze   29: #include "chars.h"
        !            30: #include "main.h"
1.10      schwarze   31:
                     32: #define        INDENT            7
                     33: #define        HALFINDENT        3
1.1       kristaps   34:
1.11      schwarze   35: struct mtermp {
                     36:        int               fl;
                     37: #define        MANT_LITERAL     (1 << 0)
1.13      schwarze   38:        /*
                     39:         * Default amount to indent the left margin after leading text
                     40:         * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
                     41:         * indent).  This needs to be saved because `HP' and so on, if
                     42:         * not having a specified value, must default.
                     43:         *
                     44:         * Note that this is the indentation AFTER the left offset, so
                     45:         * the total offset is usually offset + lmargin.
                     46:         */
                     47:        size_t            lmargin;
                     48:        /*
                     49:         * The default offset, i.e., the amount between any text and the
                     50:         * page boundary.
                     51:         */
                     52:        size_t            offset;
1.11      schwarze   53: };
                     54:
1.1       kristaps   55: #define        DECL_ARGS         struct termp *p, \
1.11      schwarze   56:                          struct mtermp *mt, \
1.1       kristaps   57:                          const struct man_node *n, \
                     58:                          const struct man_meta *m
                     59:
                     60: struct termact {
                     61:        int             (*pre)(DECL_ARGS);
                     62:        void            (*post)(DECL_ARGS);
                     63: };
                     64:
1.18    ! schwarze   65: static int               arg2width(const struct man_node *);
        !            66: static int               arg2height(const struct man_node *);
        !            67:
        !            68: static void              print_head(struct termp *,
        !            69:                                const struct man_meta *);
        !            70: static void              print_body(DECL_ARGS);
        !            71: static void              print_node(DECL_ARGS);
        !            72: static void              print_foot(struct termp *,
        !            73:                                const struct man_meta *);
        !            74: static void              print_bvspace(struct termp *,
        !            75:                                const struct man_node *);
        !            76:
1.1       kristaps   77: static int               pre_B(DECL_ARGS);
                     78: static int               pre_BI(DECL_ARGS);
1.11      schwarze   79: static int               pre_HP(DECL_ARGS);
1.1       kristaps   80: static int               pre_I(DECL_ARGS);
                     81: static int               pre_IP(DECL_ARGS);
                     82: static int               pre_IR(DECL_ARGS);
                     83: static int               pre_PP(DECL_ARGS);
                     84: static int               pre_RB(DECL_ARGS);
                     85: static int               pre_RI(DECL_ARGS);
1.13      schwarze   86: static int               pre_RS(DECL_ARGS);
1.1       kristaps   87: static int               pre_SH(DECL_ARGS);
                     88: static int               pre_SS(DECL_ARGS);
                     89: static int               pre_TP(DECL_ARGS);
1.11      schwarze   90: static int               pre_br(DECL_ARGS);
                     91: static int               pre_fi(DECL_ARGS);
1.14      schwarze   92: static int               pre_ign(DECL_ARGS);
1.11      schwarze   93: static int               pre_nf(DECL_ARGS);
                     94: static int               pre_r(DECL_ARGS);
                     95: static int               pre_sp(DECL_ARGS);
1.1       kristaps   96:
                     97: static void              post_B(DECL_ARGS);
                     98: static void              post_I(DECL_ARGS);
1.11      schwarze   99: static void              post_IP(DECL_ARGS);
                    100: static void              post_HP(DECL_ARGS);
1.13      schwarze  101: static void              post_RS(DECL_ARGS);
1.1       kristaps  102: static void              post_SH(DECL_ARGS);
                    103: static void              post_SS(DECL_ARGS);
1.11      schwarze  104: static void              post_TP(DECL_ARGS);
                    105: static void              post_i(DECL_ARGS);
1.1       kristaps  106:
1.17      schwarze  107: static const struct termact termacts[MAN_MAX] = {
1.8       schwarze  108:        { pre_br, NULL }, /* br */
1.1       kristaps  109:        { NULL, NULL }, /* TH */
                    110:        { pre_SH, post_SH }, /* SH */
                    111:        { pre_SS, post_SS }, /* SS */
1.11      schwarze  112:        { pre_TP, post_TP }, /* TP */
1.1       kristaps  113:        { pre_PP, NULL }, /* LP */
                    114:        { pre_PP, NULL }, /* PP */
                    115:        { pre_PP, NULL }, /* P */
1.11      schwarze  116:        { pre_IP, post_IP }, /* IP */
                    117:        { pre_HP, post_HP }, /* HP */
1.1       kristaps  118:        { NULL, NULL }, /* SM */
                    119:        { pre_B, post_B }, /* SB */
                    120:        { pre_BI, NULL }, /* BI */
1.17      schwarze  121:        { pre_BI, NULL }, /* IB */
                    122:        { pre_RB, NULL }, /* BR */
1.1       kristaps  123:        { pre_RB, NULL }, /* RB */
                    124:        { NULL, NULL }, /* R */
                    125:        { pre_B, post_B }, /* B */
                    126:        { pre_I, post_I }, /* I */
                    127:        { pre_IR, NULL }, /* IR */
                    128:        { pre_RI, NULL }, /* RI */
1.13      schwarze  129:        { NULL, NULL }, /* na */
1.11      schwarze  130:        { pre_I, post_i }, /* i */
                    131:        { pre_sp, NULL }, /* sp */
                    132:        { pre_nf, NULL }, /* nf */
                    133:        { pre_fi, NULL }, /* fi */
                    134:        { pre_r, NULL }, /* r */
1.13      schwarze  135:        { NULL, NULL }, /* RE */
                    136:        { pre_RS, post_RS }, /* RS */
1.14      schwarze  137:        { pre_ign, NULL }, /* DT */
                    138:        { pre_ign, NULL }, /* UC */
1.1       kristaps  139: };
1.11      schwarze  140:
1.1       kristaps  141:
                    142:
1.16      schwarze  143: void
1.18    ! schwarze  144: terminal_man(void *arg, const struct man *man)
1.1       kristaps  145: {
1.18    ! schwarze  146:        struct termp            *p;
        !           147:        const struct man_node   *n;
        !           148:        const struct man_meta   *m;
        !           149:        struct mtermp            mt;
        !           150:
        !           151:        p = (struct termp *)arg;
        !           152:
        !           153:        if (NULL == p->symtab)
        !           154:                switch (p->enc) {
        !           155:                case (TERMENC_ASCII):
        !           156:                        p->symtab = chars_init(CHARS_ASCII);
        !           157:                        break;
        !           158:                default:
        !           159:                        abort();
        !           160:                        /* NOTREACHED */
        !           161:                }
        !           162:
        !           163:        n = man_node(man);
        !           164:        m = man_meta(man);
1.1       kristaps  165:
1.18    ! schwarze  166:        print_head(p, m);
1.1       kristaps  167:        p->flags |= TERMP_NOSPACE;
1.11      schwarze  168:
                    169:        mt.fl = 0;
                    170:        mt.lmargin = INDENT;
1.13      schwarze  171:        mt.offset = INDENT;
1.11      schwarze  172:
1.18    ! schwarze  173:        if (n->child)
        !           174:                print_body(p, &mt, n->child, m);
        !           175:        print_foot(p, m);
1.1       kristaps  176: }
                    177:
                    178:
1.18    ! schwarze  179: static int
        !           180: arg2height(const struct man_node *n)
1.11      schwarze  181: {
1.18    ! schwarze  182:        struct roffsu    su;
1.11      schwarze  183:
1.18    ! schwarze  184:        assert(MAN_TEXT == n->type);
        !           185:        assert(n->string);
        !           186:        if ( ! a2roffsu(n->string, &su, SCALE_VS))
        !           187:                SCALE_VS_INIT(&su, strlen(n->string));
1.11      schwarze  188:
1.18    ! schwarze  189:        return((int)term_vspan(&su));
1.11      schwarze  190: }
                    191:
                    192:
                    193: static int
1.18    ! schwarze  194: arg2width(const struct man_node *n)
1.11      schwarze  195: {
1.18    ! schwarze  196:        struct roffsu    su;
1.11      schwarze  197:
                    198:        assert(MAN_TEXT == n->type);
                    199:        assert(n->string);
1.18    ! schwarze  200:        if ( ! a2roffsu(n->string, &su, SCALE_BU))
        !           201:                return(-1);
        !           202:
        !           203:        return((int)term_hspan(&su));
        !           204: }
1.11      schwarze  205:
                    206:
1.18    ! schwarze  207: static void
        !           208: print_bvspace(struct termp *p, const struct man_node *n)
        !           209: {
        !           210:        term_newln(p);
1.11      schwarze  211:
1.18    ! schwarze  212:        if (NULL == n->prev)
        !           213:                return;
1.11      schwarze  214:
1.18    ! schwarze  215:        if (MAN_SS == n->prev->tok)
        !           216:                return;
        !           217:        if (MAN_SH == n->prev->tok)
        !           218:                return;
1.11      schwarze  219:
1.18    ! schwarze  220:        term_vspace(p);
1.14      schwarze  221: }
                    222:
                    223:
                    224: /* ARGSUSED */
                    225: static int
                    226: pre_ign(DECL_ARGS)
                    227: {
                    228:
                    229:        return(0);
1.11      schwarze  230: }
                    231:
                    232:
1.1       kristaps  233: /* ARGSUSED */
                    234: static int
                    235: pre_I(DECL_ARGS)
                    236: {
                    237:
1.15      schwarze  238:        p->under++;
1.1       kristaps  239:        return(1);
                    240: }
                    241:
                    242:
                    243: /* ARGSUSED */
1.11      schwarze  244: static int
                    245: pre_r(DECL_ARGS)
                    246: {
                    247:
1.15      schwarze  248:        p->bold = p->under = 0;
1.11      schwarze  249:        return(1);
                    250: }
                    251:
                    252:
                    253: /* ARGSUSED */
                    254: static void
                    255: post_i(DECL_ARGS)
                    256: {
                    257:
                    258:        if (n->nchild)
1.15      schwarze  259:                p->under--;
1.11      schwarze  260: }
                    261:
                    262:
                    263: /* ARGSUSED */
1.1       kristaps  264: static void
                    265: post_I(DECL_ARGS)
                    266: {
                    267:
1.15      schwarze  268:        p->under--;
1.1       kristaps  269: }
                    270:
                    271:
                    272: /* ARGSUSED */
                    273: static int
1.11      schwarze  274: pre_fi(DECL_ARGS)
                    275: {
                    276:
                    277:        mt->fl &= ~MANT_LITERAL;
                    278:        return(1);
                    279: }
                    280:
                    281:
                    282: /* ARGSUSED */
                    283: static int
                    284: pre_nf(DECL_ARGS)
                    285: {
                    286:
                    287:        term_newln(p);
                    288:        mt->fl |= MANT_LITERAL;
                    289:        return(1);
                    290: }
                    291:
                    292:
                    293: /* ARGSUSED */
                    294: static int
1.1       kristaps  295: pre_IR(DECL_ARGS)
                    296: {
                    297:        const struct man_node *nn;
                    298:        int              i;
                    299:
                    300:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
                    301:                if ( ! (i % 2))
1.15      schwarze  302:                        p->under++;
1.1       kristaps  303:                if (i > 0)
                    304:                        p->flags |= TERMP_NOSPACE;
1.11      schwarze  305:                print_node(p, mt, nn, m);
1.1       kristaps  306:                if ( ! (i % 2))
1.15      schwarze  307:                        p->under--;
1.1       kristaps  308:        }
                    309:        return(0);
                    310: }
                    311:
                    312:
                    313: /* ARGSUSED */
                    314: static int
1.17      schwarze  315: pre_RB(DECL_ARGS)
1.1       kristaps  316: {
                    317:        const struct man_node *nn;
                    318:        int              i;
                    319:
                    320:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17      schwarze  321:                if (i % 2 && MAN_RB == n->tok)
                    322:                        p->bold++;
                    323:                else if ( ! (i % 2) && MAN_RB != n->tok)
1.15      schwarze  324:                        p->bold++;
1.17      schwarze  325:
1.1       kristaps  326:                if (i > 0)
                    327:                        p->flags |= TERMP_NOSPACE;
1.17      schwarze  328:
1.11      schwarze  329:                print_node(p, mt, nn, m);
1.17      schwarze  330:
                    331:                if (i % 2 && MAN_RB == n->tok)
1.15      schwarze  332:                        p->bold--;
1.17      schwarze  333:                else if ( ! (i % 2) && MAN_RB != n->tok)
1.15      schwarze  334:                        p->bold--;
1.1       kristaps  335:        }
                    336:        return(0);
                    337: }
                    338:
                    339:
                    340: /* ARGSUSED */
                    341: static int
                    342: pre_RI(DECL_ARGS)
                    343: {
                    344:        const struct man_node *nn;
                    345:        int              i;
                    346:
                    347:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
                    348:                if ( ! (i % 2))
1.15      schwarze  349:                        p->under++;
1.1       kristaps  350:                if (i > 0)
                    351:                        p->flags |= TERMP_NOSPACE;
1.11      schwarze  352:                print_node(p, mt, nn, m);
1.1       kristaps  353:                if ( ! (i % 2))
1.15      schwarze  354:                        p->under--;
1.1       kristaps  355:        }
                    356:        return(0);
                    357: }
                    358:
                    359:
                    360: /* ARGSUSED */
                    361: static int
                    362: pre_BI(DECL_ARGS)
                    363: {
1.17      schwarze  364:        const struct man_node   *nn;
                    365:        int                      i;
1.1       kristaps  366:
                    367:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17      schwarze  368:                if (i % 2 && MAN_BI == n->tok)
1.15      schwarze  369:                        p->under++;
1.17      schwarze  370:                else if (i % 2)
                    371:                        p->bold++;
                    372:                else if (MAN_BI == n->tok)
                    373:                        p->bold++;
1.15      schwarze  374:                else
1.17      schwarze  375:                        p->under++;
                    376:
                    377:                if (i)
1.1       kristaps  378:                        p->flags |= TERMP_NOSPACE;
1.11      schwarze  379:                print_node(p, mt, nn, m);
1.17      schwarze  380:
                    381:                if (i % 2 && MAN_BI == n->tok)
1.15      schwarze  382:                        p->under--;
1.17      schwarze  383:                else if (i % 2)
                    384:                        p->bold--;
                    385:                else if (MAN_BI == n->tok)
                    386:                        p->bold--;
1.15      schwarze  387:                else
1.17      schwarze  388:                        p->under--;
1.1       kristaps  389:        }
                    390:        return(0);
                    391: }
                    392:
                    393:
                    394: /* ARGSUSED */
                    395: static int
                    396: pre_B(DECL_ARGS)
                    397: {
                    398:
1.15      schwarze  399:        p->bold++;
1.1       kristaps  400:        return(1);
                    401: }
                    402:
                    403:
                    404: /* ARGSUSED */
                    405: static void
                    406: post_B(DECL_ARGS)
                    407: {
                    408:
1.15      schwarze  409:        p->bold--;
1.1       kristaps  410: }
                    411:
                    412:
                    413: /* ARGSUSED */
                    414: static int
1.11      schwarze  415: pre_sp(DECL_ARGS)
                    416: {
                    417:        int              i, len;
                    418:
1.18    ! schwarze  419:        len = n->child ? arg2height(n->child) : 1;
1.11      schwarze  420:
                    421:        if (0 == len)
                    422:                term_newln(p);
                    423:        for (i = 0; i < len; i++)
                    424:                term_vspace(p);
                    425:
                    426:        return(0);
                    427: }
                    428:
                    429:
                    430: /* ARGSUSED */
                    431: static int
1.8       schwarze  432: pre_br(DECL_ARGS)
                    433: {
                    434:
                    435:        term_newln(p);
                    436:        return(0);
                    437: }
                    438:
                    439:
                    440: /* ARGSUSED */
                    441: static int
1.11      schwarze  442: pre_HP(DECL_ARGS)
                    443: {
                    444:        size_t                   len;
                    445:        int                      ival;
                    446:        const struct man_node   *nn;
                    447:
                    448:        switch (n->type) {
                    449:        case (MAN_BLOCK):
1.18    ! schwarze  450:                print_bvspace(p, n);
1.11      schwarze  451:                return(1);
                    452:        case (MAN_BODY):
                    453:                p->flags |= TERMP_NOBREAK;
                    454:                p->flags |= TERMP_TWOSPACE;
                    455:                break;
                    456:        default:
                    457:                return(0);
                    458:        }
                    459:
1.13      schwarze  460:        len = mt->lmargin;
1.11      schwarze  461:        ival = -1;
                    462:
                    463:        /* Calculate offset. */
                    464:
                    465:        if (NULL != (nn = n->parent->head->child))
1.18    ! schwarze  466:                if ((ival = arg2width(nn)) >= 0)
1.11      schwarze  467:                        len = (size_t)ival;
                    468:
                    469:        if (0 == len)
                    470:                len = 1;
                    471:
1.13      schwarze  472:        p->offset = mt->offset;
                    473:        p->rmargin = mt->offset + len;
1.11      schwarze  474:
                    475:        if (ival >= 0)
1.13      schwarze  476:                mt->lmargin = (size_t)ival;
1.11      schwarze  477:
                    478:        return(1);
                    479: }
                    480:
                    481:
                    482: /* ARGSUSED */
                    483: static void
                    484: post_HP(DECL_ARGS)
                    485: {
                    486:
                    487:        switch (n->type) {
                    488:        case (MAN_BLOCK):
                    489:                term_flushln(p);
                    490:                break;
                    491:        case (MAN_BODY):
                    492:                term_flushln(p);
                    493:                p->flags &= ~TERMP_NOBREAK;
                    494:                p->flags &= ~TERMP_TWOSPACE;
1.13      schwarze  495:                p->offset = mt->offset;
1.11      schwarze  496:                p->rmargin = p->maxrmargin;
                    497:                break;
                    498:        default:
                    499:                break;
                    500:        }
                    501: }
                    502:
                    503:
                    504: /* ARGSUSED */
                    505: static int
1.1       kristaps  506: pre_PP(DECL_ARGS)
                    507: {
                    508:
1.11      schwarze  509:        switch (n->type) {
                    510:        case (MAN_BLOCK):
                    511:                mt->lmargin = INDENT;
1.18    ! schwarze  512:                print_bvspace(p, n);
1.11      schwarze  513:                break;
                    514:        default:
1.13      schwarze  515:                p->offset = mt->offset;
1.11      schwarze  516:                break;
                    517:        }
                    518:
                    519:        return(1);
1.1       kristaps  520: }
                    521:
                    522:
                    523: /* ARGSUSED */
                    524: static int
                    525: pre_IP(DECL_ARGS)
                    526: {
1.11      schwarze  527:        const struct man_node   *nn;
                    528:        size_t                   len;
                    529:        int                      ival;
                    530:
                    531:        switch (n->type) {
                    532:        case (MAN_BODY):
                    533:                p->flags |= TERMP_NOLPAD;
                    534:                p->flags |= TERMP_NOSPACE;
                    535:                break;
                    536:        case (MAN_HEAD):
                    537:                p->flags |= TERMP_NOBREAK;
                    538:                p->flags |= TERMP_TWOSPACE;
                    539:                break;
                    540:        case (MAN_BLOCK):
1.18    ! schwarze  541:                print_bvspace(p, n);
1.11      schwarze  542:                /* FALLTHROUGH */
                    543:        default:
                    544:                return(1);
                    545:        }
                    546:
1.13      schwarze  547:        len = mt->lmargin;
1.11      schwarze  548:        ival = -1;
                    549:
                    550:        /* Calculate offset. */
                    551:
                    552:        if (NULL != (nn = n->parent->head->child))
                    553:                if (NULL != (nn = nn->next)) {
                    554:                        for ( ; nn->next; nn = nn->next)
                    555:                                /* Do nothing. */ ;
1.18    ! schwarze  556:                        if ((ival = arg2width(nn)) >= 0)
1.11      schwarze  557:                                len = (size_t)ival;
                    558:                }
                    559:
                    560:        switch (n->type) {
                    561:        case (MAN_HEAD):
                    562:                /* Handle zero-width lengths. */
                    563:                if (0 == len)
                    564:                        len = 1;
                    565:
1.13      schwarze  566:                p->offset = mt->offset;
                    567:                p->rmargin = mt->offset + len;
1.11      schwarze  568:                if (ival < 0)
                    569:                        break;
                    570:
                    571:                /* Set the saved left-margin. */
1.13      schwarze  572:                mt->lmargin = (size_t)ival;
1.1       kristaps  573:
1.11      schwarze  574:                /* Don't print the length value. */
                    575:                for (nn = n->child; nn->next; nn = nn->next)
                    576:                        print_node(p, mt, nn, m);
                    577:                return(0);
                    578:        case (MAN_BODY):
1.13      schwarze  579:                p->offset = mt->offset + len;
1.11      schwarze  580:                p->rmargin = p->maxrmargin;
                    581:                break;
                    582:        default:
                    583:                break;
                    584:        }
1.1       kristaps  585:
1.11      schwarze  586:        return(1);
                    587: }
1.1       kristaps  588:
                    589:
1.11      schwarze  590: /* ARGSUSED */
                    591: static void
                    592: post_IP(DECL_ARGS)
                    593: {
1.4       schwarze  594:
1.11      schwarze  595:        switch (n->type) {
                    596:        case (MAN_HEAD):
                    597:                term_flushln(p);
                    598:                p->flags &= ~TERMP_NOBREAK;
                    599:                p->flags &= ~TERMP_TWOSPACE;
                    600:                p->rmargin = p->maxrmargin;
                    601:                break;
                    602:        case (MAN_BODY):
                    603:                term_flushln(p);
                    604:                p->flags &= ~TERMP_NOLPAD;
                    605:                break;
                    606:        default:
                    607:                break;
                    608:        }
1.1       kristaps  609: }
                    610:
                    611:
                    612: /* ARGSUSED */
                    613: static int
                    614: pre_TP(DECL_ARGS)
                    615: {
1.11      schwarze  616:        const struct man_node   *nn;
                    617:        size_t                   len;
                    618:        int                      ival;
                    619:
                    620:        switch (n->type) {
                    621:        case (MAN_HEAD):
                    622:                p->flags |= TERMP_NOBREAK;
                    623:                p->flags |= TERMP_TWOSPACE;
                    624:                break;
                    625:        case (MAN_BODY):
                    626:                p->flags |= TERMP_NOLPAD;
                    627:                p->flags |= TERMP_NOSPACE;
                    628:                break;
                    629:        case (MAN_BLOCK):
1.18    ! schwarze  630:                print_bvspace(p, n);
1.11      schwarze  631:                /* FALLTHROUGH */
                    632:        default:
                    633:                return(1);
                    634:        }
                    635:
                    636:        len = (size_t)mt->lmargin;
                    637:        ival = -1;
                    638:
                    639:        /* Calculate offset. */
1.1       kristaps  640:
1.11      schwarze  641:        if (NULL != (nn = n->parent->head->child))
                    642:                if (NULL != nn->next)
1.18    ! schwarze  643:                        if ((ival = arg2width(nn)) >= 0)
1.11      schwarze  644:                                len = (size_t)ival;
1.8       schwarze  645:
1.11      schwarze  646:        switch (n->type) {
                    647:        case (MAN_HEAD):
                    648:                /* Handle zero-length properly. */
                    649:                if (0 == len)
                    650:                        len = 1;
                    651:
1.13      schwarze  652:                p->offset = mt->offset;
                    653:                p->rmargin = mt->offset + len;
1.11      schwarze  654:
                    655:                /* Don't print same-line elements. */
                    656:                for (nn = n->child; nn; nn = nn->next)
                    657:                        if (nn->line > n->line)
                    658:                                print_node(p, mt, nn, m);
                    659:
                    660:                if (ival >= 0)
1.13      schwarze  661:                        mt->lmargin = (size_t)ival;
1.11      schwarze  662:
                    663:                return(0);
                    664:        case (MAN_BODY):
1.13      schwarze  665:                p->offset = mt->offset + len;
1.11      schwarze  666:                p->rmargin = p->maxrmargin;
                    667:                break;
                    668:        default:
                    669:                break;
                    670:        }
1.1       kristaps  671:
1.11      schwarze  672:        return(1);
                    673: }
1.1       kristaps  674:
                    675:
1.11      schwarze  676: /* ARGSUSED */
                    677: static void
                    678: post_TP(DECL_ARGS)
                    679: {
1.1       kristaps  680:
1.11      schwarze  681:        switch (n->type) {
                    682:        case (MAN_HEAD):
                    683:                term_flushln(p);
                    684:                p->flags &= ~TERMP_NOBREAK;
                    685:                p->flags &= ~TERMP_TWOSPACE;
                    686:                p->rmargin = p->maxrmargin;
                    687:                break;
                    688:        case (MAN_BODY):
                    689:                term_flushln(p);
                    690:                p->flags &= ~TERMP_NOLPAD;
                    691:                break;
                    692:        default:
                    693:                break;
                    694:        }
1.1       kristaps  695: }
                    696:
                    697:
                    698: /* ARGSUSED */
                    699: static int
                    700: pre_SS(DECL_ARGS)
                    701: {
                    702:
1.11      schwarze  703:        switch (n->type) {
                    704:        case (MAN_BLOCK):
                    705:                mt->lmargin = INDENT;
1.13      schwarze  706:                mt->offset = INDENT;
1.11      schwarze  707:                /* If following a prior empty `SS', no vspace. */
                    708:                if (n->prev && MAN_SS == n->prev->tok)
                    709:                        if (NULL == n->prev->body->child)
                    710:                                break;
                    711:                if (NULL == n->prev)
                    712:                        break;
                    713:                term_vspace(p);
                    714:                break;
                    715:        case (MAN_HEAD):
1.15      schwarze  716:                p->bold++;
1.11      schwarze  717:                p->offset = HALFINDENT;
                    718:                break;
                    719:        case (MAN_BODY):
1.13      schwarze  720:                p->offset = mt->offset;
1.11      schwarze  721:                break;
                    722:        default:
                    723:                break;
                    724:        }
                    725:
1.1       kristaps  726:        return(1);
                    727: }
                    728:
                    729:
                    730: /* ARGSUSED */
                    731: static void
                    732: post_SS(DECL_ARGS)
                    733: {
                    734:
1.11      schwarze  735:        switch (n->type) {
                    736:        case (MAN_HEAD):
                    737:                term_newln(p);
1.15      schwarze  738:                p->bold--;
1.11      schwarze  739:                break;
                    740:        case (MAN_BODY):
                    741:                term_newln(p);
                    742:                break;
                    743:        default:
                    744:                break;
                    745:        }
1.1       kristaps  746: }
                    747:
                    748:
                    749: /* ARGSUSED */
                    750: static int
                    751: pre_SH(DECL_ARGS)
                    752: {
                    753:
1.11      schwarze  754:        switch (n->type) {
                    755:        case (MAN_BLOCK):
                    756:                mt->lmargin = INDENT;
1.13      schwarze  757:                mt->offset = INDENT;
1.11      schwarze  758:                /* If following a prior empty `SH', no vspace. */
                    759:                if (n->prev && MAN_SH == n->prev->tok)
                    760:                        if (NULL == n->prev->body->child)
                    761:                                break;
                    762:                term_vspace(p);
                    763:                break;
                    764:        case (MAN_HEAD):
1.15      schwarze  765:                p->bold++;
1.11      schwarze  766:                p->offset = 0;
                    767:                break;
                    768:        case (MAN_BODY):
1.13      schwarze  769:                p->offset = mt->offset;
1.11      schwarze  770:                break;
                    771:        default:
                    772:                break;
                    773:        }
                    774:
1.1       kristaps  775:        return(1);
                    776: }
                    777:
                    778:
                    779: /* ARGSUSED */
                    780: static void
                    781: post_SH(DECL_ARGS)
                    782: {
                    783:
1.11      schwarze  784:        switch (n->type) {
                    785:        case (MAN_HEAD):
                    786:                term_newln(p);
1.15      schwarze  787:                p->bold--;
1.11      schwarze  788:                break;
                    789:        case (MAN_BODY):
                    790:                term_newln(p);
                    791:                break;
                    792:        default:
1.13      schwarze  793:                break;
                    794:        }
                    795: }
                    796:
                    797:
                    798: /* ARGSUSED */
                    799: static int
                    800: pre_RS(DECL_ARGS)
                    801: {
                    802:        const struct man_node   *nn;
                    803:        int                      ival;
                    804:
                    805:        switch (n->type) {
                    806:        case (MAN_BLOCK):
                    807:                term_newln(p);
                    808:                return(1);
                    809:        case (MAN_HEAD):
                    810:                return(0);
                    811:        default:
                    812:                break;
                    813:        }
                    814:
                    815:        if (NULL == (nn = n->parent->head->child)) {
                    816:                mt->offset = mt->lmargin + INDENT;
                    817:                p->offset = mt->offset;
                    818:                return(1);
                    819:        }
                    820:
1.18    ! schwarze  821:        if ((ival = arg2width(nn)) < 0)
1.13      schwarze  822:                return(1);
                    823:
                    824:        mt->offset = INDENT + (size_t)ival;
                    825:        p->offset = mt->offset;
                    826:
                    827:        return(1);
                    828: }
                    829:
                    830:
                    831: /* ARGSUSED */
                    832: static void
                    833: post_RS(DECL_ARGS)
                    834: {
                    835:
                    836:        switch (n->type) {
                    837:        case (MAN_BLOCK):
                    838:                mt->offset = mt->lmargin = INDENT;
                    839:                break;
                    840:        default:
                    841:                term_newln(p);
                    842:                p->offset = INDENT;
1.11      schwarze  843:                break;
                    844:        }
1.1       kristaps  845: }
                    846:
                    847:
                    848: static void
                    849: print_node(DECL_ARGS)
                    850: {
                    851:        int              c, sz;
                    852:
                    853:        c = 1;
                    854:
                    855:        switch (n->type) {
                    856:        case(MAN_TEXT):
                    857:                if (0 == *n->string) {
                    858:                        term_vspace(p);
                    859:                        break;
                    860:                }
                    861:                /*
                    862:                 * Note!  This is hacky.  Here, we recognise the `\c'
                    863:                 * escape embedded in so many -man pages.  It's supposed
                    864:                 * to remove the subsequent space, so we mark NOSPACE if
                    865:                 * it's encountered in the string.
                    866:                 */
                    867:                sz = (int)strlen(n->string);
                    868:                term_word(p, n->string);
                    869:                if (sz >= 2 && n->string[sz - 1] == 'c' &&
                    870:                                n->string[sz - 2] == '\\')
                    871:                        p->flags |= TERMP_NOSPACE;
1.11      schwarze  872:                /* FIXME: this means that macro lines are munged!  */
                    873:                if (MANT_LITERAL & mt->fl) {
                    874:                        p->flags |= TERMP_NOSPACE;
                    875:                        term_flushln(p);
                    876:                }
1.1       kristaps  877:                break;
                    878:        default:
1.11      schwarze  879:                if (termacts[n->tok].pre)
                    880:                        c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1       kristaps  881:                break;
                    882:        }
                    883:
                    884:        if (c && n->child)
1.11      schwarze  885:                print_body(p, mt, n->child, m);
1.1       kristaps  886:
1.11      schwarze  887:        if (MAN_TEXT != n->type)
1.1       kristaps  888:                if (termacts[n->tok].post)
1.11      schwarze  889:                        (*termacts[n->tok].post)(p, mt, n, m);
1.1       kristaps  890: }
                    891:
                    892:
                    893: static void
                    894: print_body(DECL_ARGS)
                    895: {
1.11      schwarze  896:
                    897:        print_node(p, mt, n, m);
1.1       kristaps  898:        if ( ! n->next)
                    899:                return;
1.11      schwarze  900:        print_body(p, mt, n->next, m);
1.1       kristaps  901: }
                    902:
                    903:
                    904: static void
                    905: print_foot(struct termp *p, const struct man_meta *meta)
                    906: {
                    907:        struct tm       *tm;
1.17      schwarze  908:        char             buf[BUFSIZ];
1.1       kristaps  909:
                    910:        tm = localtime(&meta->date);
                    911:
1.3       schwarze  912:        if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
1.17      schwarze  913:                (void)strlcpy(buf, "(invalid date)", BUFSIZ);
1.1       kristaps  914:
                    915:        term_vspace(p);
                    916:
                    917:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
                    918:        p->rmargin = p->maxrmargin - strlen(buf);
                    919:        p->offset = 0;
                    920:
                    921:        if (meta->source)
                    922:                term_word(p, meta->source);
                    923:        if (meta->source)
                    924:                term_word(p, "");
                    925:        term_flushln(p);
                    926:
                    927:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    928:        p->offset = p->rmargin;
                    929:        p->rmargin = p->maxrmargin;
                    930:        p->flags &= ~TERMP_NOBREAK;
                    931:
                    932:        term_word(p, buf);
                    933:        term_flushln(p);
                    934: }
                    935:
                    936:
                    937: static void
                    938: print_head(struct termp *p, const struct man_meta *meta)
                    939: {
                    940:        char            *buf, *title;
                    941:
                    942:        p->rmargin = p->maxrmargin;
                    943:        p->offset = 0;
                    944:
                    945:        if (NULL == (buf = malloc(p->rmargin)))
1.16      schwarze  946:                err(EXIT_FAILURE, "malloc");
1.1       kristaps  947:        if (NULL == (title = malloc(p->rmargin)))
1.16      schwarze  948:                err(EXIT_FAILURE, "malloc");
1.1       kristaps  949:
                    950:        if (meta->vol)
                    951:                (void)strlcpy(buf, meta->vol, p->rmargin);
                    952:        else
                    953:                *buf = 0;
                    954:
                    955:        (void)snprintf(title, p->rmargin, "%s(%d)",
                    956:                        meta->title, meta->msec);
                    957:
                    958:        p->offset = 0;
1.5       schwarze  959:        p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1       kristaps  960:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
                    961:
                    962:        term_word(p, title);
                    963:        term_flushln(p);
                    964:
                    965:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    966:        p->offset = p->rmargin;
                    967:        p->rmargin = p->maxrmargin - strlen(title);
                    968:
                    969:        term_word(p, buf);
                    970:        term_flushln(p);
                    971:
                    972:        p->offset = p->rmargin;
                    973:        p->rmargin = p->maxrmargin;
                    974:        p->flags &= ~TERMP_NOBREAK;
                    975:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    976:
                    977:        term_word(p, title);
                    978:        term_flushln(p);
                    979:
                    980:        p->rmargin = p->maxrmargin;
                    981:        p->offset = 0;
                    982:        p->flags &= ~TERMP_NOSPACE;
                    983:
                    984:        free(title);
                    985:        free(buf);
                    986: }
                    987: