Annotation of src/usr.bin/mandoc/eqn_html.c, Revision 1.9
1.9 ! schwarze 1: /* $OpenBSD: eqn_html.c,v 1.8 2017/06/20 17:24:09 schwarze Exp $ */
1.1 schwarze 2: /*
1.3 schwarze 3: * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
1.7 schwarze 4: * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
1.5 schwarze 18: #include <sys/types.h>
19:
1.1 schwarze 20: #include <assert.h>
1.9 ! schwarze 21: #include <ctype.h>
1.1 schwarze 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.5 schwarze 30: static void
31: eqn_box(struct html *p, const struct eqn_box *bp)
1.1 schwarze 32: {
1.5 schwarze 33: struct tag *post, *row, *cell, *t;
34: const struct eqn_box *child, *parent;
1.9 ! schwarze 35: const unsigned char *cp;
1.5 schwarze 36: size_t i, j, rows;
1.9 ! schwarze 37: enum htmltag tag;
! 38: enum eqn_fontt font;
1.3 schwarze 39:
40: if (NULL == bp)
1.5 schwarze 41: return;
1.3 schwarze 42:
1.5 schwarze 43: post = NULL;
1.3 schwarze 44:
45: /*
1.5 schwarze 46: * Special handling for a matrix, which is presented to us in
47: * column order, but must be printed in row-order.
1.3 schwarze 48: */
1.5 schwarze 49: if (EQN_MATRIX == bp->type) {
50: if (NULL == bp->first)
51: goto out;
1.6 schwarze 52: if (EQN_LIST != bp->first->type) {
53: eqn_box(p, bp->first);
54: goto out;
55: }
1.5 schwarze 56: if (NULL == (parent = bp->first->first))
57: goto out;
58: /* Estimate the number of rows, first. */
59: if (NULL == (child = parent->first))
60: goto out;
61: for (rows = 0; NULL != child; rows++)
62: child = child->next;
63: /* Print row-by-row. */
1.7 schwarze 64: post = print_otag(p, TAG_MTABLE, "");
1.5 schwarze 65: for (i = 0; i < rows; i++) {
66: parent = bp->first->first;
1.7 schwarze 67: row = print_otag(p, TAG_MTR, "");
1.5 schwarze 68: while (NULL != parent) {
69: child = parent->first;
70: for (j = 0; j < i; j++) {
71: if (NULL == child)
72: break;
73: child = child->next;
74: }
1.7 schwarze 75: cell = print_otag(p, TAG_MTD, "");
1.5 schwarze 76: /*
77: * If we have no data for this
78: * particular cell, then print a
79: * placeholder and continue--don't puke.
80: */
81: if (NULL != child)
82: eqn_box(p, child->first);
83: print_tagq(p, cell);
84: parent = parent->next;
85: }
86: print_tagq(p, row);
87: }
88: goto out;
1.4 schwarze 89: }
1.3 schwarze 90:
91: switch (bp->pos) {
1.8 schwarze 92: case EQNPOS_TO:
1.7 schwarze 93: post = print_otag(p, TAG_MOVER, "");
1.4 schwarze 94: break;
1.8 schwarze 95: case EQNPOS_SUP:
1.7 schwarze 96: post = print_otag(p, TAG_MSUP, "");
1.3 schwarze 97: break;
1.8 schwarze 98: case EQNPOS_FROM:
1.7 schwarze 99: post = print_otag(p, TAG_MUNDER, "");
1.4 schwarze 100: break;
1.8 schwarze 101: case EQNPOS_SUB:
1.7 schwarze 102: post = print_otag(p, TAG_MSUB, "");
1.3 schwarze 103: break;
1.8 schwarze 104: case EQNPOS_OVER:
1.7 schwarze 105: post = print_otag(p, TAG_MFRAC, "");
1.3 schwarze 106: break;
1.8 schwarze 107: case EQNPOS_FROMTO:
1.7 schwarze 108: post = print_otag(p, TAG_MUNDEROVER, "");
1.4 schwarze 109: break;
1.8 schwarze 110: case EQNPOS_SUBSUP:
1.7 schwarze 111: post = print_otag(p, TAG_MSUBSUP, "");
1.5 schwarze 112: break;
1.8 schwarze 113: case EQNPOS_SQRT:
1.7 schwarze 114: post = print_otag(p, TAG_MSQRT, "");
1.3 schwarze 115: break;
116: default:
117: break;
118: }
119:
1.5 schwarze 120: if (bp->top || bp->bottom) {
121: assert(NULL == post);
122: if (bp->top && NULL == bp->bottom)
1.7 schwarze 123: post = print_otag(p, TAG_MOVER, "");
1.5 schwarze 124: else if (bp->top && bp->bottom)
1.7 schwarze 125: post = print_otag(p, TAG_MUNDEROVER, "");
1.5 schwarze 126: else if (bp->bottom)
1.7 schwarze 127: post = print_otag(p, TAG_MUNDER, "");
1.5 schwarze 128: }
129:
130: if (EQN_PILE == bp->type) {
131: assert(NULL == post);
1.6 schwarze 132: if (bp->first != NULL && bp->first->type == EQN_LIST)
1.7 schwarze 133: post = print_otag(p, TAG_MTABLE, "");
1.6 schwarze 134: } else if (bp->type == EQN_LIST &&
135: bp->parent && bp->parent->type == EQN_PILE) {
1.5 schwarze 136: assert(NULL == post);
1.7 schwarze 137: post = print_otag(p, TAG_MTR, "");
138: print_otag(p, TAG_MTD, "");
1.5 schwarze 139: }
1.3 schwarze 140:
1.9 ! schwarze 141: if (bp->text != NULL) {
! 142: assert(post == NULL);
! 143: tag = TAG_MI;
! 144: cp = (unsigned char *)bp->text;
! 145: if (isdigit(cp[0]) || (cp[0] == '.' && isdigit(cp[1]))) {
! 146: tag = TAG_MN;
! 147: while (*++cp != '\0') {
! 148: if (*cp != '.' && !isdigit(*cp)) {
! 149: tag = TAG_MI;
! 150: break;
! 151: }
! 152: }
! 153: } else if (*cp != '\0' && isalpha(*cp) == 0) {
! 154: tag = TAG_MO;
! 155: while (*++cp != '\0') {
! 156: if (isalnum(*cp)) {
! 157: tag = TAG_MI;
! 158: break;
! 159: }
! 160: }
! 161: }
! 162: font = bp->font;
! 163: if (bp->text[0] != '\0' &&
! 164: (((tag == TAG_MN || tag == TAG_MO) &&
! 165: font == EQNFONT_ROMAN) ||
! 166: (tag == TAG_MI && font == (bp->text[1] == '\0' ?
! 167: EQNFONT_ITALIC : EQNFONT_ROMAN))))
! 168: font = EQNFONT_NONE;
! 169: switch (font) {
! 170: case EQNFONT_NONE:
! 171: post = print_otag(p, tag, "");
! 172: break;
! 173: case EQNFONT_ROMAN:
! 174: post = print_otag(p, tag, "?", "fontstyle", "normal");
! 175: break;
! 176: case EQNFONT_BOLD:
! 177: case EQNFONT_FAT:
! 178: post = print_otag(p, tag, "?", "fontweight", "bold");
! 179: break;
! 180: case EQNFONT_ITALIC:
! 181: post = print_otag(p, tag, "?", "fontstyle", "italic");
! 182: break;
! 183: default:
! 184: abort();
! 185: }
1.5 schwarze 186: print_text(p, bp->text);
187: } else if (NULL == post) {
1.7 schwarze 188: if (NULL != bp->left || NULL != bp->right)
189: post = print_otag(p, TAG_MFENCED, "??",
190: "open", bp->left == NULL ? "" : bp->left,
191: "close", bp->right == NULL ? "" : bp->right);
1.5 schwarze 192: if (NULL == post)
1.7 schwarze 193: post = print_otag(p, TAG_MROW, "");
1.5 schwarze 194: else
1.7 schwarze 195: print_otag(p, TAG_MROW, "");
1.3 schwarze 196: }
197:
1.5 schwarze 198: eqn_box(p, bp->first);
199:
200: out:
201: if (NULL != bp->bottom) {
1.7 schwarze 202: t = print_otag(p, TAG_MO, "");
1.5 schwarze 203: print_text(p, bp->bottom);
204: print_tagq(p, t);
205: }
206: if (NULL != bp->top) {
1.7 schwarze 207: t = print_otag(p, TAG_MO, "");
1.5 schwarze 208: print_text(p, bp->top);
209: print_tagq(p, t);
210: }
211:
212: if (NULL != post)
1.3 schwarze 213: print_tagq(p, post);
214:
1.5 schwarze 215: eqn_box(p, bp->next);
216: }
217:
218: void
219: print_eqn(struct html *p, const struct eqn *ep)
220: {
221: struct tag *t;
222:
1.7 schwarze 223: t = print_otag(p, TAG_MATH, "c", "eqn");
1.5 schwarze 224:
225: p->flags |= HTML_NONOSPACE;
226: eqn_box(p, ep->root);
227: p->flags &= ~HTML_NONOSPACE;
1.3 schwarze 228:
1.5 schwarze 229: print_tagq(p, t);
1.1 schwarze 230: }