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

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