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

Annotation of mandoc/man_term.c, Revision 1.15

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

CVSweb