1 /* Id: tbl_data.c,v 1.28 2014/01/05 18:37:53 joerg Exp */
3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
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.
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.
29 #include "libmandoc.h"
32 static int getdata(struct tbl_node
*, struct tbl_span
*,
33 int, const char *, int *);
34 static struct tbl_span
*newspan(struct tbl_node
*, int,
38 getdata(struct tbl_node
*tbl
, struct tbl_span
*dp
,
39 int ln
, const char *p
, int *pos
)
46 if (dp
->last
&& dp
->last
->layout
)
47 cp
= dp
->last
->layout
->next
;
48 else if (NULL
== dp
->last
)
49 cp
= dp
->layout
->first
;
52 * Skip over spanners, since
53 * we want to match data with data layout cells in the header.
56 while (cp
&& TBL_CELL_SPAN
== cp
->pos
)
60 * Stop processing when we reach the end of the available layout
61 * cells. This means that we have extra input.
65 mandoc_msg(MANDOCERR_TBLEXTRADAT
,
66 tbl
->parse
, ln
, *pos
, NULL
);
67 /* Skip to the end... */
73 dat
= mandoc_calloc(1, sizeof(struct tbl_dat
));
75 dat
->pos
= TBL_DATA_NONE
;
77 assert(TBL_CELL_SPAN
!= cp
->pos
);
79 for (spans
= 0, cp
= cp
->next
; cp
; cp
= cp
->next
)
80 if (TBL_CELL_SPAN
== cp
->pos
)
91 dp
->last
= dp
->first
= dat
;
94 while (p
[*pos
] && p
[*pos
] != tbl
->opts
.tab
)
98 * Check for a continued-data scope opening. This consists of a
99 * trailing `T{' at the end of the line. Subsequent lines,
100 * until a standalone `T}', are included in our cell.
103 if (*pos
- sv
== 2 && 'T' == p
[sv
] && '{' == p
[sv
+ 1]) {
104 tbl
->part
= TBL_PART_CDATA
;
108 assert(*pos
- sv
>= 0);
110 dat
->string
= mandoc_malloc((size_t)(*pos
- sv
+ 1));
111 memcpy(dat
->string
, &p
[sv
], (size_t)(*pos
- sv
));
112 dat
->string
[*pos
- sv
] = '\0';
117 if ( ! strcmp(dat
->string
, "_"))
118 dat
->pos
= TBL_DATA_HORIZ
;
119 else if ( ! strcmp(dat
->string
, "="))
120 dat
->pos
= TBL_DATA_DHORIZ
;
121 else if ( ! strcmp(dat
->string
, "\\_"))
122 dat
->pos
= TBL_DATA_NHORIZ
;
123 else if ( ! strcmp(dat
->string
, "\\="))
124 dat
->pos
= TBL_DATA_NDHORIZ
;
126 dat
->pos
= TBL_DATA_DATA
;
128 if (TBL_CELL_HORIZ
== dat
->layout
->pos
||
129 TBL_CELL_DHORIZ
== dat
->layout
->pos
||
130 TBL_CELL_DOWN
== dat
->layout
->pos
)
131 if (TBL_DATA_DATA
== dat
->pos
&& '\0' != *dat
->string
)
132 mandoc_msg(MANDOCERR_TBLIGNDATA
,
133 tbl
->parse
, ln
, sv
, NULL
);
140 tbl_cdata(struct tbl_node
*tbl
, int ln
, const char *p
)
148 dat
= tbl
->last_span
->last
;
150 if (p
[pos
] == 'T' && p
[pos
+ 1] == '}') {
152 if (p
[pos
] == tbl
->opts
.tab
) {
153 tbl
->part
= TBL_PART_DATA
;
155 return(getdata(tbl
, tbl
->last_span
, ln
, p
, &pos
));
156 } else if ('\0' == p
[pos
]) {
157 tbl
->part
= TBL_PART_DATA
;
161 /* Fallthrough: T} is part of a word. */
164 dat
->pos
= TBL_DATA_DATA
;
167 sz
= strlen(p
) + strlen(dat
->string
) + 2;
168 dat
->string
= mandoc_realloc(dat
->string
, sz
);
169 strlcat(dat
->string
, " ", sz
);
170 strlcat(dat
->string
, p
, sz
);
172 dat
->string
= mandoc_strdup(p
);
174 if (TBL_CELL_DOWN
== dat
->layout
->pos
)
175 mandoc_msg(MANDOCERR_TBLIGNDATA
,
176 tbl
->parse
, ln
, pos
, NULL
);
181 static struct tbl_span
*
182 newspan(struct tbl_node
*tbl
, int line
, struct tbl_row
*rp
)
186 dp
= mandoc_calloc(1, sizeof(struct tbl_span
));
188 dp
->opts
= &tbl
->opts
;
190 dp
->head
= tbl
->first_head
;
192 if (tbl
->last_span
) {
193 tbl
->last_span
->next
= dp
;
196 tbl
->last_span
= tbl
->first_span
= dp
;
197 tbl
->current_span
= NULL
;
198 dp
->flags
|= TBL_SPAN_FIRST
;
205 tbl_data(struct tbl_node
*tbl
, int ln
, const char *p
)
213 if ('\0' == p
[pos
]) {
214 mandoc_msg(MANDOCERR_TBL
, tbl
->parse
, ln
, pos
, NULL
);
219 * Choose a layout row: take the one following the last parsed
220 * span's. If that doesn't exist, use the last parsed span's.
221 * If there's no last parsed span, use the first row. Lastly,
222 * if the last span was a horizontal line, use the same layout
223 * (it doesn't "consume" the layout).
226 if (tbl
->last_span
) {
227 assert(tbl
->last_span
->layout
);
228 if (tbl
->last_span
->pos
== TBL_SPAN_DATA
) {
229 for (rp
= tbl
->last_span
->layout
->next
;
230 rp
&& rp
->first
; rp
= rp
->next
) {
231 switch (rp
->first
->pos
) {
232 case (TBL_CELL_HORIZ
):
233 dp
= newspan(tbl
, ln
, rp
);
234 dp
->pos
= TBL_SPAN_HORIZ
;
236 case (TBL_CELL_DHORIZ
):
237 dp
= newspan(tbl
, ln
, rp
);
238 dp
->pos
= TBL_SPAN_DHORIZ
;
246 rp
= tbl
->last_span
->layout
;
249 rp
= tbl
->last_span
->layout
;
255 dp
= newspan(tbl
, ln
, rp
);
257 if ( ! strcmp(p
, "_")) {
258 dp
->pos
= TBL_SPAN_HORIZ
;
260 } else if ( ! strcmp(p
, "=")) {
261 dp
->pos
= TBL_SPAN_DHORIZ
;
265 dp
->pos
= TBL_SPAN_DATA
;
267 /* This returns 0 when TBL_PART_CDATA is entered. */
269 while ('\0' != p
[pos
])
270 if ( ! getdata(tbl
, dp
, ln
, p
, &pos
))