1*260e9a87SYuri Pankov /* $Id: eqn_html.c,v 1.10 2014/10/12 19:31:41 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3*260e9a87SYuri Pankov * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 495c635efSGarrett D'Amore * 595c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 695c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 795c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 895c635efSGarrett D'Amore * 995c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1095c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1195c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1295c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1395c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1495c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1595c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1695c635efSGarrett D'Amore */ 1795c635efSGarrett D'Amore #include "config.h" 18*260e9a87SYuri Pankov 19*260e9a87SYuri Pankov #include <sys/types.h> 2095c635efSGarrett D'Amore 2195c635efSGarrett D'Amore #include <assert.h> 2295c635efSGarrett D'Amore #include <stdio.h> 2395c635efSGarrett D'Amore #include <stdlib.h> 2495c635efSGarrett D'Amore #include <string.h> 2595c635efSGarrett D'Amore 2695c635efSGarrett D'Amore #include "mandoc.h" 2795c635efSGarrett D'Amore #include "out.h" 2895c635efSGarrett D'Amore #include "html.h" 2995c635efSGarrett D'Amore 30*260e9a87SYuri Pankov static void 31*260e9a87SYuri Pankov eqn_box(struct html *p, const struct eqn_box *bp) 32*260e9a87SYuri Pankov { 33*260e9a87SYuri Pankov struct tag *post, *row, *cell, *t; 34*260e9a87SYuri Pankov struct htmlpair tag[2]; 35*260e9a87SYuri Pankov const struct eqn_box *child, *parent; 36*260e9a87SYuri Pankov size_t i, j, rows; 3795c635efSGarrett D'Amore 38*260e9a87SYuri Pankov if (NULL == bp) 39*260e9a87SYuri Pankov return; 4095c635efSGarrett D'Amore 41*260e9a87SYuri Pankov post = NULL; 42*260e9a87SYuri Pankov 43*260e9a87SYuri Pankov /* 44*260e9a87SYuri Pankov * Special handling for a matrix, which is presented to us in 45*260e9a87SYuri Pankov * column order, but must be printed in row-order. 46*260e9a87SYuri Pankov */ 47*260e9a87SYuri Pankov if (EQN_MATRIX == bp->type) { 48*260e9a87SYuri Pankov if (NULL == bp->first) 49*260e9a87SYuri Pankov goto out; 50*260e9a87SYuri Pankov if (EQN_LIST != bp->first->type) { 51*260e9a87SYuri Pankov eqn_box(p, bp->first); 52*260e9a87SYuri Pankov goto out; 53*260e9a87SYuri Pankov } 54*260e9a87SYuri Pankov if (NULL == (parent = bp->first->first)) 55*260e9a87SYuri Pankov goto out; 56*260e9a87SYuri Pankov /* Estimate the number of rows, first. */ 57*260e9a87SYuri Pankov if (NULL == (child = parent->first)) 58*260e9a87SYuri Pankov goto out; 59*260e9a87SYuri Pankov for (rows = 0; NULL != child; rows++) 60*260e9a87SYuri Pankov child = child->next; 61*260e9a87SYuri Pankov /* Print row-by-row. */ 62*260e9a87SYuri Pankov post = print_otag(p, TAG_MTABLE, 0, NULL); 63*260e9a87SYuri Pankov for (i = 0; i < rows; i++) { 64*260e9a87SYuri Pankov parent = bp->first->first; 65*260e9a87SYuri Pankov row = print_otag(p, TAG_MTR, 0, NULL); 66*260e9a87SYuri Pankov while (NULL != parent) { 67*260e9a87SYuri Pankov child = parent->first; 68*260e9a87SYuri Pankov for (j = 0; j < i; j++) { 69*260e9a87SYuri Pankov if (NULL == child) 70*260e9a87SYuri Pankov break; 71*260e9a87SYuri Pankov child = child->next; 72*260e9a87SYuri Pankov } 73*260e9a87SYuri Pankov cell = print_otag 74*260e9a87SYuri Pankov (p, TAG_MTD, 0, NULL); 75*260e9a87SYuri Pankov /* 76*260e9a87SYuri Pankov * If we have no data for this 77*260e9a87SYuri Pankov * particular cell, then print a 78*260e9a87SYuri Pankov * placeholder and continue--don't puke. 79*260e9a87SYuri Pankov */ 80*260e9a87SYuri Pankov if (NULL != child) 81*260e9a87SYuri Pankov eqn_box(p, child->first); 82*260e9a87SYuri Pankov print_tagq(p, cell); 83*260e9a87SYuri Pankov parent = parent->next; 84*260e9a87SYuri Pankov } 85*260e9a87SYuri Pankov print_tagq(p, row); 86*260e9a87SYuri Pankov } 87*260e9a87SYuri Pankov goto out; 88*260e9a87SYuri Pankov } 89*260e9a87SYuri Pankov 90*260e9a87SYuri Pankov switch (bp->pos) { 91*260e9a87SYuri Pankov case (EQNPOS_TO): 92*260e9a87SYuri Pankov post = print_otag(p, TAG_MOVER, 0, NULL); 93*260e9a87SYuri Pankov break; 94*260e9a87SYuri Pankov case (EQNPOS_SUP): 95*260e9a87SYuri Pankov post = print_otag(p, TAG_MSUP, 0, NULL); 96*260e9a87SYuri Pankov break; 97*260e9a87SYuri Pankov case (EQNPOS_FROM): 98*260e9a87SYuri Pankov post = print_otag(p, TAG_MUNDER, 0, NULL); 99*260e9a87SYuri Pankov break; 100*260e9a87SYuri Pankov case (EQNPOS_SUB): 101*260e9a87SYuri Pankov post = print_otag(p, TAG_MSUB, 0, NULL); 102*260e9a87SYuri Pankov break; 103*260e9a87SYuri Pankov case (EQNPOS_OVER): 104*260e9a87SYuri Pankov post = print_otag(p, TAG_MFRAC, 0, NULL); 105*260e9a87SYuri Pankov break; 106*260e9a87SYuri Pankov case (EQNPOS_FROMTO): 107*260e9a87SYuri Pankov post = print_otag(p, TAG_MUNDEROVER, 0, NULL); 108*260e9a87SYuri Pankov break; 109*260e9a87SYuri Pankov case (EQNPOS_SUBSUP): 110*260e9a87SYuri Pankov post = print_otag(p, TAG_MSUBSUP, 0, NULL); 111*260e9a87SYuri Pankov break; 112*260e9a87SYuri Pankov case (EQNPOS_SQRT): 113*260e9a87SYuri Pankov post = print_otag(p, TAG_MSQRT, 0, NULL); 114*260e9a87SYuri Pankov break; 115*260e9a87SYuri Pankov default: 116*260e9a87SYuri Pankov break; 117*260e9a87SYuri Pankov } 118*260e9a87SYuri Pankov 119*260e9a87SYuri Pankov if (bp->top || bp->bottom) { 120*260e9a87SYuri Pankov assert(NULL == post); 121*260e9a87SYuri Pankov if (bp->top && NULL == bp->bottom) 122*260e9a87SYuri Pankov post = print_otag(p, TAG_MOVER, 0, NULL); 123*260e9a87SYuri Pankov else if (bp->top && bp->bottom) 124*260e9a87SYuri Pankov post = print_otag(p, TAG_MUNDEROVER, 0, NULL); 125*260e9a87SYuri Pankov else if (bp->bottom) 126*260e9a87SYuri Pankov post = print_otag(p, TAG_MUNDER, 0, NULL); 127*260e9a87SYuri Pankov } 128*260e9a87SYuri Pankov 129*260e9a87SYuri Pankov if (EQN_PILE == bp->type) { 130*260e9a87SYuri Pankov assert(NULL == post); 131*260e9a87SYuri Pankov if (bp->first != NULL && bp->first->type == EQN_LIST) 132*260e9a87SYuri Pankov post = print_otag(p, TAG_MTABLE, 0, NULL); 133*260e9a87SYuri Pankov } else if (bp->type == EQN_LIST && 134*260e9a87SYuri Pankov bp->parent && bp->parent->type == EQN_PILE) { 135*260e9a87SYuri Pankov assert(NULL == post); 136*260e9a87SYuri Pankov post = print_otag(p, TAG_MTR, 0, NULL); 137*260e9a87SYuri Pankov print_otag(p, TAG_MTD, 0, NULL); 138*260e9a87SYuri Pankov } 139*260e9a87SYuri Pankov 140*260e9a87SYuri Pankov if (NULL != bp->text) { 141*260e9a87SYuri Pankov assert(NULL == post); 142*260e9a87SYuri Pankov post = print_otag(p, TAG_MI, 0, NULL); 143*260e9a87SYuri Pankov print_text(p, bp->text); 144*260e9a87SYuri Pankov } else if (NULL == post) { 145*260e9a87SYuri Pankov if (NULL != bp->left || NULL != bp->right) { 146*260e9a87SYuri Pankov PAIR_INIT(&tag[0], ATTR_OPEN, 147*260e9a87SYuri Pankov NULL == bp->left ? "" : bp->left); 148*260e9a87SYuri Pankov PAIR_INIT(&tag[1], ATTR_CLOSE, 149*260e9a87SYuri Pankov NULL == bp->right ? "" : bp->right); 150*260e9a87SYuri Pankov post = print_otag(p, TAG_MFENCED, 2, tag); 151*260e9a87SYuri Pankov } 152*260e9a87SYuri Pankov if (NULL == post) 153*260e9a87SYuri Pankov post = print_otag(p, TAG_MROW, 0, NULL); 154*260e9a87SYuri Pankov else 155*260e9a87SYuri Pankov print_otag(p, TAG_MROW, 0, NULL); 156*260e9a87SYuri Pankov } 157*260e9a87SYuri Pankov 158*260e9a87SYuri Pankov eqn_box(p, bp->first); 159*260e9a87SYuri Pankov 160*260e9a87SYuri Pankov out: 161*260e9a87SYuri Pankov if (NULL != bp->bottom) { 162*260e9a87SYuri Pankov t = print_otag(p, TAG_MO, 0, NULL); 163*260e9a87SYuri Pankov print_text(p, bp->bottom); 164*260e9a87SYuri Pankov print_tagq(p, t); 165*260e9a87SYuri Pankov } 166*260e9a87SYuri Pankov if (NULL != bp->top) { 167*260e9a87SYuri Pankov t = print_otag(p, TAG_MO, 0, NULL); 168*260e9a87SYuri Pankov print_text(p, bp->top); 169*260e9a87SYuri Pankov print_tagq(p, t); 170*260e9a87SYuri Pankov } 171*260e9a87SYuri Pankov 172*260e9a87SYuri Pankov if (NULL != post) 173*260e9a87SYuri Pankov print_tagq(p, post); 174*260e9a87SYuri Pankov 175*260e9a87SYuri Pankov eqn_box(p, bp->next); 176*260e9a87SYuri Pankov } 17795c635efSGarrett D'Amore 17895c635efSGarrett D'Amore void 17995c635efSGarrett D'Amore print_eqn(struct html *p, const struct eqn *ep) 18095c635efSGarrett D'Amore { 18195c635efSGarrett D'Amore struct htmlpair tag; 18295c635efSGarrett D'Amore struct tag *t; 18395c635efSGarrett D'Amore 18495c635efSGarrett D'Amore PAIR_CLASS_INIT(&tag, "eqn"); 185*260e9a87SYuri Pankov t = print_otag(p, TAG_MATH, 1, &tag); 18695c635efSGarrett D'Amore 18795c635efSGarrett D'Amore p->flags |= HTML_NONOSPACE; 18895c635efSGarrett D'Amore eqn_box(p, ep->root); 18995c635efSGarrett D'Amore p->flags &= ~HTML_NONOSPACE; 19095c635efSGarrett D'Amore 19195c635efSGarrett D'Amore print_tagq(p, t); 19295c635efSGarrett D'Amore } 193