From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from krisdoz.my.domain (kristaps@localhost [127.0.0.1]) by krisdoz.my.domain (8.14.5/8.14.5) with ESMTP id s8SDYF5d026949 for ; Sun, 28 Sep 2014 09:34:15 -0400 (EDT) Received: (from kristaps@localhost) by krisdoz.my.domain (8.14.5/8.14.3/Submit) id s8SDYFL1007863; Sun, 28 Sep 2014 09:34:15 -0400 (EDT) Date: Sun, 28 Sep 2014 09:34:15 -0400 (EDT) Message-Id: <201409281334.s8SDYFL1007863@krisdoz.my.domain> X-Mailinglist: mdocml-source Reply-To: source@mdocml.bsd.lv MIME-Version: 1.0 From: kristaps@mdocml.bsd.lv To: source@mdocml.bsd.lv Subject: mdocml: Support a decent subset of eqn(7) in MathML. X-Mailer: activitymail 1.26, http://search.cpan.org/dist/activitymail/ Content-Type: text/plain; charset=utf-8 Log Message: ----------- Support a decent subset of eqn(7) in MathML. This has basic support for positions (under, sup, sub, sub/sup) and piles. It *does not* support right-left grouping (among many other things), e.g., a sub b over c sub d Which it will interpret, for the time being, as a sub { b over { c sub d } } instead of { a sub b } over { c sub d } However, left-right grouping works fine. Modified Files: -------------- mdocml: eqn_html.c Revision Data ------------- Index: eqn_html.c =================================================================== RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/eqn_html.c,v retrieving revision 1.4 retrieving revision 1.5 diff -Leqn_html.c -Leqn_html.c -u -p -r1.4 -r1.5 --- eqn_html.c +++ eqn_html.c @@ -35,7 +35,8 @@ static const enum htmltag fontmap[EQNFON TAG_I /* EQNFONT_ITALIC */ }; -static void eqn_box(struct html *, const struct eqn_box *); +static const struct eqn_box * + eqn_box(struct html *, const struct eqn_box *, int); void @@ -45,37 +46,164 @@ print_eqn(struct html *p, const struct e struct tag *t; PAIR_CLASS_INIT(&tag, "eqn"); - t = print_otag(p, TAG_SPAN, 1, &tag); + t = print_otag(p, TAG_MATH, 1, &tag); p->flags |= HTML_NONOSPACE; - eqn_box(p, ep->root); + eqn_box(p, ep->root, 1); p->flags &= ~HTML_NONOSPACE; print_tagq(p, t); } -static void -eqn_box(struct html *p, const struct eqn_box *bp) +/* + * This function is fairly brittle. + * This is because the eqn syntax doesn't play so nicely with recusive + * formats, e.g., + * foo sub bar sub baz + * ...needs to resolve into + * foo bar, baz + * In other words, we need to embed some recursive work. + * FIXME: this does NOT handle right-left associativity or precedence! + */ +static const struct eqn_box * +eqn_box(struct html *p, const struct eqn_box *bp, int next) { - struct tag *t; - - t = EQNFONT_NONE == bp->font ? NULL : - print_otag(p, fontmap[(int)bp->font], 0, NULL); - - if (bp->left) - print_text(p, bp->left); - - if (bp->text) - print_text(p, bp->text); - - if (bp->first) - eqn_box(p, bp->first); - - if (NULL != t) - print_tagq(p, t); - if (bp->right) - print_text(p, bp->right); - - if (bp->next) - eqn_box(p, bp->next); + struct tag *post, *pilet, *tmp; + struct htmlpair tag[2]; + int skiptwo; + + if (NULL == bp) + return(NULL); + + post = pilet = NULL; + skiptwo = 0; + + /* + * If we're a "row" under a pile, then open up the piling + * context here. + * We do this first because the pile surrounds the content of + * the contained expression. + */ + if (NULL != bp->parent && bp->parent->pile != EQNPILE_NONE) { + pilet = print_otag(p, TAG_MTR, 0, NULL); + print_otag(p, TAG_MTD, 0, NULL); + } + + /* + * If we're establishing a pile, start the table mode now. + * If we've already in a pile row, then don't override "pilet", + * because we'll be closed out anyway. + */ + if (bp->pile != EQNPILE_NONE) { + tmp = print_otag(p, TAG_MTABLE, 0, NULL); + pilet = (NULL == pilet) ? tmp : pilet; + } + + /* + * Positioning. + * This is the most complicated part, and actually doesn't quite + * work (FIXME) because it doesn't account for associativity. + * Setting "post" will mean that we're only going to process a + * single or double following expression. + */ + switch (bp->pos) { + case (EQNPOS_SUP): + post = print_otag(p, TAG_MSUP, 0, NULL); + break; + case (EQNPOS_FROM): + /* FALLTHROUGH */ + case (EQNPOS_SUB): + post = print_otag(p, TAG_MSUB, 0, NULL); + break; + case (EQNPOS_OVER): + post = print_otag(p, TAG_MFRAC, 0, NULL); + break; + case (EQNPOS_SUBSUP): + /* This requires two elements. */ + post = print_otag(p, TAG_MSUBSUP, 0, NULL); + skiptwo = 1; + break; + default: + break; + } + + /*t = EQNFONT_NONE == bp->font ? NULL : + print_otag(p, fontmap[(int)bp->font], 0, NULL);*/ + + if (NULL != bp->text) { + assert(NULL == bp->first); + /* + * We have text. + * This can be a number, a function, a variable, or + * pretty much anything else. + * First, check for some known functions. + * If we're going to create a structural node (e.g., + * sqrt), then set the "post" variable only if it's not + * already set. + */ + if (0 == strcmp(bp->text, "sqrt")) { + tmp = print_otag(p, TAG_MSQRT, 0, NULL); + post = (NULL == post) ? tmp : post; + } else if (0 == strcmp(bp->text, "+") || + 0 == strcmp(bp->text, "-") || + 0 == strcmp(bp->text, "=") || + 0 == strcmp(bp->text, "(") || + 0 == strcmp(bp->text, ")") || + 0 == strcmp(bp->text, "/")) { + tmp = print_otag(p, TAG_MO, 0, NULL); + print_text(p, bp->text); + print_tagq(p, tmp); + } else { + tmp = print_otag(p, TAG_MI, 0, NULL); + print_text(p, bp->text); + print_tagq(p, tmp); + } + } else if (NULL != bp->first) { + assert(NULL == bp->text); + /* + * If we're a "fenced" component (i.e., having + * brackets), then process those brackets now. + * Otherwise, introduce a dummy row (if we're not + * already in a table context). + */ + tmp = NULL; + if (NULL != bp->left || NULL != bp->right) { + PAIR_INIT(&tag[0], ATTR_OPEN, + NULL != bp->left ? bp->left : ""); + PAIR_INIT(&tag[1], ATTR_CLOSE, + NULL != bp->right ? bp->right : ""); + tmp = print_otag(p, TAG_MFENCED, 2, tag); + print_otag(p, TAG_MROW, 0, NULL); + } else if (NULL == pilet) + tmp = print_otag(p, TAG_MROW, 0, NULL); + eqn_box(p, bp->first, 1); + if (NULL != tmp) + print_tagq(p, tmp); + } + + /* + * If a positional context, invoke the "next" context. + * This is recursive and will return the end of the recursive + * chain of "next" contexts. + */ + if (NULL != post) { + bp = eqn_box(p, bp->next, 0); + if (skiptwo) + bp = eqn_box(p, bp->next, 0); + print_tagq(p, post); + } + + /* + * If we're being piled (either directly, in the table, or + * indirectly in a table row), then close that out. + */ + if (NULL != pilet) + print_tagq(p, pilet); + + /* + * If we're normally processing, then grab the next node. + * If we're in a recursive context, then don't seek to the next + * node; further recursion has already been handled. + */ + return(next ? eqn_box(p, bp->next, 1) : bp); } -- To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv