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

Annotation of mandoc/man_term.c, Revision 1.28

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

CVSweb