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

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

1.1     ! kristaps    1: /* $Id: man_term.c,v 1.7 2009/04/05 16:34:22 kristaps Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the
        !             7:  * above copyright notice and this permission notice appear in all
        !             8:  * copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
        !            11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
        !            12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
        !            13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
        !            14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
        !            15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
        !            16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        !            17:  * PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19: #include <assert.h>
        !            20: #include <err.h>
        !            21: #include <stdio.h>
        !            22: #include <stdlib.h>
        !            23: #include <string.h>
        !            24:
        !            25: #include "term.h"
        !            26: #include "man.h"
        !            27:
        !            28: #define        DECL_ARGS         struct termp *p, \
        !            29:                          const struct man_node *n, \
        !            30:                          const struct man_meta *m
        !            31:
        !            32: struct termact {
        !            33:        int             (*pre)(DECL_ARGS);
        !            34:        void            (*post)(DECL_ARGS);
        !            35: };
        !            36:
        !            37: static int               pre_B(DECL_ARGS);
        !            38: static int               pre_BI(DECL_ARGS);
        !            39: static int               pre_BR(DECL_ARGS);
        !            40: static int               pre_I(DECL_ARGS);
        !            41: static int               pre_IB(DECL_ARGS);
        !            42: static int               pre_IP(DECL_ARGS);
        !            43: static int               pre_IR(DECL_ARGS);
        !            44: static int               pre_PP(DECL_ARGS);
        !            45: static int               pre_RB(DECL_ARGS);
        !            46: static int               pre_RI(DECL_ARGS);
        !            47: static int               pre_SH(DECL_ARGS);
        !            48: static int               pre_SS(DECL_ARGS);
        !            49: static int               pre_TP(DECL_ARGS);
        !            50:
        !            51: static void              post_B(DECL_ARGS);
        !            52: static void              post_I(DECL_ARGS);
        !            53: static void              post_SH(DECL_ARGS);
        !            54: static void              post_SS(DECL_ARGS);
        !            55:
        !            56: static const struct termact termacts[MAN_MAX] = {
        !            57:        { NULL, NULL }, /* __ */
        !            58:        { NULL, NULL }, /* TH */
        !            59:        { pre_SH, post_SH }, /* SH */
        !            60:        { pre_SS, post_SS }, /* SS */
        !            61:        { pre_TP, NULL }, /* TP */
        !            62:        { pre_PP, NULL }, /* LP */
        !            63:        { pre_PP, NULL }, /* PP */
        !            64:        { pre_PP, NULL }, /* P */
        !            65:        { pre_IP, NULL }, /* IP */
        !            66:        { pre_PP, NULL }, /* HP */ /* FIXME */
        !            67:        { NULL, NULL }, /* SM */
        !            68:        { pre_B, post_B }, /* SB */
        !            69:        { pre_BI, NULL }, /* BI */
        !            70:        { pre_IB, NULL }, /* IB */
        !            71:        { pre_BR, NULL }, /* BR */
        !            72:        { pre_RB, NULL }, /* RB */
        !            73:        { NULL, NULL }, /* R */
        !            74:        { pre_B, post_B }, /* B */
        !            75:        { pre_I, post_I }, /* I */
        !            76:        { pre_IR, NULL }, /* IR */
        !            77:        { pre_RI, NULL }, /* RI */
        !            78:        { pre_PP, NULL }, /* br */
        !            79:        { NULL, NULL }, /* na */
        !            80:        { pre_I, post_I }, /* i */
        !            81: };
        !            82:
        !            83: static void              print_head(struct termp *,
        !            84:                                const struct man_meta *);
        !            85: static void              print_body(DECL_ARGS);
        !            86: static void              print_node(DECL_ARGS);
        !            87: static void              print_foot(struct termp *,
        !            88:                                const struct man_meta *);
        !            89:
        !            90:
        !            91: int
        !            92: man_run(struct termp *p, const struct man *m)
        !            93: {
        !            94:
        !            95:        print_head(p, man_meta(m));
        !            96:        p->flags |= TERMP_NOSPACE;
        !            97:        print_body(p, man_node(m), man_meta(m));
        !            98:        print_foot(p, man_meta(m));
        !            99:
        !           100:        return(1);
        !           101: }
        !           102:
        !           103:
        !           104: /* ARGSUSED */
        !           105: static int
        !           106: pre_I(DECL_ARGS)
        !           107: {
        !           108:
        !           109:        p->flags |= TERMP_UNDER;
        !           110:        return(1);
        !           111: }
        !           112:
        !           113:
        !           114: /* ARGSUSED */
        !           115: static void
        !           116: post_I(DECL_ARGS)
        !           117: {
        !           118:
        !           119:        p->flags &= ~TERMP_UNDER;
        !           120: }
        !           121:
        !           122:
        !           123: /* ARGSUSED */
        !           124: static int
        !           125: pre_IR(DECL_ARGS)
        !           126: {
        !           127:        const struct man_node *nn;
        !           128:        int              i;
        !           129:
        !           130:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           131:                if ( ! (i % 2))
        !           132:                        p->flags |= TERMP_UNDER;
        !           133:                if (i > 0)
        !           134:                        p->flags |= TERMP_NOSPACE;
        !           135:                print_node(p, nn, m);
        !           136:                if ( ! (i % 2))
        !           137:                        p->flags &= ~TERMP_UNDER;
        !           138:        }
        !           139:        return(0);
        !           140: }
        !           141:
        !           142:
        !           143: /* ARGSUSED */
        !           144: static int
        !           145: pre_IB(DECL_ARGS)
        !           146: {
        !           147:        const struct man_node *nn;
        !           148:        int              i;
        !           149:
        !           150:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           151:                p->flags |= i % 2 ? TERMP_BOLD : TERMP_UNDER;
        !           152:                if (i > 0)
        !           153:                        p->flags |= TERMP_NOSPACE;
        !           154:                print_node(p, nn, m);
        !           155:                p->flags &= i % 2 ? ~TERMP_BOLD : ~TERMP_UNDER;
        !           156:        }
        !           157:        return(0);
        !           158: }
        !           159:
        !           160:
        !           161: /* ARGSUSED */
        !           162: static int
        !           163: pre_RB(DECL_ARGS)
        !           164: {
        !           165:        const struct man_node *nn;
        !           166:        int              i;
        !           167:
        !           168:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           169:                if (i % 2)
        !           170:                        p->flags |= TERMP_BOLD;
        !           171:                if (i > 0)
        !           172:                        p->flags |= TERMP_NOSPACE;
        !           173:                print_node(p, nn, m);
        !           174:                if (i % 2)
        !           175:                        p->flags &= ~TERMP_BOLD;
        !           176:        }
        !           177:        return(0);
        !           178: }
        !           179:
        !           180:
        !           181: /* ARGSUSED */
        !           182: static int
        !           183: pre_RI(DECL_ARGS)
        !           184: {
        !           185:        const struct man_node *nn;
        !           186:        int              i;
        !           187:
        !           188:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           189:                if ( ! (i % 2))
        !           190:                        p->flags |= TERMP_UNDER;
        !           191:                if (i > 0)
        !           192:                        p->flags |= TERMP_NOSPACE;
        !           193:                print_node(p, nn, m);
        !           194:                if ( ! (i % 2))
        !           195:                        p->flags &= ~TERMP_UNDER;
        !           196:        }
        !           197:        return(0);
        !           198: }
        !           199:
        !           200:
        !           201: /* ARGSUSED */
        !           202: static int
        !           203: pre_BR(DECL_ARGS)
        !           204: {
        !           205:        const struct man_node *nn;
        !           206:        int              i;
        !           207:
        !           208:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           209:                if ( ! (i % 2))
        !           210:                        p->flags |= TERMP_BOLD;
        !           211:                if (i > 0)
        !           212:                        p->flags |= TERMP_NOSPACE;
        !           213:                print_node(p, nn, m);
        !           214:                if ( ! (i % 2))
        !           215:                        p->flags &= ~TERMP_BOLD;
        !           216:        }
        !           217:        return(0);
        !           218: }
        !           219:
        !           220:
        !           221: /* ARGSUSED */
        !           222: static int
        !           223: pre_BI(DECL_ARGS)
        !           224: {
        !           225:        const struct man_node *nn;
        !           226:        int              i;
        !           227:
        !           228:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           229:                p->flags |= i % 2 ? TERMP_UNDER : TERMP_BOLD;
        !           230:                if (i > 0)
        !           231:                        p->flags |= TERMP_NOSPACE;
        !           232:                print_node(p, nn, m);
        !           233:                p->flags &= i % 2 ? ~TERMP_UNDER : ~TERMP_BOLD;
        !           234:        }
        !           235:        return(0);
        !           236: }
        !           237:
        !           238:
        !           239: /* ARGSUSED */
        !           240: static int
        !           241: pre_B(DECL_ARGS)
        !           242: {
        !           243:
        !           244:        p->flags |= TERMP_BOLD;
        !           245:        return(1);
        !           246: }
        !           247:
        !           248:
        !           249: /* ARGSUSED */
        !           250: static void
        !           251: post_B(DECL_ARGS)
        !           252: {
        !           253:
        !           254:        p->flags &= ~TERMP_BOLD;
        !           255: }
        !           256:
        !           257:
        !           258: /* ARGSUSED */
        !           259: static int
        !           260: pre_PP(DECL_ARGS)
        !           261: {
        !           262:
        !           263:        term_vspace(p);
        !           264:        p->offset = INDENT;
        !           265:        return(0);
        !           266: }
        !           267:
        !           268:
        !           269: /* ARGSUSED */
        !           270: static int
        !           271: pre_IP(DECL_ARGS)
        !           272: {
        !           273: #if 0
        !           274:        const struct man_node *nn;
        !           275:        size_t           offs;
        !           276: #endif
        !           277:
        !           278:        term_vspace(p);
        !           279:        p->offset = INDENT;
        !           280:
        !           281: #if 0
        !           282:        if (NULL == (nn = n->child))
        !           283:                return(1);
        !           284:        if (MAN_TEXT != nn->type)
        !           285:                errx(1, "expected text line argument");
        !           286:
        !           287:        if (nn->next) {
        !           288:                if (MAN_TEXT != nn->next->type)
        !           289:                        errx(1, "expected text line argument");
        !           290:                offs = (size_t)atoi(nn->next->string);
        !           291:        } else
        !           292:                offs = strlen(nn->string);
        !           293:
        !           294:        p->offset += offs;
        !           295: #endif
        !           296:        p->flags |= TERMP_NOSPACE;
        !           297:        return(0);
        !           298: }
        !           299:
        !           300:
        !           301: /* ARGSUSED */
        !           302: static int
        !           303: pre_TP(DECL_ARGS)
        !           304: {
        !           305:        const struct man_node *nn;
        !           306:        size_t           offs;
        !           307:
        !           308:        term_vspace(p);
        !           309:        p->offset = INDENT;
        !           310:
        !           311:        if (NULL == (nn = n->child))
        !           312:                return(1);
        !           313:
        !           314:        if (nn->line == n->line) {
        !           315:                if (MAN_TEXT != nn->type)
        !           316:                        errx(1, "expected text line argument");
        !           317:                offs = (size_t)atoi(nn->string);
        !           318:                nn = nn->next;
        !           319:        } else
        !           320:                offs = INDENT;
        !           321:
        !           322:        for ( ; nn; nn = nn->next)
        !           323:                print_node(p, nn, m);
        !           324:
        !           325:        term_flushln(p);
        !           326:        p->flags |= TERMP_NOSPACE;
        !           327:        p->offset += offs;
        !           328:        return(0);
        !           329: }
        !           330:
        !           331:
        !           332: /* ARGSUSED */
        !           333: static int
        !           334: pre_SS(DECL_ARGS)
        !           335: {
        !           336:
        !           337:        term_vspace(p);
        !           338:        p->flags |= TERMP_BOLD;
        !           339:        return(1);
        !           340: }
        !           341:
        !           342:
        !           343: /* ARGSUSED */
        !           344: static void
        !           345: post_SS(DECL_ARGS)
        !           346: {
        !           347:
        !           348:        term_flushln(p);
        !           349:        p->flags &= ~TERMP_BOLD;
        !           350:        p->flags |= TERMP_NOSPACE;
        !           351: }
        !           352:
        !           353:
        !           354: /* ARGSUSED */
        !           355: static int
        !           356: pre_SH(DECL_ARGS)
        !           357: {
        !           358:
        !           359:        term_vspace(p);
        !           360:        p->offset = 0;
        !           361:        p->flags |= TERMP_BOLD;
        !           362:        return(1);
        !           363: }
        !           364:
        !           365:
        !           366: /* ARGSUSED */
        !           367: static void
        !           368: post_SH(DECL_ARGS)
        !           369: {
        !           370:
        !           371:        term_flushln(p);
        !           372:        p->offset = INDENT;
        !           373:        p->flags &= ~TERMP_BOLD;
        !           374:        p->flags |= TERMP_NOSPACE;
        !           375: }
        !           376:
        !           377:
        !           378: static void
        !           379: print_node(DECL_ARGS)
        !           380: {
        !           381:        int              c, sz;
        !           382:
        !           383:        c = 1;
        !           384:
        !           385:        switch (n->type) {
        !           386:        case(MAN_ELEM):
        !           387:                if (termacts[n->tok].pre)
        !           388:                        c = (*termacts[n->tok].pre)(p, n, m);
        !           389:                break;
        !           390:        case(MAN_TEXT):
        !           391:                if (0 == *n->string) {
        !           392:                        term_vspace(p);
        !           393:                        break;
        !           394:                }
        !           395:                /*
        !           396:                 * Note!  This is hacky.  Here, we recognise the `\c'
        !           397:                 * escape embedded in so many -man pages.  It's supposed
        !           398:                 * to remove the subsequent space, so we mark NOSPACE if
        !           399:                 * it's encountered in the string.
        !           400:                 */
        !           401:                sz = (int)strlen(n->string);
        !           402:                term_word(p, n->string);
        !           403:                if (sz >= 2 && n->string[sz - 1] == 'c' &&
        !           404:                                n->string[sz - 2] == '\\')
        !           405:                        p->flags |= TERMP_NOSPACE;
        !           406:                break;
        !           407:        default:
        !           408:                break;
        !           409:        }
        !           410:
        !           411:        if (c && n->child)
        !           412:                print_body(p, n->child, m);
        !           413:
        !           414:        switch (n->type) {
        !           415:        case (MAN_ELEM):
        !           416:                if (termacts[n->tok].post)
        !           417:                        (*termacts[n->tok].post)(p, n, m);
        !           418:                break;
        !           419:        default:
        !           420:                break;
        !           421:        }
        !           422: }
        !           423:
        !           424:
        !           425: static void
        !           426: print_body(DECL_ARGS)
        !           427: {
        !           428:        print_node(p, n, m);
        !           429:        if ( ! n->next)
        !           430:                return;
        !           431:        print_body(p, n->next, m);
        !           432: }
        !           433:
        !           434:
        !           435: static void
        !           436: print_foot(struct termp *p, const struct man_meta *meta)
        !           437: {
        !           438:        struct tm       *tm;
        !           439:        char            *buf;
        !           440:
        !           441:        if (NULL == (buf = malloc(p->rmargin)))
        !           442:                err(1, "malloc");
        !           443:
        !           444:        tm = localtime(&meta->date);
        !           445:
        !           446:        if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
        !           447:                err(1, "strftime");
        !           448:
        !           449:        term_vspace(p);
        !           450:
        !           451:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
        !           452:        p->rmargin = p->maxrmargin - strlen(buf);
        !           453:        p->offset = 0;
        !           454:
        !           455:        if (meta->source)
        !           456:                term_word(p, meta->source);
        !           457:        if (meta->source)
        !           458:                term_word(p, "");
        !           459:        term_flushln(p);
        !           460:
        !           461:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
        !           462:        p->offset = p->rmargin;
        !           463:        p->rmargin = p->maxrmargin;
        !           464:        p->flags &= ~TERMP_NOBREAK;
        !           465:
        !           466:        term_word(p, buf);
        !           467:        term_flushln(p);
        !           468:
        !           469:        free(buf);
        !           470: }
        !           471:
        !           472:
        !           473: static void
        !           474: print_head(struct termp *p, const struct man_meta *meta)
        !           475: {
        !           476:        char            *buf, *title;
        !           477:
        !           478:        p->rmargin = p->maxrmargin;
        !           479:        p->offset = 0;
        !           480:
        !           481:        if (NULL == (buf = malloc(p->rmargin)))
        !           482:                err(1, "malloc");
        !           483:        if (NULL == (title = malloc(p->rmargin)))
        !           484:                err(1, "malloc");
        !           485:
        !           486:        if (meta->vol)
        !           487:                (void)strlcpy(buf, meta->vol, p->rmargin);
        !           488:        else
        !           489:                *buf = 0;
        !           490:
        !           491:        (void)snprintf(title, p->rmargin, "%s(%d)",
        !           492:                        meta->title, meta->msec);
        !           493:
        !           494:        p->offset = 0;
        !           495:        p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
        !           496:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
        !           497:
        !           498:        term_word(p, title);
        !           499:        term_flushln(p);
        !           500:
        !           501:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
        !           502:        p->offset = p->rmargin;
        !           503:        p->rmargin = p->maxrmargin - strlen(title);
        !           504:
        !           505:        term_word(p, buf);
        !           506:        term_flushln(p);
        !           507:
        !           508:        p->offset = p->rmargin;
        !           509:        p->rmargin = p->maxrmargin;
        !           510:        p->flags &= ~TERMP_NOBREAK;
        !           511:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
        !           512:
        !           513:        term_word(p, title);
        !           514:        term_flushln(p);
        !           515:
        !           516:        p->rmargin = p->maxrmargin;
        !           517:        p->offset = 0;
        !           518:        p->flags &= ~TERMP_NOSPACE;
        !           519:
        !           520:        free(title);
        !           521:        free(buf);
        !           522: }
        !           523: