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

Annotation of mandoc/man_term.c, Revision 1.38

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

CVSweb