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

Annotation of mandoc/man_term.c, Revision 1.2

1.2     ! kristaps    1: /* $Id: man_term.c,v 1.1 2009/03/26 14:38:11 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);
                     43: static int               pre_I(DECL_ARGS);
                     44: static int               pre_PP(DECL_ARGS);
                     45: static int               pre_SH(DECL_ARGS);
                     46: static int               pre_SS(DECL_ARGS);
                     47: static int               pre_TP(DECL_ARGS);
                     48:
                     49: static void              post_B(DECL_ARGS);
                     50: static void              post_I(DECL_ARGS);
                     51: static void              post_SH(DECL_ARGS);
                     52: static void              post_SS(DECL_ARGS);
                     53:
                     54: static const struct termact termacts[MAN_MAX] = {
                     55:        { NULL, NULL }, /* __ */
                     56:        { NULL, NULL }, /* TH */
                     57:        { pre_SH, post_SH }, /* SH */
                     58:        { pre_SS, post_SS }, /* SS */
                     59:        { pre_TP, NULL }, /* TP */
                     60:        { pre_PP, NULL }, /* LP */
                     61:        { pre_PP, NULL }, /* PP */
                     62:        { pre_PP, NULL }, /* P */
                     63:        { NULL, NULL }, /* IP */
                     64:        { pre_PP, NULL }, /* HP */ /* XXX */
                     65:        { NULL, NULL }, /* SM */
                     66:        { pre_B, post_B }, /* SB */
                     67:        { NULL, NULL }, /* BI */
                     68:        { NULL, NULL }, /* IB */
                     69:        { NULL, NULL }, /* BR */
                     70:        { NULL, NULL }, /* RB */
                     71:        { NULL, NULL }, /* R */
                     72:        { pre_B, post_B }, /* B */
                     73:        { pre_I, post_I }, /* I */
                     74:        { NULL, NULL }, /* IR */
                     75:        { NULL, NULL }, /* RI */
                     76: };
                     77:
                     78: static void              print_head(struct termp *,
                     79:                                const struct man_meta *);
                     80: static void              print_body(DECL_ARGS);
                     81: static void              print_node(DECL_ARGS);
                     82: static void              print_foot(struct termp *,
                     83:                                const struct man_meta *);
                     84:
                     85:
                     86: int
                     87: man_run(struct termp *p, const struct man *m)
                     88: {
                     89:
                     90:        print_head(p, man_meta(m));
                     91:        p->flags |= TERMP_NOSPACE;
                     92:        print_body(p, man_node(m), man_meta(m));
                     93:        print_foot(p, man_meta(m));
                     94:
                     95:        return(1);
                     96: }
                     97:
                     98:
                     99: static int
                    100: pre_I(DECL_ARGS)
                    101: {
                    102:
                    103:        p->flags |= TERMP_UNDER;
                    104:        return(1);
                    105: }
                    106:
                    107:
                    108: static void
                    109: post_I(DECL_ARGS)
                    110: {
                    111:
                    112:        p->flags &= ~TERMP_UNDER;
                    113: }
                    114:
                    115:
                    116: static int
                    117: pre_B(DECL_ARGS)
                    118: {
                    119:
                    120:        p->flags |= TERMP_BOLD;
                    121:        return(1);
                    122: }
                    123:
                    124:
                    125: static void
                    126: post_B(DECL_ARGS)
                    127: {
                    128:
                    129:        p->flags &= ~TERMP_BOLD;
                    130: }
                    131:
                    132:
                    133: static int
                    134: pre_PP(DECL_ARGS)
                    135: {
                    136:
                    137:        term_vspace(p);
                    138:        p->offset = INDENT;
                    139:        return(0);
                    140: }
                    141:
                    142:
                    143: static int
                    144: pre_TP(DECL_ARGS)
                    145: {
                    146:        const struct man_node *nn;
                    147:        size_t           offs;
                    148:
                    149:        term_vspace(p);
                    150:        p->offset = INDENT;
                    151:
                    152:        if (NULL == (nn = n->child))
                    153:                return(1);
                    154:
                    155:        if (nn->line == n->line) {
                    156:                if (MAN_TEXT != nn->type)
                    157:                        errx(1, "expected text line argument");
                    158:                offs = atoi(nn->string);
                    159:                nn = nn->next;
                    160:        } else
                    161:                offs = INDENT;
                    162:
                    163:        for ( ; nn; nn = nn->next)
                    164:                print_node(p, nn, m);
                    165:
                    166:        term_flushln(p);
                    167:        p->flags |= TERMP_NOSPACE;
                    168:        p->offset += offs;
                    169:        return(0);
                    170: }
                    171:
                    172:
                    173: static int
                    174: pre_SS(DECL_ARGS)
                    175: {
                    176:
                    177:        term_vspace(p);
                    178:        p->flags |= TERMP_BOLD;
                    179:        return(1);
                    180: }
                    181:
                    182:
                    183: static void
                    184: post_SS(DECL_ARGS)
                    185: {
                    186:
                    187:        term_flushln(p);
                    188:        p->flags &= ~TERMP_BOLD;
                    189:        p->flags |= TERMP_NOSPACE;
                    190: }
                    191:
                    192:
                    193: static int
                    194: pre_SH(DECL_ARGS)
                    195: {
                    196:
                    197:        term_vspace(p);
                    198:        p->offset = 0;
                    199:        p->flags |= TERMP_BOLD;
                    200:        return(1);
                    201: }
                    202:
                    203:
                    204: static void
                    205: post_SH(DECL_ARGS)
                    206: {
                    207:
                    208:        term_flushln(p);
                    209:        p->offset = INDENT;
                    210:        p->flags &= ~TERMP_BOLD;
                    211:        p->flags |= TERMP_NOSPACE;
                    212: }
                    213:
                    214:
                    215: static void
                    216: print_node(DECL_ARGS)
                    217: {
                    218:        int              c;
                    219:
                    220:        c = 1;
                    221:
                    222:        switch (n->type) {
                    223:        case(MAN_ELEM):
                    224:                if (termacts[n->tok].pre)
                    225:                        c = (*termacts[n->tok].pre)(p, n, m);
                    226:                break;
                    227:        case(MAN_TEXT):
                    228:                if (*n->string) {
                    229:                        term_word(p, n->string);
                    230:                        break;
                    231:                }
                    232:                term_vspace(p);
                    233:                break;
                    234:        default:
                    235:                break;
                    236:        }
                    237:
                    238:        if (c && n->child)
                    239:                print_body(p, n->child, m);
                    240:
                    241:        switch (n->type) {
                    242:        case (MAN_ELEM):
                    243:                if (termacts[n->tok].post)
                    244:                        (*termacts[n->tok].post)(p, n, m);
                    245:                break;
                    246:        default:
                    247:                break;
                    248:        }
                    249: }
                    250:
                    251:
                    252: static void
                    253: print_body(DECL_ARGS)
                    254: {
                    255:        print_node(p, n, m);
                    256:        if ( ! n->next)
                    257:                return;
                    258:        print_body(p, n->next, m);
                    259: }
                    260:
                    261:
                    262: static void
                    263: print_foot(struct termp *p, const struct man_meta *meta)
                    264: {
                    265:        struct tm       *tm;
                    266:        char            *buf;
                    267:
                    268:        if (NULL == (buf = malloc(p->rmargin)))
                    269:                err(1, "malloc");
                    270:
                    271:        tm = localtime(&meta->date);
                    272:
                    273: #ifdef __OpenBSD__
                    274:        if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
                    275: #else
                    276:        if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
                    277: #endif
                    278:                err(1, "strftime");
                    279:
                    280:        /*
                    281:         * This is /slightly/ different from regular groff output
                    282:         * because we don't have page numbers.  Print the following:
                    283:         *
                    284:         * OS                                            MDOCDATE
                    285:         */
                    286:
                    287:        term_vspace(p);
                    288:
                    289:        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
                    290:        p->rmargin = p->maxrmargin - strlen(buf);
                    291:        p->offset = 0;
                    292:
                    293:        if (meta->source)
                    294:                term_word(p, meta->source);
                    295:        if (meta->source)
                    296:                term_word(p, "");
                    297:        term_flushln(p);
                    298:
                    299:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    300:        p->offset = p->rmargin;
                    301:        p->rmargin = p->maxrmargin;
                    302:        p->flags &= ~TERMP_NOBREAK;
                    303:
                    304:        term_word(p, buf);
                    305:        term_flushln(p);
                    306:
                    307:        free(buf);
                    308: }
                    309:
                    310:
                    311: static void
                    312: print_head(struct termp *p, const struct man_meta *meta)
                    313: {
                    314:        char            *buf, *title;
                    315:
                    316:        p->rmargin = p->maxrmargin;
                    317:        p->offset = 0;
                    318:
                    319:        if (NULL == (buf = malloc(p->rmargin)))
                    320:                err(1, "malloc");
                    321:        if (NULL == (title = malloc(p->rmargin)))
                    322:                err(1, "malloc");
                    323:
                    324:        /*
                    325:         * The header is strange.  It has three components, which are
                    326:         * really two with the first duplicated.  It goes like this:
                    327:         *
                    328:         * IDENTIFIER              TITLE                   IDENTIFIER
                    329:         *
                    330:         * The IDENTIFIER is NAME(SECTION), which is the command-name
                    331:         * (if given, or "unknown" if not) followed by the manual page
                    332:         * section.  These are given in `Dt'.  The TITLE is a free-form
                    333:         * string depending on the manual volume.  If not specified, it
                    334:         * switches on the manual section.
                    335:         */
                    336:
                    337:        if (meta->vol)
                    338:                (void)strlcpy(buf, meta->vol, p->rmargin);
                    339:        else
                    340:                *buf = 0;
                    341:
                    342:        (void)snprintf(title, p->rmargin, "%s(%d)",
                    343:                        meta->title, meta->msec);
                    344:
                    345:        p->offset = 0;
                    346:        p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
                    347:        p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
                    348:
                    349:        term_word(p, title);
                    350:        term_flushln(p);
                    351:
                    352:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    353:        p->offset = p->rmargin;
                    354:        p->rmargin = p->maxrmargin - strlen(title);
                    355:
                    356:        term_word(p, buf);
                    357:        term_flushln(p);
                    358:
                    359:        p->offset = p->rmargin;
                    360:        p->rmargin = p->maxrmargin;
                    361:        p->flags &= ~TERMP_NOBREAK;
                    362:        p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
                    363:
                    364:        term_word(p, title);
                    365:        term_flushln(p);
                    366:
                    367:        p->rmargin = p->maxrmargin;
                    368:        p->offset = 0;
                    369:        p->flags &= ~TERMP_NOSPACE;
                    370:
                    371:        free(title);
                    372:        free(buf);
                    373: }
                    374:

CVSweb