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

Annotation of mandoc/man_term.c, Revision 1.89

1.89    ! kristaps    1: /*     $Id: man_term.c,v 1.88 2010/12/06 14:04:11 kristaps Exp $ */
1.1       kristaps    2: /*
1.80      schwarze    3:  * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.8       kristaps    6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    8:  *
1.8       kristaps    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       kristaps   16:  */
1.55      kristaps   17: #ifdef HAVE_CONFIG_H
                     18: #include "config.h"
                     19: #endif
                     20:
1.28      kristaps   21: #include <sys/types.h>
                     22:
1.1       kristaps   23: #include <assert.h>
1.18      kristaps   24: #include <ctype.h>
1.1       kristaps   25: #include <stdio.h>
                     26: #include <stdlib.h>
                     27: #include <string.h>
                     28:
1.71      kristaps   29: #include "mandoc.h"
1.40      kristaps   30: #include "out.h"
1.36      kristaps   31: #include "man.h"
1.1       kristaps   32: #include "term.h"
1.36      kristaps   33: #include "chars.h"
                     34: #include "main.h"
1.1       kristaps   35:
1.18      kristaps   36: #define        INDENT            7
                     37: #define        HALFINDENT        3
                     38:
1.44      kristaps   39: /* FIXME: have PD set the default vspace width. */
                     40:
1.24      kristaps   41: struct mtermp {
                     42:        int               fl;
1.19      kristaps   43: #define        MANT_LITERAL     (1 << 0)
1.26      kristaps   44:        /*
                     45:         * Default amount to indent the left margin after leading text
                     46:         * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
                     47:         * indent).  This needs to be saved because `HP' and so on, if
                     48:         * not having a specified value, must default.
                     49:         *
                     50:         * Note that this is the indentation AFTER the left offset, so
                     51:         * the total offset is usually offset + lmargin.
                     52:         */
                     53:        size_t            lmargin;
                     54:        /*
                     55:         * The default offset, i.e., the amount between any text and the
                     56:         * page boundary.
                     57:         */
                     58:        size_t            offset;
1.24      kristaps   59: };
1.19      kristaps   60:
1.1       kristaps   61: #define        DECL_ARGS         struct termp *p, \
1.24      kristaps   62:                          struct mtermp *mt, \
1.1       kristaps   63:                          const struct man_node *n, \
                     64:                          const struct man_meta *m
                     65:
                     66: struct termact {
                     67:        int             (*pre)(DECL_ARGS);
                     68:        void            (*post)(DECL_ARGS);
1.56      kristaps   69:        int               flags;
                     70: #define        MAN_NOTEXT       (1 << 0) /* Never has text children. */
1.1       kristaps   71: };
                     72:
1.77      kristaps   73: static int               a2width(const struct termp *, const char *);
                     74: static size_t            a2height(const struct termp *, const char *);
1.39      kristaps   75:
1.52      kristaps   76: static void              print_man_nodelist(DECL_ARGS);
1.45      kristaps   77: static void              print_man_node(DECL_ARGS);
1.74      kristaps   78: static void              print_man_head(struct termp *, const void *);
1.73      kristaps   79: static void              print_man_foot(struct termp *, const void *);
1.39      kristaps   80: static void              print_bvspace(struct termp *,
                     81:                                const struct man_node *);
                     82:
1.88      kristaps   83: static int               pre_alternate(DECL_ARGS);
1.1       kristaps   84: static int               pre_B(DECL_ARGS);
1.19      kristaps   85: static int               pre_HP(DECL_ARGS);
1.1       kristaps   86: static int               pre_I(DECL_ARGS);
1.4       kristaps   87: static int               pre_IP(DECL_ARGS);
1.1       kristaps   88: static int               pre_PP(DECL_ARGS);
1.26      kristaps   89: static int               pre_RS(DECL_ARGS);
1.1       kristaps   90: static int               pre_SH(DECL_ARGS);
                     91: static int               pre_SS(DECL_ARGS);
                     92: static int               pre_TP(DECL_ARGS);
1.29      kristaps   93: static int               pre_ign(DECL_ARGS);
1.83      kristaps   94: static int               pre_in(DECL_ARGS);
1.84      kristaps   95: static int               pre_literal(DECL_ARGS);
1.19      kristaps   96: static int               pre_sp(DECL_ARGS);
1.89    ! kristaps   97: static int               pre_ft(DECL_ARGS);
1.1       kristaps   98:
1.22      kristaps   99: static void              post_IP(DECL_ARGS);
1.20      kristaps  100: static void              post_HP(DECL_ARGS);
1.26      kristaps  101: static void              post_RS(DECL_ARGS);
1.1       kristaps  102: static void              post_SH(DECL_ARGS);
                    103: static void              post_SS(DECL_ARGS);
1.21      kristaps  104: static void              post_TP(DECL_ARGS);
1.1       kristaps  105:
1.32      kristaps  106: static const struct termact termacts[MAN_MAX] = {
1.82      kristaps  107:        { pre_sp, NULL, MAN_NOTEXT }, /* br */
1.56      kristaps  108:        { NULL, NULL, 0 }, /* TH */
                    109:        { pre_SH, post_SH, 0 }, /* SH */
                    110:        { pre_SS, post_SS, 0 }, /* SS */
                    111:        { pre_TP, post_TP, 0 }, /* TP */
                    112:        { pre_PP, NULL, 0 }, /* LP */
                    113:        { pre_PP, NULL, 0 }, /* PP */
                    114:        { pre_PP, NULL, 0 }, /* P */
                    115:        { pre_IP, post_IP, 0 }, /* IP */
                    116:        { pre_HP, post_HP, 0 }, /* HP */
                    117:        { NULL, NULL, 0 }, /* SM */
                    118:        { pre_B, NULL, 0 }, /* SB */
1.88      kristaps  119:        { pre_alternate, NULL, 0 }, /* BI */
                    120:        { pre_alternate, NULL, 0 }, /* IB */
                    121:        { pre_alternate, NULL, 0 }, /* BR */
                    122:        { pre_alternate, NULL, 0 }, /* RB */
1.56      kristaps  123:        { NULL, NULL, 0 }, /* R */
                    124:        { pre_B, NULL, 0 }, /* B */
                    125:        { pre_I, NULL, 0 }, /* I */
1.88      kristaps  126:        { pre_alternate, NULL, 0 }, /* IR */
                    127:        { pre_alternate, NULL, 0 }, /* RI */
1.56      kristaps  128:        { NULL, NULL, MAN_NOTEXT }, /* na */
                    129:        { pre_I, NULL, 0 }, /* i */
                    130:        { pre_sp, NULL, MAN_NOTEXT }, /* sp */
1.84      kristaps  131:        { pre_literal, NULL, 0 }, /* nf */
                    132:        { pre_literal, NULL, 0 }, /* fi */
1.56      kristaps  133:        { NULL, NULL, 0 }, /* r */
                    134:        { NULL, NULL, 0 }, /* RE */
                    135:        { pre_RS, post_RS, 0 }, /* RS */
                    136:        { pre_ign, NULL, 0 }, /* DT */
                    137:        { pre_ign, NULL, 0 }, /* UC */
                    138:        { pre_ign, NULL, 0 }, /* PD */
1.70      joerg     139:        { pre_ign, NULL, 0 }, /* AT */
1.83      kristaps  140:        { pre_in, NULL, MAN_NOTEXT }, /* in */
1.89    ! kristaps  141:        { pre_ft, NULL, MAN_NOTEXT }, /* ft */
1.1       kristaps  142: };
                    143:
                    144:
                    145:
1.31      kristaps  146: void
1.36      kristaps  147: terminal_man(void *arg, const struct man *man)
1.1       kristaps  148: {
1.36      kristaps  149:        struct termp            *p;
                    150:        const struct man_node   *n;
                    151:        const struct man_meta   *m;
                    152:        struct mtermp            mt;
                    153:
                    154:        p = (struct termp *)arg;
                    155:
1.58      kristaps  156:        p->overstep = 0;
1.65      joerg     157:        p->maxrmargin = p->defrmargin;
1.77      kristaps  158:        p->tabwidth = term_len(p, 5);
1.73      kristaps  159:
1.36      kristaps  160:        if (NULL == p->symtab)
                    161:                switch (p->enc) {
                    162:                case (TERMENC_ASCII):
                    163:                        p->symtab = chars_init(CHARS_ASCII);
                    164:                        break;
                    165:                default:
                    166:                        abort();
                    167:                        /* NOTREACHED */
                    168:                }
                    169:
                    170:        n = man_node(man);
                    171:        m = man_meta(man);
1.1       kristaps  172:
1.75      schwarze  173:        term_begin(p, print_man_head, print_man_foot, m);
1.1       kristaps  174:        p->flags |= TERMP_NOSPACE;
1.19      kristaps  175:
1.24      kristaps  176:        mt.fl = 0;
1.77      kristaps  177:        mt.lmargin = term_len(p, INDENT);
                    178:        mt.offset = term_len(p, INDENT);
1.24      kristaps  179:
1.36      kristaps  180:        if (n->child)
1.52      kristaps  181:                print_man_nodelist(p, &mt, n->child, m);
1.73      kristaps  182:
                    183:        term_end(p);
1.1       kristaps  184: }
                    185:
                    186:
1.77      kristaps  187: static size_t
                    188: a2height(const struct termp *p, const char *cp)
1.18      kristaps  189: {
1.40      kristaps  190:        struct roffsu    su;
1.18      kristaps  191:
1.77      kristaps  192:        if ( ! a2roffsu(cp, &su, SCALE_VS))
                    193:                SCALE_VS_INIT(&su, term_strlen(p, cp));
1.18      kristaps  194:
1.77      kristaps  195:        return(term_vspan(p, &su));
1.18      kristaps  196: }
                    197:
                    198:
                    199: static int
1.77      kristaps  200: a2width(const struct termp *p, const char *cp)
1.38      kristaps  201: {
1.40      kristaps  202:        struct roffsu    su;
1.38      kristaps  203:
1.77      kristaps  204:        if ( ! a2roffsu(cp, &su, SCALE_BU))
1.41      kristaps  205:                return(-1);
1.40      kristaps  206:
1.77      kristaps  207:        return((int)term_hspan(p, &su));
1.38      kristaps  208: }
                    209:
                    210:
1.39      kristaps  211: static void
                    212: print_bvspace(struct termp *p, const struct man_node *n)
1.18      kristaps  213: {
1.39      kristaps  214:        term_newln(p);
1.18      kristaps  215:
1.39      kristaps  216:        if (NULL == n->prev)
                    217:                return;
1.18      kristaps  218:
1.39      kristaps  219:        if (MAN_SS == n->prev->tok)
                    220:                return;
                    221:        if (MAN_SH == n->prev->tok)
                    222:                return;
1.18      kristaps  223:
1.39      kristaps  224:        term_vspace(p);
1.18      kristaps  225: }
                    226:
                    227:
1.3       kristaps  228: /* ARGSUSED */
1.1       kristaps  229: static int
1.29      kristaps  230: pre_ign(DECL_ARGS)
                    231: {
                    232:
                    233:        return(0);
                    234: }
                    235:
                    236:
                    237: /* ARGSUSED */
                    238: static int
1.1       kristaps  239: pre_I(DECL_ARGS)
                    240: {
                    241:
1.52      kristaps  242:        term_fontrepl(p, TERMFONT_UNDER);
1.19      kristaps  243:        return(1);
                    244: }
                    245:
                    246:
                    247: /* ARGSUSED */
1.3       kristaps  248: static int
1.84      kristaps  249: pre_literal(DECL_ARGS)
1.19      kristaps  250: {
                    251:
1.81      kristaps  252:        term_newln(p);
1.88      kristaps  253:
                    254:        if (MAN_nf == n->tok)
1.84      kristaps  255:                mt->fl |= MANT_LITERAL;
1.88      kristaps  256:        else
1.84      kristaps  257:                mt->fl &= ~MANT_LITERAL;
                    258:
1.19      kristaps  259:        return(1);
                    260: }
                    261:
                    262: /* ARGSUSED */
                    263: static int
1.88      kristaps  264: pre_alternate(DECL_ARGS)
1.3       kristaps  265: {
1.88      kristaps  266:        enum termfont            font[2];
                    267:        const struct man_node   *nn;
                    268:        int                      savelit, i;
1.3       kristaps  269:
1.88      kristaps  270:        switch (n->tok) {
                    271:        case (MAN_RB):
                    272:                font[0] = TERMFONT_NONE;
                    273:                font[1] = TERMFONT_BOLD;
                    274:                break;
                    275:        case (MAN_RI):
                    276:                font[0] = TERMFONT_NONE;
                    277:                font[1] = TERMFONT_UNDER;
                    278:                break;
                    279:        case (MAN_BR):
                    280:                font[0] = TERMFONT_BOLD;
                    281:                font[1] = TERMFONT_NONE;
                    282:                break;
                    283:        case (MAN_BI):
                    284:                font[0] = TERMFONT_BOLD;
                    285:                font[1] = TERMFONT_UNDER;
                    286:                break;
                    287:        case (MAN_IR):
                    288:                font[0] = TERMFONT_UNDER;
                    289:                font[1] = TERMFONT_NONE;
                    290:                break;
                    291:        case (MAN_IB):
                    292:                font[0] = TERMFONT_UNDER;
                    293:                font[1] = TERMFONT_BOLD;
                    294:                break;
                    295:        default:
                    296:                abort();
                    297:        }
1.35      kristaps  298:
1.88      kristaps  299:        savelit = MANT_LITERAL & mt->fl;
                    300:        mt->fl &= ~MANT_LITERAL;
1.35      kristaps  301:
1.88      kristaps  302:        for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
                    303:                term_fontrepl(p, font[i]);
                    304:                if (savelit && NULL == nn->next)
                    305:                        mt->fl |= MANT_LITERAL;
1.45      kristaps  306:                print_man_node(p, mt, nn, m);
1.88      kristaps  307:                if (nn->next)
1.4       kristaps  308:                        p->flags |= TERMP_NOSPACE;
1.3       kristaps  309:        }
                    310:
                    311:        return(0);
                    312: }
                    313:
                    314: /* ARGSUSED */
1.1       kristaps  315: static int
                    316: pre_B(DECL_ARGS)
                    317: {
                    318:
1.52      kristaps  319:        term_fontrepl(p, TERMFONT_BOLD);
1.1       kristaps  320:        return(1);
1.89    ! kristaps  321: }
        !           322:
        !           323: /* ARGSUSED */
        !           324: static int
        !           325: pre_ft(DECL_ARGS)
        !           326: {
        !           327:        const char      *cp;
        !           328:
        !           329:        if (NULL == n->child) {
        !           330:                term_fontlast(p);
        !           331:                return(0);
        !           332:        }
        !           333:
        !           334:        cp = n->child->string;
        !           335:        switch (*cp) {
        !           336:        case ('4'):
        !           337:                /* FALLTHROUGH */
        !           338:        case ('3'):
        !           339:                /* FALLTHROUGH */
        !           340:        case ('B'):
        !           341:                term_fontrepl(p, TERMFONT_BOLD);
        !           342:                break;
        !           343:        case ('2'):
        !           344:                /* FALLTHROUGH */
        !           345:        case ('I'):
        !           346:                term_fontrepl(p, TERMFONT_UNDER);
        !           347:                break;
        !           348:        case ('P'):
        !           349:                term_fontlast(p);
        !           350:                break;
        !           351:        case ('1'):
        !           352:                /* FALLTHROUGH */
        !           353:        case ('C'):
        !           354:                /* FALLTHROUGH */
        !           355:        case ('R'):
        !           356:                term_fontrepl(p, TERMFONT_NONE);
        !           357:                break;
        !           358:        default:
        !           359:                break;
        !           360:        }
        !           361:        return(0);
1.83      kristaps  362: }
                    363:
                    364: /* ARGSUSED */
                    365: static int
                    366: pre_in(DECL_ARGS)
                    367: {
                    368:        int              len, less;
                    369:        size_t           v;
                    370:        const char      *cp;
                    371:
                    372:        term_newln(p);
                    373:
                    374:        if (NULL == n->child) {
                    375:                p->offset = mt->offset;
                    376:                return(0);
                    377:        }
                    378:
                    379:        cp = n->child->string;
                    380:        less = 0;
                    381:
                    382:        if ('-' == *cp)
                    383:                less = -1;
                    384:        else if ('+' == *cp)
                    385:                less = 1;
                    386:        else
                    387:                cp--;
                    388:
                    389:        if ((len = a2width(p, ++cp)) < 0)
                    390:                return(0);
                    391:
                    392:        v = (size_t)len;
                    393:
                    394:        if (less < 0)
                    395:                p->offset -= p->offset > v ? v : p->offset;
                    396:        else if (less > 0)
                    397:                p->offset += v;
                    398:        else
                    399:                p->offset = v;
                    400:
                    401:        return(0);
1.1       kristaps  402: }
                    403:
                    404:
1.3       kristaps  405: /* ARGSUSED */
1.1       kristaps  406: static int
1.19      kristaps  407: pre_sp(DECL_ARGS)
                    408: {
1.77      kristaps  409:        size_t           i, len;
1.19      kristaps  410:
1.82      kristaps  411:        switch (n->tok) {
                    412:        case (MAN_br):
                    413:                len = 0;
                    414:                break;
                    415:        default:
                    416:                len = n->child ? a2height(p, n->child->string) : 1;
                    417:                break;
                    418:        }
1.38      kristaps  419:
1.19      kristaps  420:        if (0 == len)
                    421:                term_newln(p);
1.82      kristaps  422:        for (i = 0; i < len; i++)
1.19      kristaps  423:                term_vspace(p);
                    424:
1.15      kristaps  425:        return(0);
                    426: }
                    427:
                    428:
                    429: /* ARGSUSED */
                    430: static int
1.19      kristaps  431: pre_HP(DECL_ARGS)
                    432: {
1.24      kristaps  433:        size_t                   len;
                    434:        int                      ival;
                    435:        const struct man_node   *nn;
1.19      kristaps  436:
1.20      kristaps  437:        switch (n->type) {
                    438:        case (MAN_BLOCK):
1.39      kristaps  439:                print_bvspace(p, n);
1.24      kristaps  440:                return(1);
1.20      kristaps  441:        case (MAN_BODY):
                    442:                p->flags |= TERMP_NOBREAK;
                    443:                p->flags |= TERMP_TWOSPACE;
                    444:                break;
                    445:        default:
                    446:                return(0);
                    447:        }
                    448:
1.26      kristaps  449:        len = mt->lmargin;
1.24      kristaps  450:        ival = -1;
                    451:
                    452:        /* Calculate offset. */
                    453:
1.39      kristaps  454:        if (NULL != (nn = n->parent->head->child))
1.77      kristaps  455:                if ((ival = a2width(p, nn->string)) >= 0)
1.24      kristaps  456:                        len = (size_t)ival;
                    457:
                    458:        if (0 == len)
1.77      kristaps  459:                len = term_len(p, 1);
1.24      kristaps  460:
1.26      kristaps  461:        p->offset = mt->offset;
                    462:        p->rmargin = mt->offset + len;
1.24      kristaps  463:
                    464:        if (ival >= 0)
1.26      kristaps  465:                mt->lmargin = (size_t)ival;
1.24      kristaps  466:
1.19      kristaps  467:        return(1);
                    468: }
                    469:
                    470:
                    471: /* ARGSUSED */
1.20      kristaps  472: static void
                    473: post_HP(DECL_ARGS)
                    474: {
                    475:
                    476:        switch (n->type) {
1.24      kristaps  477:        case (MAN_BLOCK):
                    478:                term_flushln(p);
                    479:                break;
1.20      kristaps  480:        case (MAN_BODY):
                    481:                term_flushln(p);
                    482:                p->flags &= ~TERMP_NOBREAK;
                    483:                p->flags &= ~TERMP_TWOSPACE;
1.26      kristaps  484:                p->offset = mt->offset;
1.20      kristaps  485:                p->rmargin = p->maxrmargin;
                    486:                break;
                    487:        default:
                    488:                break;
                    489:        }
                    490: }
                    491:
                    492:
                    493: /* ARGSUSED */
1.19      kristaps  494: static int
1.1       kristaps  495: pre_PP(DECL_ARGS)
                    496: {
                    497:
1.19      kristaps  498:        switch (n->type) {
                    499:        case (MAN_BLOCK):
1.77      kristaps  500:                mt->lmargin = term_len(p, INDENT);
1.39      kristaps  501:                print_bvspace(p, n);
1.19      kristaps  502:                break;
                    503:        default:
1.26      kristaps  504:                p->offset = mt->offset;
1.19      kristaps  505:                break;
                    506:        }
                    507:
1.87      kristaps  508:        return(MAN_HEAD != n->type);
1.1       kristaps  509: }
                    510:
                    511:
1.3       kristaps  512: /* ARGSUSED */
1.1       kristaps  513: static int
1.4       kristaps  514: pre_IP(DECL_ARGS)
                    515: {
1.22      kristaps  516:        const struct man_node   *nn;
                    517:        size_t                   len;
                    518:        int                      ival;
1.18      kristaps  519:
1.22      kristaps  520:        switch (n->type) {
                    521:        case (MAN_BODY):
                    522:                p->flags |= TERMP_NOLPAD;
                    523:                p->flags |= TERMP_NOSPACE;
                    524:                break;
                    525:        case (MAN_HEAD):
                    526:                p->flags |= TERMP_NOBREAK;
                    527:                break;
1.23      kristaps  528:        case (MAN_BLOCK):
1.39      kristaps  529:                print_bvspace(p, n);
1.23      kristaps  530:                /* FALLTHROUGH */
1.22      kristaps  531:        default:
                    532:                return(1);
                    533:        }
1.18      kristaps  534:
1.26      kristaps  535:        len = mt->lmargin;
1.22      kristaps  536:        ival = -1;
1.4       kristaps  537:
1.22      kristaps  538:        /* Calculate offset. */
1.4       kristaps  539:
1.22      kristaps  540:        if (NULL != (nn = n->parent->head->child))
                    541:                if (NULL != (nn = nn->next)) {
                    542:                        for ( ; nn->next; nn = nn->next)
                    543:                                /* Do nothing. */ ;
1.77      kristaps  544:                        if ((ival = a2width(p, nn->string)) >= 0)
1.22      kristaps  545:                                len = (size_t)ival;
                    546:                }
1.4       kristaps  547:
1.22      kristaps  548:        switch (n->type) {
                    549:        case (MAN_HEAD):
1.23      kristaps  550:                /* Handle zero-width lengths. */
                    551:                if (0 == len)
1.77      kristaps  552:                        len = term_len(p, 1);
1.23      kristaps  553:
1.26      kristaps  554:                p->offset = mt->offset;
                    555:                p->rmargin = mt->offset + len;
1.22      kristaps  556:                if (ival < 0)
                    557:                        break;
1.18      kristaps  558:
1.24      kristaps  559:                /* Set the saved left-margin. */
1.26      kristaps  560:                mt->lmargin = (size_t)ival;
1.24      kristaps  561:
1.22      kristaps  562:                /* Don't print the length value. */
                    563:                for (nn = n->child; nn->next; nn = nn->next)
1.45      kristaps  564:                        print_man_node(p, mt, nn, m);
1.22      kristaps  565:                return(0);
1.23      kristaps  566:        case (MAN_BODY):
1.26      kristaps  567:                p->offset = mt->offset + len;
1.23      kristaps  568:                p->rmargin = p->maxrmargin;
                    569:                break;
1.22      kristaps  570:        default:
                    571:                break;
1.18      kristaps  572:        }
                    573:
1.22      kristaps  574:        return(1);
                    575: }
1.18      kristaps  576:
                    577:
1.22      kristaps  578: /* ARGSUSED */
                    579: static void
                    580: post_IP(DECL_ARGS)
                    581: {
1.4       kristaps  582:
1.22      kristaps  583:        switch (n->type) {
                    584:        case (MAN_HEAD):
                    585:                term_flushln(p);
                    586:                p->flags &= ~TERMP_NOBREAK;
                    587:                p->rmargin = p->maxrmargin;
                    588:                break;
                    589:        case (MAN_BODY):
                    590:                term_flushln(p);
                    591:                p->flags &= ~TERMP_NOLPAD;
                    592:                break;
                    593:        default:
                    594:                break;
                    595:        }
1.4       kristaps  596: }
                    597:
                    598:
                    599: /* ARGSUSED */
                    600: static int
1.1       kristaps  601: pre_TP(DECL_ARGS)
                    602: {
1.23      kristaps  603:        const struct man_node   *nn;
                    604:        size_t                   len;
                    605:        int                      ival;
1.1       kristaps  606:
1.21      kristaps  607:        switch (n->type) {
                    608:        case (MAN_HEAD):
                    609:                p->flags |= TERMP_NOBREAK;
                    610:                p->flags |= TERMP_TWOSPACE;
                    611:                break;
                    612:        case (MAN_BODY):
                    613:                p->flags |= TERMP_NOLPAD;
                    614:                p->flags |= TERMP_NOSPACE;
1.23      kristaps  615:                break;
                    616:        case (MAN_BLOCK):
1.39      kristaps  617:                print_bvspace(p, n);
1.23      kristaps  618:                /* FALLTHROUGH */
                    619:        default:
                    620:                return(1);
                    621:        }
                    622:
1.24      kristaps  623:        len = (size_t)mt->lmargin;
1.23      kristaps  624:        ival = -1;
                    625:
                    626:        /* Calculate offset. */
                    627:
1.56      kristaps  628:        if (NULL != (nn = n->parent->head->child)) {
                    629:                while (nn && MAN_TEXT != nn->type)
                    630:                        nn = nn->next;
                    631:                if (nn && nn->next)
1.77      kristaps  632:                        if ((ival = a2width(p, nn->string)) >= 0)
1.23      kristaps  633:                                len = (size_t)ival;
1.56      kristaps  634:        }
1.23      kristaps  635:
                    636:        switch (n->type) {
                    637:        case (MAN_HEAD):
                    638:                /* Handle zero-length properly. */
                    639:                if (0 == len)
1.77      kristaps  640:                        len = term_len(p, 1);
1.23      kristaps  641:
1.26      kristaps  642:                p->offset = mt->offset;
                    643:                p->rmargin = mt->offset + len;
1.23      kristaps  644:
                    645:                /* Don't print same-line elements. */
                    646:                for (nn = n->child; nn; nn = nn->next)
                    647:                        if (nn->line > n->line)
1.45      kristaps  648:                                print_man_node(p, mt, nn, m);
1.24      kristaps  649:
                    650:                if (ival >= 0)
1.26      kristaps  651:                        mt->lmargin = (size_t)ival;
1.24      kristaps  652:
1.23      kristaps  653:                return(0);
                    654:        case (MAN_BODY):
1.26      kristaps  655:                p->offset = mt->offset + len;
1.23      kristaps  656:                p->rmargin = p->maxrmargin;
1.21      kristaps  657:                break;
                    658:        default:
                    659:                break;
                    660:        }
1.16      kristaps  661:
1.21      kristaps  662:        return(1);
                    663: }
1.1       kristaps  664:
                    665:
1.21      kristaps  666: /* ARGSUSED */
                    667: static void
                    668: post_TP(DECL_ARGS)
                    669: {
1.1       kristaps  670:
1.21      kristaps  671:        switch (n->type) {
                    672:        case (MAN_HEAD):
                    673:                term_flushln(p);
                    674:                p->flags &= ~TERMP_NOBREAK;
                    675:                p->flags &= ~TERMP_TWOSPACE;
                    676:                p->rmargin = p->maxrmargin;
                    677:                break;
                    678:        case (MAN_BODY):
                    679:                term_flushln(p);
                    680:                p->flags &= ~TERMP_NOLPAD;
                    681:                break;
                    682:        default:
                    683:                break;
                    684:        }
1.1       kristaps  685: }
                    686:
                    687:
1.3       kristaps  688: /* ARGSUSED */
1.1       kristaps  689: static int
                    690: pre_SS(DECL_ARGS)
                    691: {
                    692:
1.19      kristaps  693:        switch (n->type) {
                    694:        case (MAN_BLOCK):
1.77      kristaps  695:                mt->lmargin = term_len(p, INDENT);
                    696:                mt->offset = term_len(p, INDENT);
1.24      kristaps  697:                /* If following a prior empty `SS', no vspace. */
                    698:                if (n->prev && MAN_SS == n->prev->tok)
                    699:                        if (NULL == n->prev->body->child)
                    700:                                break;
                    701:                if (NULL == n->prev)
                    702:                        break;
                    703:                term_vspace(p);
1.19      kristaps  704:                break;
                    705:        case (MAN_HEAD):
1.52      kristaps  706:                term_fontrepl(p, TERMFONT_BOLD);
1.77      kristaps  707:                p->offset = term_len(p, HALFINDENT);
1.19      kristaps  708:                break;
1.24      kristaps  709:        case (MAN_BODY):
1.26      kristaps  710:                p->offset = mt->offset;
1.24      kristaps  711:                break;
1.19      kristaps  712:        default:
                    713:                break;
                    714:        }
                    715:
1.1       kristaps  716:        return(1);
                    717: }
                    718:
                    719:
1.3       kristaps  720: /* ARGSUSED */
1.1       kristaps  721: static void
                    722: post_SS(DECL_ARGS)
                    723: {
                    724:
1.19      kristaps  725:        switch (n->type) {
                    726:        case (MAN_HEAD):
                    727:                term_newln(p);
                    728:                break;
1.24      kristaps  729:        case (MAN_BODY):
                    730:                term_newln(p);
                    731:                break;
1.19      kristaps  732:        default:
                    733:                break;
                    734:        }
1.1       kristaps  735: }
                    736:
                    737:
1.3       kristaps  738: /* ARGSUSED */
1.1       kristaps  739: static int
                    740: pre_SH(DECL_ARGS)
                    741: {
1.22      kristaps  742:
1.19      kristaps  743:        switch (n->type) {
                    744:        case (MAN_BLOCK):
1.77      kristaps  745:                mt->lmargin = term_len(p, INDENT);
                    746:                mt->offset = term_len(p, INDENT);
1.22      kristaps  747:                /* If following a prior empty `SH', no vspace. */
1.19      kristaps  748:                if (n->prev && MAN_SH == n->prev->tok)
                    749:                        if (NULL == n->prev->body->child)
                    750:                                break;
1.61      kristaps  751:                /* If the first macro, no vspae. */
                    752:                if (NULL == n->prev)
                    753:                        break;
1.19      kristaps  754:                term_vspace(p);
                    755:                break;
                    756:        case (MAN_HEAD):
1.52      kristaps  757:                term_fontrepl(p, TERMFONT_BOLD);
1.19      kristaps  758:                p->offset = 0;
                    759:                break;
                    760:        case (MAN_BODY):
1.26      kristaps  761:                p->offset = mt->offset;
1.19      kristaps  762:                break;
                    763:        default:
                    764:                break;
                    765:        }
1.1       kristaps  766:
                    767:        return(1);
                    768: }
                    769:
                    770:
1.3       kristaps  771: /* ARGSUSED */
1.1       kristaps  772: static void
                    773: post_SH(DECL_ARGS)
                    774: {
                    775:
1.19      kristaps  776:        switch (n->type) {
                    777:        case (MAN_HEAD):
                    778:                term_newln(p);
                    779:                break;
                    780:        case (MAN_BODY):
                    781:                term_newln(p);
                    782:                break;
                    783:        default:
                    784:                break;
                    785:        }
1.1       kristaps  786: }
                    787:
                    788:
1.26      kristaps  789: /* ARGSUSED */
                    790: static int
                    791: pre_RS(DECL_ARGS)
                    792: {
                    793:        const struct man_node   *nn;
                    794:        int                      ival;
                    795:
                    796:        switch (n->type) {
                    797:        case (MAN_BLOCK):
                    798:                term_newln(p);
                    799:                return(1);
                    800:        case (MAN_HEAD):
                    801:                return(0);
                    802:        default:
                    803:                break;
                    804:        }
                    805:
                    806:        if (NULL == (nn = n->parent->head->child)) {
1.77      kristaps  807:                mt->offset = mt->lmargin + term_len(p, INDENT);
1.26      kristaps  808:                p->offset = mt->offset;
                    809:                return(1);
                    810:        }
                    811:
1.77      kristaps  812:        if ((ival = a2width(p, nn->string)) < 0)
1.26      kristaps  813:                return(1);
                    814:
1.77      kristaps  815:        mt->offset = term_len(p, INDENT) + (size_t)ival;
1.26      kristaps  816:        p->offset = mt->offset;
                    817:
                    818:        return(1);
                    819: }
                    820:
                    821:
                    822: /* ARGSUSED */
                    823: static void
                    824: post_RS(DECL_ARGS)
                    825: {
                    826:
                    827:        switch (n->type) {
                    828:        case (MAN_BLOCK):
1.77      kristaps  829:                mt->offset = mt->lmargin = term_len(p, INDENT);
1.59      kristaps  830:                break;
                    831:        case (MAN_HEAD):
1.26      kristaps  832:                break;
                    833:        default:
                    834:                term_newln(p);
1.77      kristaps  835:                p->offset = term_len(p, INDENT);
1.26      kristaps  836:                break;
                    837:        }
                    838: }
                    839:
                    840:
1.1       kristaps  841: static void
1.45      kristaps  842: print_man_node(DECL_ARGS)
1.1       kristaps  843: {
1.65      joerg     844:        size_t           rm, rmax;
1.54      kristaps  845:        int              c;
1.1       kristaps  846:
                    847:        c = 1;
                    848:
                    849:        switch (n->type) {
                    850:        case(MAN_TEXT):
1.4       kristaps  851:                if (0 == *n->string) {
                    852:                        term_vspace(p);
1.1       kristaps  853:                        break;
                    854:                }
1.54      kristaps  855:
1.4       kristaps  856:                term_word(p, n->string);
1.52      kristaps  857:
1.19      kristaps  858:                /* FIXME: this means that macro lines are munged!  */
1.52      kristaps  859:
1.24      kristaps  860:                if (MANT_LITERAL & mt->fl) {
1.65      joerg     861:                        rm = p->rmargin;
                    862:                        rmax = p->maxrmargin;
1.60      kristaps  863:                        p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1.19      kristaps  864:                        p->flags |= TERMP_NOSPACE;
                    865:                        term_flushln(p);
1.65      joerg     866:                        p->rmargin = rm;
                    867:                        p->maxrmargin = rmax;
1.19      kristaps  868:                }
1.1       kristaps  869:                break;
                    870:        default:
1.56      kristaps  871:                if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
                    872:                        term_fontrepl(p, TERMFONT_NONE);
1.19      kristaps  873:                if (termacts[n->tok].pre)
1.24      kristaps  874:                        c = (*termacts[n->tok].pre)(p, mt, n, m);
1.1       kristaps  875:                break;
                    876:        }
                    877:
                    878:        if (c && n->child)
1.52      kristaps  879:                print_man_nodelist(p, mt, n->child, m);
1.1       kristaps  880:
1.51      kristaps  881:        if (MAN_TEXT != n->type) {
1.1       kristaps  882:                if (termacts[n->tok].post)
1.24      kristaps  883:                        (*termacts[n->tok].post)(p, mt, n, m);
1.56      kristaps  884:                if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
                    885:                        term_fontrepl(p, TERMFONT_NONE);
1.51      kristaps  886:        }
1.63      kristaps  887:
                    888:        if (MAN_EOS & n->flags)
                    889:                p->flags |= TERMP_SENTENCE;
1.1       kristaps  890: }
                    891:
                    892:
                    893: static void
1.52      kristaps  894: print_man_nodelist(DECL_ARGS)
1.1       kristaps  895: {
1.19      kristaps  896:
1.45      kristaps  897:        print_man_node(p, mt, n, m);
1.1       kristaps  898:        if ( ! n->next)
                    899:                return;
1.52      kristaps  900:        print_man_nodelist(p, mt, n->next, m);
1.1       kristaps  901: }
                    902:
                    903:
1.31      kristaps  904: static void
1.73      kristaps  905: print_man_foot(struct termp *p, const void *arg)
1.1       kristaps  906: {
1.43      kristaps  907:        char            buf[DATESIZ];
1.73      kristaps  908:        const struct man_meta *meta;
                    909:
                    910:        meta = (const struct man_meta *)arg;
1.1       kristaps  911:
1.52      kristaps  912:        term_fontrepl(p, TERMFONT_NONE);
1.50      kristaps  913:
1.72      kristaps  914:        if (meta->rawdate)
                    915:                strlcpy(buf, meta->rawdate, DATESIZ);
                    916:        else
                    917:                time2a(meta->date, buf, DATESIZ);
1.1       kristaps  918:
1.69      joerg     919:        term_vspace(p);
                    920:        term_vspace(p);
1.1       kristaps  921:        term_vspace(p);
                    922:
                    923:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1.77      kristaps  924:        p->rmargin = p->maxrmargin - term_strlen(p, buf);
1.1       kristaps  925:        p->offset = 0;
1.85      kristaps  926:
                    927:        /* term_strlen() can return zero. */
                    928:        if (p->rmargin == p->maxrmargin)
                    929:                p->rmargin--;
1.1       kristaps  930:
                    931:        if (meta->source)
                    932:                term_word(p, meta->source);
                    933:        if (meta->source)
                    934:                term_word(p, "");
                    935:        term_flushln(p);
                    936:
                    937:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    938:        p->offset = p->rmargin;
                    939:        p->rmargin = p->maxrmargin;
                    940:        p->flags &= ~TERMP_NOBREAK;
                    941:
                    942:        term_word(p, buf);
                    943:        term_flushln(p);
                    944: }
                    945:
                    946:
1.31      kristaps  947: static void
1.73      kristaps  948: print_man_head(struct termp *p, const void *arg)
1.1       kristaps  949: {
1.46      kristaps  950:        char            buf[BUFSIZ], title[BUFSIZ];
1.57      kristaps  951:        size_t          buflen, titlen;
1.73      kristaps  952:        const struct man_meta *m;
                    953:
                    954:        m = (const struct man_meta *)arg;
1.1       kristaps  955:
1.62      kristaps  956:        /*
                    957:         * Note that old groff would spit out some spaces before the
                    958:         * header.  We discontinue this strange behaviour, but at one
                    959:         * point we did so here.
                    960:         */
                    961:
1.1       kristaps  962:        p->rmargin = p->maxrmargin;
1.58      kristaps  963:
1.1       kristaps  964:        p->offset = 0;
1.46      kristaps  965:        buf[0] = title[0] = '\0';
1.1       kristaps  966:
1.46      kristaps  967:        if (m->vol)
                    968:                strlcpy(buf, m->vol, BUFSIZ);
1.77      kristaps  969:        buflen = term_strlen(p, buf);
1.1       kristaps  970:
1.64      kristaps  971:        snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.77      kristaps  972:        titlen = term_strlen(p, title);
1.1       kristaps  973:
                    974:        p->offset = 0;
1.57      kristaps  975:        p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1.77      kristaps  976:            (p->maxrmargin -
                    977:             term_strlen(p, buf) + term_len(p, 1)) / 2 :
1.57      kristaps  978:            p->maxrmargin - buflen;
1.1       kristaps  979:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
                    980:
                    981:        term_word(p, title);
                    982:        term_flushln(p);
                    983:
                    984:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    985:        p->offset = p->rmargin;
1.57      kristaps  986:        p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
                    987:            p->maxrmargin - titlen : p->maxrmargin;
1.1       kristaps  988:
                    989:        term_word(p, buf);
                    990:        term_flushln(p);
                    991:
                    992:        p->flags &= ~TERMP_NOBREAK;
1.57      kristaps  993:        if (p->rmargin + titlen <= p->maxrmargin) {
                    994:                p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    995:                p->offset = p->rmargin;
                    996:                p->rmargin = p->maxrmargin;
                    997:                term_word(p, title);
                    998:                term_flushln(p);
                    999:        }
1.1       kristaps 1000:
                   1001:        p->rmargin = p->maxrmargin;
                   1002:        p->offset = 0;
                   1003:        p->flags &= ~TERMP_NOSPACE;
1.61      kristaps 1004:
1.62      kristaps 1005:        /*
                   1006:         * Groff likes to have some leading spaces before content.  Well
                   1007:         * that's fine by me.
                   1008:         */
                   1009:
1.61      kristaps 1010:        term_vspace(p);
                   1011:        term_vspace(p);
                   1012:        term_vspace(p);
1.1       kristaps 1013: }

CVSweb