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

Annotation of mandoc/man_term.c, Revision 1.31

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

CVSweb