[BACK]Return to man_term.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/man_term.c, Revision 1.30

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