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

Annotation of mandoc/man_term.c, Revision 1.142

1.142   ! schwarze    1: /*     $Id: man_term.c,v 1.141 2014/03/08 15:50:41 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.141     schwarze  723:                if (nn->string && 0 == (MAN_LINE & nn->flags))
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.141     schwarze  740:                nn = n->child;
                    741:                while (NULL != nn && 0 == (MAN_LINE & nn->flags))
                    742:                        nn = nn->next;
                    743:
                    744:                while (NULL != nn) {
                    745:                        print_man_node(p, mt, nn, meta);
                    746:                        nn = nn->next;
                    747:                }
1.24      kristaps  748:
1.94      schwarze  749:                if (savelit)
                    750:                        mt->fl |= MANT_LITERAL;
1.24      kristaps  751:                if (ival >= 0)
1.116     schwarze  752:                        mt->lmargin[mt->lmargincur] = (size_t)ival;
1.24      kristaps  753:
1.23      kristaps  754:                return(0);
                    755:        case (MAN_BODY):
1.26      kristaps  756:                p->offset = mt->offset + len;
1.140     schwarze  757:                p->rmargin = p->maxrmargin > p->offset ?
                    758:                                p->maxrmargin : p->offset;
1.139     schwarze  759:                p->trailspace = 0;
1.130     schwarze  760:                p->flags &= ~TERMP_NOBREAK;
1.21      kristaps  761:                break;
                    762:        default:
                    763:                break;
                    764:        }
1.16      kristaps  765:
1.21      kristaps  766:        return(1);
                    767: }
1.1       kristaps  768:
                    769:
1.21      kristaps  770: /* ARGSUSED */
                    771: static void
                    772: post_TP(DECL_ARGS)
                    773: {
1.1       kristaps  774:
1.21      kristaps  775:        switch (n->type) {
                    776:        case (MAN_HEAD):
                    777:                term_flushln(p);
                    778:                break;
                    779:        case (MAN_BODY):
1.94      schwarze  780:                term_newln(p);
1.138     schwarze  781:                p->offset = mt->offset;
1.21      kristaps  782:                break;
                    783:        default:
                    784:                break;
                    785:        }
1.1       kristaps  786: }
                    787:
                    788:
1.3       kristaps  789: /* ARGSUSED */
1.1       kristaps  790: static int
                    791: pre_SS(DECL_ARGS)
                    792: {
1.134     schwarze  793:        int      i;
1.1       kristaps  794:
1.19      kristaps  795:        switch (n->type) {
                    796:        case (MAN_BLOCK):
1.113     kristaps  797:                mt->fl &= ~MANT_LITERAL;
1.122     schwarze  798:                mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
                    799:                mt->offset = term_len(p, p->defindent);
1.24      kristaps  800:                /* If following a prior empty `SS', no vspace. */
                    801:                if (n->prev && MAN_SS == n->prev->tok)
                    802:                        if (NULL == n->prev->body->child)
                    803:                                break;
                    804:                if (NULL == n->prev)
                    805:                        break;
1.134     schwarze  806:                for (i = 0; i < mt->pardist; i++)
                    807:                        term_vspace(p);
1.19      kristaps  808:                break;
                    809:        case (MAN_HEAD):
1.52      kristaps  810:                term_fontrepl(p, TERMFONT_BOLD);
1.133     schwarze  811:                p->offset = term_len(p, 3);
1.19      kristaps  812:                break;
1.24      kristaps  813:        case (MAN_BODY):
1.26      kristaps  814:                p->offset = mt->offset;
1.24      kristaps  815:                break;
1.19      kristaps  816:        default:
                    817:                break;
                    818:        }
                    819:
1.1       kristaps  820:        return(1);
                    821: }
                    822:
                    823:
1.3       kristaps  824: /* ARGSUSED */
1.1       kristaps  825: static void
                    826: post_SS(DECL_ARGS)
                    827: {
                    828:
1.19      kristaps  829:        switch (n->type) {
                    830:        case (MAN_HEAD):
                    831:                term_newln(p);
                    832:                break;
1.24      kristaps  833:        case (MAN_BODY):
                    834:                term_newln(p);
                    835:                break;
1.19      kristaps  836:        default:
                    837:                break;
                    838:        }
1.1       kristaps  839: }
                    840:
                    841:
1.3       kristaps  842: /* ARGSUSED */
1.1       kristaps  843: static int
                    844: pre_SH(DECL_ARGS)
                    845: {
1.134     schwarze  846:        int      i;
1.22      kristaps  847:
1.19      kristaps  848:        switch (n->type) {
                    849:        case (MAN_BLOCK):
1.113     kristaps  850:                mt->fl &= ~MANT_LITERAL;
1.122     schwarze  851:                mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
                    852:                mt->offset = term_len(p, p->defindent);
1.22      kristaps  853:                /* If following a prior empty `SH', no vspace. */
1.19      kristaps  854:                if (n->prev && MAN_SH == n->prev->tok)
                    855:                        if (NULL == n->prev->body->child)
                    856:                                break;
1.61      kristaps  857:                /* If the first macro, no vspae. */
                    858:                if (NULL == n->prev)
                    859:                        break;
1.134     schwarze  860:                for (i = 0; i < mt->pardist; i++)
                    861:                        term_vspace(p);
1.19      kristaps  862:                break;
                    863:        case (MAN_HEAD):
1.52      kristaps  864:                term_fontrepl(p, TERMFONT_BOLD);
1.19      kristaps  865:                p->offset = 0;
                    866:                break;
                    867:        case (MAN_BODY):
1.26      kristaps  868:                p->offset = mt->offset;
1.19      kristaps  869:                break;
                    870:        default:
                    871:                break;
                    872:        }
1.1       kristaps  873:
                    874:        return(1);
                    875: }
                    876:
                    877:
1.3       kristaps  878: /* ARGSUSED */
1.1       kristaps  879: static void
                    880: post_SH(DECL_ARGS)
                    881: {
                    882:
1.19      kristaps  883:        switch (n->type) {
                    884:        case (MAN_HEAD):
                    885:                term_newln(p);
                    886:                break;
                    887:        case (MAN_BODY):
                    888:                term_newln(p);
                    889:                break;
                    890:        default:
                    891:                break;
                    892:        }
1.1       kristaps  893: }
                    894:
1.26      kristaps  895: /* ARGSUSED */
                    896: static int
                    897: pre_RS(DECL_ARGS)
                    898: {
1.110     kristaps  899:        int              ival;
                    900:        size_t           sz;
1.26      kristaps  901:
                    902:        switch (n->type) {
                    903:        case (MAN_BLOCK):
                    904:                term_newln(p);
                    905:                return(1);
                    906:        case (MAN_HEAD):
                    907:                return(0);
                    908:        default:
                    909:                break;
                    910:        }
                    911:
1.122     schwarze  912:        sz = term_len(p, p->defindent);
1.26      kristaps  913:
1.110     kristaps  914:        if (NULL != (n = n->parent->head->child))
                    915:                if ((ival = a2width(p, n->string)) >= 0)
                    916:                        sz = (size_t)ival;
1.26      kristaps  917:
1.110     kristaps  918:        mt->offset += sz;
1.140     schwarze  919:        p->offset = mt->offset;
                    920:        p->rmargin = p->maxrmargin > p->offset ?
                    921:                        p->maxrmargin : p->offset;
1.26      kristaps  922:
1.116     schwarze  923:        if (++mt->lmarginsz < MAXMARGINS)
                    924:                mt->lmargincur = mt->lmarginsz;
                    925:
                    926:        mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1];
1.26      kristaps  927:        return(1);
                    928: }
                    929:
                    930: /* ARGSUSED */
                    931: static void
                    932: post_RS(DECL_ARGS)
                    933: {
1.110     kristaps  934:        int              ival;
                    935:        size_t           sz;
1.26      kristaps  936:
                    937:        switch (n->type) {
                    938:        case (MAN_BLOCK):
1.110     kristaps  939:                return;
1.59      kristaps  940:        case (MAN_HEAD):
1.110     kristaps  941:                return;
1.26      kristaps  942:        default:
                    943:                term_newln(p);
                    944:                break;
                    945:        }
1.110     kristaps  946:
1.122     schwarze  947:        sz = term_len(p, p->defindent);
1.110     kristaps  948:
                    949:        if (NULL != (n = n->parent->head->child))
                    950:                if ((ival = a2width(p, n->string)) >= 0)
                    951:                        sz = (size_t)ival;
                    952:
                    953:        mt->offset = mt->offset < sz ?  0 : mt->offset - sz;
                    954:        p->offset = mt->offset;
1.116     schwarze  955:
                    956:        if (--mt->lmarginsz < MAXMARGINS)
                    957:                mt->lmargincur = mt->lmarginsz;
1.137     schwarze  958: }
                    959:
                    960: /* ARGSUSED */
                    961: static int
                    962: pre_UR(DECL_ARGS)
                    963: {
                    964:
                    965:        return (MAN_HEAD != n->type);
                    966: }
                    967:
                    968: /* ARGSUSED */
                    969: static void
                    970: post_UR(DECL_ARGS)
                    971: {
                    972:
                    973:        if (MAN_BLOCK != n->type)
                    974:                return;
                    975:
                    976:        term_word(p, "<");
                    977:        p->flags |= TERMP_NOSPACE;
                    978:
                    979:        if (NULL != n->child->child)
                    980:                print_man_node(p, mt, n->child->child, meta);
                    981:
                    982:        p->flags |= TERMP_NOSPACE;
                    983:        term_word(p, ">");
1.26      kristaps  984: }
                    985:
1.1       kristaps  986: static void
1.45      kristaps  987: print_man_node(DECL_ARGS)
1.1       kristaps  988: {
1.65      joerg     989:        size_t           rm, rmax;
1.54      kristaps  990:        int              c;
1.1       kristaps  991:
                    992:        switch (n->type) {
                    993:        case(MAN_TEXT):
1.97      kristaps  994:                /*
                    995:                 * If we have a blank line, output a vertical space.
                    996:                 * If we have a space as the first character, break
                    997:                 * before printing the line's data.
                    998:                 */
1.96      kristaps  999:                if ('\0' == *n->string) {
1.4       kristaps 1000:                        term_vspace(p);
1.98      schwarze 1001:                        return;
1.97      kristaps 1002:                } else if (' ' == *n->string && MAN_LINE & n->flags)
1.96      kristaps 1003:                        term_newln(p);
1.54      kristaps 1004:
1.4       kristaps 1005:                term_word(p, n->string);
1.130     schwarze 1006:                goto out;
1.52      kristaps 1007:
1.102     kristaps 1008:        case (MAN_EQN):
1.115     kristaps 1009:                term_eqn(p, n->eqn);
1.97      kristaps 1010:                return;
1.91      kristaps 1011:        case (MAN_TBL):
1.97      kristaps 1012:                /*
                   1013:                 * Tables are preceded by a newline.  Then process a
                   1014:                 * table line, which will cause line termination,
                   1015:                 */
1.93      kristaps 1016:                if (TBL_SPAN_FIRST & n->span->flags)
                   1017:                        term_newln(p);
1.92      kristaps 1018:                term_tbl(p, n->span);
1.97      kristaps 1019:                return;
1.1       kristaps 1020:        default:
                   1021:                break;
                   1022:        }
                   1023:
1.97      kristaps 1024:        if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
                   1025:                term_fontrepl(p, TERMFONT_NONE);
                   1026:
                   1027:        c = 1;
                   1028:        if (termacts[n->tok].pre)
1.135     schwarze 1029:                c = (*termacts[n->tok].pre)(p, mt, n, meta);
1.97      kristaps 1030:
1.1       kristaps 1031:        if (c && n->child)
1.135     schwarze 1032:                print_man_nodelist(p, mt, n->child, meta);
1.1       kristaps 1033:
1.97      kristaps 1034:        if (termacts[n->tok].post)
1.135     schwarze 1035:                (*termacts[n->tok].post)(p, mt, n, meta);
1.97      kristaps 1036:        if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
                   1037:                term_fontrepl(p, TERMFONT_NONE);
1.63      kristaps 1038:
1.130     schwarze 1039: out:
                   1040:        /*
                   1041:         * If we're in a literal context, make sure that words
                   1042:         * together on the same line stay together.  This is a
                   1043:         * POST-printing call, so we check the NEXT word.  Since
                   1044:         * -man doesn't have nested macros, we don't need to be
                   1045:         * more specific than this.
                   1046:         */
                   1047:        if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
1.142   ! schwarze 1048:            (NULL == n->next || MAN_LINE & n->next->flags)) {
1.130     schwarze 1049:                rm = p->rmargin;
                   1050:                rmax = p->maxrmargin;
                   1051:                p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
                   1052:                p->flags |= TERMP_NOSPACE;
                   1053:                if (NULL != n->string && '\0' != *n->string)
                   1054:                        term_flushln(p);
                   1055:                else
                   1056:                        term_newln(p);
                   1057:                if (rm < rmax && n->parent->tok == MAN_HP) {
                   1058:                        p->offset = rm;
                   1059:                        p->rmargin = rmax;
                   1060:                } else
                   1061:                        p->rmargin = rm;
                   1062:                p->maxrmargin = rmax;
                   1063:        }
1.63      kristaps 1064:        if (MAN_EOS & n->flags)
                   1065:                p->flags |= TERMP_SENTENCE;
1.1       kristaps 1066: }
                   1067:
                   1068:
                   1069: static void
1.52      kristaps 1070: print_man_nodelist(DECL_ARGS)
1.1       kristaps 1071: {
1.19      kristaps 1072:
1.135     schwarze 1073:        print_man_node(p, mt, n, meta);
1.1       kristaps 1074:        if ( ! n->next)
                   1075:                return;
1.135     schwarze 1076:        print_man_nodelist(p, mt, n->next, meta);
1.1       kristaps 1077: }
                   1078:
                   1079:
1.31      kristaps 1080: static void
1.73      kristaps 1081: print_man_foot(struct termp *p, const void *arg)
1.1       kristaps 1082: {
1.123     schwarze 1083:        char            title[BUFSIZ];
                   1084:        size_t          datelen;
1.73      kristaps 1085:        const struct man_meta *meta;
                   1086:
                   1087:        meta = (const struct man_meta *)arg;
1.125     schwarze 1088:        assert(meta->title);
                   1089:        assert(meta->msec);
                   1090:        assert(meta->date);
1.1       kristaps 1091:
1.52      kristaps 1092:        term_fontrepl(p, TERMFONT_NONE);
1.50      kristaps 1093:
1.69      joerg    1094:        term_vspace(p);
1.126     schwarze 1095:
                   1096:        /*
                   1097:         * Temporary, undocumented option to imitate mdoc(7) output.
                   1098:         * In the bottom right corner, use the source instead of
                   1099:         * the title.
                   1100:         */
                   1101:
                   1102:        if ( ! p->mdocstyle) {
                   1103:                term_vspace(p);
                   1104:                term_vspace(p);
                   1105:                snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
                   1106:        } else if (meta->source) {
                   1107:                strlcpy(title, meta->source, BUFSIZ);
                   1108:        } else {
                   1109:                title[0] = '\0';
                   1110:        }
1.125     schwarze 1111:        datelen = term_strlen(p, meta->date);
1.1       kristaps 1112:
1.126     schwarze 1113:        /* Bottom left corner: manual source. */
                   1114:
1.1       kristaps 1115:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.139     schwarze 1116:        p->trailspace = 1;
1.1       kristaps 1117:        p->offset = 0;
1.123     schwarze 1118:        p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
1.1       kristaps 1119:
                   1120:        if (meta->source)
                   1121:                term_word(p, meta->source);
                   1122:        term_flushln(p);
                   1123:
1.126     schwarze 1124:        /* At the bottom in the middle: manual date. */
                   1125:
1.117     schwarze 1126:        p->flags |= TERMP_NOSPACE;
1.1       kristaps 1127:        p->offset = p->rmargin;
1.123     schwarze 1128:        p->rmargin = p->maxrmargin - term_strlen(p, title);
                   1129:        if (p->offset + datelen >= p->rmargin)
                   1130:                p->rmargin = p->offset + datelen;
                   1131:
1.125     schwarze 1132:        term_word(p, meta->date);
1.123     schwarze 1133:        term_flushln(p);
                   1134:
1.126     schwarze 1135:        /* Bottom right corner: manual title and section. */
                   1136:
1.123     schwarze 1137:        p->flags &= ~TERMP_NOBREAK;
                   1138:        p->flags |= TERMP_NOSPACE;
1.139     schwarze 1139:        p->trailspace = 0;
1.123     schwarze 1140:        p->offset = p->rmargin;
1.1       kristaps 1141:        p->rmargin = p->maxrmargin;
                   1142:
1.123     schwarze 1143:        term_word(p, title);
1.1       kristaps 1144:        term_flushln(p);
                   1145: }
                   1146:
                   1147:
1.31      kristaps 1148: static void
1.73      kristaps 1149: print_man_head(struct termp *p, const void *arg)
1.1       kristaps 1150: {
1.46      kristaps 1151:        char            buf[BUFSIZ], title[BUFSIZ];
1.57      kristaps 1152:        size_t          buflen, titlen;
1.135     schwarze 1153:        const struct man_meta *meta;
1.73      kristaps 1154:
1.135     schwarze 1155:        meta = (const struct man_meta *)arg;
                   1156:        assert(meta->title);
                   1157:        assert(meta->msec);
1.1       kristaps 1158:
1.135     schwarze 1159:        if (meta->vol)
                   1160:                strlcpy(buf, meta->vol, BUFSIZ);
1.126     schwarze 1161:        else
                   1162:                buf[0] = '\0';
1.77      kristaps 1163:        buflen = term_strlen(p, buf);
1.1       kristaps 1164:
1.126     schwarze 1165:        /* Top left corner: manual title and section. */
                   1166:
1.135     schwarze 1167:        snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
1.77      kristaps 1168:        titlen = term_strlen(p, title);
1.1       kristaps 1169:
1.118     schwarze 1170:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1.139     schwarze 1171:        p->trailspace = 1;
1.1       kristaps 1172:        p->offset = 0;
1.57      kristaps 1173:        p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77      kristaps 1174:            (p->maxrmargin -
                   1175:             term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57      kristaps 1176:            p->maxrmargin - buflen;
1.1       kristaps 1177:
                   1178:        term_word(p, title);
                   1179:        term_flushln(p);
                   1180:
1.126     schwarze 1181:        /* At the top in the middle: manual volume. */
                   1182:
1.117     schwarze 1183:        p->flags |= TERMP_NOSPACE;
1.1       kristaps 1184:        p->offset = p->rmargin;
1.57      kristaps 1185:        p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
                   1186:            p->maxrmargin - titlen : p->maxrmargin;
1.1       kristaps 1187:
                   1188:        term_word(p, buf);
                   1189:        term_flushln(p);
                   1190:
1.126     schwarze 1191:        /* Top right corner: title and section, again. */
                   1192:
1.1       kristaps 1193:        p->flags &= ~TERMP_NOBREAK;
1.139     schwarze 1194:        p->trailspace = 0;
1.57      kristaps 1195:        if (p->rmargin + titlen <= p->maxrmargin) {
1.117     schwarze 1196:                p->flags |= TERMP_NOSPACE;
1.57      kristaps 1197:                p->offset = p->rmargin;
                   1198:                p->rmargin = p->maxrmargin;
                   1199:                term_word(p, title);
                   1200:                term_flushln(p);
                   1201:        }
1.1       kristaps 1202:
1.118     schwarze 1203:        p->flags &= ~TERMP_NOSPACE;
                   1204:        p->offset = 0;
1.1       kristaps 1205:        p->rmargin = p->maxrmargin;
1.61      kristaps 1206:
1.62      kristaps 1207:        /*
1.126     schwarze 1208:         * Groff prints three blank lines before the content.
                   1209:         * Do the same, except in the temporary, undocumented
                   1210:         * mode imitating mdoc(7) output.
1.62      kristaps 1211:         */
                   1212:
1.61      kristaps 1213:        term_vspace(p);
1.126     schwarze 1214:        if ( ! p->mdocstyle) {
                   1215:                term_vspace(p);
                   1216:                term_vspace(p);
                   1217:        }
1.1       kristaps 1218: }

CVSweb