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

Annotation of mandoc/man_term.c, Revision 1.22

1.22    ! kristaps    1: /*     $Id: man_term.c,v 1.21 2009/08/13 12:31:50 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_BLOCK):
        !           478:                fmt_block_vspace(p, n);
        !           479:                return(1);
        !           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:        default:
        !           489:                return(1);
        !           490:        }
1.18      kristaps  491:
1.22    ! kristaps  492:        len = INDENT * 2;
        !           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_BODY):
        !           507:                p->offset = INDENT + len;
        !           508:                p->rmargin = p->maxrmargin;
        !           509:                break;
        !           510:        case (MAN_HEAD):
        !           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);
        !           520:        default:
        !           521:                break;
1.18      kristaps  522:        }
                    523:
1.22    ! kristaps  524:        return(1);
        !           525: }
1.18      kristaps  526:
                    527:
1.22    ! kristaps  528: /* ARGSUSED */
        !           529: static void
        !           530: post_IP(DECL_ARGS)
        !           531: {
1.4       kristaps  532:
1.22    ! kristaps  533:        switch (n->type) {
        !           534:        case (MAN_HEAD):
        !           535:                term_flushln(p);
        !           536:                p->flags &= ~TERMP_NOBREAK;
        !           537:                p->flags &= ~TERMP_TWOSPACE;
        !           538:                p->rmargin = p->maxrmargin;
        !           539:                break;
        !           540:        case (MAN_BODY):
        !           541:                term_flushln(p);
        !           542:                p->flags &= ~TERMP_NOLPAD;
        !           543:                break;
        !           544:        default:
        !           545:                break;
        !           546:        }
1.4       kristaps  547: }
                    548:
                    549:
                    550: /* ARGSUSED */
                    551: static int
1.1       kristaps  552: pre_TP(DECL_ARGS)
                    553: {
                    554:
1.21      kristaps  555:        switch (n->type) {
                    556:        case (MAN_BLOCK):
                    557:                fmt_block_vspace(p, n);
                    558:                break;
                    559:        case (MAN_HEAD):
                    560:                p->rmargin = INDENT * 2;
                    561:                p->offset = INDENT;
                    562:                p->flags |= TERMP_NOBREAK;
                    563:                p->flags |= TERMP_TWOSPACE;
                    564:                break;
                    565:        case (MAN_BODY):
                    566:                p->flags |= TERMP_NOLPAD;
                    567:                p->flags |= TERMP_NOSPACE;
                    568:                p->offset = INDENT * 2;
                    569:                break;
                    570:        default:
                    571:                break;
                    572:        }
1.16      kristaps  573:
1.21      kristaps  574:        return(1);
                    575: }
1.1       kristaps  576:
                    577:
1.21      kristaps  578: /* ARGSUSED */
                    579: static void
                    580: post_TP(DECL_ARGS)
                    581: {
1.1       kristaps  582:
1.21      kristaps  583:        switch (n->type) {
                    584:        case (MAN_HEAD):
                    585:                term_flushln(p);
                    586:                p->flags &= ~TERMP_NOBREAK;
                    587:                p->flags &= ~TERMP_TWOSPACE;
                    588:                p->rmargin = p->maxrmargin;
                    589:                break;
                    590:        case (MAN_BODY):
                    591:                term_flushln(p);
                    592:                p->flags &= ~TERMP_NOLPAD;
                    593:                break;
                    594:        default:
                    595:                break;
                    596:        }
1.1       kristaps  597: }
                    598:
                    599:
1.3       kristaps  600: /* ARGSUSED */
1.1       kristaps  601: static int
                    602: pre_SS(DECL_ARGS)
                    603: {
                    604:
1.19      kristaps  605:        switch (n->type) {
                    606:        case (MAN_BLOCK):
                    607:                term_newln(p);
                    608:                if (n->prev)
                    609:                        term_vspace(p);
                    610:                break;
                    611:        case (MAN_HEAD):
                    612:                p->flags |= TERMP_BOLD;
                    613:                p->offset = HALFINDENT;
                    614:                break;
                    615:        default:
                    616:                p->offset = INDENT;
                    617:                break;
                    618:        }
                    619:
1.1       kristaps  620:        return(1);
                    621: }
                    622:
                    623:
1.3       kristaps  624: /* ARGSUSED */
1.1       kristaps  625: static void
                    626: post_SS(DECL_ARGS)
                    627: {
                    628:
1.19      kristaps  629:        switch (n->type) {
                    630:        case (MAN_HEAD):
                    631:                term_newln(p);
                    632:                p->flags &= ~TERMP_BOLD;
                    633:                break;
                    634:        default:
                    635:                break;
                    636:        }
1.1       kristaps  637: }
                    638:
                    639:
1.3       kristaps  640: /* ARGSUSED */
1.1       kristaps  641: static int
                    642: pre_SH(DECL_ARGS)
                    643: {
1.22    ! kristaps  644:
1.19      kristaps  645:        switch (n->type) {
                    646:        case (MAN_BLOCK):
1.22    ! kristaps  647:                /* If following a prior empty `SH', no vspace. */
1.19      kristaps  648:                if (n->prev && MAN_SH == n->prev->tok)
                    649:                        if (NULL == n->prev->body->child)
                    650:                                break;
                    651:                term_vspace(p);
                    652:                break;
                    653:        case (MAN_HEAD):
                    654:                p->flags |= TERMP_BOLD;
                    655:                p->offset = 0;
                    656:                break;
                    657:        case (MAN_BODY):
                    658:                p->offset = INDENT;
                    659:                break;
                    660:        default:
                    661:                break;
                    662:        }
1.1       kristaps  663:
                    664:        return(1);
                    665: }
                    666:
                    667:
1.3       kristaps  668: /* ARGSUSED */
1.1       kristaps  669: static void
                    670: post_SH(DECL_ARGS)
                    671: {
                    672:
1.19      kristaps  673:        switch (n->type) {
                    674:        case (MAN_HEAD):
                    675:                term_newln(p);
                    676:                p->flags &= ~TERMP_BOLD;
                    677:                break;
                    678:        case (MAN_BODY):
                    679:                term_newln(p);
                    680:                break;
                    681:        default:
                    682:                break;
                    683:        }
1.1       kristaps  684: }
                    685:
                    686:
                    687: static void
                    688: print_node(DECL_ARGS)
                    689: {
1.4       kristaps  690:        int              c, sz;
1.1       kristaps  691:
                    692:        c = 1;
                    693:
                    694:        switch (n->type) {
                    695:        case(MAN_TEXT):
1.4       kristaps  696:                if (0 == *n->string) {
                    697:                        term_vspace(p);
1.1       kristaps  698:                        break;
                    699:                }
1.4       kristaps  700:                /*
                    701:                 * Note!  This is hacky.  Here, we recognise the `\c'
                    702:                 * escape embedded in so many -man pages.  It's supposed
                    703:                 * to remove the subsequent space, so we mark NOSPACE if
                    704:                 * it's encountered in the string.
                    705:                 */
                    706:                sz = (int)strlen(n->string);
                    707:                term_word(p, n->string);
                    708:                if (sz >= 2 && n->string[sz - 1] == 'c' &&
                    709:                                n->string[sz - 2] == '\\')
                    710:                        p->flags |= TERMP_NOSPACE;
1.19      kristaps  711:                /* FIXME: this means that macro lines are munged!  */
                    712:                if (MANT_LITERAL & *fl) {
                    713:                        p->flags |= TERMP_NOSPACE;
                    714:                        term_flushln(p);
                    715:                }
1.1       kristaps  716:                break;
                    717:        default:
1.19      kristaps  718:                if (termacts[n->tok].pre)
                    719:                        c = (*termacts[n->tok].pre)(p, fl, n, m);
1.1       kristaps  720:                break;
                    721:        }
                    722:
                    723:        if (c && n->child)
1.19      kristaps  724:                print_body(p, fl, n->child, m);
1.1       kristaps  725:
1.19      kristaps  726:        if (MAN_TEXT != n->type)
1.1       kristaps  727:                if (termacts[n->tok].post)
1.19      kristaps  728:                        (*termacts[n->tok].post)(p, fl, n, m);
1.1       kristaps  729: }
                    730:
                    731:
                    732: static void
                    733: print_body(DECL_ARGS)
                    734: {
1.19      kristaps  735:
                    736:        print_node(p, fl, n, m);
1.1       kristaps  737:        if ( ! n->next)
                    738:                return;
1.19      kristaps  739:        print_body(p, fl, n->next, m);
1.1       kristaps  740: }
                    741:
                    742:
                    743: static void
                    744: print_foot(struct termp *p, const struct man_meta *meta)
                    745: {
                    746:        struct tm       *tm;
                    747:        char            *buf;
                    748:
                    749:        if (NULL == (buf = malloc(p->rmargin)))
                    750:                err(1, "malloc");
                    751:
                    752:        tm = localtime(&meta->date);
                    753:
                    754:        if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
                    755:                err(1, "strftime");
                    756:
                    757:        term_vspace(p);
                    758:
                    759:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
                    760:        p->rmargin = p->maxrmargin - strlen(buf);
                    761:        p->offset = 0;
                    762:
                    763:        if (meta->source)
                    764:                term_word(p, meta->source);
                    765:        if (meta->source)
                    766:                term_word(p, "");
                    767:        term_flushln(p);
                    768:
                    769:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    770:        p->offset = p->rmargin;
                    771:        p->rmargin = p->maxrmargin;
                    772:        p->flags &= ~TERMP_NOBREAK;
                    773:
                    774:        term_word(p, buf);
                    775:        term_flushln(p);
                    776:
                    777:        free(buf);
                    778: }
                    779:
                    780:
                    781: static void
                    782: print_head(struct termp *p, const struct man_meta *meta)
                    783: {
                    784:        char            *buf, *title;
                    785:
                    786:        p->rmargin = p->maxrmargin;
                    787:        p->offset = 0;
                    788:
                    789:        if (NULL == (buf = malloc(p->rmargin)))
                    790:                err(1, "malloc");
                    791:        if (NULL == (title = malloc(p->rmargin)))
                    792:                err(1, "malloc");
                    793:
                    794:        if (meta->vol)
                    795:                (void)strlcpy(buf, meta->vol, p->rmargin);
                    796:        else
                    797:                *buf = 0;
                    798:
                    799:        (void)snprintf(title, p->rmargin, "%s(%d)",
                    800:                        meta->title, meta->msec);
                    801:
                    802:        p->offset = 0;
1.10      kristaps  803:        p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1       kristaps  804:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
                    805:
                    806:        term_word(p, title);
                    807:        term_flushln(p);
                    808:
                    809:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    810:        p->offset = p->rmargin;
                    811:        p->rmargin = p->maxrmargin - strlen(title);
                    812:
                    813:        term_word(p, buf);
                    814:        term_flushln(p);
                    815:
                    816:        p->offset = p->rmargin;
                    817:        p->rmargin = p->maxrmargin;
                    818:        p->flags &= ~TERMP_NOBREAK;
                    819:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    820:
                    821:        term_word(p, title);
                    822:        term_flushln(p);
                    823:
                    824:        p->rmargin = p->maxrmargin;
                    825:        p->offset = 0;
                    826:        p->flags &= ~TERMP_NOSPACE;
                    827:
                    828:        free(title);
                    829:        free(buf);
                    830: }
                    831:

CVSweb