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

Annotation of mandoc/man_term.c, Revision 1.26

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

CVSweb