[BACK]Return to man_term.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/man_term.c, Revision 1.35

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

CVSweb