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

Annotation of mandoc/man_term.c, Revision 1.23

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

CVSweb