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

Annotation of mandoc/eqn_html.c, Revision 1.7

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

CVSweb