[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.9

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