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

Annotation of mandoc/man_term.c, Revision 1.30

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

CVSweb