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

Annotation of mandoc/term.c, Revision 1.2

1.2     ! kristaps    1: /* $Id: term.c,v 1.1 2009/02/20 11:04:23 kristaps Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
                      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>
1.2     ! kristaps   20: #include <ctype.h>
1.1       kristaps   21: #include <curses.h>
                     22: #include <err.h>
                     23: #include <stdlib.h>
                     24: #include <stdio.h>
                     25: #include <string.h>
                     26: #include <term.h>
                     27: #include <unistd.h>
                     28:
1.2     ! kristaps   29: #include "private.h"
1.1       kristaps   30:
                     31:
1.2     ! kristaps   32: enum   termesc {
        !            33:        ESC_CLEAR,
        !            34:        ESC_BOLD,
        !            35:        ESC_UNDERLINE
        !            36: };
        !            37:
        !            38: struct termp {
        !            39:        size_t            maxvisible;
        !            40:        size_t            maxcols;
        !            41:        size_t            indent;
        !            42:        size_t            col;
        !            43:        int               flags;
        !            44: #define        TERMP_BOLD       (1 << 0)
        !            45: #define        TERMP_UNDERLINE  (1 << 1)
        !            46: #define        TERMP_NOSPACE    (1 << 2)
        !            47:        char             *buf;
        !            48: };
        !            49:
        !            50: struct termact {
        !            51:        int             (*pre)(struct termp *,
        !            52:                                const struct mdoc_meta *,
1.1       kristaps   53:                                const struct mdoc_node *);
1.2     ! kristaps   54:        int             (*post)(struct termp *,
        !            55:                                const struct mdoc_meta *,
        !            56:                                const struct mdoc_node *);
        !            57: };
        !            58:
        !            59: static void              termprint_r(struct termp *,
        !            60:                                const struct mdoc_meta *,
        !            61:                                const struct mdoc_node *);
        !            62: static void              termprint_header(struct termp *,
1.1       kristaps   63:                                const struct mdoc_meta *);
1.2     ! kristaps   64: static void              termprint_footer(struct termp *,
1.1       kristaps   65:                                const struct mdoc_meta *);
                     66:
1.2     ! kristaps   67: static void              newln(struct termp *);
        !            68: static void              vspace(struct termp *);
        !            69: static void              pword(struct termp *, const char *, size_t);
        !            70: static void              word(struct termp *, const char *);
        !            71:
        !            72: static int               termp_it_pre(struct termp *,
        !            73:                                const struct mdoc_meta *,
        !            74:                                const struct mdoc_node *);
        !            75: static int               termp_ns_pre(struct termp *,
        !            76:                                const struct mdoc_meta *,
        !            77:                                const struct mdoc_node *);
        !            78: static int               termp_pp_pre(struct termp *,
        !            79:                                const struct mdoc_meta *,
        !            80:                                const struct mdoc_node *);
        !            81: static int               termp_fl_pre(struct termp *,
        !            82:                                const struct mdoc_meta *,
        !            83:                                const struct mdoc_node *);
        !            84: static int               termp_op_pre(struct termp *,
        !            85:                                const struct mdoc_meta *,
        !            86:                                const struct mdoc_node *);
        !            87: static int               termp_op_post(struct termp *,
        !            88:                                const struct mdoc_meta *,
        !            89:                                const struct mdoc_node *);
        !            90: static int               termp_bl_post(struct termp *,
        !            91:                                const struct mdoc_meta *,
        !            92:                                const struct mdoc_node *);
        !            93: static int               termp_sh_post(struct termp *,
        !            94:                                const struct mdoc_meta *,
        !            95:                                const struct mdoc_node *);
        !            96: static int               termp_sh_pre(struct termp *,
        !            97:                                const struct mdoc_meta *,
        !            98:                                const struct mdoc_node *);
        !            99: static int               termp_nd_pre(struct termp *,
        !           100:                                const struct mdoc_meta *,
        !           101:                                const struct mdoc_node *);
        !           102: static int               termp_bold_pre(struct termp *,
        !           103:                                const struct mdoc_meta *,
        !           104:                                const struct mdoc_node *);
        !           105: static int               termp_under_pre(struct termp *,
        !           106:                                const struct mdoc_meta *,
        !           107:                                const struct mdoc_node *);
        !           108: static int               termp_bold_post(struct termp *,
        !           109:                                const struct mdoc_meta *,
        !           110:                                const struct mdoc_node *);
        !           111: static int               termp_under_post(struct termp *,
        !           112:                                const struct mdoc_meta *,
        !           113:                                const struct mdoc_node *);
        !           114:
        !           115: const  struct termact termacts[MDOC_MAX] = {
        !           116:        { NULL, NULL }, /* \" */
        !           117:        { NULL, NULL }, /* Dd */
        !           118:        { NULL, NULL }, /* Dt */
        !           119:        { NULL, NULL }, /* Os */
        !           120:        { termp_sh_pre, termp_sh_post }, /* Sh */
        !           121:        { NULL, NULL }, /* Ss */
        !           122:        { termp_pp_pre, NULL }, /* Pp */
        !           123:        { NULL, NULL }, /* D1 */
        !           124:        { NULL, NULL }, /* Dl */
        !           125:        { NULL, NULL }, /* Bd */
        !           126:        { NULL, NULL }, /* Ed */
        !           127:        { NULL, termp_bl_post }, /* Bl */
        !           128:        { NULL, NULL }, /* El */
        !           129:        { termp_it_pre, NULL }, /* It */
        !           130:        { NULL, NULL }, /* Ad */
        !           131:        { NULL, NULL }, /* An */
        !           132:        { termp_under_pre, termp_under_post }, /* Ar */
        !           133:        { NULL, NULL }, /* Cd */
        !           134:        { NULL, NULL }, /* Cm */
        !           135:        { NULL, NULL }, /* Dv */
        !           136:        { NULL, NULL }, /* Er */
        !           137:        { NULL, NULL }, /* Ev */
        !           138:        { NULL, NULL }, /* Ex */
        !           139:        { NULL, NULL }, /* Fa */
        !           140:        { NULL, NULL }, /* Fd */
        !           141:        { termp_fl_pre, termp_bold_post }, /* Fl */
        !           142:        { NULL, NULL }, /* Fn */
        !           143:        { NULL, NULL }, /* Ft */
        !           144:        { NULL, NULL }, /* Ic */
        !           145:        { NULL, NULL }, /* In */
        !           146:        { NULL, NULL }, /* Li */
        !           147:        { termp_nd_pre, NULL }, /* Nd */
        !           148:        { termp_bold_pre, termp_bold_post }, /* Nm */
        !           149:        { termp_op_pre, termp_op_post }, /* Op */
        !           150:        { NULL, NULL }, /* Ot */
        !           151:        { NULL, NULL }, /* Pa */
        !           152:        { NULL, NULL }, /* Rv */
        !           153:        { NULL, NULL }, /* St */
        !           154:        { NULL, NULL }, /* Va */
        !           155:        { NULL, NULL }, /* Vt */
        !           156:        { NULL, NULL }, /* Xr */
        !           157:        { NULL, NULL }, /* %A */
        !           158:        { NULL, NULL }, /* %B */
        !           159:        { NULL, NULL }, /* %D */
        !           160:        { NULL, NULL }, /* %I */
        !           161:        { NULL, NULL }, /* %J */
        !           162:        { NULL, NULL }, /* %N */
        !           163:        { NULL, NULL }, /* %O */
        !           164:        { NULL, NULL }, /* %P */
        !           165:        { NULL, NULL }, /* %R */
        !           166:        { NULL, NULL }, /* %T */
        !           167:        { NULL, NULL }, /* %V */
        !           168:        { NULL, NULL }, /* Ac */
        !           169:        { NULL, NULL }, /* Ao */
        !           170:        { NULL, NULL }, /* Aq */
        !           171:        { NULL, NULL }, /* At */
        !           172:        { NULL, NULL }, /* Bc */
        !           173:        { NULL, NULL }, /* Bf */
        !           174:        { NULL, NULL }, /* Bo */
        !           175:        { NULL, NULL }, /* Bq */
        !           176:        { NULL, NULL }, /* Bsx */
        !           177:        { NULL, NULL }, /* Bx */
        !           178:        { NULL, NULL }, /* Db */
        !           179:        { NULL, NULL }, /* Dc */
        !           180:        { NULL, NULL }, /* Do */
        !           181:        { NULL, NULL }, /* Dq */
        !           182:        { NULL, NULL }, /* Ec */
        !           183:        { NULL, NULL }, /* Ef */
        !           184:        { NULL, NULL }, /* Em */
        !           185:        { NULL, NULL }, /* Eo */
        !           186:        { NULL, NULL }, /* Fx */
        !           187:        { NULL, NULL }, /* Ms */
        !           188:        { NULL, NULL }, /* No */
        !           189:        { termp_ns_pre, NULL }, /* Ns */
        !           190:        { NULL, NULL }, /* Nx */
        !           191:        { NULL, NULL }, /* Ox */
        !           192:        { NULL, NULL }, /* Pc */
        !           193:        { NULL, NULL }, /* Pf */
        !           194:        { NULL, NULL }, /* Po */
        !           195:        { NULL, NULL }, /* Pq */
        !           196:        { NULL, NULL }, /* Qc */
        !           197:        { NULL, NULL }, /* Ql */
        !           198:        { NULL, NULL }, /* Qo */
        !           199:        { NULL, NULL }, /* Qq */
        !           200:        { NULL, NULL }, /* Re */
        !           201:        { NULL, NULL }, /* Rs */
        !           202:        { NULL, NULL }, /* Sc */
        !           203:        { NULL, NULL }, /* So */
        !           204:        { NULL, NULL }, /* Sq */
        !           205:        { NULL, NULL }, /* Sm */
        !           206:        { NULL, NULL }, /* Sx */
        !           207:        { NULL, NULL }, /* Sy */
        !           208:        { NULL, NULL }, /* Tn */
        !           209:        { NULL, NULL }, /* Ux */
        !           210:        { NULL, NULL }, /* Xc */
        !           211:        { NULL, NULL }, /* Xo */
        !           212:        { NULL, NULL }, /* Fo */
        !           213:        { NULL, NULL }, /* Fc */
        !           214:        { NULL, NULL }, /* Oo */
        !           215:        { NULL, NULL }, /* Oc */
        !           216:        { NULL, NULL }, /* Bk */
        !           217:        { NULL, NULL }, /* Ek */
        !           218:        { NULL, NULL }, /* Bt */
        !           219:        { NULL, NULL }, /* Hf */
        !           220:        { NULL, NULL }, /* Fr */
        !           221:        { NULL, NULL }, /* Ud */
        !           222: };
        !           223:
        !           224:
        !           225: static void
        !           226: flush(struct termp *p)
        !           227: {
        !           228:        size_t           i, j, vsz, vis, maxvis;
        !           229:
        !           230:        maxvis = p->maxvisible - (p->indent * 4);
        !           231:        vis = 0;
        !           232:
        !           233:        for (j = 0; j < (p->indent * 4); j++)
        !           234:                putchar(' ');
        !           235:
        !           236:        for (i = 0; i < p->col; i++) {
        !           237:                for (j = i, vsz = 0; j < p->col; j++) {
        !           238:                        if (isspace(p->buf[j]))
        !           239:                                break;
        !           240:                        else if (27 == p->buf[j]) {
        !           241:                                assert(j + 4 <= p->col);
        !           242:                                j += 3;
        !           243:                        } else
        !           244:                                vsz++;
        !           245:                }
        !           246:                assert(vsz > 0);
        !           247:
        !           248:                if (vis && vis + vsz >= maxvis) {
        !           249:                        putchar('\n');
        !           250:                        for (j = 0; j < (p->indent * 4); j++)
        !           251:                                putchar(' ');
        !           252:                        vis = 0;
        !           253:                }
        !           254:
        !           255:                for ( ; i < p->col; i++) {
        !           256:                        if (isspace(p->buf[i]))
        !           257:                                break;
        !           258:                        putchar(p->buf[i]);
        !           259:                }
        !           260:                vis += vsz;
        !           261:                if (i < p->col) {
        !           262:                        putchar(' ');
        !           263:                        vis++;
        !           264:                }
        !           265:        }
        !           266:
        !           267:        putchar('\n');
        !           268:        p->col = 0;
        !           269: }
        !           270:
        !           271:
        !           272: static void
        !           273: newln(struct termp *p)
        !           274: {
        !           275:
        !           276:        p->flags |= TERMP_NOSPACE;
        !           277:        if (0 == p->col)
        !           278:                return;
        !           279:        flush(p);
        !           280: }
        !           281:
        !           282:
        !           283: static void
        !           284: vspace(struct termp *p)
        !           285: {
        !           286:
        !           287:        newln(p);
        !           288:        putchar('\n');
        !           289: }
        !           290:
        !           291:
        !           292: static void
        !           293: chara(struct termp *p, char c)
        !           294: {
        !           295:
        !           296:        if (p->col + 1 >= p->maxcols)
        !           297:                errx(1, "line overrun");
        !           298:
        !           299:        p->buf[(p->col)++] = c;
        !           300: }
        !           301:
        !           302:
        !           303: static void
        !           304: escape(struct termp *p, enum termesc esc)
        !           305: {
        !           306:
        !           307:        if (p->col + 4 >= p->maxcols)
        !           308:                errx(1, "line overrun");
        !           309:
        !           310:        p->buf[(p->col)++] = 27;
        !           311:        p->buf[(p->col)++] = '[';
        !           312:        switch (esc) {
        !           313:        case (ESC_CLEAR):
        !           314:                p->buf[(p->col)++] = '0';
        !           315:                break;
        !           316:        case (ESC_BOLD):
        !           317:                p->buf[(p->col)++] = '1';
        !           318:                break;
        !           319:        case (ESC_UNDERLINE):
        !           320:                p->buf[(p->col)++] = '4';
        !           321:                break;
        !           322:        default:
        !           323:                abort();
        !           324:                /* NOTREACHED */
        !           325:        }
        !           326:        p->buf[(p->col)++] = 'm';
        !           327: }
        !           328:
        !           329:
        !           330: static void
        !           331: pword(struct termp *p, const char *word, size_t len)
        !           332: {
        !           333:        size_t           i;
        !           334:
        !           335:        assert(len > 0);
        !           336:
        !           337:        if ( ! (p->flags & TERMP_NOSPACE))
        !           338:                chara(p, ' ');
        !           339:
        !           340:        p->flags &= ~TERMP_NOSPACE;
        !           341:
        !           342:        if (p->flags & TERMP_BOLD)
        !           343:                escape(p, ESC_BOLD);
        !           344:        if (p->flags & TERMP_UNDERLINE)
        !           345:                escape(p, ESC_UNDERLINE);
        !           346:
        !           347:        for (i = 0; i < len; i++)
        !           348:                chara(p, word[i]);
        !           349:
        !           350:        if (p->flags & TERMP_BOLD ||
        !           351:                        p->flags & TERMP_UNDERLINE)
        !           352:                escape(p, ESC_CLEAR);
        !           353: }
        !           354:
        !           355:
        !           356: static void
        !           357: word(struct termp *p, const char *word)
        !           358: {
        !           359:        size_t           i, j, len;
        !           360:
        !           361:        /* TODO: delimiters? */
        !           362:
        !           363:        len = strlen(word);
        !           364:        assert(len > 0);
        !           365:
        !           366:        for (j = i = 0; i < len; i++) {
        !           367:                if ( ! isspace(word[i])) {
        !           368:                        j++;
        !           369:                        continue;
        !           370:                }
        !           371:                if (0 == j)
        !           372:                        continue;
        !           373:                assert(i >= j);
        !           374:                pword(p, &word[i - j], j);
        !           375:                j = 0;
        !           376:        }
        !           377:        if (j > 0) {
        !           378:                assert(i >= j);
        !           379:                pword(p, &word[i - j], j);
        !           380:        }
        !           381: }
        !           382:
        !           383:
        !           384: static int
        !           385: termp_it_pre(struct termp *p, const struct mdoc_meta *meta,
        !           386:                const struct mdoc_node *node)
        !           387: {
        !           388:
        !           389:        switch (node->type) {
        !           390:        case (MDOC_HEAD):
        !           391:                /* TODO: only print one, if compat. */
        !           392:                vspace(p);
        !           393:                break;
1.1       kristaps  394:        default:
                    395:                break;
                    396:        }
1.2     ! kristaps  397:        return(1);
        !           398: }
1.1       kristaps  399:
1.2     ! kristaps  400:
        !           401: static int
        !           402: termp_bold_post(struct termp *p, const struct mdoc_meta *meta,
        !           403:                const struct mdoc_node *node)
        !           404: {
        !           405:
        !           406:        p->flags &= ~TERMP_BOLD;
        !           407:        return(1);
        !           408: }
        !           409:
        !           410:
        !           411: static int
        !           412: termp_under_pre(struct termp *p, const struct mdoc_meta *meta,
        !           413:                const struct mdoc_node *node)
        !           414: {
        !           415:
        !           416:        p->flags |= TERMP_UNDERLINE;
        !           417:        return(1);
1.1       kristaps  418: }
                    419:
                    420:
1.2     ! kristaps  421: static int
        !           422: termp_bold_pre(struct termp *p, const struct mdoc_meta *meta,
        !           423:                const struct mdoc_node *node)
1.1       kristaps  424: {
                    425:
1.2     ! kristaps  426:        p->flags |= TERMP_BOLD;
        !           427:        return(1);
        !           428: }
        !           429:
        !           430:
        !           431: static int
        !           432: termp_ns_pre(struct termp *p, const struct mdoc_meta *meta,
        !           433:                const struct mdoc_node *node)
        !           434: {
        !           435:
        !           436:        p->flags |= TERMP_NOSPACE;
        !           437:        return(1);
        !           438: }
        !           439:
        !           440:
        !           441: static int
        !           442: termp_pp_pre(struct termp *p, const struct mdoc_meta *meta,
        !           443:                const struct mdoc_node *node)
        !           444: {
        !           445:
        !           446:        vspace(p);
        !           447:        return(1);
        !           448: }
        !           449:
        !           450:
        !           451: static int
        !           452: termp_under_post(struct termp *p, const struct mdoc_meta *meta,
        !           453:                const struct mdoc_node *node)
        !           454: {
        !           455:
        !           456:        p->flags &= ~TERMP_UNDERLINE;
        !           457:        return(1);
        !           458: }
        !           459:
        !           460:
        !           461: static int
        !           462: termp_nd_pre(struct termp *p, const struct mdoc_meta *meta,
        !           463:                const struct mdoc_node *node)
        !           464: {
        !           465:
        !           466:        word(p, "-");
        !           467:        return(1);
        !           468: }
        !           469:
        !           470:
        !           471: static int
        !           472: termp_bl_post(struct termp *p, const struct mdoc_meta *meta,
        !           473:                const struct mdoc_node *node)
        !           474: {
        !           475:
        !           476:        switch (node->type) {
        !           477:        case (MDOC_BLOCK):
        !           478:                newln(p);
        !           479:                break;
1.1       kristaps  480:        default:
                    481:                break;
                    482:        }
1.2     ! kristaps  483:        return(1);
1.1       kristaps  484: }
                    485:
                    486:
1.2     ! kristaps  487: static int
        !           488: termp_op_post(struct termp *p, const struct mdoc_meta *meta,
        !           489:                const struct mdoc_node *node)
        !           490: {
        !           491:
        !           492:        switch (node->type) {
        !           493:        case (MDOC_BODY):
        !           494:                p->flags |= TERMP_NOSPACE;
        !           495:                word(p, "\\(rB");
        !           496:                break;
        !           497:        default:
        !           498:                break;
        !           499:        }
        !           500:        return(1);
        !           501: }
        !           502:
        !           503:
        !           504: static int
        !           505: termp_sh_post(struct termp *p, const struct mdoc_meta *meta,
        !           506:                const struct mdoc_node *node)
1.1       kristaps  507: {
                    508:
1.2     ! kristaps  509:        switch (node->type) {
        !           510:        case (MDOC_HEAD):
        !           511:                p->flags &= ~TERMP_BOLD;
        !           512:                newln(p);
        !           513:                break;
        !           514:        case (MDOC_BODY):
        !           515:                newln(p);
        !           516:                (p->indent)--;
        !           517:                break;
        !           518:        default:
        !           519:                break;
        !           520:        }
        !           521:        return(1);
        !           522: }
        !           523:
1.1       kristaps  524:
1.2     ! kristaps  525: static int
        !           526: termp_sh_pre(struct termp *p, const struct mdoc_meta *meta,
        !           527:                const struct mdoc_node *node)
        !           528: {
1.1       kristaps  529:
1.2     ! kristaps  530:        switch (node->type) {
        !           531:        case (MDOC_HEAD):
        !           532:                vspace(p);
        !           533:                p->flags |= TERMP_BOLD;
        !           534:                break;
        !           535:        case (MDOC_BODY):
        !           536:                (p->indent)++;
        !           537:                break;
        !           538:        default:
        !           539:                break;
1.1       kristaps  540:        }
1.2     ! kristaps  541:        return(1);
        !           542: }
        !           543:
1.1       kristaps  544:
1.2     ! kristaps  545: static int
        !           546: termp_op_pre(struct termp *p, const struct mdoc_meta *meta,
        !           547:                const struct mdoc_node *node)
        !           548: {
        !           549:
        !           550:        switch (node->type) {
        !           551:        case (MDOC_BODY):
        !           552:                word(p, "\\(lB");
        !           553:                p->flags |= TERMP_NOSPACE;
        !           554:                break;
        !           555:        default:
        !           556:                break;
        !           557:        }
        !           558:        return(1);
1.1       kristaps  559: }
                    560:
                    561:
                    562: static int
1.2     ! kristaps  563: termp_fl_pre(struct termp *p, const struct mdoc_meta *meta,
        !           564:                const struct mdoc_node *node)
1.1       kristaps  565: {
                    566:
1.2     ! kristaps  567:        p->flags |= TERMP_BOLD;
        !           568:        word(p, "-");
        !           569:        p->flags |= TERMP_NOSPACE;
1.1       kristaps  570:        return(1);
                    571: }
                    572:
                    573:
                    574: static void
1.2     ! kristaps  575: termprint_r(struct termp *p, const struct mdoc_meta *meta,
        !           576:                const struct mdoc_node *node)
        !           577: {
        !           578:
        !           579:        /* Pre-processing ----------------- */
        !           580:
        !           581:        if (MDOC_TEXT != node->type) {
        !           582:                if (termacts[node->tok].pre)
        !           583:                        if ( ! (*termacts[node->tok].pre)(p, meta, node))
        !           584:                                return;
        !           585:        } else /* MDOC_TEXT == node->type */
        !           586:                word(p, node->data.text.string);
        !           587:
        !           588:        /* Children ---------------------- */
        !           589:
        !           590:        if (NULL == node->child) {
        !           591:                /* No-child processing. */
        !           592:                switch (node->type) {
        !           593:                case (MDOC_ELEM):
        !           594:                        switch (node->tok) {
        !           595:                        case (MDOC_Nm):
        !           596:                                word(p, "progname"); /* TODO */
        !           597:                                break;
        !           598:                        case (MDOC_Ar):
        !           599:                                word(p, "...");
        !           600:                                break;
        !           601:                        default:
        !           602:                                break;
        !           603:                        }
        !           604:                        break;
        !           605:                default:
        !           606:                        break;
        !           607:                }
        !           608:        } else
        !           609:                termprint_r(p, meta, node->child);
        !           610:
        !           611:        /* Post-processing --------------- */
        !           612:
        !           613:        if (MDOC_TEXT != node->type) {
        !           614:                if (termacts[node->tok].post)
        !           615:                        if ( ! (*termacts[node->tok].post)(p, meta, node))
        !           616:                                return;
        !           617:        }
        !           618:
        !           619:        /* Siblings ---------------------- */
        !           620:
        !           621:        if (node->next)
        !           622:                termprint_r(p, meta, node->next);
        !           623: }
        !           624:
        !           625:
        !           626: static void
        !           627: termprint_footer(struct termp *p, const struct mdoc_meta *meta)
1.1       kristaps  628: {
                    629:        struct tm       *tm;
                    630:        char            *buf, *os;
                    631:        size_t           sz, osz, ssz, i;
                    632:
1.2     ! kristaps  633:        if (NULL == (buf = malloc(p->maxvisible)))
1.1       kristaps  634:                err(1, "malloc");
1.2     ! kristaps  635:        if (NULL == (os = malloc(p->maxvisible)))
1.1       kristaps  636:                err(1, "malloc");
                    637:
                    638:        tm = localtime(&meta->date);
1.2     ! kristaps  639:        if (NULL == strftime(buf, p->maxvisible, "%B %d, %Y", tm))
1.1       kristaps  640:                err(1, "strftime");
                    641:
1.2     ! kristaps  642:        osz = strlcpy(os, meta->os, p->maxvisible);
1.1       kristaps  643:
                    644:        sz = strlen(buf);
                    645:        ssz = sz + osz + 1;
                    646:
1.2     ! kristaps  647:        if (ssz > p->maxvisible) {
        !           648:                ssz -= p->maxvisible;
1.1       kristaps  649:                assert(ssz <= osz);
                    650:                os[osz - ssz] = 0;
                    651:                ssz = 1;
                    652:        } else
1.2     ! kristaps  653:                ssz = p->maxvisible - ssz + 1;
1.1       kristaps  654:
1.2     ! kristaps  655:        printf("\n");
1.1       kristaps  656:        printf("%s", os);
                    657:        for (i = 0; i < ssz; i++)
                    658:                printf(" ");
                    659:
                    660:        printf("%s\n", buf);
1.2     ! kristaps  661:        fflush(stdout);
1.1       kristaps  662:
                    663:        free(buf);
                    664:        free(os);
                    665: }
                    666:
                    667:
                    668: static void
1.2     ! kristaps  669: termprint_header(struct termp *p, const struct mdoc_meta *meta)
1.1       kristaps  670: {
1.2     ! kristaps  671:        char            *msec, *buf, *title, *pp;
        !           672:        size_t           ssz, tsz, ttsz, i;;
1.1       kristaps  673:
1.2     ! kristaps  674:        if (NULL == (buf = malloc(p->maxvisible)))
1.1       kristaps  675:                err(1, "malloc");
1.2     ! kristaps  676:        if (NULL == (title = malloc(p->maxvisible)))
1.1       kristaps  677:                err(1, "malloc");
                    678:
1.2     ! kristaps  679:        if (NULL == (pp = mdoc_vol2a(meta->vol)))
        !           680:                switch (meta->msec) {
        !           681:                case (MSEC_1):
        !           682:                        /* FALLTHROUGH */
        !           683:                case (MSEC_6):
        !           684:                        /* FALLTHROUGH */
        !           685:                case (MSEC_7):
        !           686:                        pp = mdoc_vol2a(VOL_URM);
        !           687:                        break;
        !           688:                case (MSEC_8):
        !           689:                        pp = mdoc_vol2a(VOL_SMM);
        !           690:                        break;
        !           691:                case (MSEC_2):
        !           692:                        /* FALLTHROUGH */
        !           693:                case (MSEC_3):
        !           694:                        /* FALLTHROUGH */
        !           695:                case (MSEC_4):
        !           696:                        /* FALLTHROUGH */
        !           697:                case (MSEC_5):
        !           698:                        pp = mdoc_vol2a(VOL_PRM);
        !           699:                        break;
        !           700:                case (MSEC_9):
        !           701:                        pp = mdoc_vol2a(VOL_KM);
        !           702:                        break;
        !           703:                default:
        !           704:                        /* FIXME: capitalise. */
        !           705:                        if (NULL == (pp = mdoc_msec2a(meta->msec)))
        !           706:                                pp = mdoc_msec2a(MSEC_local);
        !           707:                        break;
        !           708:                }
        !           709:        assert(pp);
1.1       kristaps  710:
1.2     ! kristaps  711:        tsz = strlcpy(buf, pp, p->maxvisible);
        !           712:        assert(tsz < p->maxvisible);
1.1       kristaps  713:
1.2     ! kristaps  714:        if ((pp = mdoc_arch2a(meta->arch))) {
        !           715:                tsz = strlcat(buf, " (", p->maxvisible);
        !           716:                assert(tsz < p->maxvisible);
        !           717:                tsz = strlcat(buf, pp, p->maxvisible);
        !           718:                assert(tsz < p->maxvisible);
        !           719:                tsz = strlcat(buf, ")", p->maxvisible);
        !           720:                assert(tsz < p->maxvisible);
        !           721:        }
        !           722:
        !           723:        ttsz = strlcpy(title, meta->title, p->maxvisible);
        !           724:
        !           725:        if (NULL == (msec = mdoc_msec2a(meta->msec)))
1.1       kristaps  726:                msec = "";
                    727:
                    728:        ssz = (2 * (ttsz + 2 + strlen(msec))) + tsz + 2;
                    729:
1.2     ! kristaps  730:        if (ssz > p->maxvisible) {
        !           731:                if ((ssz -= p->maxvisible) % 2)
1.1       kristaps  732:                        ssz++;
                    733:                ssz /= 2;
                    734:
                    735:                assert(ssz <= ttsz);
                    736:                title[ttsz - ssz] = 0;
                    737:                ssz = 1;
                    738:        } else
1.2     ! kristaps  739:                ssz = ((p->maxvisible - ssz) / 2) + 1;
1.1       kristaps  740:
                    741:        printf("%s(%s)", title, msec);
                    742:
                    743:        for (i = 0; i < ssz; i++)
                    744:                printf(" ");
                    745:
                    746:        printf("%s", buf);
                    747:
                    748:        for (i = 0; i < ssz; i++)
                    749:                printf(" ");
                    750:
1.2     ! kristaps  751:        printf("%s(%s)\n", title, msec);
        !           752:        fflush(stdout);
1.1       kristaps  753:
                    754:        free(title);
                    755:        free(buf);
                    756: }
                    757:
                    758:
                    759: int
                    760: termprint(const struct mdoc_node *node,
                    761:                const struct mdoc_meta *meta)
                    762: {
1.2     ! kristaps  763:        struct termp     p;
1.1       kristaps  764:
                    765:        if (ERR == setupterm(NULL, STDOUT_FILENO, NULL))
                    766:                return(0);
                    767:
1.2     ! kristaps  768:        p.maxvisible = columns < 60 ? 60 : (size_t)columns;
        !           769:        p.maxcols = 1024;
        !           770:        p.indent = p.col = 0;
        !           771:        p.flags = TERMP_NOSPACE;
        !           772:
        !           773:        if (NULL == (p.buf = malloc(p.maxcols)))
        !           774:                err(1, "malloc");
        !           775:
        !           776:        termprint_header(&p, meta);
        !           777:        termprint_r(&p, meta, node);
        !           778:        termprint_footer(&p, meta);
        !           779:
        !           780:        free(p.buf);
1.1       kristaps  781:
                    782:        return(1);
                    783: }
                    784:
                    785:

CVSweb