GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/tbl_data.c Lines: 106 113 93.8 %
Date: 2017-11-07 Branches: 81 88 92.0 %

Line Branch Exec Source
1
/*	$OpenBSD: tbl_data.c,v 1.32 2017/07/08 17:52:42 schwarze Exp $ */
2
/*
3
 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4
 * Copyright (c) 2011, 2015, 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 <stdlib.h>
23
#include <string.h>
24
#include <time.h>
25
26
#include "mandoc.h"
27
#include "mandoc_aux.h"
28
#include "libmandoc.h"
29
#include "libroff.h"
30
31
static	void		 getdata(struct tbl_node *, struct tbl_span *,
32
				int, const char *, int *);
33
static	struct tbl_span	*newspan(struct tbl_node *, int,
34
				struct tbl_row *);
35
36
37
static void
38
getdata(struct tbl_node *tbl, struct tbl_span *dp,
39
		int ln, const char *p, int *pos)
40
{
41
	struct tbl_dat	*dat;
42
	struct tbl_cell	*cp;
43
	int		 sv;
44
45
	/* Advance to the next layout cell, skipping spanners. */
46
47
205695
	cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
48

274632
	while (cp != NULL && cp->pos == TBL_CELL_SPAN)
49
102
		cp = cp->next;
50
51
	/*
52
	 * If the current layout row is out of cells, allocate
53
	 * a new cell if another row of the table has at least
54
	 * this number of columns, or discard the input if we
55
	 * are beyond the last column of the table as a whole.
56
	 */
57
58
68565
	if (cp == NULL) {
59
36
		if (dp->layout->last->col + 1 < dp->opts->cols) {
60
18
			cp = mandoc_calloc(1, sizeof(*cp));
61
18
			cp->pos = TBL_CELL_LEFT;
62
18
			dp->layout->last->next = cp;
63
18
			cp->col = dp->layout->last->col + 1;
64
18
			dp->layout->last = cp;
65
		} else {
66
36
			mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
67
18
			    ln, *pos, p + *pos);
68
216
			while (p[*pos])
69
90
				(*pos)++;
70
18
			return;
71
		}
72
18
	}
73
74
68547
	dat = mandoc_calloc(1, sizeof(*dat));
75
68547
	dat->layout = cp;
76
68547
	dat->pos = TBL_DATA_NONE;
77
68547
	dat->spans = 0;
78
137490
	for (cp = cp->next; cp != NULL; cp = cp->next)
79
44086
		if (cp->pos == TBL_CELL_SPAN)
80
198
			dat->spans++;
81
		else
82
			break;
83
84
68547
	if (dp->last == NULL)
85
26159
		dp->first = dat;
86
	else
87
42388
		dp->last->next = dat;
88
68547
	dp->last = dat;
89
90
68547
	sv = *pos;
91

1403072
	while (p[*pos] && p[*pos] != tbl->opts.tab)
92
288427
		(*pos)++;
93
94
	/*
95
	 * Check for a continued-data scope opening.  This consists of a
96
	 * trailing `T{' at the end of the line.  Subsequent lines,
97
	 * until a standalone `T}', are included in our cell.
98
	 */
99
100

115359
	if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
101
1728
		tbl->part = TBL_PART_CDATA;
102
1728
		return;
103
	}
104
105
66819
	dat->string = mandoc_strndup(p + sv, *pos - sv);
106
107
66819
	if (p[*pos])
108
43723
		(*pos)++;
109
110
66819
	if ( ! strcmp(dat->string, "_"))
111
3
		dat->pos = TBL_DATA_HORIZ;
112
66816
	else if ( ! strcmp(dat->string, "="))
113
3
		dat->pos = TBL_DATA_DHORIZ;
114
66813
	else if ( ! strcmp(dat->string, "\\_"))
115
3
		dat->pos = TBL_DATA_NHORIZ;
116
66810
	else if ( ! strcmp(dat->string, "\\="))
117
		dat->pos = TBL_DATA_NDHORIZ;
118
	else
119
		dat->pos = TBL_DATA_DATA;
120
121

70989
	if ((dat->layout->pos == TBL_CELL_HORIZ ||
122
62706
	    dat->layout->pos == TBL_CELL_DHORIZ ||
123
62706
	    dat->layout->pos == TBL_CELL_DOWN) &&
124
8340
	    dat->pos == TBL_DATA_DATA && *dat->string != '\0')
125
72
		mandoc_msg(MANDOCERR_TBLDATA_SPAN,
126
72
		    tbl->parse, ln, sv, dat->string);
127
135384
}
128
129
void
130
tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
131
{
132
	struct tbl_dat	*dat;
133
	size_t		 sz;
134
135
3420
	dat = tbl->last_span->last;
136
137

5151
	if (p[pos] == 'T' && p[pos + 1] == '}') {
138
1692
		pos += 2;
139
1692
		if (p[pos] == tbl->opts.tab) {
140
87
			tbl->part = TBL_PART_DATA;
141
87
			pos++;
142
390
			while (p[pos] != '\0')
143
108
				getdata(tbl, tbl->last_span, ln, p, &pos);
144
87
			return;
145
1605
		} else if (p[pos] == '\0') {
146
1605
			tbl->part = TBL_PART_DATA;
147
1605
			return;
148
		}
149
150
		/* Fallthrough: T} is part of a word. */
151
	}
152
153
1728
	dat->pos = TBL_DATA_DATA;
154
1728
	dat->block = 1;
155
156
1728
	if (dat->string != NULL) {
157
		sz = strlen(p + pos) + strlen(dat->string) + 2;
158
		dat->string = mandoc_realloc(dat->string, sz);
159
		(void)strlcat(dat->string, " ", sz);
160
		(void)strlcat(dat->string, p + pos, sz);
161
	} else
162
1728
		dat->string = mandoc_strdup(p + pos);
163
164
1728
	if (dat->layout->pos == TBL_CELL_DOWN)
165
		mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
166
		    ln, pos, dat->string);
167
5148
}
168
169
static struct tbl_span *
170
newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
171
{
172
	struct tbl_span	*dp;
173
174
53158
	dp = mandoc_calloc(1, sizeof(*dp));
175
26579
	dp->line = line;
176
26579
	dp->opts = &tbl->opts;
177
26579
	dp->layout = rp;
178
26579
	dp->prev = tbl->last_span;
179
180
26579
	if (dp->prev == NULL) {
181
6901
		tbl->first_span = dp;
182
6901
		tbl->current_span = NULL;
183
6901
	} else
184
19678
		dp->prev->next = dp;
185
26579
	tbl->last_span = dp;
186
187
26579
	return dp;
188
}
189
190
void
191
tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
192
{
193
	struct tbl_row	*rp;
194
	struct tbl_cell	*cp;
195
	struct tbl_span	*sp;
196
197
33438
	rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
198

58593
	    sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
199
5994
	    sp->layout->next : sp->layout;
200
201
26537
	assert(rp != NULL);
202
203
26537
	if ( ! strcmp(p, "_")) {
204
333
		sp = newspan(tbl, ln, rp);
205
333
		sp->pos = TBL_SPAN_HORIZ;
206
333
		return;
207
26204
	} else if ( ! strcmp(p, "=")) {
208
30
		sp = newspan(tbl, ln, rp);
209
30
		sp->pos = TBL_SPAN_DHORIZ;
210
30
		return;
211
	}
212
213
	/*
214
	 * If the layout row contains nothing but horizontal lines,
215
	 * allocate an empty span for it and assign the current span
216
	 * to the next layout row accepting data.
217
	 */
218
219
26258
	while (rp->next != NULL) {
220
13666
		if (rp->last->col + 1 < tbl->opts.cols)
221
			break;
222
29498
		for (cp = rp->first; cp != NULL; cp = cp->next)
223

28319
			if (cp->pos != TBL_CELL_HORIZ &&
224
13612
			    cp->pos != TBL_CELL_DHORIZ)
225
				break;
226
13654
		if (cp != NULL)
227
			break;
228
42
		sp = newspan(tbl, ln, rp);
229
42
		sp->pos = TBL_SPAN_DATA;
230
42
		rp = rp->next;
231
	}
232
233
	/* Process a real data row. */
234
235
26174
	sp = newspan(tbl, ln, rp);
236
26174
	sp->pos = TBL_SPAN_DATA;
237
189262
	while (p[pos] != '\0')
238
68457
		getdata(tbl, sp, ln, p, &pos);
239
52711
}