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

1.22    ! schwarze    1: /*     $Id: man_term.c,v 1.21 2009/12/24 02:08:14 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.1       kristaps  136: };
1.11      schwarze  137:
1.1       kristaps  138:
                    139:
1.16      schwarze  140: void
1.18      schwarze  141: terminal_man(void *arg, const struct man *man)
1.1       kristaps  142: {
1.18      schwarze  143:        struct termp            *p;
                    144:        const struct man_node   *n;
                    145:        const struct man_meta   *m;
                    146:        struct mtermp            mt;
                    147:
                    148:        p = (struct termp *)arg;
                    149:
                    150:        if (NULL == p->symtab)
                    151:                switch (p->enc) {
                    152:                case (TERMENC_ASCII):
                    153:                        p->symtab = chars_init(CHARS_ASCII);
                    154:                        break;
                    155:                default:
                    156:                        abort();
                    157:                        /* NOTREACHED */
                    158:                }
                    159:
                    160:        n = man_node(man);
                    161:        m = man_meta(man);
1.1       kristaps  162:
1.19      schwarze  163:        print_man_head(p, m);
1.1       kristaps  164:        p->flags |= TERMP_NOSPACE;
1.11      schwarze  165:
                    166:        mt.fl = 0;
                    167:        mt.lmargin = INDENT;
1.13      schwarze  168:        mt.offset = INDENT;
1.11      schwarze  169:
1.18      schwarze  170:        if (n->child)
1.21      schwarze  171:                print_man_nodelist(p, &mt, n->child, m);
1.19      schwarze  172:        print_man_foot(p, m);
1.1       kristaps  173: }
                    174:
                    175:
1.18      schwarze  176: static int
1.19      schwarze  177: a2height(const struct man_node *n)
1.11      schwarze  178: {
1.18      schwarze  179:        struct roffsu    su;
1.11      schwarze  180:
1.18      schwarze  181:        assert(MAN_TEXT == n->type);
                    182:        assert(n->string);
                    183:        if ( ! a2roffsu(n->string, &su, SCALE_VS))
                    184:                SCALE_VS_INIT(&su, strlen(n->string));
1.11      schwarze  185:
1.18      schwarze  186:        return((int)term_vspan(&su));
1.11      schwarze  187: }
                    188:
                    189:
                    190: static int
1.19      schwarze  191: a2width(const struct man_node *n)
1.11      schwarze  192: {
1.18      schwarze  193:        struct roffsu    su;
1.11      schwarze  194:
                    195:        assert(MAN_TEXT == n->type);
                    196:        assert(n->string);
1.18      schwarze  197:        if ( ! a2roffsu(n->string, &su, SCALE_BU))
                    198:                return(-1);
                    199:
                    200:        return((int)term_hspan(&su));
                    201: }
1.11      schwarze  202:
                    203:
1.18      schwarze  204: static void
                    205: print_bvspace(struct termp *p, const struct man_node *n)
                    206: {
                    207:        term_newln(p);
1.11      schwarze  208:
1.18      schwarze  209:        if (NULL == n->prev)
                    210:                return;
1.11      schwarze  211:
1.18      schwarze  212:        if (MAN_SS == n->prev->tok)
                    213:                return;
                    214:        if (MAN_SH == n->prev->tok)
                    215:                return;
1.11      schwarze  216:
1.18      schwarze  217:        term_vspace(p);
1.14      schwarze  218: }
                    219:
                    220:
                    221: /* ARGSUSED */
                    222: static int
                    223: pre_ign(DECL_ARGS)
                    224: {
                    225:
                    226:        return(0);
1.11      schwarze  227: }
                    228:
                    229:
1.1       kristaps  230: /* ARGSUSED */
                    231: static int
                    232: pre_I(DECL_ARGS)
                    233: {
                    234:
1.21      schwarze  235:        term_fontrepl(p, TERMFONT_UNDER);
1.1       kristaps  236:        return(1);
                    237: }
                    238:
                    239:
                    240: /* ARGSUSED */
1.11      schwarze  241: static int
                    242: pre_fi(DECL_ARGS)
                    243: {
                    244:
                    245:        mt->fl &= ~MANT_LITERAL;
                    246:        return(1);
                    247: }
                    248:
                    249:
                    250: /* ARGSUSED */
                    251: static int
                    252: pre_nf(DECL_ARGS)
                    253: {
                    254:
                    255:        term_newln(p);
                    256:        mt->fl |= MANT_LITERAL;
                    257:        return(1);
                    258: }
                    259:
                    260:
                    261: /* ARGSUSED */
                    262: static int
1.17      schwarze  263: pre_RB(DECL_ARGS)
1.1       kristaps  264: {
                    265:        const struct man_node *nn;
                    266:        int              i;
                    267:
                    268:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17      schwarze  269:                if (i % 2 && MAN_RB == n->tok)
1.21      schwarze  270:                        term_fontrepl(p, TERMFONT_BOLD);
1.17      schwarze  271:                else if ( ! (i % 2) && MAN_RB != n->tok)
1.21      schwarze  272:                        term_fontrepl(p, TERMFONT_BOLD);
                    273:                else
                    274:                        term_fontrepl(p, TERMFONT_NONE);
1.17      schwarze  275:
1.1       kristaps  276:                if (i > 0)
                    277:                        p->flags |= TERMP_NOSPACE;
1.17      schwarze  278:
1.19      schwarze  279:                print_man_node(p, mt, nn, m);
1.1       kristaps  280:        }
                    281:        return(0);
                    282: }
                    283:
                    284:
                    285: /* ARGSUSED */
                    286: static int
                    287: pre_RI(DECL_ARGS)
                    288: {
                    289:        const struct man_node *nn;
                    290:        int              i;
                    291:
                    292:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.21      schwarze  293:                if (i % 2 && MAN_RI == n->tok)
                    294:                        term_fontrepl(p, TERMFONT_UNDER);
                    295:                else if ( ! (i % 2) && MAN_RI != n->tok)
                    296:                        term_fontrepl(p, TERMFONT_UNDER);
                    297:                else
                    298:                        term_fontrepl(p, TERMFONT_NONE);
                    299:
1.1       kristaps  300:                if (i > 0)
                    301:                        p->flags |= TERMP_NOSPACE;
1.21      schwarze  302:
1.19      schwarze  303:                print_man_node(p, mt, nn, m);
1.1       kristaps  304:        }
                    305:        return(0);
                    306: }
                    307:
                    308:
                    309: /* ARGSUSED */
                    310: static int
                    311: pre_BI(DECL_ARGS)
                    312: {
1.17      schwarze  313:        const struct man_node   *nn;
                    314:        int                      i;
1.1       kristaps  315:
                    316:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
1.17      schwarze  317:                if (i % 2 && MAN_BI == n->tok)
1.21      schwarze  318:                        term_fontrepl(p, TERMFONT_UNDER);
1.17      schwarze  319:                else if (i % 2)
1.21      schwarze  320:                        term_fontrepl(p, TERMFONT_BOLD);
1.17      schwarze  321:                else if (MAN_BI == n->tok)
1.21      schwarze  322:                        term_fontrepl(p, TERMFONT_BOLD);
1.15      schwarze  323:                else
1.21      schwarze  324:                        term_fontrepl(p, TERMFONT_UNDER);
1.17      schwarze  325:
                    326:                if (i)
1.1       kristaps  327:                        p->flags |= TERMP_NOSPACE;
1.21      schwarze  328:
1.19      schwarze  329:                print_man_node(p, mt, nn, m);
1.1       kristaps  330:        }
                    331:        return(0);
                    332: }
                    333:
                    334:
                    335: /* ARGSUSED */
                    336: static int
                    337: pre_B(DECL_ARGS)
                    338: {
                    339:
1.21      schwarze  340:        term_fontrepl(p, TERMFONT_BOLD);
1.1       kristaps  341:        return(1);
                    342: }
                    343:
                    344:
                    345: /* ARGSUSED */
                    346: static int
1.11      schwarze  347: pre_sp(DECL_ARGS)
                    348: {
                    349:        int              i, len;
                    350:
1.19      schwarze  351:        len = n->child ? a2height(n->child) : 1;
1.11      schwarze  352:
                    353:        if (0 == len)
                    354:                term_newln(p);
                    355:        for (i = 0; i < len; i++)
                    356:                term_vspace(p);
                    357:
                    358:        return(0);
                    359: }
                    360:
                    361:
                    362: /* ARGSUSED */
                    363: static int
1.8       schwarze  364: pre_br(DECL_ARGS)
                    365: {
                    366:
                    367:        term_newln(p);
                    368:        return(0);
                    369: }
                    370:
                    371:
                    372: /* ARGSUSED */
                    373: static int
1.11      schwarze  374: pre_HP(DECL_ARGS)
                    375: {
                    376:        size_t                   len;
                    377:        int                      ival;
                    378:        const struct man_node   *nn;
                    379:
                    380:        switch (n->type) {
                    381:        case (MAN_BLOCK):
1.18      schwarze  382:                print_bvspace(p, n);
1.11      schwarze  383:                return(1);
                    384:        case (MAN_BODY):
                    385:                p->flags |= TERMP_NOBREAK;
                    386:                p->flags |= TERMP_TWOSPACE;
                    387:                break;
                    388:        default:
                    389:                return(0);
                    390:        }
                    391:
1.13      schwarze  392:        len = mt->lmargin;
1.11      schwarze  393:        ival = -1;
                    394:
                    395:        /* Calculate offset. */
                    396:
                    397:        if (NULL != (nn = n->parent->head->child))
1.19      schwarze  398:                if ((ival = a2width(nn)) >= 0)
1.11      schwarze  399:                        len = (size_t)ival;
                    400:
                    401:        if (0 == len)
                    402:                len = 1;
                    403:
1.13      schwarze  404:        p->offset = mt->offset;
                    405:        p->rmargin = mt->offset + len;
1.11      schwarze  406:
                    407:        if (ival >= 0)
1.13      schwarze  408:                mt->lmargin = (size_t)ival;
1.11      schwarze  409:
                    410:        return(1);
                    411: }
                    412:
                    413:
                    414: /* ARGSUSED */
                    415: static void
                    416: post_HP(DECL_ARGS)
                    417: {
                    418:
                    419:        switch (n->type) {
                    420:        case (MAN_BLOCK):
                    421:                term_flushln(p);
                    422:                break;
                    423:        case (MAN_BODY):
                    424:                term_flushln(p);
                    425:                p->flags &= ~TERMP_NOBREAK;
                    426:                p->flags &= ~TERMP_TWOSPACE;
1.13      schwarze  427:                p->offset = mt->offset;
1.11      schwarze  428:                p->rmargin = p->maxrmargin;
                    429:                break;
                    430:        default:
                    431:                break;
                    432:        }
                    433: }
                    434:
                    435:
                    436: /* ARGSUSED */
                    437: static int
1.1       kristaps  438: pre_PP(DECL_ARGS)
                    439: {
                    440:
1.11      schwarze  441:        switch (n->type) {
                    442:        case (MAN_BLOCK):
                    443:                mt->lmargin = INDENT;
1.18      schwarze  444:                print_bvspace(p, n);
1.11      schwarze  445:                break;
                    446:        default:
1.13      schwarze  447:                p->offset = mt->offset;
1.11      schwarze  448:                break;
                    449:        }
                    450:
                    451:        return(1);
1.1       kristaps  452: }
                    453:
                    454:
                    455: /* ARGSUSED */
                    456: static int
                    457: pre_IP(DECL_ARGS)
                    458: {
1.11      schwarze  459:        const struct man_node   *nn;
                    460:        size_t                   len;
                    461:        int                      ival;
                    462:
                    463:        switch (n->type) {
                    464:        case (MAN_BODY):
                    465:                p->flags |= TERMP_NOLPAD;
                    466:                p->flags |= TERMP_NOSPACE;
                    467:                break;
                    468:        case (MAN_HEAD):
                    469:                p->flags |= TERMP_NOBREAK;
                    470:                p->flags |= TERMP_TWOSPACE;
                    471:                break;
                    472:        case (MAN_BLOCK):
1.18      schwarze  473:                print_bvspace(p, n);
1.11      schwarze  474:                /* FALLTHROUGH */
                    475:        default:
                    476:                return(1);
                    477:        }
                    478:
1.13      schwarze  479:        len = mt->lmargin;
1.11      schwarze  480:        ival = -1;
                    481:
                    482:        /* Calculate offset. */
                    483:
                    484:        if (NULL != (nn = n->parent->head->child))
                    485:                if (NULL != (nn = nn->next)) {
                    486:                        for ( ; nn->next; nn = nn->next)
                    487:                                /* Do nothing. */ ;
1.19      schwarze  488:                        if ((ival = a2width(nn)) >= 0)
1.11      schwarze  489:                                len = (size_t)ival;
                    490:                }
                    491:
                    492:        switch (n->type) {
                    493:        case (MAN_HEAD):
                    494:                /* Handle zero-width lengths. */
                    495:                if (0 == len)
                    496:                        len = 1;
                    497:
1.13      schwarze  498:                p->offset = mt->offset;
                    499:                p->rmargin = mt->offset + len;
1.11      schwarze  500:                if (ival < 0)
                    501:                        break;
                    502:
                    503:                /* Set the saved left-margin. */
1.13      schwarze  504:                mt->lmargin = (size_t)ival;
1.1       kristaps  505:
1.11      schwarze  506:                /* Don't print the length value. */
                    507:                for (nn = n->child; nn->next; nn = nn->next)
1.19      schwarze  508:                        print_man_node(p, mt, nn, m);
1.11      schwarze  509:                return(0);
                    510:        case (MAN_BODY):
1.13      schwarze  511:                p->offset = mt->offset + len;
1.11      schwarze  512:                p->rmargin = p->maxrmargin;
                    513:                break;
                    514:        default:
                    515:                break;
                    516:        }
1.1       kristaps  517:
1.11      schwarze  518:        return(1);
                    519: }
1.1       kristaps  520:
                    521:
1.11      schwarze  522: /* ARGSUSED */
                    523: static void
                    524: post_IP(DECL_ARGS)
                    525: {
1.4       schwarze  526:
1.11      schwarze  527:        switch (n->type) {
                    528:        case (MAN_HEAD):
                    529:                term_flushln(p);
                    530:                p->flags &= ~TERMP_NOBREAK;
                    531:                p->flags &= ~TERMP_TWOSPACE;
                    532:                p->rmargin = p->maxrmargin;
                    533:                break;
                    534:        case (MAN_BODY):
                    535:                term_flushln(p);
                    536:                p->flags &= ~TERMP_NOLPAD;
                    537:                break;
                    538:        default:
                    539:                break;
                    540:        }
1.1       kristaps  541: }
                    542:
                    543:
                    544: /* ARGSUSED */
                    545: static int
                    546: pre_TP(DECL_ARGS)
                    547: {
1.11      schwarze  548:        const struct man_node   *nn;
                    549:        size_t                   len;
                    550:        int                      ival;
                    551:
                    552:        switch (n->type) {
                    553:        case (MAN_HEAD):
                    554:                p->flags |= TERMP_NOBREAK;
                    555:                p->flags |= TERMP_TWOSPACE;
                    556:                break;
                    557:        case (MAN_BODY):
                    558:                p->flags |= TERMP_NOLPAD;
                    559:                p->flags |= TERMP_NOSPACE;
                    560:                break;
                    561:        case (MAN_BLOCK):
1.18      schwarze  562:                print_bvspace(p, n);
1.11      schwarze  563:                /* FALLTHROUGH */
                    564:        default:
                    565:                return(1);
                    566:        }
                    567:
                    568:        len = (size_t)mt->lmargin;
                    569:        ival = -1;
                    570:
                    571:        /* Calculate offset. */
1.1       kristaps  572:
1.22    ! schwarze  573:        if (NULL != (nn = n->parent->head->child)) {
        !           574:                while (nn && MAN_TEXT != nn->type)
        !           575:                        nn = nn->next;
        !           576:                if (nn && nn->next)
1.19      schwarze  577:                        if ((ival = a2width(nn)) >= 0)
1.11      schwarze  578:                                len = (size_t)ival;
1.22    ! schwarze  579:        }
1.8       schwarze  580:
1.11      schwarze  581:        switch (n->type) {
                    582:        case (MAN_HEAD):
                    583:                /* Handle zero-length properly. */
                    584:                if (0 == len)
                    585:                        len = 1;
                    586:
1.13      schwarze  587:                p->offset = mt->offset;
                    588:                p->rmargin = mt->offset + len;
1.11      schwarze  589:
                    590:                /* Don't print same-line elements. */
                    591:                for (nn = n->child; nn; nn = nn->next)
                    592:                        if (nn->line > n->line)
1.19      schwarze  593:                                print_man_node(p, mt, nn, m);
1.11      schwarze  594:
                    595:                if (ival >= 0)
1.13      schwarze  596:                        mt->lmargin = (size_t)ival;
1.11      schwarze  597:
                    598:                return(0);
                    599:        case (MAN_BODY):
1.13      schwarze  600:                p->offset = mt->offset + len;
1.11      schwarze  601:                p->rmargin = p->maxrmargin;
                    602:                break;
                    603:        default:
                    604:                break;
                    605:        }
1.1       kristaps  606:
1.11      schwarze  607:        return(1);
                    608: }
1.1       kristaps  609:
                    610:
1.11      schwarze  611: /* ARGSUSED */
                    612: static void
                    613: post_TP(DECL_ARGS)
                    614: {
1.1       kristaps  615:
1.11      schwarze  616:        switch (n->type) {
                    617:        case (MAN_HEAD):
                    618:                term_flushln(p);
                    619:                p->flags &= ~TERMP_NOBREAK;
                    620:                p->flags &= ~TERMP_TWOSPACE;
                    621:                p->rmargin = p->maxrmargin;
                    622:                break;
                    623:        case (MAN_BODY):
                    624:                term_flushln(p);
                    625:                p->flags &= ~TERMP_NOLPAD;
                    626:                break;
                    627:        default:
                    628:                break;
                    629:        }
1.1       kristaps  630: }
                    631:
                    632:
                    633: /* ARGSUSED */
                    634: static int
                    635: pre_SS(DECL_ARGS)
                    636: {
                    637:
1.11      schwarze  638:        switch (n->type) {
                    639:        case (MAN_BLOCK):
                    640:                mt->lmargin = INDENT;
1.13      schwarze  641:                mt->offset = INDENT;
1.11      schwarze  642:                /* If following a prior empty `SS', no vspace. */
                    643:                if (n->prev && MAN_SS == n->prev->tok)
                    644:                        if (NULL == n->prev->body->child)
                    645:                                break;
                    646:                if (NULL == n->prev)
                    647:                        break;
                    648:                term_vspace(p);
                    649:                break;
                    650:        case (MAN_HEAD):
1.21      schwarze  651:                term_fontrepl(p, TERMFONT_BOLD);
1.11      schwarze  652:                p->offset = HALFINDENT;
                    653:                break;
                    654:        case (MAN_BODY):
1.13      schwarze  655:                p->offset = mt->offset;
1.11      schwarze  656:                break;
                    657:        default:
                    658:                break;
                    659:        }
                    660:
1.1       kristaps  661:        return(1);
                    662: }
                    663:
                    664:
                    665: /* ARGSUSED */
                    666: static void
                    667: post_SS(DECL_ARGS)
                    668: {
                    669:
1.11      schwarze  670:        switch (n->type) {
                    671:        case (MAN_HEAD):
                    672:                term_newln(p);
                    673:                break;
                    674:        case (MAN_BODY):
                    675:                term_newln(p);
                    676:                break;
                    677:        default:
                    678:                break;
                    679:        }
1.1       kristaps  680: }
                    681:
                    682:
                    683: /* ARGSUSED */
                    684: static int
                    685: pre_SH(DECL_ARGS)
                    686: {
                    687:
1.11      schwarze  688:        switch (n->type) {
                    689:        case (MAN_BLOCK):
                    690:                mt->lmargin = INDENT;
1.13      schwarze  691:                mt->offset = INDENT;
1.11      schwarze  692:                /* If following a prior empty `SH', no vspace. */
                    693:                if (n->prev && MAN_SH == n->prev->tok)
                    694:                        if (NULL == n->prev->body->child)
                    695:                                break;
                    696:                term_vspace(p);
                    697:                break;
                    698:        case (MAN_HEAD):
1.21      schwarze  699:                term_fontrepl(p, TERMFONT_BOLD);
1.11      schwarze  700:                p->offset = 0;
                    701:                break;
                    702:        case (MAN_BODY):
1.13      schwarze  703:                p->offset = mt->offset;
1.11      schwarze  704:                break;
                    705:        default:
                    706:                break;
                    707:        }
                    708:
1.1       kristaps  709:        return(1);
                    710: }
                    711:
                    712:
                    713: /* ARGSUSED */
                    714: static void
                    715: post_SH(DECL_ARGS)
                    716: {
                    717:
1.11      schwarze  718:        switch (n->type) {
                    719:        case (MAN_HEAD):
                    720:                term_newln(p);
                    721:                break;
                    722:        case (MAN_BODY):
                    723:                term_newln(p);
                    724:                break;
                    725:        default:
1.13      schwarze  726:                break;
                    727:        }
                    728: }
                    729:
                    730:
                    731: /* ARGSUSED */
                    732: static int
                    733: pre_RS(DECL_ARGS)
                    734: {
                    735:        const struct man_node   *nn;
                    736:        int                      ival;
                    737:
                    738:        switch (n->type) {
                    739:        case (MAN_BLOCK):
                    740:                term_newln(p);
                    741:                return(1);
                    742:        case (MAN_HEAD):
                    743:                return(0);
                    744:        default:
                    745:                break;
                    746:        }
                    747:
                    748:        if (NULL == (nn = n->parent->head->child)) {
                    749:                mt->offset = mt->lmargin + INDENT;
                    750:                p->offset = mt->offset;
                    751:                return(1);
                    752:        }
                    753:
1.19      schwarze  754:        if ((ival = a2width(nn)) < 0)
1.13      schwarze  755:                return(1);
                    756:
                    757:        mt->offset = INDENT + (size_t)ival;
                    758:        p->offset = mt->offset;
                    759:
                    760:        return(1);
                    761: }
                    762:
                    763:
                    764: /* ARGSUSED */
                    765: static void
                    766: post_RS(DECL_ARGS)
                    767: {
                    768:
                    769:        switch (n->type) {
                    770:        case (MAN_BLOCK):
                    771:                mt->offset = mt->lmargin = INDENT;
                    772:                break;
                    773:        default:
                    774:                term_newln(p);
                    775:                p->offset = INDENT;
1.11      schwarze  776:                break;
                    777:        }
1.1       kristaps  778: }
                    779:
                    780:
                    781: static void
1.19      schwarze  782: print_man_node(DECL_ARGS)
1.1       kristaps  783: {
1.21      schwarze  784:        int              c;
1.1       kristaps  785:
                    786:        c = 1;
                    787:
                    788:        switch (n->type) {
                    789:        case(MAN_TEXT):
                    790:                if (0 == *n->string) {
                    791:                        term_vspace(p);
                    792:                        break;
                    793:                }
1.21      schwarze  794:
1.1       kristaps  795:                term_word(p, n->string);
1.21      schwarze  796:
1.11      schwarze  797:                /* FIXME: this means that macro lines are munged!  */
1.21      schwarze  798:
1.11      schwarze  799:                if (MANT_LITERAL & mt->fl) {
                    800:                        p->flags |= TERMP_NOSPACE;
                    801:                        term_flushln(p);
                    802:                }
1.1       kristaps  803:                break;
                    804:        default:
1.21      schwarze  805:                term_fontrepl(p, TERMFONT_NONE);
1.11      schwarze  806:                if (termacts[n->tok].pre)
                    807:                        c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1       kristaps  808:                break;
                    809:        }
                    810:
                    811:        if (c && n->child)
1.21      schwarze  812:                print_man_nodelist(p, mt, n->child, m);
1.1       kristaps  813:
1.21      schwarze  814:        if (MAN_TEXT != n->type) {
1.1       kristaps  815:                if (termacts[n->tok].post)
1.11      schwarze  816:                        (*termacts[n->tok].post)(p, mt, n, m);
1.21      schwarze  817:                term_fontrepl(p, TERMFONT_NONE);
                    818:        }
1.1       kristaps  819: }
                    820:
                    821:
                    822: static void
1.21      schwarze  823: print_man_nodelist(DECL_ARGS)
1.1       kristaps  824: {
1.11      schwarze  825:
1.19      schwarze  826:        print_man_node(p, mt, n, m);
1.1       kristaps  827:        if ( ! n->next)
                    828:                return;
1.21      schwarze  829:        print_man_nodelist(p, mt, n->next, m);
1.1       kristaps  830: }
                    831:
                    832:
                    833: static void
1.19      schwarze  834: print_man_foot(struct termp *p, const struct man_meta *meta)
1.1       kristaps  835: {
1.19      schwarze  836:        char            buf[DATESIZ];
1.21      schwarze  837:
                    838:        term_fontrepl(p, TERMFONT_NONE);
1.1       kristaps  839:
1.19      schwarze  840:        time2a(meta->date, buf, DATESIZ);
1.1       kristaps  841:
                    842:        term_vspace(p);
                    843:
                    844:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
                    845:        p->rmargin = p->maxrmargin - strlen(buf);
                    846:        p->offset = 0;
                    847:
                    848:        if (meta->source)
                    849:                term_word(p, meta->source);
                    850:        if (meta->source)
                    851:                term_word(p, "");
                    852:        term_flushln(p);
                    853:
                    854:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    855:        p->offset = p->rmargin;
                    856:        p->rmargin = p->maxrmargin;
                    857:        p->flags &= ~TERMP_NOBREAK;
                    858:
                    859:        term_word(p, buf);
                    860:        term_flushln(p);
                    861: }
                    862:
                    863:
                    864: static void
1.20      schwarze  865: print_man_head(struct termp *p, const struct man_meta *m)
1.1       kristaps  866: {
1.20      schwarze  867:        char            buf[BUFSIZ], title[BUFSIZ];
1.1       kristaps  868:
                    869:        p->rmargin = p->maxrmargin;
                    870:        p->offset = 0;
1.20      schwarze  871:        buf[0] = title[0] = '\0';
1.1       kristaps  872:
1.20      schwarze  873:        if (m->vol)
                    874:                strlcpy(buf, m->vol, BUFSIZ);
1.1       kristaps  875:
1.20      schwarze  876:        snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
1.1       kristaps  877:
                    878:        p->offset = 0;
1.5       schwarze  879:        p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1       kristaps  880:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
                    881:
                    882:        term_word(p, title);
                    883:        term_flushln(p);
                    884:
                    885:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    886:        p->offset = p->rmargin;
                    887:        p->rmargin = p->maxrmargin - strlen(title);
                    888:
                    889:        term_word(p, buf);
                    890:        term_flushln(p);
                    891:
                    892:        p->offset = p->rmargin;
                    893:        p->rmargin = p->maxrmargin;
                    894:        p->flags &= ~TERMP_NOBREAK;
                    895:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    896:
                    897:        term_word(p, title);
                    898:        term_flushln(p);
                    899:
                    900:        p->rmargin = p->maxrmargin;
                    901:        p->offset = 0;
                    902:        p->flags &= ~TERMP_NOSPACE;
                    903: }