[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.23

1.23    ! schwarze    1: /*     $Id: man_term.c,v 1.22 2010/02/26 12:42:29 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 <stdio.h>
                     22: #include <stdlib.h>
                     23: #include <string.h>
                     24:
1.18      schwarze   25: #include "out.h"
                     26: #include "man.h"
1.1       kristaps   27: #include "term.h"
1.18      schwarze   28: #include "chars.h"
                     29: #include "main.h"
1.10      schwarze   30:
                     31: #define        INDENT            7
                     32: #define        HALFINDENT        3
1.1       kristaps   33:
1.19      schwarze   34: /* FIXME: have PD set the default vspace width. */
                     35:
1.11      schwarze   36: struct mtermp {
                     37:        int               fl;
                     38: #define        MANT_LITERAL     (1 << 0)
1.13      schwarze   39:        /*
                     40:         * Default amount to indent the left margin after leading text
                     41:         * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
                     42:         * indent).  This needs to be saved because `HP' and so on, if
                     43:         * not having a specified value, must default.
                     44:         *
                     45:         * Note that this is the indentation AFTER the left offset, so
                     46:         * the total offset is usually offset + lmargin.
                     47:         */
                     48:        size_t            lmargin;
                     49:        /*
                     50:         * The default offset, i.e., the amount between any text and the
                     51:         * page boundary.
                     52:         */
                     53:        size_t            offset;
1.11      schwarze   54: };
                     55:
1.1       kristaps   56: #define        DECL_ARGS         struct termp *p, \
1.11      schwarze   57:                          struct mtermp *mt, \
1.1       kristaps   58:                          const struct man_node *n, \
                     59:                          const struct man_meta *m
                     60:
                     61: struct termact {
                     62:        int             (*pre)(DECL_ARGS);
                     63:        void            (*post)(DECL_ARGS);
                     64: };
                     65:
1.19      schwarze   66: static int               a2width(const struct man_node *);
                     67: static int               a2height(const struct man_node *);
1.18      schwarze   68:
1.19      schwarze   69: static void              print_man_head(struct termp *,
1.18      schwarze   70:                                const struct man_meta *);
1.21      schwarze   71: static void              print_man_nodelist(DECL_ARGS);
1.19      schwarze   72: static void              print_man_node(DECL_ARGS);
                     73: static void              print_man_foot(struct termp *,
1.18      schwarze   74:                                const struct man_meta *);
                     75: static void              print_bvspace(struct termp *,
                     76:                                const struct man_node *);
                     77:
1.1       kristaps   78: static int               pre_B(DECL_ARGS);
                     79: static int               pre_BI(DECL_ARGS);
1.11      schwarze   80: static int               pre_HP(DECL_ARGS);
1.1       kristaps   81: static int               pre_I(DECL_ARGS);
                     82: static int               pre_IP(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_sp(DECL_ARGS);
1.1       kristaps   95:
1.11      schwarze   96: static void              post_IP(DECL_ARGS);
                     97: static void              post_HP(DECL_ARGS);
1.13      schwarze   98: static void              post_RS(DECL_ARGS);
1.1       kristaps   99: static void              post_SH(DECL_ARGS);
                    100: static void              post_SS(DECL_ARGS);
1.11      schwarze  101: static void              post_TP(DECL_ARGS);
1.1       kristaps  102:
1.17      schwarze  103: static const struct termact termacts[MAN_MAX] = {
1.8       schwarze  104:        { pre_br, NULL }, /* br */
1.1       kristaps  105:        { NULL, NULL }, /* TH */
                    106:        { pre_SH, post_SH }, /* SH */
                    107:        { pre_SS, post_SS }, /* SS */
1.11      schwarze  108:        { pre_TP, post_TP }, /* TP */
1.1       kristaps  109:        { pre_PP, NULL }, /* LP */
                    110:        { pre_PP, NULL }, /* PP */
                    111:        { pre_PP, NULL }, /* P */
1.11      schwarze  112:        { pre_IP, post_IP }, /* IP */
                    113:        { pre_HP, post_HP }, /* HP */
1.1       kristaps  114:        { NULL, NULL }, /* SM */
1.21      schwarze  115:        { pre_B, NULL }, /* SB */
1.1       kristaps  116:        { pre_BI, NULL }, /* BI */
1.17      schwarze  117:        { pre_BI, NULL }, /* IB */
                    118:        { pre_RB, NULL }, /* BR */
1.1       kristaps  119:        { pre_RB, NULL }, /* RB */
                    120:        { NULL, NULL }, /* R */
1.21      schwarze  121:        { pre_B, NULL }, /* B */
                    122:        { pre_I, NULL }, /* I */
                    123:        { pre_RI, NULL }, /* IR */
1.1       kristaps  124:        { pre_RI, NULL }, /* RI */
1.13      schwarze  125:        { NULL, NULL }, /* na */
1.21      schwarze  126:        { pre_I, NULL }, /* i */
1.11      schwarze  127:        { pre_sp, NULL }, /* sp */
                    128:        { pre_nf, NULL }, /* nf */
                    129:        { pre_fi, NULL }, /* fi */
1.21      schwarze  130:        { NULL, NULL }, /* r */
1.13      schwarze  131:        { NULL, NULL }, /* RE */
                    132:        { pre_RS, post_RS }, /* RS */
1.14      schwarze  133:        { pre_ign, NULL }, /* DT */
                    134:        { pre_ign, NULL }, /* UC */
1.19      schwarze  135:        { pre_ign, NULL }, /* PD */
1.23    ! schwarze  136:        { pre_sp, NULL }, /* Sp */
        !           137:        { pre_nf, NULL }, /* Vb */
        !           138:        { pre_fi, NULL }, /* Ve */
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.19      schwarze  166:        print_man_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)
1.21      schwarze  174:                print_man_nodelist(p, &mt, n->child, m);
1.19      schwarze  175:        print_man_foot(p, m);
1.1       kristaps  176: }
                    177:
                    178:
1.18      schwarze  179: static int
1.19      schwarze  180: a2height(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.19      schwarze  194: a2width(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.21      schwarze  238:        term_fontrepl(p, TERMFONT_UNDER);
1.1       kristaps  239:        return(1);
                    240: }
                    241:
                    242:
                    243: /* ARGSUSED */
1.11      schwarze  244: static int
                    245: pre_fi(DECL_ARGS)
                    246: {
                    247:
                    248:        mt->fl &= ~MANT_LITERAL;
                    249:        return(1);
                    250: }
                    251:
                    252:
                    253: /* ARGSUSED */
                    254: static int
                    255: pre_nf(DECL_ARGS)
                    256: {
                    257:
                    258:        term_newln(p);
                    259:        mt->fl |= MANT_LITERAL;
                    260:        return(1);
                    261: }
                    262:
                    263:
                    264: /* ARGSUSED */
                    265: static int
1.17      schwarze  266: pre_RB(DECL_ARGS)
1.1       kristaps  267: {
                    268:        const struct man_node *nn;
                    269:        int              i;
                    270:
                    271:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17      schwarze  272:                if (i % 2 && MAN_RB == n->tok)
1.21      schwarze  273:                        term_fontrepl(p, TERMFONT_BOLD);
1.17      schwarze  274:                else if ( ! (i % 2) && MAN_RB != n->tok)
1.21      schwarze  275:                        term_fontrepl(p, TERMFONT_BOLD);
                    276:                else
                    277:                        term_fontrepl(p, TERMFONT_NONE);
1.17      schwarze  278:
1.1       kristaps  279:                if (i > 0)
                    280:                        p->flags |= TERMP_NOSPACE;
1.17      schwarze  281:
1.19      schwarze  282:                print_man_node(p, mt, nn, m);
1.1       kristaps  283:        }
                    284:        return(0);
                    285: }
                    286:
                    287:
                    288: /* ARGSUSED */
                    289: static int
                    290: pre_RI(DECL_ARGS)
                    291: {
                    292:        const struct man_node *nn;
                    293:        int              i;
                    294:
                    295:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.21      schwarze  296:                if (i % 2 && MAN_RI == n->tok)
                    297:                        term_fontrepl(p, TERMFONT_UNDER);
                    298:                else if ( ! (i % 2) && MAN_RI != n->tok)
                    299:                        term_fontrepl(p, TERMFONT_UNDER);
                    300:                else
                    301:                        term_fontrepl(p, TERMFONT_NONE);
                    302:
1.1       kristaps  303:                if (i > 0)
                    304:                        p->flags |= TERMP_NOSPACE;
1.21      schwarze  305:
1.19      schwarze  306:                print_man_node(p, mt, nn, m);
1.1       kristaps  307:        }
                    308:        return(0);
                    309: }
                    310:
                    311:
                    312: /* ARGSUSED */
                    313: static int
                    314: pre_BI(DECL_ARGS)
                    315: {
1.17      schwarze  316:        const struct man_node   *nn;
                    317:        int                      i;
1.1       kristaps  318:
                    319:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17      schwarze  320:                if (i % 2 && MAN_BI == n->tok)
1.21      schwarze  321:                        term_fontrepl(p, TERMFONT_UNDER);
1.17      schwarze  322:                else if (i % 2)
1.21      schwarze  323:                        term_fontrepl(p, TERMFONT_BOLD);
1.17      schwarze  324:                else if (MAN_BI == n->tok)
1.21      schwarze  325:                        term_fontrepl(p, TERMFONT_BOLD);
1.15      schwarze  326:                else
1.21      schwarze  327:                        term_fontrepl(p, TERMFONT_UNDER);
1.17      schwarze  328:
                    329:                if (i)
1.1       kristaps  330:                        p->flags |= TERMP_NOSPACE;
1.21      schwarze  331:
1.19      schwarze  332:                print_man_node(p, mt, nn, m);
1.1       kristaps  333:        }
                    334:        return(0);
                    335: }
                    336:
                    337:
                    338: /* ARGSUSED */
                    339: static int
                    340: pre_B(DECL_ARGS)
                    341: {
                    342:
1.21      schwarze  343:        term_fontrepl(p, TERMFONT_BOLD);
1.1       kristaps  344:        return(1);
                    345: }
                    346:
                    347:
                    348: /* ARGSUSED */
                    349: static int
1.11      schwarze  350: pre_sp(DECL_ARGS)
                    351: {
                    352:        int              i, len;
                    353:
1.19      schwarze  354:        len = n->child ? a2height(n->child) : 1;
1.11      schwarze  355:
                    356:        if (0 == len)
                    357:                term_newln(p);
                    358:        for (i = 0; i < len; i++)
                    359:                term_vspace(p);
                    360:
                    361:        return(0);
                    362: }
                    363:
                    364:
                    365: /* ARGSUSED */
                    366: static int
1.8       schwarze  367: pre_br(DECL_ARGS)
                    368: {
                    369:
                    370:        term_newln(p);
                    371:        return(0);
                    372: }
                    373:
                    374:
                    375: /* ARGSUSED */
                    376: static int
1.11      schwarze  377: pre_HP(DECL_ARGS)
                    378: {
                    379:        size_t                   len;
                    380:        int                      ival;
                    381:        const struct man_node   *nn;
                    382:
                    383:        switch (n->type) {
                    384:        case (MAN_BLOCK):
1.18      schwarze  385:                print_bvspace(p, n);
1.11      schwarze  386:                return(1);
                    387:        case (MAN_BODY):
                    388:                p->flags |= TERMP_NOBREAK;
                    389:                p->flags |= TERMP_TWOSPACE;
                    390:                break;
                    391:        default:
                    392:                return(0);
                    393:        }
                    394:
1.13      schwarze  395:        len = mt->lmargin;
1.11      schwarze  396:        ival = -1;
                    397:
                    398:        /* Calculate offset. */
                    399:
                    400:        if (NULL != (nn = n->parent->head->child))
1.19      schwarze  401:                if ((ival = a2width(nn)) >= 0)
1.11      schwarze  402:                        len = (size_t)ival;
                    403:
                    404:        if (0 == len)
                    405:                len = 1;
                    406:
1.13      schwarze  407:        p->offset = mt->offset;
                    408:        p->rmargin = mt->offset + len;
1.11      schwarze  409:
                    410:        if (ival >= 0)
1.13      schwarze  411:                mt->lmargin = (size_t)ival;
1.11      schwarze  412:
                    413:        return(1);
                    414: }
                    415:
                    416:
                    417: /* ARGSUSED */
                    418: static void
                    419: post_HP(DECL_ARGS)
                    420: {
                    421:
                    422:        switch (n->type) {
                    423:        case (MAN_BLOCK):
                    424:                term_flushln(p);
                    425:                break;
                    426:        case (MAN_BODY):
                    427:                term_flushln(p);
                    428:                p->flags &= ~TERMP_NOBREAK;
                    429:                p->flags &= ~TERMP_TWOSPACE;
1.13      schwarze  430:                p->offset = mt->offset;
1.11      schwarze  431:                p->rmargin = p->maxrmargin;
                    432:                break;
                    433:        default:
                    434:                break;
                    435:        }
                    436: }
                    437:
                    438:
                    439: /* ARGSUSED */
                    440: static int
1.1       kristaps  441: pre_PP(DECL_ARGS)
                    442: {
                    443:
1.11      schwarze  444:        switch (n->type) {
                    445:        case (MAN_BLOCK):
                    446:                mt->lmargin = INDENT;
1.18      schwarze  447:                print_bvspace(p, n);
1.11      schwarze  448:                break;
                    449:        default:
1.13      schwarze  450:                p->offset = mt->offset;
1.11      schwarze  451:                break;
                    452:        }
                    453:
                    454:        return(1);
1.1       kristaps  455: }
                    456:
                    457:
                    458: /* ARGSUSED */
                    459: static int
                    460: pre_IP(DECL_ARGS)
                    461: {
1.11      schwarze  462:        const struct man_node   *nn;
                    463:        size_t                   len;
                    464:        int                      ival;
                    465:
                    466:        switch (n->type) {
                    467:        case (MAN_BODY):
                    468:                p->flags |= TERMP_NOLPAD;
                    469:                p->flags |= TERMP_NOSPACE;
                    470:                break;
                    471:        case (MAN_HEAD):
                    472:                p->flags |= TERMP_NOBREAK;
                    473:                p->flags |= TERMP_TWOSPACE;
                    474:                break;
                    475:        case (MAN_BLOCK):
1.18      schwarze  476:                print_bvspace(p, n);
1.11      schwarze  477:                /* FALLTHROUGH */
                    478:        default:
                    479:                return(1);
                    480:        }
                    481:
1.13      schwarze  482:        len = mt->lmargin;
1.11      schwarze  483:        ival = -1;
                    484:
                    485:        /* Calculate offset. */
                    486:
                    487:        if (NULL != (nn = n->parent->head->child))
                    488:                if (NULL != (nn = nn->next)) {
                    489:                        for ( ; nn->next; nn = nn->next)
                    490:                                /* Do nothing. */ ;
1.19      schwarze  491:                        if ((ival = a2width(nn)) >= 0)
1.11      schwarze  492:                                len = (size_t)ival;
                    493:                }
                    494:
                    495:        switch (n->type) {
                    496:        case (MAN_HEAD):
                    497:                /* Handle zero-width lengths. */
                    498:                if (0 == len)
                    499:                        len = 1;
                    500:
1.13      schwarze  501:                p->offset = mt->offset;
                    502:                p->rmargin = mt->offset + len;
1.11      schwarze  503:                if (ival < 0)
                    504:                        break;
                    505:
                    506:                /* Set the saved left-margin. */
1.13      schwarze  507:                mt->lmargin = (size_t)ival;
1.1       kristaps  508:
1.11      schwarze  509:                /* Don't print the length value. */
                    510:                for (nn = n->child; nn->next; nn = nn->next)
1.19      schwarze  511:                        print_man_node(p, mt, nn, m);
1.11      schwarze  512:                return(0);
                    513:        case (MAN_BODY):
1.13      schwarze  514:                p->offset = mt->offset + len;
1.11      schwarze  515:                p->rmargin = p->maxrmargin;
                    516:                break;
                    517:        default:
                    518:                break;
                    519:        }
1.1       kristaps  520:
1.11      schwarze  521:        return(1);
                    522: }
1.1       kristaps  523:
                    524:
1.11      schwarze  525: /* ARGSUSED */
                    526: static void
                    527: post_IP(DECL_ARGS)
                    528: {
1.4       schwarze  529:
1.11      schwarze  530:        switch (n->type) {
                    531:        case (MAN_HEAD):
                    532:                term_flushln(p);
                    533:                p->flags &= ~TERMP_NOBREAK;
                    534:                p->flags &= ~TERMP_TWOSPACE;
                    535:                p->rmargin = p->maxrmargin;
                    536:                break;
                    537:        case (MAN_BODY):
                    538:                term_flushln(p);
                    539:                p->flags &= ~TERMP_NOLPAD;
                    540:                break;
                    541:        default:
                    542:                break;
                    543:        }
1.1       kristaps  544: }
                    545:
                    546:
                    547: /* ARGSUSED */
                    548: static int
                    549: pre_TP(DECL_ARGS)
                    550: {
1.11      schwarze  551:        const struct man_node   *nn;
                    552:        size_t                   len;
                    553:        int                      ival;
                    554:
                    555:        switch (n->type) {
                    556:        case (MAN_HEAD):
                    557:                p->flags |= TERMP_NOBREAK;
                    558:                p->flags |= TERMP_TWOSPACE;
                    559:                break;
                    560:        case (MAN_BODY):
                    561:                p->flags |= TERMP_NOLPAD;
                    562:                p->flags |= TERMP_NOSPACE;
                    563:                break;
                    564:        case (MAN_BLOCK):
1.18      schwarze  565:                print_bvspace(p, n);
1.11      schwarze  566:                /* FALLTHROUGH */
                    567:        default:
                    568:                return(1);
                    569:        }
                    570:
                    571:        len = (size_t)mt->lmargin;
                    572:        ival = -1;
                    573:
                    574:        /* Calculate offset. */
1.1       kristaps  575:
1.22      schwarze  576:        if (NULL != (nn = n->parent->head->child)) {
                    577:                while (nn && MAN_TEXT != nn->type)
                    578:                        nn = nn->next;
                    579:                if (nn && nn->next)
1.19      schwarze  580:                        if ((ival = a2width(nn)) >= 0)
1.11      schwarze  581:                                len = (size_t)ival;
1.22      schwarze  582:        }
1.8       schwarze  583:
1.11      schwarze  584:        switch (n->type) {
                    585:        case (MAN_HEAD):
                    586:                /* Handle zero-length properly. */
                    587:                if (0 == len)
                    588:                        len = 1;
                    589:
1.13      schwarze  590:                p->offset = mt->offset;
                    591:                p->rmargin = mt->offset + len;
1.11      schwarze  592:
                    593:                /* Don't print same-line elements. */
                    594:                for (nn = n->child; nn; nn = nn->next)
                    595:                        if (nn->line > n->line)
1.19      schwarze  596:                                print_man_node(p, mt, nn, m);
1.11      schwarze  597:
                    598:                if (ival >= 0)
1.13      schwarze  599:                        mt->lmargin = (size_t)ival;
1.11      schwarze  600:
                    601:                return(0);
                    602:        case (MAN_BODY):
1.13      schwarze  603:                p->offset = mt->offset + len;
1.11      schwarze  604:                p->rmargin = p->maxrmargin;
                    605:                break;
                    606:        default:
                    607:                break;
                    608:        }
1.1       kristaps  609:
1.11      schwarze  610:        return(1);
                    611: }
1.1       kristaps  612:
                    613:
1.11      schwarze  614: /* ARGSUSED */
                    615: static void
                    616: post_TP(DECL_ARGS)
                    617: {
1.1       kristaps  618:
1.11      schwarze  619:        switch (n->type) {
                    620:        case (MAN_HEAD):
                    621:                term_flushln(p);
                    622:                p->flags &= ~TERMP_NOBREAK;
                    623:                p->flags &= ~TERMP_TWOSPACE;
                    624:                p->rmargin = p->maxrmargin;
                    625:                break;
                    626:        case (MAN_BODY):
                    627:                term_flushln(p);
                    628:                p->flags &= ~TERMP_NOLPAD;
                    629:                break;
                    630:        default:
                    631:                break;
                    632:        }
1.1       kristaps  633: }
                    634:
                    635:
                    636: /* ARGSUSED */
                    637: static int
                    638: pre_SS(DECL_ARGS)
                    639: {
                    640:
1.11      schwarze  641:        switch (n->type) {
                    642:        case (MAN_BLOCK):
                    643:                mt->lmargin = INDENT;
1.13      schwarze  644:                mt->offset = INDENT;
1.11      schwarze  645:                /* If following a prior empty `SS', no vspace. */
                    646:                if (n->prev && MAN_SS == n->prev->tok)
                    647:                        if (NULL == n->prev->body->child)
                    648:                                break;
                    649:                if (NULL == n->prev)
                    650:                        break;
                    651:                term_vspace(p);
                    652:                break;
                    653:        case (MAN_HEAD):
1.21      schwarze  654:                term_fontrepl(p, TERMFONT_BOLD);
1.11      schwarze  655:                p->offset = HALFINDENT;
                    656:                break;
                    657:        case (MAN_BODY):
1.13      schwarze  658:                p->offset = mt->offset;
1.11      schwarze  659:                break;
                    660:        default:
                    661:                break;
                    662:        }
                    663:
1.1       kristaps  664:        return(1);
                    665: }
                    666:
                    667:
                    668: /* ARGSUSED */
                    669: static void
                    670: post_SS(DECL_ARGS)
                    671: {
                    672:
1.11      schwarze  673:        switch (n->type) {
                    674:        case (MAN_HEAD):
                    675:                term_newln(p);
                    676:                break;
                    677:        case (MAN_BODY):
                    678:                term_newln(p);
                    679:                break;
                    680:        default:
                    681:                break;
                    682:        }
1.1       kristaps  683: }
                    684:
                    685:
                    686: /* ARGSUSED */
                    687: static int
                    688: pre_SH(DECL_ARGS)
                    689: {
                    690:
1.11      schwarze  691:        switch (n->type) {
                    692:        case (MAN_BLOCK):
                    693:                mt->lmargin = INDENT;
1.13      schwarze  694:                mt->offset = INDENT;
1.11      schwarze  695:                /* If following a prior empty `SH', no vspace. */
                    696:                if (n->prev && MAN_SH == n->prev->tok)
                    697:                        if (NULL == n->prev->body->child)
                    698:                                break;
                    699:                term_vspace(p);
                    700:                break;
                    701:        case (MAN_HEAD):
1.21      schwarze  702:                term_fontrepl(p, TERMFONT_BOLD);
1.11      schwarze  703:                p->offset = 0;
                    704:                break;
                    705:        case (MAN_BODY):
1.13      schwarze  706:                p->offset = mt->offset;
1.11      schwarze  707:                break;
                    708:        default:
                    709:                break;
                    710:        }
                    711:
1.1       kristaps  712:        return(1);
                    713: }
                    714:
                    715:
                    716: /* ARGSUSED */
                    717: static void
                    718: post_SH(DECL_ARGS)
                    719: {
                    720:
1.11      schwarze  721:        switch (n->type) {
                    722:        case (MAN_HEAD):
                    723:                term_newln(p);
                    724:                break;
                    725:        case (MAN_BODY):
                    726:                term_newln(p);
                    727:                break;
                    728:        default:
1.13      schwarze  729:                break;
                    730:        }
                    731: }
                    732:
                    733:
                    734: /* ARGSUSED */
                    735: static int
                    736: pre_RS(DECL_ARGS)
                    737: {
                    738:        const struct man_node   *nn;
                    739:        int                      ival;
                    740:
                    741:        switch (n->type) {
                    742:        case (MAN_BLOCK):
                    743:                term_newln(p);
                    744:                return(1);
                    745:        case (MAN_HEAD):
                    746:                return(0);
                    747:        default:
                    748:                break;
                    749:        }
                    750:
                    751:        if (NULL == (nn = n->parent->head->child)) {
                    752:                mt->offset = mt->lmargin + INDENT;
                    753:                p->offset = mt->offset;
                    754:                return(1);
                    755:        }
                    756:
1.19      schwarze  757:        if ((ival = a2width(nn)) < 0)
1.13      schwarze  758:                return(1);
                    759:
                    760:        mt->offset = INDENT + (size_t)ival;
                    761:        p->offset = mt->offset;
                    762:
                    763:        return(1);
                    764: }
                    765:
                    766:
                    767: /* ARGSUSED */
                    768: static void
                    769: post_RS(DECL_ARGS)
                    770: {
                    771:
                    772:        switch (n->type) {
                    773:        case (MAN_BLOCK):
                    774:                mt->offset = mt->lmargin = INDENT;
                    775:                break;
                    776:        default:
                    777:                term_newln(p);
                    778:                p->offset = INDENT;
1.11      schwarze  779:                break;
                    780:        }
1.1       kristaps  781: }
                    782:
                    783:
                    784: static void
1.19      schwarze  785: print_man_node(DECL_ARGS)
1.1       kristaps  786: {
1.21      schwarze  787:        int              c;
1.1       kristaps  788:
                    789:        c = 1;
                    790:
                    791:        switch (n->type) {
                    792:        case(MAN_TEXT):
                    793:                if (0 == *n->string) {
                    794:                        term_vspace(p);
                    795:                        break;
                    796:                }
1.21      schwarze  797:
1.1       kristaps  798:                term_word(p, n->string);
1.21      schwarze  799:
1.11      schwarze  800:                /* FIXME: this means that macro lines are munged!  */
1.21      schwarze  801:
1.11      schwarze  802:                if (MANT_LITERAL & mt->fl) {
                    803:                        p->flags |= TERMP_NOSPACE;
                    804:                        term_flushln(p);
                    805:                }
1.1       kristaps  806:                break;
                    807:        default:
1.21      schwarze  808:                term_fontrepl(p, TERMFONT_NONE);
1.11      schwarze  809:                if (termacts[n->tok].pre)
                    810:                        c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1       kristaps  811:                break;
                    812:        }
                    813:
                    814:        if (c && n->child)
1.21      schwarze  815:                print_man_nodelist(p, mt, n->child, m);
1.1       kristaps  816:
1.21      schwarze  817:        if (MAN_TEXT != n->type) {
1.1       kristaps  818:                if (termacts[n->tok].post)
1.11      schwarze  819:                        (*termacts[n->tok].post)(p, mt, n, m);
1.21      schwarze  820:                term_fontrepl(p, TERMFONT_NONE);
                    821:        }
1.1       kristaps  822: }
                    823:
                    824:
                    825: static void
1.21      schwarze  826: print_man_nodelist(DECL_ARGS)
1.1       kristaps  827: {
1.11      schwarze  828:
1.19      schwarze  829:        print_man_node(p, mt, n, m);
1.1       kristaps  830:        if ( ! n->next)
                    831:                return;
1.21      schwarze  832:        print_man_nodelist(p, mt, n->next, m);
1.1       kristaps  833: }
                    834:
                    835:
                    836: static void
1.19      schwarze  837: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1       kristaps  838: {
1.19      schwarze  839:        char            buf[DATESIZ];
1.21      schwarze  840:
                    841:        term_fontrepl(p, TERMFONT_NONE);
1.1       kristaps  842:
1.19      schwarze  843:        time2a(meta->date, buf, DATESIZ);
1.1       kristaps  844:
                    845:        term_vspace(p);
                    846:
                    847:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
                    848:        p->rmargin = p->maxrmargin - strlen(buf);
                    849:        p->offset = 0;
                    850:
                    851:        if (meta->source)
                    852:                term_word(p, meta->source);
                    853:        if (meta->source)
                    854:                term_word(p, "");
                    855:        term_flushln(p);
                    856:
                    857:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    858:        p->offset = p->rmargin;
                    859:        p->rmargin = p->maxrmargin;
                    860:        p->flags &= ~TERMP_NOBREAK;
                    861:
                    862:        term_word(p, buf);
                    863:        term_flushln(p);
                    864: }
                    865:
                    866:
                    867: static void
1.20      schwarze  868: print_man_head(struct termp *p, const struct man_meta *m)
1.1       kristaps  869: {
1.20      schwarze  870:        char            buf[BUFSIZ], title[BUFSIZ];
1.1       kristaps  871:
                    872:        p->rmargin = p->maxrmargin;
                    873:        p->offset = 0;
1.20      schwarze  874:        buf[0] = title[0] = '\0';
1.1       kristaps  875:
1.20      schwarze  876:        if (m->vol)
                    877:                strlcpy(buf, m->vol, BUFSIZ);
1.1       kristaps  878:
1.20      schwarze  879:        snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
1.1       kristaps  880:
                    881:        p->offset = 0;
1.5       schwarze  882:        p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1       kristaps  883:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
                    884:
                    885:        term_word(p, title);
                    886:        term_flushln(p);
                    887:
                    888:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    889:        p->offset = p->rmargin;
                    890:        p->rmargin = p->maxrmargin - strlen(title);
                    891:
                    892:        term_word(p, buf);
                    893:        term_flushln(p);
                    894:
                    895:        p->offset = p->rmargin;
                    896:        p->rmargin = p->maxrmargin;
                    897:        p->flags &= ~TERMP_NOBREAK;
                    898:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    899:
                    900:        term_word(p, title);
                    901:        term_flushln(p);
                    902:
                    903:        p->rmargin = p->maxrmargin;
                    904:        p->offset = 0;
                    905:        p->flags &= ~TERMP_NOSPACE;
                    906: }