[BACK]Return to tbl_term.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/tbl_term.c, Revision 1.6

1.6     ! schwarze    1: /*     $Id: tbl_term.c,v 1.5 2011/01/04 22:28:17 schwarze Exp $ */
1.1       schwarze    2: /*
1.5       schwarze    3:  * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@kth.se>
1.1       schwarze    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 above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      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.
                     16:  */
                     17: #include <assert.h>
                     18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <string.h>
                     21:
1.5       schwarze   22: #include "mandoc.h"
1.2       schwarze   23: #include "out.h"
                     24: #include "term.h"
1.1       schwarze   25:
1.6     ! schwarze   26: static size_t  term_tbl_len(size_t, void *);
        !            27: static size_t  term_tbl_strlen(const char *, void *);
        !            28: static void    tbl_char(struct termp *, char, size_t);
        !            29: static void    tbl_data(struct termp *, const struct tbl *,
        !            30:                        const struct tbl_dat *,
        !            31:                        const struct roffcol *);
        !            32: static void    tbl_hframe(struct termp *, const struct tbl_span *);
        !            33: static void    tbl_literal(struct termp *, const struct tbl_dat *,
        !            34:                        const struct roffcol *);
        !            35: static void    tbl_number(struct termp *, const struct tbl *,
        !            36:                        const struct tbl_dat *,
        !            37:                        const struct roffcol *);
        !            38: static void    tbl_hrule(struct termp *, const struct tbl_span *);
        !            39: static void    tbl_vframe(struct termp *, const struct tbl *);
        !            40: static void    tbl_vrule(struct termp *, const struct tbl_head *);
1.1       schwarze   41:
1.6     ! schwarze   42:
        !            43: static size_t
        !            44: term_tbl_strlen(const char *p, void *arg)
        !            45: {
        !            46:
        !            47:        return(term_strlen((const struct termp *)arg, p));
        !            48: }
        !            49:
        !            50: static size_t
        !            51: term_tbl_len(size_t sz, void *arg)
        !            52: {
        !            53:
        !            54:        return(term_len((const struct termp *)arg, sz));
        !            55: }
1.5       schwarze   56:
                     57: void
                     58: term_tbl(struct termp *tp, const struct tbl_span *sp)
                     59: {
1.6     ! schwarze   60:        const struct tbl_head   *hp;
        !            61:        const struct tbl_dat    *dp;
        !            62:        struct roffcol          *col;
        !            63:        size_t                   rmargin, maxrmargin;
        !            64:
        !            65:        rmargin = tp->rmargin;
        !            66:        maxrmargin = tp->maxrmargin;
        !            67:
        !            68:        tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
1.5       schwarze   69:
                     70:        /* Inhibit printing of spaces: we do padding ourselves. */
                     71:
                     72:        tp->flags |= TERMP_NONOSPACE;
                     73:        tp->flags |= TERMP_NOSPACE;
1.1       schwarze   74:
                     75:        /*
1.6     ! schwarze   76:         * The first time we're invoked for a given table block,
        !            77:         * calculate the table widths and decimal positions.
1.1       schwarze   78:         */
                     79:
1.5       schwarze   80:        if (TBL_SPAN_FIRST & sp->flags) {
1.6     ! schwarze   81:                term_flushln(tp);
        !            82:
        !            83:                tp->tbl.len = term_tbl_len;
        !            84:                tp->tbl.slen = term_tbl_strlen;
        !            85:                tp->tbl.arg = tp;
1.5       schwarze   86:
1.6     ! schwarze   87:                tblcalc(&tp->tbl, sp);
1.5       schwarze   88:        }
1.2       schwarze   89:
1.5       schwarze   90:        /* Horizontal frame at the start of boxed tables. */
1.1       schwarze   91:
1.5       schwarze   92:        if (TBL_SPAN_FIRST & sp->flags)
                     93:                tbl_hframe(tp, sp);
                     94:
                     95:        /* Vertical frame at the start of each row. */
                     96:
                     97:        tbl_vframe(tp, sp->tbl);
1.1       schwarze   98:
                     99:        /*
1.5       schwarze  100:         * Now print the actual data itself depending on the span type.
                    101:         * Spanner spans get a horizontal rule; data spanners have their
                    102:         * data printed by matching data to header.
1.1       schwarze  103:         */
                    104:
1.5       schwarze  105:        switch (sp->pos) {
                    106:        case (TBL_SPAN_HORIZ):
                    107:                /* FALLTHROUGH */
                    108:        case (TBL_SPAN_DHORIZ):
                    109:                tbl_hrule(tp, sp);
                    110:                break;
                    111:        case (TBL_SPAN_DATA):
                    112:                /* Iterate over template headers. */
                    113:                dp = sp->first;
                    114:                for (hp = sp->head; hp; hp = hp->next) {
                    115:                        switch (hp->pos) {
1.1       schwarze  116:                        case (TBL_HEAD_VERT):
                    117:                                /* FALLTHROUGH */
                    118:                        case (TBL_HEAD_DVERT):
1.6     ! schwarze  119:                                tbl_vrule(tp, hp);
1.5       schwarze  120:                                continue;
1.1       schwarze  121:                        case (TBL_HEAD_DATA):
                    122:                                break;
                    123:                        }
1.6     ! schwarze  124:
        !           125:                        col = &tp->tbl.cols[hp->ident];
        !           126:                        tbl_data(tp, sp->tbl, dp, col);
1.5       schwarze  127:
                    128:                        /* Go to the next data cell. */
                    129:                        if (dp)
                    130:                                dp = dp->next;
1.1       schwarze  131:                }
1.5       schwarze  132:                break;
1.1       schwarze  133:        }
                    134:
1.5       schwarze  135:        tbl_vframe(tp, sp->tbl);
                    136:        term_flushln(tp);
1.1       schwarze  137:
1.5       schwarze  138:        /*
                    139:         * If we're the last row, clean up after ourselves: clear the
                    140:         * existing table configuration and set it to NULL.
                    141:         */
1.1       schwarze  142:
1.5       schwarze  143:        if (TBL_SPAN_LAST & sp->flags) {
                    144:                tbl_hframe(tp, sp);
1.6     ! schwarze  145:                assert(tp->tbl.cols);
        !           146:                free(tp->tbl.cols);
        !           147:                tp->tbl.cols = NULL;
1.1       schwarze  148:        }
                    149:
1.5       schwarze  150:        tp->flags &= ~TERMP_NONOSPACE;
1.6     ! schwarze  151:        tp->rmargin = rmargin;
        !           152:        tp->maxrmargin = maxrmargin;
1.1       schwarze  153:
                    154: }
                    155:
                    156: static void
1.5       schwarze  157: tbl_hrule(struct termp *tp, const struct tbl_span *sp)
1.1       schwarze  158: {
1.5       schwarze  159:        const struct tbl_head *hp;
                    160:        char             c;
1.6     ! schwarze  161:        size_t           width;
1.1       schwarze  162:
                    163:        /*
                    164:         * An hrule extends across the entire table and is demarked by a
                    165:         * standalone `_' or whatnot in lieu of a table row.  Spanning
                    166:         * headers are marked by a `+', as are table boundaries.
                    167:         */
                    168:
                    169:        c = '-';
1.5       schwarze  170:        if (TBL_SPAN_DHORIZ == sp->pos)
1.1       schwarze  171:                c = '=';
                    172:
                    173:        /* FIXME: don't use `+' between data and a spanner! */
                    174:
1.5       schwarze  175:        for (hp = sp->head; hp; hp = hp->next) {
1.6     ! schwarze  176:                width = tp->tbl.cols[hp->ident].width;
1.5       schwarze  177:                switch (hp->pos) {
1.1       schwarze  178:                case (TBL_HEAD_DATA):
1.5       schwarze  179:                        tbl_char(tp, c, width);
1.1       schwarze  180:                        break;
                    181:                case (TBL_HEAD_DVERT):
1.5       schwarze  182:                        tbl_char(tp, '+', width);
1.1       schwarze  183:                        /* FALLTHROUGH */
                    184:                case (TBL_HEAD_VERT):
1.5       schwarze  185:                        tbl_char(tp, '+', width);
1.1       schwarze  186:                        break;
                    187:                default:
                    188:                        abort();
                    189:                        /* NOTREACHED */
                    190:                }
                    191:        }
                    192: }
                    193:
                    194: static void
1.5       schwarze  195: tbl_hframe(struct termp *tp, const struct tbl_span *sp)
1.1       schwarze  196: {
1.5       schwarze  197:        const struct tbl_head *hp;
1.6     ! schwarze  198:        size_t           width;
1.1       schwarze  199:
1.5       schwarze  200:        if ( ! (TBL_OPT_BOX & sp->tbl->opts ||
                    201:                        TBL_OPT_DBOX & sp->tbl->opts))
1.1       schwarze  202:                return;
                    203:
                    204:        /*
                    205:         * Print out the horizontal part of a frame or double frame.  A
                    206:         * double frame has an unbroken `-' outer line the width of the
                    207:         * table, bordered by `+'.  The frame (or inner frame, in the
                    208:         * case of the double frame) is a `-' bordered by `+' and broken
                    209:         * by `+' whenever a span is encountered.
                    210:         */
                    211:
1.5       schwarze  212:        if (TBL_OPT_DBOX & sp->tbl->opts) {
                    213:                term_word(tp, "+");
                    214:                for (hp = sp->head; hp; hp = hp->next) {
1.6     ! schwarze  215:                        width = tp->tbl.cols[hp->ident].width;
1.5       schwarze  216:                        tbl_char(tp, '-', width);
                    217:                }
                    218:                term_word(tp, "+");
                    219:                term_flushln(tp);
1.1       schwarze  220:        }
                    221:
1.5       schwarze  222:        term_word(tp, "+");
                    223:        for (hp = sp->head; hp; hp = hp->next) {
1.6     ! schwarze  224:                width = tp->tbl.cols[hp->ident].width;
1.5       schwarze  225:                switch (hp->pos) {
1.1       schwarze  226:                case (TBL_HEAD_DATA):
1.5       schwarze  227:                        tbl_char(tp, '-', width);
1.1       schwarze  228:                        break;
                    229:                default:
1.5       schwarze  230:                        tbl_char(tp, '+', width);
1.1       schwarze  231:                        break;
                    232:                }
                    233:        }
1.5       schwarze  234:        term_word(tp, "+");
                    235:        term_flushln(tp);
1.1       schwarze  236: }
                    237:
                    238: static void
1.5       schwarze  239: tbl_data(struct termp *tp, const struct tbl *tbl,
                    240:                const struct tbl_dat *dp,
1.6     ! schwarze  241:                const struct roffcol *col)
1.1       schwarze  242: {
1.5       schwarze  243:        enum tbl_cellt   pos;
1.1       schwarze  244:
1.5       schwarze  245:        if (NULL == dp) {
1.6     ! schwarze  246:                tbl_char(tp, ASCII_NBRSP, col->width);
1.1       schwarze  247:                return;
1.5       schwarze  248:        }
1.1       schwarze  249:
1.5       schwarze  250:        switch (dp->pos) {
                    251:        case (TBL_DATA_NONE):
1.6     ! schwarze  252:                tbl_char(tp, ASCII_NBRSP, col->width);
1.5       schwarze  253:                return;
                    254:        case (TBL_DATA_HORIZ):
                    255:                /* FALLTHROUGH */
                    256:        case (TBL_DATA_NHORIZ):
1.6     ! schwarze  257:                tbl_char(tp, '-', col->width);
1.5       schwarze  258:                return;
                    259:        case (TBL_DATA_NDHORIZ):
1.1       schwarze  260:                /* FALLTHROUGH */
1.5       schwarze  261:        case (TBL_DATA_DHORIZ):
1.6     ! schwarze  262:                tbl_char(tp, '=', col->width);
1.5       schwarze  263:                return;
1.1       schwarze  264:        default:
                    265:                break;
                    266:        }
1.5       schwarze  267:
1.6     ! schwarze  268:        pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
1.1       schwarze  269:
1.5       schwarze  270:        switch (pos) {
1.1       schwarze  271:        case (TBL_CELL_HORIZ):
1.6     ! schwarze  272:                tbl_char(tp, '-', col->width);
1.5       schwarze  273:                break;
1.1       schwarze  274:        case (TBL_CELL_DHORIZ):
1.6     ! schwarze  275:                tbl_char(tp, '=', col->width);
1.1       schwarze  276:                break;
                    277:        case (TBL_CELL_LONG):
                    278:                /* FALLTHROUGH */
                    279:        case (TBL_CELL_CENTRE):
                    280:                /* FALLTHROUGH */
                    281:        case (TBL_CELL_LEFT):
                    282:                /* FALLTHROUGH */
                    283:        case (TBL_CELL_RIGHT):
1.6     ! schwarze  284:                tbl_literal(tp, dp, col);
1.1       schwarze  285:                break;
                    286:        case (TBL_CELL_NUMBER):
1.6     ! schwarze  287:                tbl_number(tp, tbl, dp, col);
1.4       schwarze  288:                break;
1.1       schwarze  289:        default:
                    290:                abort();
                    291:                /* NOTREACHED */
                    292:        }
                    293: }
1.6     ! schwarze  294:
1.1       schwarze  295: static void
1.6     ! schwarze  296: tbl_vrule(struct termp *tp, const struct tbl_head *hp)
1.1       schwarze  297: {
                    298:
1.5       schwarze  299:        switch (hp->pos) {
                    300:        case (TBL_HEAD_VERT):
                    301:                term_word(tp, "|");
                    302:                break;
                    303:        case (TBL_HEAD_DVERT):
                    304:                term_word(tp, "||");
                    305:                break;
                    306:        default:
                    307:                break;
                    308:        }
1.1       schwarze  309: }
                    310:
                    311: static void
1.5       schwarze  312: tbl_vframe(struct termp *tp, const struct tbl *tbl)
1.1       schwarze  313: {
                    314:
1.5       schwarze  315:        if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)
                    316:                term_word(tp, "|");
                    317: }
1.1       schwarze  318:
1.6     ! schwarze  319: static void
        !           320: tbl_char(struct termp *tp, char c, size_t len)
1.5       schwarze  321: {
1.6     ! schwarze  322:        size_t          i, sz;
1.5       schwarze  323:        char            cp[2];
1.1       schwarze  324:
1.5       schwarze  325:        cp[0] = c;
                    326:        cp[1] = '\0';
1.1       schwarze  327:
1.5       schwarze  328:        sz = term_strlen(tp, cp);
1.1       schwarze  329:
1.5       schwarze  330:        for (i = 0; i < len; i += sz)
                    331:                term_word(tp, cp);
1.1       schwarze  332: }
                    333:
                    334: static void
1.6     ! schwarze  335: tbl_literal(struct termp *tp, const struct tbl_dat *dp,
        !           336:                const struct roffcol *col)
1.1       schwarze  337: {
1.6     ! schwarze  338:        size_t           padl, padr, ssz;
1.5       schwarze  339:        enum tbl_cellt   pos;
1.6     ! schwarze  340:        const char      *str;
1.1       schwarze  341:
                    342:        padl = padr = 0;
                    343:
1.6     ! schwarze  344:        pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
        !           345:        str = dp && dp->string ? dp->string : "";
        !           346:
1.5       schwarze  347:        ssz = term_len(tp, 1);
                    348:
                    349:        switch (pos) {
1.1       schwarze  350:        case (TBL_CELL_LONG):
1.5       schwarze  351:                padl = ssz;
1.6     ! schwarze  352:                padr = col->width - term_strlen(tp, str) - ssz;
1.1       schwarze  353:                break;
                    354:        case (TBL_CELL_CENTRE):
1.6     ! schwarze  355:                padl = col->width - term_strlen(tp, str);
1.1       schwarze  356:                if (padl % 2)
                    357:                        padr++;
                    358:                padl /= 2;
                    359:                padr += padl;
                    360:                break;
                    361:        case (TBL_CELL_RIGHT):
1.6     ! schwarze  362:                padl = col->width - term_strlen(tp, str);
1.1       schwarze  363:                break;
                    364:        default:
1.6     ! schwarze  365:                padr = col->width - term_strlen(tp, str);
1.1       schwarze  366:                break;
                    367:        }
                    368:
1.5       schwarze  369:        tbl_char(tp, ASCII_NBRSP, padl);
1.6     ! schwarze  370:        term_word(tp, str);
1.5       schwarze  371:        tbl_char(tp, ASCII_NBRSP, padr);
1.1       schwarze  372: }
                    373:
1.5       schwarze  374: static void
1.6     ! schwarze  375: tbl_number(struct termp *tp, const struct tbl *tbl,
1.5       schwarze  376:                const struct tbl_dat *dp,
1.6     ! schwarze  377:                const struct roffcol *col)
1.5       schwarze  378: {
1.6     ! schwarze  379:        char            *cp;
        !           380:        char             buf[2];
        !           381:        const char      *str;
        !           382:        size_t           sz, psz, ssz, d, padl;
        !           383:        int              i;
1.5       schwarze  384:
                    385:        /*
                    386:         * See calc_data_number().  Left-pad by taking the offset of our
                    387:         * and the maximum decimal; right-pad by the remaining amount.
                    388:         */
                    389:
1.6     ! schwarze  390:        str = dp && dp->string ? dp->string : "";
1.5       schwarze  391:
1.6     ! schwarze  392:        sz = term_strlen(tp, str);
1.5       schwarze  393:
1.6     ! schwarze  394:        buf[0] = tbl->decimal;
        !           395:        buf[1] = '\0';
1.5       schwarze  396:
1.6     ! schwarze  397:        psz = term_strlen(tp, buf);
1.5       schwarze  398:
1.6     ! schwarze  399:        if (NULL != (cp = strrchr(str, tbl->decimal))) {
1.5       schwarze  400:                buf[1] = '\0';
1.6     ! schwarze  401:                for (ssz = 0, i = 0; cp != &str[i]; i++) {
        !           402:                        buf[0] = str[i];
1.5       schwarze  403:                        ssz += term_strlen(tp, buf);
                    404:                }
                    405:                d = ssz + psz;
                    406:        } else
                    407:                d = sz + psz;
                    408:
                    409:        sz += term_len(tp, 2);
1.6     ! schwarze  410:        d += term_len(tp, 1);
1.5       schwarze  411:
1.6     ! schwarze  412:        padl = col->decimal - d;
1.5       schwarze  413:
1.6     ! schwarze  414:        tbl_char(tp, ASCII_NBRSP, padl);
        !           415:        term_word(tp, str);
        !           416:        tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
1.5       schwarze  417: }
1.1       schwarze  418: