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

Annotation of src/usr.bin/mandoc/eqn_html.c, Revision 1.3

1.3     ! schwarze    1: /*     $Id: eqn_html.c,v 1.2 2014/04/20 16:44:44 schwarze Exp $ */
1.1       schwarze    2: /*
1.3     ! schwarze    3:  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
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:
                     22: #include "mandoc.h"
                     23: #include "out.h"
                     24: #include "html.h"
                     25:
                     26: static const enum htmltag fontmap[EQNFONT__MAX] = {
                     27:        TAG_SPAN, /* EQNFONT_NONE */
                     28:        TAG_SPAN, /* EQNFONT_ROMAN */
                     29:        TAG_B, /* EQNFONT_BOLD */
                     30:        TAG_B, /* EQNFONT_FAT */
                     31:        TAG_I /* EQNFONT_ITALIC */
                     32: };
                     33:
1.3     ! schwarze   34: static const struct eqn_box *
        !            35:        eqn_box(struct html *, const struct eqn_box *, int);
1.1       schwarze   36:
                     37:
                     38: void
                     39: print_eqn(struct html *p, const struct eqn *ep)
                     40: {
                     41:        struct htmlpair  tag;
                     42:        struct tag      *t;
                     43:
                     44:        PAIR_CLASS_INIT(&tag, "eqn");
1.3     ! schwarze   45:        t = print_otag(p, TAG_MATH, 1, &tag);
1.1       schwarze   46:
                     47:        p->flags |= HTML_NONOSPACE;
1.3     ! schwarze   48:        eqn_box(p, ep->root, 1);
1.1       schwarze   49:        p->flags &= ~HTML_NONOSPACE;
                     50:
                     51:        print_tagq(p, t);
                     52: }
                     53:
1.3     ! schwarze   54: /*
        !            55:  * This function is fairly brittle.
        !            56:  * This is because the eqn syntax doesn't play so nicely with recusive
        !            57:  * formats, e.g.,
        !            58:  *     foo sub bar sub baz
        !            59:  * ...needs to resolve into
        !            60:  *     <msub> foo <msub> bar, baz </msub> </msub>
        !            61:  * In other words, we need to embed some recursive work.
        !            62:  * FIXME: this does NOT handle right-left associativity or precedence!
        !            63:  */
        !            64: static const struct eqn_box *
        !            65: eqn_box(struct html *p, const struct eqn_box *bp, int next)
1.1       schwarze   66: {
1.3     ! schwarze   67:        struct tag      *post, *pilet, *tmp;
        !            68:        struct htmlpair  tag[2];
        !            69:        int              skiptwo;
        !            70:
        !            71:        if (NULL == bp)
        !            72:                return(NULL);
        !            73:
        !            74:        post = pilet = NULL;
        !            75:        skiptwo = 0;
        !            76:
        !            77:        /*
        !            78:         * If we're a "row" under a pile, then open up the piling
        !            79:         * context here.
        !            80:         * We do this first because the pile surrounds the content of
        !            81:         * the contained expression.
        !            82:         */
        !            83:        if (NULL != bp->parent && bp->parent->pile != EQNPILE_NONE) {
        !            84:                pilet = print_otag(p, TAG_MTR, 0, NULL);
        !            85:                print_otag(p, TAG_MTD, 0, NULL);
        !            86:        }
        !            87:
        !            88:        /*
        !            89:         * If we're establishing a pile, start the table mode now.
        !            90:         * If we've already in a pile row, then don't override "pilet",
        !            91:         * because we'll be closed out anyway.
        !            92:         */
        !            93:        if (bp->pile != EQNPILE_NONE) {
        !            94:                tmp = print_otag(p, TAG_MTABLE, 0, NULL);
        !            95:                pilet = (NULL == pilet) ? tmp : pilet;
        !            96:        }
        !            97:
        !            98:        /*
        !            99:         * Positioning.
        !           100:         * This is the most complicated part, and actually doesn't quite
        !           101:         * work (FIXME) because it doesn't account for associativity.
        !           102:         * Setting "post" will mean that we're only going to process a
        !           103:         * single or double following expression.
        !           104:         */
        !           105:        switch (bp->pos) {
        !           106:        case (EQNPOS_SUP):
        !           107:                post = print_otag(p, TAG_MSUP, 0, NULL);
        !           108:                break;
        !           109:        case (EQNPOS_FROM):
        !           110:                /* FALLTHROUGH */
        !           111:        case (EQNPOS_SUB):
        !           112:                post = print_otag(p, TAG_MSUB, 0, NULL);
        !           113:                break;
        !           114:        case (EQNPOS_OVER):
        !           115:                post = print_otag(p, TAG_MFRAC, 0, NULL);
        !           116:                break;
        !           117:        case (EQNPOS_SUBSUP):
        !           118:                /* This requires two elements. */
        !           119:                post = print_otag(p, TAG_MSUBSUP, 0, NULL);
        !           120:                skiptwo = 1;
        !           121:                break;
        !           122:        default:
        !           123:                break;
        !           124:        }
        !           125:
        !           126:        /*t = EQNFONT_NONE == bp->font ? NULL :
        !           127:            print_otag(p, fontmap[(int)bp->font], 0, NULL);*/
        !           128:
        !           129:        if (NULL != bp->text) {
        !           130:                assert(NULL == bp->first);
        !           131:                /*
        !           132:                 * We have text.
        !           133:                 * This can be a number, a function, a variable, or
        !           134:                 * pretty much anything else.
        !           135:                 * First, check for some known functions.
        !           136:                 * If we're going to create a structural node (e.g.,
        !           137:                 * sqrt), then set the "post" variable only if it's not
        !           138:                 * already set.
        !           139:                 */
        !           140:                if (0 == strcmp(bp->text, "sqrt")) {
        !           141:                        tmp = print_otag(p, TAG_MSQRT, 0, NULL);
        !           142:                        post = (NULL == post) ? tmp : post;
        !           143:                } else if (0 == strcmp(bp->text, "+") ||
        !           144:                           0 == strcmp(bp->text, "-") ||
        !           145:                           0 == strcmp(bp->text, "=") ||
        !           146:                           0 == strcmp(bp->text, "(") ||
        !           147:                           0 == strcmp(bp->text, ")") ||
        !           148:                           0 == strcmp(bp->text, "/")) {
        !           149:                        tmp = print_otag(p, TAG_MO, 0, NULL);
        !           150:                        print_text(p, bp->text);
        !           151:                        print_tagq(p, tmp);
        !           152:                } else {
        !           153:                        tmp = print_otag(p, TAG_MI, 0, NULL);
        !           154:                        print_text(p, bp->text);
        !           155:                        print_tagq(p, tmp);
        !           156:                }
        !           157:        } else if (NULL != bp->first) {
        !           158:                assert(NULL == bp->text);
        !           159:                /*
        !           160:                 * If we're a "fenced" component (i.e., having
        !           161:                 * brackets), then process those brackets now.
        !           162:                 * Otherwise, introduce a dummy row (if we're not
        !           163:                 * already in a table context).
        !           164:                 */
        !           165:                tmp = NULL;
        !           166:                if (NULL != bp->left || NULL != bp->right) {
        !           167:                        PAIR_INIT(&tag[0], ATTR_OPEN,
        !           168:                                NULL != bp->left ? bp->left : "");
        !           169:                        PAIR_INIT(&tag[1], ATTR_CLOSE,
        !           170:                                NULL != bp->right ? bp->right : "");
        !           171:                        tmp = print_otag(p, TAG_MFENCED, 2, tag);
        !           172:                        print_otag(p, TAG_MROW, 0, NULL);
        !           173:                } else if (NULL == pilet)
        !           174:                        tmp = print_otag(p, TAG_MROW, 0, NULL);
        !           175:                eqn_box(p, bp->first, 1);
        !           176:                if (NULL != tmp)
        !           177:                        print_tagq(p, tmp);
        !           178:        }
        !           179:
        !           180:        /*
        !           181:         * If a positional context, invoke the "next" context.
        !           182:         * This is recursive and will return the end of the recursive
        !           183:         * chain of "next" contexts.
        !           184:         */
        !           185:        if (NULL != post) {
        !           186:                bp = eqn_box(p, bp->next, 0);
        !           187:                if (skiptwo)
        !           188:                        bp = eqn_box(p, bp->next, 0);
        !           189:                print_tagq(p, post);
        !           190:        }
        !           191:
        !           192:        /*
        !           193:         * If we're being piled (either directly, in the table, or
        !           194:         * indirectly in a table row), then close that out.
        !           195:         */
        !           196:        if (NULL != pilet)
        !           197:                print_tagq(p, pilet);
        !           198:
        !           199:        /*
        !           200:         * If we're normally processing, then grab the next node.
        !           201:         * If we're in a recursive context, then don't seek to the next
        !           202:         * node; further recursion has already been handled.
        !           203:         */
        !           204:        return(next ? eqn_box(p, bp->next, 1) : bp);
1.1       schwarze  205: }