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

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