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

Annotation of mandoc/man_term.c, Revision 1.37

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

CVSweb