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

Annotation of mandoc/man_term.c, Revision 1.39

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

CVSweb