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

Annotation of mandoc/man_term.c, Revision 1.140

1.140   ! schwarze    1: /*     $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */
1.1       kristaps    2: /*
1.128     schwarze    3:  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
1.140   ! schwarze    4:  * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
1.1       kristaps    5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
1.8       kristaps    7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    9:  *
1.8       kristaps   10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       kristaps   17:  */
1.55      kristaps   18: #ifdef HAVE_CONFIG_H
                     19: #include "config.h"
                     20: #endif
                     21:
1.28      kristaps   22: #include <sys/types.h>
                     23:
1.1       kristaps   24: #include <assert.h>
1.18      kristaps   25: #include <ctype.h>
1.1       kristaps   26: #include <stdio.h>
                     27: #include <stdlib.h>
                     28: #include <string.h>
                     29:
1.71      kristaps   30: #include "mandoc.h"
1.40      kristaps   31: #include "out.h"
1.36      kristaps   32: #include "man.h"
1.1       kristaps   33: #include "term.h"
1.36      kristaps   34: #include "main.h"
1.1       kristaps   35:
1.116     schwarze   36: #define        MAXMARGINS        64 /* maximum number of indented scopes */
1.18      kristaps   37:
1.24      kristaps   38: struct mtermp {
                     39:        int               fl;
1.19      kristaps   40: #define        MANT_LITERAL     (1 << 0)
1.116     schwarze   41:        size_t            lmargin[MAXMARGINS]; /* margins (incl. visible page) */
                     42:        int               lmargincur; /* index of current margin */
                     43:        int               lmarginsz; /* actual number of nested margins */
                     44:        size_t            offset; /* default offset to visible page */
1.134     schwarze   45:        int               pardist; /* vert. space before par., unit: [v] */
1.24      kristaps   46: };
1.19      kristaps   47:
1.1       kristaps   48: #define        DECL_ARGS         struct termp *p, \
1.24      kristaps   49:                          struct mtermp *mt, \
1.1       kristaps   50:                          const struct man_node *n, \
1.135     schwarze   51:                          const struct man_meta *meta
1.1       kristaps   52:
                     53: struct termact {
                     54:        int             (*pre)(DECL_ARGS);
                     55:        void            (*post)(DECL_ARGS);
1.56      kristaps   56:        int               flags;
                     57: #define        MAN_NOTEXT       (1 << 0) /* Never has text children. */
1.1       kristaps   58: };
                     59:
1.77      kristaps   60: static int               a2width(const struct termp *, const char *);
                     61: static size_t            a2height(const struct termp *, const char *);
1.39      kristaps   62:
1.52      kristaps   63: static void              print_man_nodelist(DECL_ARGS);
1.45      kristaps   64: static void              print_man_node(DECL_ARGS);
1.74      kristaps   65: static void              print_man_head(struct termp *, const void *);
1.73      kristaps   66: static void              print_man_foot(struct termp *, const void *);
1.39      kristaps   67: static void              print_bvspace(struct termp *,
1.134     schwarze   68:                                const struct man_node *, int);
1.39      kristaps   69:
1.1       kristaps   70: static int               pre_B(DECL_ARGS);
1.19      kristaps   71: static int               pre_HP(DECL_ARGS);
1.1       kristaps   72: static int               pre_I(DECL_ARGS);
1.4       kristaps   73: static int               pre_IP(DECL_ARGS);
1.127     kristaps   74: static int               pre_OP(DECL_ARGS);
1.134     schwarze   75: static int               pre_PD(DECL_ARGS);
1.1       kristaps   76: static int               pre_PP(DECL_ARGS);
1.26      kristaps   77: static int               pre_RS(DECL_ARGS);
1.1       kristaps   78: static int               pre_SH(DECL_ARGS);
                     79: static int               pre_SS(DECL_ARGS);
                     80: static int               pre_TP(DECL_ARGS);
1.137     schwarze   81: static int               pre_UR(DECL_ARGS);
1.127     kristaps   82: static int               pre_alternate(DECL_ARGS);
                     83: static int               pre_ft(DECL_ARGS);
1.29      kristaps   84: static int               pre_ign(DECL_ARGS);
1.83      kristaps   85: static int               pre_in(DECL_ARGS);
1.84      kristaps   86: static int               pre_literal(DECL_ARGS);
1.19      kristaps   87: static int               pre_sp(DECL_ARGS);
1.1       kristaps   88:
1.22      kristaps   89: static void              post_IP(DECL_ARGS);
1.20      kristaps   90: static void              post_HP(DECL_ARGS);
1.26      kristaps   91: static void              post_RS(DECL_ARGS);
1.1       kristaps   92: static void              post_SH(DECL_ARGS);
                     93: static void              post_SS(DECL_ARGS);
1.21      kristaps   94: static void              post_TP(DECL_ARGS);
1.137     schwarze   95: static void              post_UR(DECL_ARGS);
1.1       kristaps   96:
1.32      kristaps   97: static const struct termact termacts[MAN_MAX] = {
1.82      kristaps   98:        { pre_sp, NULL, MAN_NOTEXT }, /* br */
1.56      kristaps   99:        { NULL, NULL, 0 }, /* TH */
                    100:        { pre_SH, post_SH, 0 }, /* SH */
                    101:        { pre_SS, post_SS, 0 }, /* SS */
                    102:        { pre_TP, post_TP, 0 }, /* TP */
                    103:        { pre_PP, NULL, 0 }, /* LP */
                    104:        { pre_PP, NULL, 0 }, /* PP */
                    105:        { pre_PP, NULL, 0 }, /* P */
                    106:        { pre_IP, post_IP, 0 }, /* IP */
                    107:        { pre_HP, post_HP, 0 }, /* HP */
                    108:        { NULL, NULL, 0 }, /* SM */
                    109:        { pre_B, NULL, 0 }, /* SB */
1.88      kristaps  110:        { pre_alternate, NULL, 0 }, /* BI */
                    111:        { pre_alternate, NULL, 0 }, /* IB */
                    112:        { pre_alternate, NULL, 0 }, /* BR */
                    113:        { pre_alternate, NULL, 0 }, /* RB */
1.56      kristaps  114:        { NULL, NULL, 0 }, /* R */
                    115:        { pre_B, NULL, 0 }, /* B */
                    116:        { pre_I, NULL, 0 }, /* I */
1.88      kristaps  117:        { pre_alternate, NULL, 0 }, /* IR */
                    118:        { pre_alternate, NULL, 0 }, /* RI */
1.99      schwarze  119:        { pre_ign, NULL, MAN_NOTEXT }, /* na */
1.56      kristaps  120:        { pre_sp, NULL, MAN_NOTEXT }, /* sp */
1.84      kristaps  121:        { pre_literal, NULL, 0 }, /* nf */
                    122:        { pre_literal, NULL, 0 }, /* fi */
1.56      kristaps  123:        { NULL, NULL, 0 }, /* RE */
                    124:        { pre_RS, post_RS, 0 }, /* RS */
                    125:        { pre_ign, NULL, 0 }, /* DT */
                    126:        { pre_ign, NULL, 0 }, /* UC */
1.134     schwarze  127:        { pre_PD, NULL, MAN_NOTEXT }, /* PD */
1.70      joerg     128:        { pre_ign, NULL, 0 }, /* AT */
1.83      kristaps  129:        { pre_in, NULL, MAN_NOTEXT }, /* in */
1.89      kristaps  130:        { pre_ft, NULL, MAN_NOTEXT }, /* ft */
1.127     kristaps  131:        { pre_OP, NULL, 0 }, /* OP */
1.129     schwarze  132:        { pre_literal, NULL, 0 }, /* EX */
                    133:        { pre_literal, NULL, 0 }, /* EE */
1.137     schwarze  134:        { pre_UR, post_UR, 0 }, /* UR */
                    135:        { NULL, NULL, 0 }, /* UE */
1.1       kristaps  136: };
                    137:
                    138:
                    139:
1.31      kristaps  140: void
1.36      kristaps  141: terminal_man(void *arg, const struct man *man)
1.1       kristaps  142: {
1.36      kristaps  143:        struct termp            *p;
                    144:        const struct man_node   *n;
1.135     schwarze  145:        const struct man_meta   *meta;
1.36      kristaps  146:        struct mtermp            mt;
                    147:
                    148:        p = (struct termp *)arg;
                    149:
1.122     schwarze  150:        if (0 == p->defindent)
                    151:                p->defindent = 7;
                    152:
1.58      kristaps  153:        p->overstep = 0;
1.65      joerg     154:        p->maxrmargin = p->defrmargin;
1.77      kristaps  155:        p->tabwidth = term_len(p, 5);
1.73      kristaps  156:
1.36      kristaps  157:        if (NULL == p->symtab)
1.109     kristaps  158:                p->symtab = mchars_alloc();
1.36      kristaps  159:
                    160:        n = man_node(man);
1.135     schwarze  161:        meta = man_meta(man);
1.1       kristaps  162:
1.135     schwarze  163:        term_begin(p, print_man_head, print_man_foot, meta);
1.1       kristaps  164:        p->flags |= TERMP_NOSPACE;
1.19      kristaps  165:
1.116     schwarze  166:        memset(&mt, 0, sizeof(struct mtermp));
                    167:
1.122     schwarze  168:        mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
                    169:        mt.offset = term_len(p, p->defindent);
1.134     schwarze  170:        mt.pardist = 1;
1.24      kristaps  171:
1.36      kristaps  172:        if (n->child)
1.135     schwarze  173:                print_man_nodelist(p, &mt, n->child, meta);
1.73      kristaps  174:
                    175:        term_end(p);
1.1       kristaps  176: }
                    177:
                    178:
1.77      kristaps  179: static size_t
                    180: a2height(const struct termp *p, const char *cp)
1.18      kristaps  181: {
1.40      kristaps  182:        struct roffsu    su;
1.18      kristaps  183:
1.77      kristaps  184:        if ( ! a2roffsu(cp, &su, SCALE_VS))
1.112     kristaps  185:                SCALE_VS_INIT(&su, atoi(cp));
1.18      kristaps  186:
1.77      kristaps  187:        return(term_vspan(p, &su));
1.18      kristaps  188: }
                    189:
                    190:
                    191: static int
1.77      kristaps  192: a2width(const struct termp *p, const char *cp)
1.38      kristaps  193: {
1.40      kristaps  194:        struct roffsu    su;
1.38      kristaps  195:
1.77      kristaps  196:        if ( ! a2roffsu(cp, &su, SCALE_BU))
1.41      kristaps  197:                return(-1);
1.40      kristaps  198:
1.77      kristaps  199:        return((int)term_hspan(p, &su));
1.38      kristaps  200: }
                    201:
1.111     kristaps  202: /*
                    203:  * Printing leading vertical space before a block.
                    204:  * This is used for the paragraph macros.
                    205:  * The rules are pretty simple, since there's very little nesting going
                    206:  * on here.  Basically, if we're the first within another block (SS/SH),
                    207:  * then don't emit vertical space.  If we are (RS), then do.  If not the
                    208:  * first, print it.
                    209:  */
1.39      kristaps  210: static void
1.134     schwarze  211: print_bvspace(struct termp *p, const struct man_node *n, int pardist)
1.18      kristaps  212: {
1.134     schwarze  213:        int      i;
1.111     kristaps  214:
1.39      kristaps  215:        term_newln(p);
1.101     schwarze  216:
1.111     kristaps  217:        if (n->body && n->body->child)
                    218:                if (MAN_TBL == n->body->child->type)
                    219:                        return;
                    220:
                    221:        if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
                    222:                if (NULL == n->prev)
                    223:                        return;
1.18      kristaps  224:
1.134     schwarze  225:        for (i = 0; i < pardist; i++)
                    226:                term_vspace(p);
1.18      kristaps  227: }
                    228:
1.3       kristaps  229: /* ARGSUSED */
1.1       kristaps  230: static int
1.29      kristaps  231: pre_ign(DECL_ARGS)
                    232: {
                    233:
                    234:        return(0);
                    235: }
                    236:
                    237:
                    238: /* ARGSUSED */
                    239: static int
1.1       kristaps  240: pre_I(DECL_ARGS)
                    241: {
                    242:
1.52      kristaps  243:        term_fontrepl(p, TERMFONT_UNDER);
1.19      kristaps  244:        return(1);
                    245: }
                    246:
                    247:
                    248: /* ARGSUSED */
1.3       kristaps  249: static int
1.84      kristaps  250: pre_literal(DECL_ARGS)
1.19      kristaps  251: {
                    252:
1.81      kristaps  253:        term_newln(p);
1.88      kristaps  254:
1.129     schwarze  255:        if (MAN_nf == n->tok || MAN_EX == n->tok)
1.84      kristaps  256:                mt->fl |= MANT_LITERAL;
1.88      kristaps  257:        else
1.84      kristaps  258:                mt->fl &= ~MANT_LITERAL;
                    259:
1.117     schwarze  260:        /*
                    261:         * Unlike .IP and .TP, .HP does not have a HEAD.
                    262:         * So in case a second call to term_flushln() is needed,
                    263:         * indentation has to be set up explicitly.
                    264:         */
                    265:        if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
1.121     schwarze  266:                p->offset = p->rmargin;
1.117     schwarze  267:                p->rmargin = p->maxrmargin;
1.139     schwarze  268:                p->trailspace = 0;
                    269:                p->flags &= ~TERMP_NOBREAK;
1.117     schwarze  270:                p->flags |= TERMP_NOSPACE;
                    271:        }
                    272:
1.99      schwarze  273:        return(0);
1.19      kristaps  274: }
                    275:
                    276: /* ARGSUSED */
                    277: static int
1.134     schwarze  278: pre_PD(DECL_ARGS)
                    279: {
                    280:
                    281:        n = n->child;
                    282:        if (0 == n) {
                    283:                mt->pardist = 1;
                    284:                return(0);
                    285:        }
                    286:        assert(MAN_TEXT == n->type);
                    287:        mt->pardist = atoi(n->string);
                    288:        return(0);
                    289: }
                    290:
                    291: /* ARGSUSED */
                    292: static int
1.88      kristaps  293: pre_alternate(DECL_ARGS)
1.3       kristaps  294: {
1.88      kristaps  295:        enum termfont            font[2];
                    296:        const struct man_node   *nn;
                    297:        int                      savelit, i;
1.3       kristaps  298:
1.88      kristaps  299:        switch (n->tok) {
                    300:        case (MAN_RB):
                    301:                font[0] = TERMFONT_NONE;
                    302:                font[1] = TERMFONT_BOLD;
                    303:                break;
                    304:        case (MAN_RI):
                    305:                font[0] = TERMFONT_NONE;
                    306:                font[1] = TERMFONT_UNDER;
                    307:                break;
                    308:        case (MAN_BR):
                    309:                font[0] = TERMFONT_BOLD;
                    310:                font[1] = TERMFONT_NONE;
                    311:                break;
                    312:        case (MAN_BI):
                    313:                font[0] = TERMFONT_BOLD;
                    314:                font[1] = TERMFONT_UNDER;
                    315:                break;
                    316:        case (MAN_IR):
                    317:                font[0] = TERMFONT_UNDER;
                    318:                font[1] = TERMFONT_NONE;
                    319:                break;
                    320:        case (MAN_IB):
                    321:                font[0] = TERMFONT_UNDER;
                    322:                font[1] = TERMFONT_BOLD;
                    323:                break;
                    324:        default:
                    325:                abort();
                    326:        }
1.35      kristaps  327:
1.88      kristaps  328:        savelit = MANT_LITERAL & mt->fl;
                    329:        mt->fl &= ~MANT_LITERAL;
1.35      kristaps  330:
1.88      kristaps  331:        for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
                    332:                term_fontrepl(p, font[i]);
                    333:                if (savelit && NULL == nn->next)
                    334:                        mt->fl |= MANT_LITERAL;
1.135     schwarze  335:                print_man_node(p, mt, nn, meta);
1.88      kristaps  336:                if (nn->next)
1.4       kristaps  337:                        p->flags |= TERMP_NOSPACE;
1.3       kristaps  338:        }
                    339:
                    340:        return(0);
                    341: }
                    342:
                    343: /* ARGSUSED */
1.1       kristaps  344: static int
                    345: pre_B(DECL_ARGS)
                    346: {
                    347:
1.52      kristaps  348:        term_fontrepl(p, TERMFONT_BOLD);
1.1       kristaps  349:        return(1);
1.127     kristaps  350: }
                    351:
                    352: /* ARGSUSED */
                    353: static int
                    354: pre_OP(DECL_ARGS)
                    355: {
                    356:
                    357:        term_word(p, "[");
                    358:        p->flags |= TERMP_NOSPACE;
                    359:
                    360:        if (NULL != (n = n->child)) {
                    361:                term_fontrepl(p, TERMFONT_BOLD);
                    362:                term_word(p, n->string);
                    363:        }
                    364:        if (NULL != n && NULL != n->next) {
                    365:                term_fontrepl(p, TERMFONT_UNDER);
                    366:                term_word(p, n->next->string);
                    367:        }
                    368:
                    369:        term_fontrepl(p, TERMFONT_NONE);
                    370:        p->flags |= TERMP_NOSPACE;
                    371:        term_word(p, "]");
                    372:        return(0);
1.89      kristaps  373: }
                    374:
                    375: /* ARGSUSED */
                    376: static int
                    377: pre_ft(DECL_ARGS)
                    378: {
                    379:        const char      *cp;
                    380:
                    381:        if (NULL == n->child) {
                    382:                term_fontlast(p);
                    383:                return(0);
                    384:        }
                    385:
                    386:        cp = n->child->string;
                    387:        switch (*cp) {
                    388:        case ('4'):
                    389:                /* FALLTHROUGH */
                    390:        case ('3'):
                    391:                /* FALLTHROUGH */
                    392:        case ('B'):
                    393:                term_fontrepl(p, TERMFONT_BOLD);
                    394:                break;
                    395:        case ('2'):
                    396:                /* FALLTHROUGH */
                    397:        case ('I'):
                    398:                term_fontrepl(p, TERMFONT_UNDER);
                    399:                break;
                    400:        case ('P'):
                    401:                term_fontlast(p);
                    402:                break;
                    403:        case ('1'):
                    404:                /* FALLTHROUGH */
                    405:        case ('C'):
                    406:                /* FALLTHROUGH */
                    407:        case ('R'):
                    408:                term_fontrepl(p, TERMFONT_NONE);
                    409:                break;
                    410:        default:
                    411:                break;
                    412:        }
                    413:        return(0);
1.83      kristaps  414: }
                    415:
                    416: /* ARGSUSED */
                    417: static int
                    418: pre_in(DECL_ARGS)
                    419: {
                    420:        int              len, less;
                    421:        size_t           v;
                    422:        const char      *cp;
                    423:
                    424:        term_newln(p);
                    425:
                    426:        if (NULL == n->child) {
                    427:                p->offset = mt->offset;
                    428:                return(0);
                    429:        }
                    430:
                    431:        cp = n->child->string;
                    432:        less = 0;
                    433:
                    434:        if ('-' == *cp)
                    435:                less = -1;
                    436:        else if ('+' == *cp)
                    437:                less = 1;
                    438:        else
                    439:                cp--;
                    440:
                    441:        if ((len = a2width(p, ++cp)) < 0)
                    442:                return(0);
                    443:
                    444:        v = (size_t)len;
                    445:
                    446:        if (less < 0)
                    447:                p->offset -= p->offset > v ? v : p->offset;
                    448:        else if (less > 0)
                    449:                p->offset += v;
                    450:        else
                    451:                p->offset = v;
1.95      kristaps  452:
                    453:        /* Don't let this creep beyond the right margin. */
                    454:
                    455:        if (p->offset > p->rmargin)
                    456:                p->offset = p->rmargin;
1.83      kristaps  457:
                    458:        return(0);
1.1       kristaps  459: }
                    460:
                    461:
1.3       kristaps  462: /* ARGSUSED */
1.1       kristaps  463: static int
1.19      kristaps  464: pre_sp(DECL_ARGS)
                    465: {
1.131     schwarze  466:        char            *s;
1.77      kristaps  467:        size_t           i, len;
1.131     schwarze  468:        int              neg;
1.112     kristaps  469:
                    470:        if ((NULL == n->prev && n->parent)) {
1.132     schwarze  471:                switch (n->parent->tok) {
                    472:                case (MAN_SH):
                    473:                        /* FALLTHROUGH */
                    474:                case (MAN_SS):
                    475:                        /* FALLTHROUGH */
                    476:                case (MAN_PP):
                    477:                        /* FALLTHROUGH */
                    478:                case (MAN_LP):
                    479:                        /* FALLTHROUGH */
                    480:                case (MAN_P):
                    481:                        /* FALLTHROUGH */
1.112     kristaps  482:                        return(0);
1.132     schwarze  483:                default:
                    484:                        break;
                    485:                }
1.112     kristaps  486:        }
1.19      kristaps  487:
1.131     schwarze  488:        neg = 0;
1.82      kristaps  489:        switch (n->tok) {
                    490:        case (MAN_br):
                    491:                len = 0;
                    492:                break;
                    493:        default:
1.131     schwarze  494:                if (NULL == n->child) {
                    495:                        len = 1;
                    496:                        break;
                    497:                }
                    498:                s = n->child->string;
                    499:                if ('-' == *s) {
                    500:                        neg = 1;
                    501:                        s++;
                    502:                }
                    503:                len = a2height(p, s);
1.82      kristaps  504:                break;
                    505:        }
1.38      kristaps  506:
1.19      kristaps  507:        if (0 == len)
                    508:                term_newln(p);
1.131     schwarze  509:        else if (neg)
                    510:                p->skipvsp += len;
                    511:        else
                    512:                for (i = 0; i < len; i++)
                    513:                        term_vspace(p);
1.19      kristaps  514:
1.15      kristaps  515:        return(0);
                    516: }
                    517:
                    518:
                    519: /* ARGSUSED */
                    520: static int
1.19      kristaps  521: pre_HP(DECL_ARGS)
                    522: {
1.117     schwarze  523:        size_t                   len, one;
1.24      kristaps  524:        int                      ival;
                    525:        const struct man_node   *nn;
1.19      kristaps  526:
1.20      kristaps  527:        switch (n->type) {
                    528:        case (MAN_BLOCK):
1.134     schwarze  529:                print_bvspace(p, n, mt->pardist);
1.24      kristaps  530:                return(1);
1.20      kristaps  531:        case (MAN_BODY):
                    532:                break;
                    533:        default:
                    534:                return(0);
                    535:        }
                    536:
1.130     schwarze  537:        if ( ! (MANT_LITERAL & mt->fl)) {
                    538:                p->flags |= TERMP_NOBREAK;
1.139     schwarze  539:                p->trailspace = 2;
1.130     schwarze  540:        }
                    541:
1.116     schwarze  542:        len = mt->lmargin[mt->lmargincur];
1.24      kristaps  543:        ival = -1;
                    544:
                    545:        /* Calculate offset. */
                    546:
1.39      kristaps  547:        if (NULL != (nn = n->parent->head->child))
1.77      kristaps  548:                if ((ival = a2width(p, nn->string)) >= 0)
1.24      kristaps  549:                        len = (size_t)ival;
                    550:
1.117     schwarze  551:        one = term_len(p, 1);
1.121     schwarze  552:        if (len < one)
1.117     schwarze  553:                len = one;
1.24      kristaps  554:
1.26      kristaps  555:        p->offset = mt->offset;
                    556:        p->rmargin = mt->offset + len;
1.24      kristaps  557:
                    558:        if (ival >= 0)
1.116     schwarze  559:                mt->lmargin[mt->lmargincur] = (size_t)ival;
1.24      kristaps  560:
1.19      kristaps  561:        return(1);
                    562: }
                    563:
                    564:
                    565: /* ARGSUSED */
1.20      kristaps  566: static void
                    567: post_HP(DECL_ARGS)
                    568: {
                    569:
                    570:        switch (n->type) {
                    571:        case (MAN_BODY):
1.136     schwarze  572:                term_newln(p);
1.20      kristaps  573:                p->flags &= ~TERMP_NOBREAK;
1.139     schwarze  574:                p->trailspace = 0;
1.26      kristaps  575:                p->offset = mt->offset;
1.20      kristaps  576:                p->rmargin = p->maxrmargin;
                    577:                break;
                    578:        default:
                    579:                break;
                    580:        }
                    581: }
                    582:
                    583:
                    584: /* ARGSUSED */
1.19      kristaps  585: static int
1.1       kristaps  586: pre_PP(DECL_ARGS)
                    587: {
                    588:
1.19      kristaps  589:        switch (n->type) {
                    590:        case (MAN_BLOCK):
1.122     schwarze  591:                mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
1.134     schwarze  592:                print_bvspace(p, n, mt->pardist);
1.19      kristaps  593:                break;
                    594:        default:
1.26      kristaps  595:                p->offset = mt->offset;
1.19      kristaps  596:                break;
                    597:        }
                    598:
1.87      kristaps  599:        return(MAN_HEAD != n->type);
1.1       kristaps  600: }
                    601:
                    602:
1.3       kristaps  603: /* ARGSUSED */
1.1       kristaps  604: static int
1.4       kristaps  605: pre_IP(DECL_ARGS)
                    606: {
1.22      kristaps  607:        const struct man_node   *nn;
                    608:        size_t                   len;
1.94      schwarze  609:        int                      savelit, ival;
1.18      kristaps  610:
1.22      kristaps  611:        switch (n->type) {
                    612:        case (MAN_BODY):
                    613:                p->flags |= TERMP_NOSPACE;
                    614:                break;
                    615:        case (MAN_HEAD):
                    616:                p->flags |= TERMP_NOBREAK;
1.139     schwarze  617:                p->trailspace = 1;
1.22      kristaps  618:                break;
1.23      kristaps  619:        case (MAN_BLOCK):
1.134     schwarze  620:                print_bvspace(p, n, mt->pardist);
1.23      kristaps  621:                /* FALLTHROUGH */
1.22      kristaps  622:        default:
                    623:                return(1);
                    624:        }
1.18      kristaps  625:
1.116     schwarze  626:        len = mt->lmargin[mt->lmargincur];
1.22      kristaps  627:        ival = -1;
1.4       kristaps  628:
1.94      schwarze  629:        /* Calculate the offset from the optional second argument. */
1.22      kristaps  630:        if (NULL != (nn = n->parent->head->child))
1.94      schwarze  631:                if (NULL != (nn = nn->next))
1.77      kristaps  632:                        if ((ival = a2width(p, nn->string)) >= 0)
1.22      kristaps  633:                                len = (size_t)ival;
1.4       kristaps  634:
1.22      kristaps  635:        switch (n->type) {
                    636:        case (MAN_HEAD):
1.23      kristaps  637:                /* Handle zero-width lengths. */
                    638:                if (0 == len)
1.77      kristaps  639:                        len = term_len(p, 1);
1.23      kristaps  640:
1.26      kristaps  641:                p->offset = mt->offset;
                    642:                p->rmargin = mt->offset + len;
1.22      kristaps  643:                if (ival < 0)
                    644:                        break;
1.18      kristaps  645:
1.24      kristaps  646:                /* Set the saved left-margin. */
1.116     schwarze  647:                mt->lmargin[mt->lmargincur] = (size_t)ival;
1.24      kristaps  648:
1.94      schwarze  649:                savelit = MANT_LITERAL & mt->fl;
                    650:                mt->fl &= ~MANT_LITERAL;
                    651:
                    652:                if (n->child)
1.135     schwarze  653:                        print_man_node(p, mt, n->child, meta);
1.94      schwarze  654:
                    655:                if (savelit)
                    656:                        mt->fl |= MANT_LITERAL;
                    657:
1.22      kristaps  658:                return(0);
1.23      kristaps  659:        case (MAN_BODY):
1.26      kristaps  660:                p->offset = mt->offset + len;
1.140   ! schwarze  661:                p->rmargin = p->maxrmargin > p->offset ?
        !           662:                                p->maxrmargin : p->offset;
1.23      kristaps  663:                break;
1.22      kristaps  664:        default:
                    665:                break;
1.18      kristaps  666:        }
                    667:
1.22      kristaps  668:        return(1);
                    669: }
1.18      kristaps  670:
                    671:
1.22      kristaps  672: /* ARGSUSED */
                    673: static void
                    674: post_IP(DECL_ARGS)
                    675: {
1.4       kristaps  676:
1.22      kristaps  677:        switch (n->type) {
                    678:        case (MAN_HEAD):
                    679:                term_flushln(p);
                    680:                p->flags &= ~TERMP_NOBREAK;
1.139     schwarze  681:                p->trailspace = 0;
1.22      kristaps  682:                p->rmargin = p->maxrmargin;
                    683:                break;
                    684:        case (MAN_BODY):
1.94      schwarze  685:                term_newln(p);
1.138     schwarze  686:                p->offset = mt->offset;
1.22      kristaps  687:                break;
                    688:        default:
                    689:                break;
                    690:        }
1.4       kristaps  691: }
                    692:
                    693:
                    694: /* ARGSUSED */
                    695: static int
1.1       kristaps  696: pre_TP(DECL_ARGS)
                    697: {
1.23      kristaps  698:        const struct man_node   *nn;
                    699:        size_t                   len;
1.94      schwarze  700:        int                      savelit, ival;
1.1       kristaps  701:
1.21      kristaps  702:        switch (n->type) {
                    703:        case (MAN_HEAD):
                    704:                p->flags |= TERMP_NOBREAK;
1.139     schwarze  705:                p->trailspace = 1;
1.21      kristaps  706:                break;
                    707:        case (MAN_BODY):
                    708:                p->flags |= TERMP_NOSPACE;
1.23      kristaps  709:                break;
                    710:        case (MAN_BLOCK):
1.134     schwarze  711:                print_bvspace(p, n, mt->pardist);
1.23      kristaps  712:                /* FALLTHROUGH */
                    713:        default:
                    714:                return(1);
                    715:        }
                    716:
1.116     schwarze  717:        len = (size_t)mt->lmargin[mt->lmargincur];
1.23      kristaps  718:        ival = -1;
                    719:
                    720:        /* Calculate offset. */
                    721:
1.116     schwarze  722:        if (NULL != (nn = n->parent->head->child))
1.120     schwarze  723:                if (nn->string && nn->parent->line == nn->line)
1.77      kristaps  724:                        if ((ival = a2width(p, nn->string)) >= 0)
1.23      kristaps  725:                                len = (size_t)ival;
                    726:
                    727:        switch (n->type) {
                    728:        case (MAN_HEAD):
                    729:                /* Handle zero-length properly. */
                    730:                if (0 == len)
1.77      kristaps  731:                        len = term_len(p, 1);
1.23      kristaps  732:
1.26      kristaps  733:                p->offset = mt->offset;
                    734:                p->rmargin = mt->offset + len;
1.23      kristaps  735:
1.94      schwarze  736:                savelit = MANT_LITERAL & mt->fl;
                    737:                mt->fl &= ~MANT_LITERAL;
                    738:
1.23      kristaps  739:                /* Don't print same-line elements. */
1.94      schwarze  740:                for (nn = n->child; nn; nn = nn->next)
1.23      kristaps  741:                        if (nn->line > n->line)
1.135     schwarze  742:                                print_man_node(p, mt, nn, meta);
1.24      kristaps  743:
1.94      schwarze  744:                if (savelit)
                    745:                        mt->fl |= MANT_LITERAL;
1.24      kristaps  746:                if (ival >= 0)
1.116     schwarze  747:                        mt->lmargin[mt->lmargincur] = (size_t)ival;
1.24      kristaps  748:
1.23      kristaps  749:                return(0);
                    750:        case (MAN_BODY):
1.26      kristaps  751:                p->offset = mt->offset + len;
1.140   ! schwarze  752:                p->rmargin = p->maxrmargin > p->offset ?
        !           753:                                p->maxrmargin : p->offset;
1.139     schwarze  754:                p->trailspace = 0;
1.130     schwarze  755:                p->flags &= ~TERMP_NOBREAK;
1.21      kristaps  756:                break;
                    757:        default:
                    758:                break;
                    759:        }
1.16      kristaps  760:
1.21      kristaps  761:        return(1);
                    762: }
1.1       kristaps  763:
                    764:
1.21      kristaps  765: /* ARGSUSED */
                    766: static void
                    767: post_TP(DECL_ARGS)
                    768: {
1.1       kristaps  769:
1.21      kristaps  770:        switch (n->type) {
                    771:        case (MAN_HEAD):
                    772:                term_flushln(p);
                    773:                break;
                    774:        case (MAN_BODY):
1.94      schwarze  775:                term_newln(p);
1.138     schwarze  776:                p->offset = mt->offset;
1.21      kristaps  777:                break;
                    778:        default:
                    779:                break;
                    780:        }
1.1       kristaps  781: }
                    782:
                    783:
1.3       kristaps  784: /* ARGSUSED */
1.1       kristaps  785: static int
                    786: pre_SS(DECL_ARGS)
                    787: {
1.134     schwarze  788:        int      i;
1.1       kristaps  789:
1.19      kristaps  790:        switch (n->type) {
                    791:        case (MAN_BLOCK):
1.113     kristaps  792:                mt->fl &= ~MANT_LITERAL;
1.122     schwarze  793:                mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
                    794:                mt->offset = term_len(p, p->defindent);
1.24      kristaps  795:                /* If following a prior empty `SS', no vspace. */
                    796:                if (n->prev && MAN_SS == n->prev->tok)
                    797:                        if (NULL == n->prev->body->child)
                    798:                                break;
                    799:                if (NULL == n->prev)
                    800:                        break;
1.134     schwarze  801:                for (i = 0; i < mt->pardist; i++)
                    802:                        term_vspace(p);
1.19      kristaps  803:                break;
                    804:        case (MAN_HEAD):
1.52      kristaps  805:                term_fontrepl(p, TERMFONT_BOLD);
1.133     schwarze  806:                p->offset = term_len(p, 3);
1.19      kristaps  807:                break;
1.24      kristaps  808:        case (MAN_BODY):
1.26      kristaps  809:                p->offset = mt->offset;
1.24      kristaps  810:                break;
1.19      kristaps  811:        default:
                    812:                break;
                    813:        }
                    814:
1.1       kristaps  815:        return(1);
                    816: }
                    817:
                    818:
1.3       kristaps  819: /* ARGSUSED */
1.1       kristaps  820: static void
                    821: post_SS(DECL_ARGS)
                    822: {
                    823:
1.19      kristaps  824:        switch (n->type) {
                    825:        case (MAN_HEAD):
                    826:                term_newln(p);
                    827:                break;
1.24      kristaps  828:        case (MAN_BODY):
                    829:                term_newln(p);
                    830:                break;
1.19      kristaps  831:        default:
                    832:                break;
                    833:        }
1.1       kristaps  834: }
                    835:
                    836:
1.3       kristaps  837: /* ARGSUSED */
1.1       kristaps  838: static int
                    839: pre_SH(DECL_ARGS)
                    840: {
1.134     schwarze  841:        int      i;
1.22      kristaps  842:
1.19      kristaps  843:        switch (n->type) {
                    844:        case (MAN_BLOCK):
1.113     kristaps  845:                mt->fl &= ~MANT_LITERAL;
1.122     schwarze  846:                mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
                    847:                mt->offset = term_len(p, p->defindent);
1.22      kristaps  848:                /* If following a prior empty `SH', no vspace. */
1.19      kristaps  849:                if (n->prev && MAN_SH == n->prev->tok)
                    850:                        if (NULL == n->prev->body->child)
                    851:                                break;
1.61      kristaps  852:                /* If the first macro, no vspae. */
                    853:                if (NULL == n->prev)
                    854:                        break;
1.134     schwarze  855:                for (i = 0; i < mt->pardist; i++)
                    856:                        term_vspace(p);
1.19      kristaps  857:                break;
                    858:        case (MAN_HEAD):
1.52      kristaps  859:                term_fontrepl(p, TERMFONT_BOLD);
1.19      kristaps  860:                p->offset = 0;
                    861:                break;
                    862:        case (MAN_BODY):
1.26      kristaps  863:                p->offset = mt->offset;
1.19      kristaps  864:                break;
                    865:        default:
                    866:                break;
                    867:        }
1.1       kristaps  868:
                    869:        return(1);
                    870: }
                    871:
                    872:
1.3       kristaps  873: /* ARGSUSED */
1.1       kristaps  874: static void
                    875: post_SH(DECL_ARGS)
                    876: {
                    877:
1.19      kristaps  878:        switch (n->type) {
                    879:        case (MAN_HEAD):
                    880:                term_newln(p);
                    881:                break;
                    882:        case (MAN_BODY):
                    883:                term_newln(p);
                    884:                break;
                    885:        default:
                    886:                break;
                    887:        }
1.1       kristaps  888: }
                    889:
1.26      kristaps  890: /* ARGSUSED */
                    891: static int
                    892: pre_RS(DECL_ARGS)
                    893: {
1.110     kristaps  894:        int              ival;
                    895:        size_t           sz;
1.26      kristaps  896:
                    897:        switch (n->type) {
                    898:        case (MAN_BLOCK):
                    899:                term_newln(p);
                    900:                return(1);
                    901:        case (MAN_HEAD):
                    902:                return(0);
                    903:        default:
                    904:                break;
                    905:        }
                    906:
1.122     schwarze  907:        sz = term_len(p, p->defindent);
1.26      kristaps  908:
1.110     kristaps  909:        if (NULL != (n = n->parent->head->child))
                    910:                if ((ival = a2width(p, n->string)) >= 0)
                    911:                        sz = (size_t)ival;
1.26      kristaps  912:
1.110     kristaps  913:        mt->offset += sz;
1.140   ! schwarze  914:        p->offset = mt->offset;
        !           915:        p->rmargin = p->maxrmargin > p->offset ?
        !           916:                        p->maxrmargin : p->offset;
1.26      kristaps  917:
1.116     schwarze  918:        if (++mt->lmarginsz < MAXMARGINS)
                    919:                mt->lmargincur = mt->lmarginsz;
                    920:
                    921:        mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1];
1.26      kristaps  922:        return(1);
                    923: }
                    924:
                    925: /* ARGSUSED */
                    926: static void
                    927: post_RS(DECL_ARGS)
                    928: {
1.110     kristaps  929:        int              ival;
                    930:        size_t           sz;
1.26      kristaps  931:
                    932:        switch (n->type) {
                    933:        case (MAN_BLOCK):
1.110     kristaps  934:                return;
1.59      kristaps  935:        case (MAN_HEAD):
1.110     kristaps  936:                return;
1.26      kristaps  937:        default:
                    938:                term_newln(p);
                    939:                break;
                    940:        }
1.110     kristaps  941:
1.122     schwarze  942:        sz = term_len(p, p->defindent);
1.110     kristaps  943:
                    944:        if (NULL != (n = n->parent->head->child))
                    945:                if ((ival = a2width(p, n->string)) >= 0)
                    946:                        sz = (size_t)ival;
                    947:
                    948:        mt->offset = mt->offset < sz ?  0 : mt->offset - sz;
                    949:        p->offset = mt->offset;
1.116     schwarze  950:
                    951:        if (--mt->lmarginsz < MAXMARGINS)
                    952:                mt->lmargincur = mt->lmarginsz;
1.137     schwarze  953: }
                    954:
                    955: /* ARGSUSED */
                    956: static int
                    957: pre_UR(DECL_ARGS)
                    958: {
                    959:
                    960:        return (MAN_HEAD != n->type);
                    961: }
                    962:
                    963: /* ARGSUSED */
                    964: static void
                    965: post_UR(DECL_ARGS)
                    966: {
                    967:
                    968:        if (MAN_BLOCK != n->type)
                    969:                return;
                    970:
                    971:        term_word(p, "<");
                    972:        p->flags |= TERMP_NOSPACE;
                    973:
                    974:        if (NULL != n->child->child)
                    975:                print_man_node(p, mt, n->child->child, meta);
                    976:
                    977:        p->flags |= TERMP_NOSPACE;
                    978:        term_word(p, ">");
1.26      kristaps  979: }
                    980:
1.1       kristaps  981: static void
1.45      kristaps  982: print_man_node(DECL_ARGS)
1.1       kristaps  983: {
1.65      joerg     984:        size_t           rm, rmax;
1.54      kristaps  985:        int              c;
1.1       kristaps  986:
                    987:        switch (n->type) {
                    988:        case(MAN_TEXT):
1.97      kristaps  989:                /*
                    990:                 * If we have a blank line, output a vertical space.
                    991:                 * If we have a space as the first character, break
                    992:                 * before printing the line's data.
                    993:                 */
1.96      kristaps  994:                if ('\0' == *n->string) {
1.4       kristaps  995:                        term_vspace(p);
1.98      schwarze  996:                        return;
1.97      kristaps  997:                } else if (' ' == *n->string && MAN_LINE & n->flags)
1.96      kristaps  998:                        term_newln(p);
1.54      kristaps  999:
1.4       kristaps 1000:                term_word(p, n->string);
1.130     schwarze 1001:                goto out;
1.52      kristaps 1002:
1.102     kristaps 1003:        case (MAN_EQN):
1.115     kristaps 1004:                term_eqn(p, n->eqn);
1.97      kristaps 1005:                return;
1.91      kristaps 1006:        case (MAN_TBL):
1.97      kristaps 1007:                /*
                   1008:                 * Tables are preceded by a newline.  Then process a
                   1009:                 * table line, which will cause line termination,
                   1010:                 */
1.93      kristaps 1011:                if (TBL_SPAN_FIRST & n->span->flags)
                   1012:                        term_newln(p);
1.92      kristaps 1013:                term_tbl(p, n->span);
1.97      kristaps 1014:                return;
1.1       kristaps 1015:        default:
                   1016:                break;
                   1017:        }
                   1018:
1.97      kristaps 1019:        if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
                   1020:                term_fontrepl(p, TERMFONT_NONE);
                   1021:
                   1022:        c = 1;
                   1023:        if (termacts[n->tok].pre)
1.135     schwarze 1024:                c = (*termacts[n->tok].pre)(p, mt, n, meta);
1.97      kristaps 1025:
1.1       kristaps 1026:        if (c && n->child)
1.135     schwarze 1027:                print_man_nodelist(p, mt, n->child, meta);
1.1       kristaps 1028:
1.97      kristaps 1029:        if (termacts[n->tok].post)
1.135     schwarze 1030:                (*termacts[n->tok].post)(p, mt, n, meta);
1.97      kristaps 1031:        if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
                   1032:                term_fontrepl(p, TERMFONT_NONE);
1.63      kristaps 1033:
1.130     schwarze 1034: out:
                   1035:        /*
                   1036:         * If we're in a literal context, make sure that words
                   1037:         * together on the same line stay together.  This is a
                   1038:         * POST-printing call, so we check the NEXT word.  Since
                   1039:         * -man doesn't have nested macros, we don't need to be
                   1040:         * more specific than this.
                   1041:         */
                   1042:        if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
1.136     schwarze 1043:            (NULL == n->next || n->next->line > n->line)) {
1.130     schwarze 1044:                rm = p->rmargin;
                   1045:                rmax = p->maxrmargin;
                   1046:                p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
                   1047:                p->flags |= TERMP_NOSPACE;
                   1048:                if (NULL != n->string && '\0' != *n->string)
                   1049:                        term_flushln(p);
                   1050:                else
                   1051:                        term_newln(p);
                   1052:                if (rm < rmax && n->parent->tok == MAN_HP) {
                   1053:                        p->offset = rm;
                   1054:                        p->rmargin = rmax;
                   1055:                } else
                   1056:                        p->rmargin = rm;
                   1057:                p->maxrmargin = rmax;
                   1058:        }
1.63      kristaps 1059:        if (MAN_EOS & n->flags)
                   1060:                p->flags |= TERMP_SENTENCE;
1.1       kristaps 1061: }
                   1062:
                   1063:
                   1064: static void
1.52      kristaps 1065: print_man_nodelist(DECL_ARGS)
1.1       kristaps 1066: {
1.19      kristaps 1067:
1.135     schwarze 1068:        print_man_node(p, mt, n, meta);
1.1       kristaps 1069:        if ( ! n->next)
                   1070:                return;
1.135     schwarze 1071:        print_man_nodelist(p, mt, n->next, meta);
1.1       kristaps 1072: }
                   1073:
                   1074:
1.31      kristaps 1075: static void
1.73      kristaps 1076: print_man_foot(struct termp *p, const void *arg)
1.1       kristaps 1077: {
1.123     schwarze 1078:        char            title[BUFSIZ];
                   1079:        size_t          datelen;
1.73      kristaps 1080:        const struct man_meta *meta;
                   1081:
                   1082:        meta = (const struct man_meta *)arg;
1.125     schwarze 1083:        assert(meta->title);
                   1084:        assert(meta->msec);
                   1085:        assert(meta->date);
1.1       kristaps 1086:
1.52      kristaps 1087:        term_fontrepl(p, TERMFONT_NONE);
1.50      kristaps 1088:
1.69      joerg    1089:        term_vspace(p);
1.126     schwarze 1090:
                   1091:        /*
                   1092:         * Temporary, undocumented option to imitate mdoc(7) output.
                   1093:         * In the bottom right corner, use the source instead of
                   1094:         * the title.
                   1095:         */
                   1096:
                   1097:        if ( ! p->mdocstyle) {
                   1098:                term_vspace(p);
                   1099:                term_vspace(p);
                   1100:                snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
                   1101:        } else if (meta->source) {
                   1102:                strlcpy(title, meta->source, BUFSIZ);
                   1103:        } else {
                   1104:                title[0] = '\0';
                   1105:        }
1.125     schwarze 1106:        datelen = term_strlen(p, meta->date);
1.1       kristaps 1107:
1.126     schwarze 1108:        /* Bottom left corner: manual source. */
                   1109:
1.1       kristaps 1110:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.139     schwarze 1111:        p->trailspace = 1;
1.1       kristaps 1112:        p->offset = 0;
1.123     schwarze 1113:        p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
1.1       kristaps 1114:
                   1115:        if (meta->source)
                   1116:                term_word(p, meta->source);
                   1117:        term_flushln(p);
                   1118:
1.126     schwarze 1119:        /* At the bottom in the middle: manual date. */
                   1120:
1.117     schwarze 1121:        p->flags |= TERMP_NOSPACE;
1.1       kristaps 1122:        p->offset = p->rmargin;
1.123     schwarze 1123:        p->rmargin = p->maxrmargin - term_strlen(p, title);
                   1124:        if (p->offset + datelen >= p->rmargin)
                   1125:                p->rmargin = p->offset + datelen;
                   1126:
1.125     schwarze 1127:        term_word(p, meta->date);
1.123     schwarze 1128:        term_flushln(p);
                   1129:
1.126     schwarze 1130:        /* Bottom right corner: manual title and section. */
                   1131:
1.123     schwarze 1132:        p->flags &= ~TERMP_NOBREAK;
                   1133:        p->flags |= TERMP_NOSPACE;
1.139     schwarze 1134:        p->trailspace = 0;
1.123     schwarze 1135:        p->offset = p->rmargin;
1.1       kristaps 1136:        p->rmargin = p->maxrmargin;
                   1137:
1.123     schwarze 1138:        term_word(p, title);
1.1       kristaps 1139:        term_flushln(p);
                   1140: }
                   1141:
                   1142:
1.31      kristaps 1143: static void
1.73      kristaps 1144: print_man_head(struct termp *p, const void *arg)
1.1       kristaps 1145: {
1.46      kristaps 1146:        char            buf[BUFSIZ], title[BUFSIZ];
1.57      kristaps 1147:        size_t          buflen, titlen;
1.135     schwarze 1148:        const struct man_meta *meta;
1.73      kristaps 1149:
1.135     schwarze 1150:        meta = (const struct man_meta *)arg;
                   1151:        assert(meta->title);
                   1152:        assert(meta->msec);
1.1       kristaps 1153:
1.135     schwarze 1154:        if (meta->vol)
                   1155:                strlcpy(buf, meta->vol, BUFSIZ);
1.126     schwarze 1156:        else
                   1157:                buf[0] = '\0';
1.77      kristaps 1158:        buflen = term_strlen(p, buf);
1.1       kristaps 1159:
1.126     schwarze 1160:        /* Top left corner: manual title and section. */
                   1161:
1.135     schwarze 1162:        snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
1.77      kristaps 1163:        titlen = term_strlen(p, title);
1.1       kristaps 1164:
1.118     schwarze 1165:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1.139     schwarze 1166:        p->trailspace = 1;
1.1       kristaps 1167:        p->offset = 0;
1.57      kristaps 1168:        p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77      kristaps 1169:            (p->maxrmargin -
                   1170:             term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57      kristaps 1171:            p->maxrmargin - buflen;
1.1       kristaps 1172:
                   1173:        term_word(p, title);
                   1174:        term_flushln(p);
                   1175:
1.126     schwarze 1176:        /* At the top in the middle: manual volume. */
                   1177:
1.117     schwarze 1178:        p->flags |= TERMP_NOSPACE;
1.1       kristaps 1179:        p->offset = p->rmargin;
1.57      kristaps 1180:        p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
                   1181:            p->maxrmargin - titlen : p->maxrmargin;
1.1       kristaps 1182:
                   1183:        term_word(p, buf);
                   1184:        term_flushln(p);
                   1185:
1.126     schwarze 1186:        /* Top right corner: title and section, again. */
                   1187:
1.1       kristaps 1188:        p->flags &= ~TERMP_NOBREAK;
1.139     schwarze 1189:        p->trailspace = 0;
1.57      kristaps 1190:        if (p->rmargin + titlen <= p->maxrmargin) {
1.117     schwarze 1191:                p->flags |= TERMP_NOSPACE;
1.57      kristaps 1192:                p->offset = p->rmargin;
                   1193:                p->rmargin = p->maxrmargin;
                   1194:                term_word(p, title);
                   1195:                term_flushln(p);
                   1196:        }
1.1       kristaps 1197:
1.118     schwarze 1198:        p->flags &= ~TERMP_NOSPACE;
                   1199:        p->offset = 0;
1.1       kristaps 1200:        p->rmargin = p->maxrmargin;
1.61      kristaps 1201:
1.62      kristaps 1202:        /*
1.126     schwarze 1203:         * Groff prints three blank lines before the content.
                   1204:         * Do the same, except in the temporary, undocumented
                   1205:         * mode imitating mdoc(7) output.
1.62      kristaps 1206:         */
                   1207:
1.61      kristaps 1208:        term_vspace(p);
1.126     schwarze 1209:        if ( ! p->mdocstyle) {
                   1210:                term_vspace(p);
                   1211:                term_vspace(p);
                   1212:        }
1.1       kristaps 1213: }

CVSweb