1 |
|
|
/* $OpenBSD: tbl_data.c,v 1.28 2015/10/06 18:30:44 schwarze Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
4 |
|
|
* Copyright (c) 2011, 2015 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 |
|
|
cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next; |
48 |
|
|
while (cp != NULL && cp->pos == TBL_CELL_SPAN) |
49 |
|
|
cp = cp->next; |
50 |
|
|
|
51 |
|
|
/* |
52 |
|
|
* Stop processing when we reach the end of the available layout |
53 |
|
|
* cells. This means that we have extra input. |
54 |
|
|
*/ |
55 |
|
|
|
56 |
|
|
if (cp == NULL) { |
57 |
|
|
mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse, |
58 |
|
|
ln, *pos, p + *pos); |
59 |
|
|
/* Skip to the end... */ |
60 |
|
|
while (p[*pos]) |
61 |
|
|
(*pos)++; |
62 |
|
|
return; |
63 |
|
|
} |
64 |
|
|
|
65 |
|
|
dat = mandoc_calloc(1, sizeof(*dat)); |
66 |
|
|
dat->layout = cp; |
67 |
|
|
dat->pos = TBL_DATA_NONE; |
68 |
|
|
dat->spans = 0; |
69 |
|
|
for (cp = cp->next; cp != NULL; cp = cp->next) |
70 |
|
|
if (cp->pos == TBL_CELL_SPAN) |
71 |
|
|
dat->spans++; |
72 |
|
|
else |
73 |
|
|
break; |
74 |
|
|
|
75 |
|
|
if (dp->last == NULL) |
76 |
|
|
dp->first = dat; |
77 |
|
|
else |
78 |
|
|
dp->last->next = dat; |
79 |
|
|
dp->last = dat; |
80 |
|
|
|
81 |
|
|
sv = *pos; |
82 |
|
|
while (p[*pos] && p[*pos] != tbl->opts.tab) |
83 |
|
|
(*pos)++; |
84 |
|
|
|
85 |
|
|
/* |
86 |
|
|
* Check for a continued-data scope opening. This consists of a |
87 |
|
|
* trailing `T{' at the end of the line. Subsequent lines, |
88 |
|
|
* until a standalone `T}', are included in our cell. |
89 |
|
|
*/ |
90 |
|
|
|
91 |
|
|
if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') { |
92 |
|
|
tbl->part = TBL_PART_CDATA; |
93 |
|
|
return; |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
dat->string = mandoc_strndup(p + sv, *pos - sv); |
97 |
|
|
|
98 |
|
|
if (p[*pos]) |
99 |
|
|
(*pos)++; |
100 |
|
|
|
101 |
|
|
if ( ! strcmp(dat->string, "_")) |
102 |
|
|
dat->pos = TBL_DATA_HORIZ; |
103 |
|
|
else if ( ! strcmp(dat->string, "=")) |
104 |
|
|
dat->pos = TBL_DATA_DHORIZ; |
105 |
|
|
else if ( ! strcmp(dat->string, "\\_")) |
106 |
|
|
dat->pos = TBL_DATA_NHORIZ; |
107 |
|
|
else if ( ! strcmp(dat->string, "\\=")) |
108 |
|
|
dat->pos = TBL_DATA_NDHORIZ; |
109 |
|
|
else |
110 |
|
|
dat->pos = TBL_DATA_DATA; |
111 |
|
|
|
112 |
|
|
if ((dat->layout->pos == TBL_CELL_HORIZ || |
113 |
|
|
dat->layout->pos == TBL_CELL_DHORIZ || |
114 |
|
|
dat->layout->pos == TBL_CELL_DOWN) && |
115 |
|
|
dat->pos == TBL_DATA_DATA && *dat->string != '\0') |
116 |
|
|
mandoc_msg(MANDOCERR_TBLDATA_SPAN, |
117 |
|
|
tbl->parse, ln, sv, dat->string); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
int |
121 |
|
|
tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos) |
122 |
|
|
{ |
123 |
|
|
struct tbl_dat *dat; |
124 |
|
|
size_t sz; |
125 |
|
|
|
126 |
|
|
dat = tbl->last_span->last; |
127 |
|
|
|
128 |
|
|
if (p[pos] == 'T' && p[pos + 1] == '}') { |
129 |
|
|
pos += 2; |
130 |
|
|
if (p[pos] == tbl->opts.tab) { |
131 |
|
|
tbl->part = TBL_PART_DATA; |
132 |
|
|
pos++; |
133 |
|
|
while (p[pos] != '\0') |
134 |
|
|
getdata(tbl, tbl->last_span, ln, p, &pos); |
135 |
|
|
return 1; |
136 |
|
|
} else if (p[pos] == '\0') { |
137 |
|
|
tbl->part = TBL_PART_DATA; |
138 |
|
|
return 1; |
139 |
|
|
} |
140 |
|
|
|
141 |
|
|
/* Fallthrough: T} is part of a word. */ |
142 |
|
|
} |
143 |
|
|
|
144 |
|
|
dat->pos = TBL_DATA_DATA; |
145 |
|
|
|
146 |
|
|
if (dat->string != NULL) { |
147 |
|
|
sz = strlen(p + pos) + strlen(dat->string) + 2; |
148 |
|
|
dat->string = mandoc_realloc(dat->string, sz); |
149 |
|
|
(void)strlcat(dat->string, " ", sz); |
150 |
|
|
(void)strlcat(dat->string, p + pos, sz); |
151 |
|
|
} else |
152 |
|
|
dat->string = mandoc_strdup(p + pos); |
153 |
|
|
|
154 |
|
|
if (dat->layout->pos == TBL_CELL_DOWN) |
155 |
|
|
mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse, |
156 |
|
|
ln, pos, dat->string); |
157 |
|
|
|
158 |
|
|
return 0; |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
static struct tbl_span * |
162 |
|
|
newspan(struct tbl_node *tbl, int line, struct tbl_row *rp) |
163 |
|
|
{ |
164 |
|
|
struct tbl_span *dp; |
165 |
|
|
|
166 |
|
|
dp = mandoc_calloc(1, sizeof(*dp)); |
167 |
|
|
dp->line = line; |
168 |
|
|
dp->opts = &tbl->opts; |
169 |
|
|
dp->layout = rp; |
170 |
|
|
dp->prev = tbl->last_span; |
171 |
|
|
|
172 |
|
|
if (dp->prev == NULL) { |
173 |
|
|
tbl->first_span = dp; |
174 |
|
|
tbl->current_span = NULL; |
175 |
|
|
} else |
176 |
|
|
dp->prev->next = dp; |
177 |
|
|
tbl->last_span = dp; |
178 |
|
|
|
179 |
|
|
return dp; |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
void |
183 |
|
|
tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos) |
184 |
|
|
{ |
185 |
|
|
struct tbl_span *dp; |
186 |
|
|
struct tbl_row *rp; |
187 |
|
|
|
188 |
|
|
/* |
189 |
|
|
* Choose a layout row: take the one following the last parsed |
190 |
|
|
* span's. If that doesn't exist, use the last parsed span's. |
191 |
|
|
* If there's no last parsed span, use the first row. Lastly, |
192 |
|
|
* if the last span was a horizontal line, use the same layout |
193 |
|
|
* (it doesn't "consume" the layout). |
194 |
|
|
*/ |
195 |
|
|
|
196 |
|
|
if (tbl->last_span != NULL) { |
197 |
|
|
if (tbl->last_span->pos == TBL_SPAN_DATA) { |
198 |
|
|
for (rp = tbl->last_span->layout->next; |
199 |
|
|
rp != NULL && rp->first != NULL; |
200 |
|
|
rp = rp->next) { |
201 |
|
|
switch (rp->first->pos) { |
202 |
|
|
case TBL_CELL_HORIZ: |
203 |
|
|
dp = newspan(tbl, ln, rp); |
204 |
|
|
dp->pos = TBL_SPAN_HORIZ; |
205 |
|
|
continue; |
206 |
|
|
case TBL_CELL_DHORIZ: |
207 |
|
|
dp = newspan(tbl, ln, rp); |
208 |
|
|
dp->pos = TBL_SPAN_DHORIZ; |
209 |
|
|
continue; |
210 |
|
|
default: |
211 |
|
|
break; |
212 |
|
|
} |
213 |
|
|
break; |
214 |
|
|
} |
215 |
|
|
} else |
216 |
|
|
rp = tbl->last_span->layout; |
217 |
|
|
|
218 |
|
|
if (rp == NULL) |
219 |
|
|
rp = tbl->last_span->layout; |
220 |
|
|
} else |
221 |
|
|
rp = tbl->first_row; |
222 |
|
|
|
223 |
|
|
assert(rp); |
224 |
|
|
|
225 |
|
|
dp = newspan(tbl, ln, rp); |
226 |
|
|
|
227 |
|
|
if ( ! strcmp(p, "_")) { |
228 |
|
|
dp->pos = TBL_SPAN_HORIZ; |
229 |
|
|
return; |
230 |
|
|
} else if ( ! strcmp(p, "=")) { |
231 |
|
|
dp->pos = TBL_SPAN_DHORIZ; |
232 |
|
|
return; |
233 |
|
|
} |
234 |
|
|
|
235 |
|
|
dp->pos = TBL_SPAN_DATA; |
236 |
|
|
|
237 |
|
|
while (p[pos] != '\0') |
238 |
|
|
getdata(tbl, dp, ln, p, &pos); |
239 |
|
|
} |