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

Annotation of mandoc/man_term.c, Revision 1.27

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

CVSweb