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

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