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

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