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

Annotation of mandoc/man_term.c, Revision 1.24

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

CVSweb