GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/tbl_data.c Lines: 106 113 93.8 %
Date: 2017-11-13 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
69558
	cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
48

92868
	while (cp != NULL && cp->pos == TBL_CELL_SPAN)
49
34
		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
23186
	if (cp == NULL) {
59
12
		if (dp->layout->last->col + 1 < dp->opts->cols) {
60
6
			cp = mandoc_calloc(1, sizeof(*cp));
61
6
			cp->pos = TBL_CELL_LEFT;
62
6
			dp->layout->last->next = cp;
63
6
			cp->col = dp->layout->last->col + 1;
64
6
			dp->layout->last = cp;
65
		} else {
66
12
			mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
67
6
			    ln, *pos, p + *pos);
68
72
			while (p[*pos])
69
30
				(*pos)++;
70
6
			return;
71
		}
72
6
	}
73
74
23180
	dat = mandoc_calloc(1, sizeof(*dat));
75
23180
	dat->layout = cp;
76
23180
	dat->pos = TBL_DATA_NONE;
77
23180
	dat->spans = 0;
78
46492
	for (cp = cp->next; cp != NULL; cp = cp->next)
79
14944
		if (cp->pos == TBL_CELL_SPAN)
80
66
			dat->spans++;
81
		else
82
			break;
83
84
23180
	if (dp->last == NULL)
85
8802
		dp->first = dat;
86
	else
87
14378
		dp->last->next = dat;
88
23180
	dp->last = dat;
89
90
23180
	sv = *pos;
91

484375
	while (p[*pos] && p[*pos] != tbl->opts.tab)
92
100003
		(*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

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

23994
	if ((dat->layout->pos == TBL_CELL_HORIZ ||
122
21233
	    dat->layout->pos == TBL_CELL_DHORIZ ||
123
21233
	    dat->layout->pos == TBL_CELL_DOWN) &&
124
2780
	    dat->pos == TBL_DATA_DATA && *dat->string != '\0')
125
24
		mandoc_msg(MANDOCERR_TBLDATA_SPAN,
126
24
		    tbl->parse, ln, sv, dat->string);
127
45790
}
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
1140
	dat = tbl->last_span->last;
136
137

1717
	if (p[pos] == 'T' && p[pos + 1] == '}') {
138
564
		pos += 2;
139
564
		if (p[pos] == tbl->opts.tab) {
140
29
			tbl->part = TBL_PART_DATA;
141
29
			pos++;
142
130
			while (p[pos] != '\0')
143
36
				getdata(tbl, tbl->last_span, ln, p, &pos);
144
29
			return;
145
535
		} else if (p[pos] == '\0') {
146
535
			tbl->part = TBL_PART_DATA;
147
535
			return;
148
		}
149
150
		/* Fallthrough: T} is part of a word. */
151
	}
152
153
576
	dat->pos = TBL_DATA_DATA;
154
576
	dat->block = 1;
155
156
576
	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
576
		dat->string = mandoc_strdup(p + pos);
163
164
576
	if (dat->layout->pos == TBL_CELL_DOWN)
165
		mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
166
		    ln, pos, dat->string);
167
1716
}
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
17884
	dp = mandoc_calloc(1, sizeof(*dp));
175
8942
	dp->line = line;
176
8942
	dp->opts = &tbl->opts;
177
8942
	dp->layout = rp;
178
8942
	dp->prev = tbl->last_span;
179
180
8942
	if (dp->prev == NULL) {
181
2308
		tbl->first_span = dp;
182
2308
		tbl->current_span = NULL;
183
2308
	} else
184
6634
		dp->prev->next = dp;
185
8942
	tbl->last_span = dp;
186
187
8942
	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
11236
	rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
198

19755
	    sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
199
2073
	    sp->layout->next : sp->layout;
200
201
8928
	assert(rp != NULL);
202
203
8928
	if ( ! strcmp(p, "_")) {
204
111
		sp = newspan(tbl, ln, rp);
205
111
		sp->pos = TBL_SPAN_HORIZ;
206
111
		return;
207
8817
	} else if ( ! strcmp(p, "=")) {
208
10
		sp = newspan(tbl, ln, rp);
209
10
		sp->pos = TBL_SPAN_DHORIZ;
210
10
		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
17642
	while (rp->next != NULL) {
220
4555
		if (rp->last->col + 1 < tbl->opts.cols)
221
			break;
222
9832
		for (cp = rp->first; cp != NULL; cp = cp->next)
223

9439
			if (cp->pos != TBL_CELL_HORIZ &&
224
4537
			    cp->pos != TBL_CELL_DHORIZ)
225
				break;
226
4551
		if (cp != NULL)
227
			break;
228
14
		sp = newspan(tbl, ln, rp);
229
14
		sp->pos = TBL_SPAN_DATA;
230
14
		rp = rp->next;
231
	}
232
233
	/* Process a real data row. */
234
235
8807
	sp = newspan(tbl, ln, rp);
236
8807
	sp->pos = TBL_SPAN_DATA;
237
63914
	while (p[pos] != '\0')
238
23150
		getdata(tbl, sp, ln, p, &pos);
239
17735
}