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

Annotation of mandoc/man_term.c, Revision 1.50

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

CVSweb