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

Annotation of mandoc/man_term.c, Revision 1.45

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

CVSweb