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

Annotation of mandoc/man_term.c, Revision 1.52

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

CVSweb