GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/eqn_html.c Lines: 120 129 93.0 %
Date: 2017-11-07 Branches: 100 131 76.3 %

Line Branch Exec Source
1
/*	$OpenBSD: eqn_html.c,v 1.13 2017/07/14 13:32:27 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 <sys/types.h>
19
20
#include <assert.h>
21
#include <ctype.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
30
static void
31
eqn_box(struct html *p, const struct eqn_box *bp)
32
{
33
	struct tag	*post, *row, *cell, *t;
34
	const struct eqn_box *child, *parent;
35
12870
	const char	*cp;
36
	size_t		 i, j, rows;
37
	enum htmltag	 tag;
38
	enum eqn_fontt	 font;
39
40
6435
	if (NULL == bp)
41
3294
		return;
42
43
	post = NULL;
44
45
	/*
46
	 * Special handling for a matrix, which is presented to us in
47
	 * column order, but must be printed in row-order.
48
	 */
49
3141
	if (EQN_MATRIX == bp->type) {
50
27
		if (NULL == bp->first)
51
			goto out;
52

36
		if (bp->first->type != EQN_LIST ||
53
18
		    bp->first->expectargs == 1) {
54
			eqn_box(p, bp->first);
55
			goto out;
56
		}
57
18
		if (NULL == (parent = bp->first->first))
58
			goto out;
59
		/* Estimate the number of rows, first. */
60
9
		if (NULL == (child = parent->first))
61
			goto out;
62
54
		for (rows = 0; NULL != child; rows++)
63
18
			child = child->next;
64
		/* Print row-by-row. */
65
9
		post = print_otag(p, TAG_MTABLE, "");
66
54
		for (i = 0; i < rows; i++) {
67
18
			parent = bp->first->first;
68
18
			row = print_otag(p, TAG_MTR, "");
69
108
			while (NULL != parent) {
70
36
				child = parent->first;
71
162
				for (j = 0; j < i; j++) {
72
54
					if (NULL == child)
73
						break;
74
18
					child = child->next;
75
				}
76
36
				cell = print_otag(p, TAG_MTD, "");
77
				/*
78
				 * If we have no data for this
79
				 * particular cell, then print a
80
				 * placeholder and continue--don't puke.
81
				 */
82
36
				if (NULL != child)
83
36
					eqn_box(p, child->first);
84
36
				print_tagq(p, cell);
85
36
				parent = parent->next;
86
			}
87
18
			print_tagq(p, row);
88
		}
89
		goto out;
90
	}
91
92


3573
	switch (bp->pos) {
93
	case EQNPOS_TO:
94
9
		post = print_otag(p, TAG_MOVER, "");
95
9
		break;
96
	case EQNPOS_SUP:
97
81
		post = print_otag(p, TAG_MSUP, "");
98
81
		break;
99
	case EQNPOS_FROM:
100
		post = print_otag(p, TAG_MUNDER, "");
101
		break;
102
	case EQNPOS_SUB:
103
126
		post = print_otag(p, TAG_MSUB, "");
104
126
		break;
105
	case EQNPOS_OVER:
106
72
		post = print_otag(p, TAG_MFRAC, "");
107
72
		break;
108
	case EQNPOS_FROMTO:
109
45
		post = print_otag(p, TAG_MUNDEROVER, "");
110
45
		break;
111
	case EQNPOS_SUBSUP:
112
63
		post = print_otag(p, TAG_MSUBSUP, "");
113
63
		break;
114
	case EQNPOS_SQRT:
115
63
		post = print_otag(p, TAG_MSQRT, "");
116
63
		break;
117
	default:
118
		break;
119
	}
120
121

6057
	if (bp->top || bp->bottom) {
122
198
		assert(NULL == post);
123

369
		if (bp->top && NULL == bp->bottom)
124
171
			post = print_otag(p, TAG_MOVER, "");
125

27
		else if (bp->top && bp->bottom)
126
			post = print_otag(p, TAG_MUNDEROVER, "");
127
27
		else if (bp->bottom)
128
27
			post = print_otag(p, TAG_MUNDER, "");
129
	}
130
131
3114
	if (EQN_PILE == bp->type) {
132
18
		assert(NULL == post);
133

36
		if (bp->first != NULL &&
134
18
		    bp->first->type == EQN_LIST &&
135
18
		    bp->first->expectargs > 1)
136
18
			post = print_otag(p, TAG_MTABLE, "");
137

3834
	} else if (bp->type == EQN_LIST && bp->expectargs > 1 &&
138
324
	    bp->parent && bp->parent->type == EQN_PILE) {
139
36
		assert(NULL == post);
140
36
		post = print_otag(p, TAG_MTR, "");
141
36
		print_otag(p, TAG_MTD, "");
142
36
	}
143
144
3114
	if (bp->text != NULL) {
145
1917
		assert(post == NULL);
146
		tag = TAG_MI;
147
1917
		cp = bp->text;
148

1917
		if (isdigit((unsigned char)cp[0]) ||
149
1683
		    (cp[0] == '.' && isdigit((unsigned char)cp[1]))) {
150
			tag = TAG_MN;
151
504
			while (*++cp != '\0') {
152

72
				if (*cp != '.' &&
153
36
				    isdigit((unsigned char)*cp) == 0) {
154
					tag = TAG_MI;
155
					break;
156
				}
157
			}
158

3357
		} else if (*cp != '\0' && isalpha((unsigned char)*cp) == 0) {
159
			tag = TAG_MO;
160
1026
			while (*cp != '\0') {
161

432
				if (cp[0] == '\\' && cp[1] != '\0') {
162
90
					cp++;
163
90
					mandoc_escape(&cp, NULL, NULL);
164
342
				} else if (isalnum((unsigned char)*cp)) {
165
					tag = TAG_MI;
166
					break;
167
				} else
168
252
					cp++;
169
			}
170
		}
171
1917
		font = bp->font;
172

3249
		if (bp->text[0] != '\0' &&
173
3816
		    (((tag == TAG_MN || tag == TAG_MO) &&
174
1908
		      font == EQNFONT_ROMAN) ||
175
2700
		     (tag == TAG_MI && font == (bp->text[1] == '\0' ?
176
		      EQNFONT_ITALIC : EQNFONT_ROMAN))))
177
1449
			font = EQNFONT_NONE;
178

1917
		switch (font) {
179
		case EQNFONT_NONE:
180
1494
			post = print_otag(p, tag, "");
181
1494
			break;
182
		case EQNFONT_ROMAN:
183
27
			post = print_otag(p, tag, "?", "fontstyle", "normal");
184
27
			break;
185
		case EQNFONT_BOLD:
186
		case EQNFONT_FAT:
187
81
			post = print_otag(p, tag, "?", "fontweight", "bold");
188
81
			break;
189
		case EQNFONT_ITALIC:
190
315
			post = print_otag(p, tag, "?", "fontstyle", "italic");
191
315
			break;
192
		default:
193
			abort();
194
		}
195
1917
		print_text(p, bp->text);
196
3114
	} else if (NULL == post) {
197

927
		if (NULL != bp->left || NULL != bp->right)
198
45
			post = print_otag(p, TAG_MFENCED, "??",
199
135
			    "open", bp->left == NULL ? "" : bp->left,
200
135
			    "close", bp->right == NULL ? "" : bp->right);
201
972
		if (NULL == post)
202
927
			post = print_otag(p, TAG_MROW, "");
203
		else
204
			print_otag(p, TAG_MROW, "");
205
	}
206
207
3114
	eqn_box(p, bp->first);
208
209
out:
210
3141
	if (NULL != bp->bottom) {
211
27
		t = print_otag(p, TAG_MO, "");
212
27
		print_text(p, bp->bottom);
213
27
		print_tagq(p, t);
214
27
	}
215
3141
	if (NULL != bp->top) {
216
171
		t = print_otag(p, TAG_MO, "");
217
171
		print_text(p, bp->top);
218
171
		print_tagq(p, t);
219
171
	}
220
221
3141
	if (NULL != post)
222
3123
		print_tagq(p, post);
223
224
3141
	eqn_box(p, bp->next);
225
9576
}
226
227
void
228
print_eqn(struct html *p, const struct eqn_box *bp)
229
{
230
	struct tag	*t;
231
232
288
	if (bp->first == NULL)
233
		return;
234
235
144
	t = print_otag(p, TAG_MATH, "c", "eqn");
236
237
144
	p->flags |= HTML_NONOSPACE;
238
144
	eqn_box(p, bp);
239
144
	p->flags &= ~HTML_NONOSPACE;
240
241
144
	print_tagq(p, t);
242
288
}