]> git.cameronkatri.com Git - mandoc.git/blob - eqn_html.c
e7393a96aa935c2e17f4318d74dce9ded7c2d0ee
[mandoc.git] / eqn_html.c
1 /* $Id: eqn_html.c,v 1.13 2017/06/23 02:32:12 schwarze Exp $ */
2 /*
3 * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
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 */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "mandoc.h"
29 #include "out.h"
30 #include "html.h"
31
32 static void
33 eqn_box(struct html *p, const struct eqn_box *bp)
34 {
35 struct tag *post, *row, *cell, *t;
36 const struct eqn_box *child, *parent;
37 const unsigned char *cp;
38 size_t i, j, rows;
39 enum htmltag tag;
40 enum eqn_fontt font;
41
42 if (NULL == bp)
43 return;
44
45 post = NULL;
46
47 /*
48 * Special handling for a matrix, which is presented to us in
49 * column order, but must be printed in row-order.
50 */
51 if (EQN_MATRIX == bp->type) {
52 if (NULL == bp->first)
53 goto out;
54 if (EQN_LIST != bp->first->type) {
55 eqn_box(p, bp->first);
56 goto out;
57 }
58 if (NULL == (parent = bp->first->first))
59 goto out;
60 /* Estimate the number of rows, first. */
61 if (NULL == (child = parent->first))
62 goto out;
63 for (rows = 0; NULL != child; rows++)
64 child = child->next;
65 /* Print row-by-row. */
66 post = print_otag(p, TAG_MTABLE, "");
67 for (i = 0; i < rows; i++) {
68 parent = bp->first->first;
69 row = print_otag(p, TAG_MTR, "");
70 while (NULL != parent) {
71 child = parent->first;
72 for (j = 0; j < i; j++) {
73 if (NULL == child)
74 break;
75 child = child->next;
76 }
77 cell = print_otag(p, TAG_MTD, "");
78 /*
79 * If we have no data for this
80 * particular cell, then print a
81 * placeholder and continue--don't puke.
82 */
83 if (NULL != child)
84 eqn_box(p, child->first);
85 print_tagq(p, cell);
86 parent = parent->next;
87 }
88 print_tagq(p, row);
89 }
90 goto out;
91 }
92
93 switch (bp->pos) {
94 case EQNPOS_TO:
95 post = print_otag(p, TAG_MOVER, "");
96 break;
97 case EQNPOS_SUP:
98 post = print_otag(p, TAG_MSUP, "");
99 break;
100 case EQNPOS_FROM:
101 post = print_otag(p, TAG_MUNDER, "");
102 break;
103 case EQNPOS_SUB:
104 post = print_otag(p, TAG_MSUB, "");
105 break;
106 case EQNPOS_OVER:
107 post = print_otag(p, TAG_MFRAC, "");
108 break;
109 case EQNPOS_FROMTO:
110 post = print_otag(p, TAG_MUNDEROVER, "");
111 break;
112 case EQNPOS_SUBSUP:
113 post = print_otag(p, TAG_MSUBSUP, "");
114 break;
115 case EQNPOS_SQRT:
116 post = print_otag(p, TAG_MSQRT, "");
117 break;
118 default:
119 break;
120 }
121
122 if (bp->top || bp->bottom) {
123 assert(NULL == post);
124 if (bp->top && NULL == bp->bottom)
125 post = print_otag(p, TAG_MOVER, "");
126 else if (bp->top && bp->bottom)
127 post = print_otag(p, TAG_MUNDEROVER, "");
128 else if (bp->bottom)
129 post = print_otag(p, TAG_MUNDER, "");
130 }
131
132 if (EQN_PILE == bp->type) {
133 assert(NULL == post);
134 if (bp->first != NULL && bp->first->type == EQN_LIST)
135 post = print_otag(p, TAG_MTABLE, "");
136 } else if (bp->type == EQN_LIST &&
137 bp->parent && bp->parent->type == EQN_PILE) {
138 assert(NULL == post);
139 post = print_otag(p, TAG_MTR, "");
140 print_otag(p, TAG_MTD, "");
141 }
142
143 if (bp->text != NULL) {
144 assert(post == NULL);
145 tag = TAG_MI;
146 cp = (unsigned char *)bp->text;
147 if (isdigit(cp[0]) || (cp[0] == '.' && isdigit(cp[1]))) {
148 tag = TAG_MN;
149 while (*++cp != '\0') {
150 if (*cp != '.' && !isdigit(*cp)) {
151 tag = TAG_MI;
152 break;
153 }
154 }
155 } else if (*cp != '\0' && isalpha(*cp) == 0) {
156 tag = TAG_MO;
157 while (*++cp != '\0') {
158 if (isalnum(*cp)) {
159 tag = TAG_MI;
160 break;
161 }
162 }
163 }
164 font = bp->font;
165 if (bp->text[0] != '\0' &&
166 (((tag == TAG_MN || tag == TAG_MO) &&
167 font == EQNFONT_ROMAN) ||
168 (tag == TAG_MI && font == (bp->text[1] == '\0' ?
169 EQNFONT_ITALIC : EQNFONT_ROMAN))))
170 font = EQNFONT_NONE;
171 switch (font) {
172 case EQNFONT_NONE:
173 post = print_otag(p, tag, "");
174 break;
175 case EQNFONT_ROMAN:
176 post = print_otag(p, tag, "?", "fontstyle", "normal");
177 break;
178 case EQNFONT_BOLD:
179 case EQNFONT_FAT:
180 post = print_otag(p, tag, "?", "fontweight", "bold");
181 break;
182 case EQNFONT_ITALIC:
183 post = print_otag(p, tag, "?", "fontstyle", "italic");
184 break;
185 default:
186 abort();
187 }
188 print_text(p, bp->text);
189 } else if (NULL == post) {
190 if (NULL != bp->left || NULL != bp->right)
191 post = print_otag(p, TAG_MFENCED, "??",
192 "open", bp->left == NULL ? "" : bp->left,
193 "close", bp->right == NULL ? "" : bp->right);
194 if (NULL == post)
195 post = print_otag(p, TAG_MROW, "");
196 else
197 print_otag(p, TAG_MROW, "");
198 }
199
200 eqn_box(p, bp->first);
201
202 out:
203 if (NULL != bp->bottom) {
204 t = print_otag(p, TAG_MO, "");
205 print_text(p, bp->bottom);
206 print_tagq(p, t);
207 }
208 if (NULL != bp->top) {
209 t = print_otag(p, TAG_MO, "");
210 print_text(p, bp->top);
211 print_tagq(p, t);
212 }
213
214 if (NULL != post)
215 print_tagq(p, post);
216
217 eqn_box(p, bp->next);
218 }
219
220 void
221 print_eqn(struct html *p, const struct eqn *ep)
222 {
223 struct tag *t;
224
225 t = print_otag(p, TAG_MATH, "c", "eqn");
226
227 p->flags |= HTML_NONOSPACE;
228 eqn_box(p, ep->root);
229 p->flags &= ~HTML_NONOSPACE;
230
231 print_tagq(p, t);
232 }