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

Annotation of mandoc/man_term.c, Revision 1.25

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

CVSweb