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

Annotation of mandoc/man_term.c, Revision 1.54

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

CVSweb