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

Annotation of mandoc/man_term.c, Revision 1.3

1.3     ! kristaps    1: /* $Id: man_term.c,v 1.2 2009/03/26 14:44:41 kristaps Exp $ */
1.1       kristaps    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:
1.2       kristaps   28: #ifdef __linux__
                     29: extern size_t            strlcpy(char *, const char *, size_t);
                     30: extern size_t            strlcat(char *, const char *, size_t);
                     31: #endif
                     32:
1.1       kristaps   33: #define        DECL_ARGS         struct termp *p, \
                     34:                          const struct man_node *n, \
                     35:                          const struct man_meta *m
                     36:
                     37: struct termact {
                     38:        int             (*pre)(DECL_ARGS);
                     39:        void            (*post)(DECL_ARGS);
                     40: };
                     41:
                     42: static int               pre_B(DECL_ARGS);
1.3     ! kristaps   43: static int               pre_BI(DECL_ARGS);
        !            44: static int               pre_BR(DECL_ARGS);
1.1       kristaps   45: static int               pre_I(DECL_ARGS);
1.3     ! kristaps   46: static int               pre_IB(DECL_ARGS);
        !            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] = {
                     61:        { NULL, NULL }, /* __ */
                     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 */
                     69:        { NULL, NULL }, /* IP */
                     70:        { pre_PP, NULL }, /* HP */ /* XXX */
                     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.1       kristaps   82: };
                     83:
                     84: static void              print_head(struct termp *,
                     85:                                const struct man_meta *);
                     86: static void              print_body(DECL_ARGS);
                     87: static void              print_node(DECL_ARGS);
                     88: static void              print_foot(struct termp *,
                     89:                                const struct man_meta *);
                     90:
                     91:
                     92: int
                     93: man_run(struct termp *p, const struct man *m)
                     94: {
                     95:
                     96:        print_head(p, man_meta(m));
                     97:        p->flags |= TERMP_NOSPACE;
                     98:        print_body(p, man_node(m), man_meta(m));
                     99:        print_foot(p, man_meta(m));
                    100:
                    101:        return(1);
                    102: }
                    103:
                    104:
1.3     ! kristaps  105: /* ARGSUSED */
1.1       kristaps  106: static int
                    107: pre_I(DECL_ARGS)
                    108: {
                    109:
                    110:        p->flags |= TERMP_UNDER;
                    111:        return(1);
                    112: }
                    113:
                    114:
1.3     ! kristaps  115: /* ARGSUSED */
1.1       kristaps  116: static void
                    117: post_I(DECL_ARGS)
                    118: {
                    119:
                    120:        p->flags &= ~TERMP_UNDER;
                    121: }
                    122:
                    123:
1.3     ! kristaps  124: /* ARGSUSED */
        !           125: static int
        !           126: pre_IR(DECL_ARGS)
        !           127: {
        !           128:        const struct man_node *nn;
        !           129:        int              i;
        !           130:
        !           131:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           132:                if ( ! (i % 2))
        !           133:                        p->flags |= TERMP_UNDER;
        !           134:                print_node(p, nn, m);
        !           135:                if ( ! (i % 2))
        !           136:                        p->flags &= ~TERMP_UNDER;
        !           137:        }
        !           138:        return(0);
        !           139: }
        !           140:
        !           141:
        !           142: /* ARGSUSED */
        !           143: static int
        !           144: pre_IB(DECL_ARGS)
        !           145: {
        !           146:        const struct man_node *nn;
        !           147:        int              i;
        !           148:
        !           149:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           150:                p->flags |= i % 2 ? TERMP_BOLD : TERMP_UNDER;
        !           151:                print_node(p, nn, m);
        !           152:                p->flags &= i % 2 ? ~TERMP_BOLD : ~TERMP_UNDER;
        !           153:        }
        !           154:        return(0);
        !           155: }
        !           156:
        !           157:
        !           158: /* ARGSUSED */
        !           159: static int
        !           160: pre_RB(DECL_ARGS)
        !           161: {
        !           162:        const struct man_node *nn;
        !           163:        int              i;
        !           164:
        !           165:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           166:                if (i % 2)
        !           167:                        p->flags |= TERMP_BOLD;
        !           168:                print_node(p, nn, m);
        !           169:                if (i % 2)
        !           170:                        p->flags &= ~TERMP_BOLD;
        !           171:        }
        !           172:        return(0);
        !           173: }
        !           174:
        !           175:
        !           176: /* ARGSUSED */
        !           177: static int
        !           178: pre_RI(DECL_ARGS)
        !           179: {
        !           180:        const struct man_node *nn;
        !           181:        int              i;
        !           182:
        !           183:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           184:                if ( ! (i % 2))
        !           185:                        p->flags |= TERMP_UNDER;
        !           186:                print_node(p, nn, m);
        !           187:                if ( ! (i % 2))
        !           188:                        p->flags &= ~TERMP_UNDER;
        !           189:        }
        !           190:        return(0);
        !           191: }
        !           192:
        !           193:
        !           194: /* ARGSUSED */
        !           195: static int
        !           196: pre_BR(DECL_ARGS)
        !           197: {
        !           198:        const struct man_node *nn;
        !           199:        int              i;
        !           200:
        !           201:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           202:                if ( ! (i % 2))
        !           203:                        p->flags |= TERMP_BOLD;
        !           204:                print_node(p, nn, m);
        !           205:                if ( ! (i % 2))
        !           206:                        p->flags &= ~TERMP_BOLD;
        !           207:        }
        !           208:        return(0);
        !           209: }
        !           210:
        !           211:
        !           212: /* ARGSUSED */
        !           213: static int
        !           214: pre_BI(DECL_ARGS)
        !           215: {
        !           216:        const struct man_node *nn;
        !           217:        int              i;
        !           218:
        !           219:        for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
        !           220:                p->flags |= i % 2 ? TERMP_UNDER : TERMP_BOLD;
        !           221:                print_node(p, nn, m);
        !           222:                p->flags &= i % 2 ? ~TERMP_UNDER : ~TERMP_BOLD;
        !           223:        }
        !           224:        return(0);
        !           225: }
        !           226:
        !           227:
        !           228: /* ARGSUSED */
1.1       kristaps  229: static int
                    230: pre_B(DECL_ARGS)
                    231: {
                    232:
                    233:        p->flags |= TERMP_BOLD;
                    234:        return(1);
                    235: }
                    236:
                    237:
1.3     ! kristaps  238: /* ARGSUSED */
1.1       kristaps  239: static void
                    240: post_B(DECL_ARGS)
                    241: {
                    242:
                    243:        p->flags &= ~TERMP_BOLD;
                    244: }
                    245:
                    246:
1.3     ! kristaps  247: /* ARGSUSED */
1.1       kristaps  248: static int
                    249: pre_PP(DECL_ARGS)
                    250: {
                    251:
                    252:        term_vspace(p);
                    253:        p->offset = INDENT;
                    254:        return(0);
                    255: }
                    256:
                    257:
1.3     ! kristaps  258: /* ARGSUSED */
1.1       kristaps  259: static int
                    260: pre_TP(DECL_ARGS)
                    261: {
                    262:        const struct man_node *nn;
                    263:        size_t           offs;
                    264:
                    265:        term_vspace(p);
                    266:        p->offset = INDENT;
                    267:
                    268:        if (NULL == (nn = n->child))
                    269:                return(1);
                    270:
                    271:        if (nn->line == n->line) {
                    272:                if (MAN_TEXT != nn->type)
                    273:                        errx(1, "expected text line argument");
1.3     ! kristaps  274:                offs = (size_t)atoi(nn->string);
1.1       kristaps  275:                nn = nn->next;
                    276:        } else
                    277:                offs = INDENT;
                    278:
                    279:        for ( ; nn; nn = nn->next)
                    280:                print_node(p, nn, m);
                    281:
                    282:        term_flushln(p);
                    283:        p->flags |= TERMP_NOSPACE;
                    284:        p->offset += offs;
                    285:        return(0);
                    286: }
                    287:
                    288:
1.3     ! kristaps  289: /* ARGSUSED */
1.1       kristaps  290: static int
                    291: pre_SS(DECL_ARGS)
                    292: {
                    293:
                    294:        term_vspace(p);
                    295:        p->flags |= TERMP_BOLD;
                    296:        return(1);
                    297: }
                    298:
                    299:
1.3     ! kristaps  300: /* ARGSUSED */
1.1       kristaps  301: static void
                    302: post_SS(DECL_ARGS)
                    303: {
                    304:
                    305:        term_flushln(p);
                    306:        p->flags &= ~TERMP_BOLD;
                    307:        p->flags |= TERMP_NOSPACE;
                    308: }
                    309:
                    310:
1.3     ! kristaps  311: /* ARGSUSED */
1.1       kristaps  312: static int
                    313: pre_SH(DECL_ARGS)
                    314: {
                    315:
                    316:        term_vspace(p);
                    317:        p->offset = 0;
                    318:        p->flags |= TERMP_BOLD;
                    319:        return(1);
                    320: }
                    321:
                    322:
1.3     ! kristaps  323: /* ARGSUSED */
1.1       kristaps  324: static void
                    325: post_SH(DECL_ARGS)
                    326: {
                    327:
                    328:        term_flushln(p);
                    329:        p->offset = INDENT;
                    330:        p->flags &= ~TERMP_BOLD;
                    331:        p->flags |= TERMP_NOSPACE;
                    332: }
                    333:
                    334:
                    335: static void
                    336: print_node(DECL_ARGS)
                    337: {
                    338:        int              c;
                    339:
                    340:        c = 1;
                    341:
                    342:        switch (n->type) {
                    343:        case(MAN_ELEM):
                    344:                if (termacts[n->tok].pre)
                    345:                        c = (*termacts[n->tok].pre)(p, n, m);
                    346:                break;
                    347:        case(MAN_TEXT):
                    348:                if (*n->string) {
                    349:                        term_word(p, n->string);
                    350:                        break;
                    351:                }
                    352:                term_vspace(p);
                    353:                break;
                    354:        default:
                    355:                break;
                    356:        }
                    357:
                    358:        if (c && n->child)
                    359:                print_body(p, n->child, m);
                    360:
                    361:        switch (n->type) {
                    362:        case (MAN_ELEM):
                    363:                if (termacts[n->tok].post)
                    364:                        (*termacts[n->tok].post)(p, n, m);
                    365:                break;
                    366:        default:
                    367:                break;
                    368:        }
                    369: }
                    370:
                    371:
                    372: static void
                    373: print_body(DECL_ARGS)
                    374: {
                    375:        print_node(p, n, m);
                    376:        if ( ! n->next)
                    377:                return;
                    378:        print_body(p, n->next, m);
                    379: }
                    380:
                    381:
                    382: static void
                    383: print_foot(struct termp *p, const struct man_meta *meta)
                    384: {
                    385:        struct tm       *tm;
                    386:        char            *buf;
                    387:
                    388:        if (NULL == (buf = malloc(p->rmargin)))
                    389:                err(1, "malloc");
                    390:
                    391:        tm = localtime(&meta->date);
                    392:
                    393: #ifdef __OpenBSD__
                    394:        if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
                    395: #else
                    396:        if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
                    397: #endif
                    398:                err(1, "strftime");
                    399:
                    400:        /*
                    401:         * This is /slightly/ different from regular groff output
                    402:         * because we don't have page numbers.  Print the following:
                    403:         *
                    404:         * OS                                            MDOCDATE
                    405:         */
                    406:
                    407:        term_vspace(p);
                    408:
                    409:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
                    410:        p->rmargin = p->maxrmargin - strlen(buf);
                    411:        p->offset = 0;
                    412:
                    413:        if (meta->source)
                    414:                term_word(p, meta->source);
                    415:        if (meta->source)
                    416:                term_word(p, "");
                    417:        term_flushln(p);
                    418:
                    419:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    420:        p->offset = p->rmargin;
                    421:        p->rmargin = p->maxrmargin;
                    422:        p->flags &= ~TERMP_NOBREAK;
                    423:
                    424:        term_word(p, buf);
                    425:        term_flushln(p);
                    426:
                    427:        free(buf);
                    428: }
                    429:
                    430:
                    431: static void
                    432: print_head(struct termp *p, const struct man_meta *meta)
                    433: {
                    434:        char            *buf, *title;
                    435:
                    436:        p->rmargin = p->maxrmargin;
                    437:        p->offset = 0;
                    438:
                    439:        if (NULL == (buf = malloc(p->rmargin)))
                    440:                err(1, "malloc");
                    441:        if (NULL == (title = malloc(p->rmargin)))
                    442:                err(1, "malloc");
                    443:
                    444:        /*
                    445:         * The header is strange.  It has three components, which are
                    446:         * really two with the first duplicated.  It goes like this:
                    447:         *
                    448:         * IDENTIFIER              TITLE                   IDENTIFIER
                    449:         *
                    450:         * The IDENTIFIER is NAME(SECTION), which is the command-name
                    451:         * (if given, or "unknown" if not) followed by the manual page
                    452:         * section.  These are given in `Dt'.  The TITLE is a free-form
                    453:         * string depending on the manual volume.  If not specified, it
                    454:         * switches on the manual section.
                    455:         */
                    456:
                    457:        if (meta->vol)
                    458:                (void)strlcpy(buf, meta->vol, p->rmargin);
                    459:        else
                    460:                *buf = 0;
                    461:
                    462:        (void)snprintf(title, p->rmargin, "%s(%d)",
                    463:                        meta->title, meta->msec);
                    464:
                    465:        p->offset = 0;
                    466:        p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
                    467:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
                    468:
                    469:        term_word(p, title);
                    470:        term_flushln(p);
                    471:
                    472:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    473:        p->offset = p->rmargin;
                    474:        p->rmargin = p->maxrmargin - strlen(title);
                    475:
                    476:        term_word(p, buf);
                    477:        term_flushln(p);
                    478:
                    479:        p->offset = p->rmargin;
                    480:        p->rmargin = p->maxrmargin;
                    481:        p->flags &= ~TERMP_NOBREAK;
                    482:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    483:
                    484:        term_word(p, title);
                    485:        term_flushln(p);
                    486:
                    487:        p->rmargin = p->maxrmargin;
                    488:        p->offset = 0;
                    489:        p->flags &= ~TERMP_NOSPACE;
                    490:
                    491:        free(title);
                    492:        free(buf);
                    493: }
                    494:

CVSweb