version 1.3, 2010/10/15 23:19:40 |
version 1.4, 2011/01/04 22:28:17 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> |
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
#include <sys/queue.h> |
|
#include <sys/types.h> |
|
|
|
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
#include <time.h> |
|
|
#include "out.h" |
#include "mandoc.h" |
#include "term.h" |
#include "libmandoc.h" |
#include "tbl_extern.h" |
#include "libroff.h" |
|
|
/* FIXME: warn about losing data contents if cell is HORIZ. */ |
static int data(struct tbl_node *, struct tbl_span *, |
|
int, const char *, int *); |
|
|
static int data(struct tbl *, struct tbl_span *, |
static int |
const char *, int, int, |
data(struct tbl_node *tbl, struct tbl_span *dp, |
const char *, int, int); |
int ln, const char *p, int *pos) |
|
{ |
|
struct tbl_dat *dat; |
|
struct tbl_cell *cp; |
|
int sv; |
|
|
|
cp = NULL; |
|
if (dp->last && dp->last->layout) |
|
cp = dp->last->layout->next; |
|
else if (NULL == dp->last) |
|
cp = dp->layout->first; |
|
|
int |
/* Skip over spanners to data formats. */ |
data(struct tbl *tbl, struct tbl_span *dp, |
|
const char *f, int ln, int pos, |
|
const char *p, int start, int end) |
|
{ |
|
struct tbl_data *dat; |
|
|
|
if (NULL == (dat = tbl_data_alloc(dp))) |
while (cp && (TBL_CELL_VERT == cp->pos || |
return(0); |
TBL_CELL_DVERT == cp->pos)) |
|
cp = cp->next; |
|
|
if (NULL == dat->cell) |
dat = mandoc_calloc(1, sizeof(struct tbl_dat)); |
if ( ! tbl_warnx(tbl, ERR_SYNTAX, f, ln, pos)) |
dat->layout = cp; |
return(0); |
dat->pos = TBL_DATA_NONE; |
|
|
assert(end >= start); |
if (NULL == dat->layout) |
if (NULL == (dat->string = malloc((size_t)(end - start + 1)))) |
TBL_MSG(tbl, MANDOCERR_TBLEXTRADAT, ln, *pos); |
return(tbl_err(tbl)); |
|
|
|
(void)memcpy(dat->string, &p[start], (size_t)(end - start)); |
if (dp->last) { |
dat->string[end - start] = 0; |
dp->last->next = dat; |
|
dp->last = dat; |
|
} else |
|
dp->last = dp->first = dat; |
|
|
/* XXX: do the strcmps, then malloc(). */ |
sv = *pos; |
|
while (p[*pos] && p[*pos] != tbl->opts.tab) |
|
(*pos)++; |
|
|
|
/* |
|
* Check for a continued-data scope opening. This consists of a |
|
* trailing `T{' at the end of the line. Subsequent lines, |
|
* until a standalone `T}', are included in our cell. |
|
*/ |
|
|
|
if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) { |
|
tbl->part = TBL_PART_CDATA; |
|
return(0); |
|
} |
|
|
|
dat->string = mandoc_malloc(*pos - sv + 1); |
|
memcpy(dat->string, &p[sv], *pos - sv); |
|
dat->string[*pos - sv] = '\0'; |
|
|
|
if (p[*pos]) |
|
(*pos)++; |
|
|
if ( ! strcmp(dat->string, "_")) |
if ( ! strcmp(dat->string, "_")) |
dat->flags |= TBL_DATA_HORIZ; |
dat->pos = TBL_DATA_HORIZ; |
else if ( ! strcmp(dat->string, "=")) |
else if ( ! strcmp(dat->string, "=")) |
dat->flags |= TBL_DATA_DHORIZ; |
dat->pos = TBL_DATA_DHORIZ; |
else if ( ! strcmp(dat->string, "\\_")) |
else if ( ! strcmp(dat->string, "\\_")) |
dat->flags |= TBL_DATA_NHORIZ; |
dat->pos = TBL_DATA_NHORIZ; |
else if ( ! strcmp(dat->string, "\\=")) |
else if ( ! strcmp(dat->string, "\\=")) |
dat->flags |= TBL_DATA_NDHORIZ; |
dat->pos = TBL_DATA_NDHORIZ; |
else |
else |
|
dat->pos = TBL_DATA_DATA; |
|
|
|
if (NULL == dat->layout) |
return(1); |
return(1); |
|
|
free(dat->string); |
if (TBL_CELL_HORIZ == dat->layout->pos || |
dat->string = NULL; |
TBL_CELL_DHORIZ == dat->layout->pos) |
|
if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string) |
|
TBL_MSG(tbl, MANDOCERR_TBLIGNDATA, ln, sv); |
|
|
return(1); |
return(1); |
} |
} |
|
|
|
int |
|
tbl_cdata(struct tbl_node *tbl, int ln, const char *p) |
|
{ |
|
struct tbl_dat *dat; |
|
size_t sz; |
|
|
|
if (0 == strcmp(p, "T}")) { |
|
tbl->part = TBL_PART_DATA; |
|
return(1); |
|
} |
|
|
|
dat = tbl->last_span->last; |
|
dat->pos = TBL_DATA_DATA; |
|
|
|
if (dat->string) { |
|
sz = strlen(p) + strlen(dat->string) + 2; |
|
dat->string = mandoc_realloc(dat->string, sz); |
|
strlcat(dat->string, " ", sz); |
|
strlcat(dat->string, p, sz); |
|
} else |
|
dat->string = mandoc_strdup(p); |
|
|
|
return(0); |
|
} |
|
|
int |
int |
tbl_data(struct tbl *tbl, const char *f, int ln, const char *p) |
tbl_data(struct tbl_node *tbl, int ln, const char *p) |
{ |
{ |
struct tbl_span *dp; |
struct tbl_span *dp; |
int i, j; |
struct tbl_row *rp; |
|
int pos; |
|
|
if ('.' == p[0] && ! isdigit((u_char)p[1])) { |
pos = 0; |
/* Comment lines end up here with just a dot. */ |
|
if ('\0' == p[1]) |
|
return(1); |
|
/* |
|
* XXX: departs from tbl convention in that we disallow |
|
* macros in the data body. |
|
*/ |
|
if (strncasecmp(p, ".T&", 3)) |
|
return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0)); |
|
return(tbl_data_close(tbl, f, ln)); |
|
} |
|
|
|
if (NULL == (dp = tbl_span_alloc(tbl))) |
if ('\0' == p[pos]) { |
|
TBL_MSG(tbl, MANDOCERR_TBL, ln, pos); |
return(0); |
return(0); |
|
} |
|
|
|
/* |
|
* Choose a layout row: take the one following the last parsed |
|
* span's. If that doesn't exist, use the last parsed span's. |
|
* If there's no last parsed span, use the first row. This can |
|
* be NULL! |
|
*/ |
|
|
|
if (tbl->last_span) { |
|
assert(tbl->last_span->layout); |
|
rp = tbl->last_span->layout->next; |
|
if (NULL == rp) |
|
rp = tbl->last_span->layout; |
|
} else |
|
rp = tbl->first_row; |
|
|
|
dp = mandoc_calloc(1, sizeof(struct tbl_span)); |
|
dp->tbl = &tbl->opts; |
|
dp->layout = rp; |
|
dp->head = tbl->first_head; |
|
|
|
if (tbl->last_span) { |
|
tbl->last_span->next = dp; |
|
tbl->last_span = dp; |
|
} else { |
|
tbl->last_span = tbl->first_span = dp; |
|
dp->flags |= TBL_SPAN_FIRST; |
|
} |
|
|
if ( ! strcmp(p, "_")) { |
if ( ! strcmp(p, "_")) { |
dp->flags |= TBL_SPAN_HORIZ; |
dp->pos = TBL_SPAN_HORIZ; |
return(1); |
return(1); |
} else if ( ! strcmp(p, "=")) { |
} else if ( ! strcmp(p, "=")) { |
dp->flags |= TBL_SPAN_DHORIZ; |
dp->pos = TBL_SPAN_DHORIZ; |
return(1); |
return(1); |
} |
} |
|
|
for (j = i = 0; p[i]; i++) { |
dp->pos = TBL_SPAN_DATA; |
if (p[i] != tbl->tab) |
|
continue; |
|
if ( ! data(tbl, dp, f, ln, i, p, j, i)) |
|
return(0); |
|
j = i + 1; |
|
} |
|
|
|
return(data(tbl, dp, f, ln, i, p, j, i)); |
/* This returns 0 when TBL_PART_CDATA is entered. */ |
} |
|
|
|
|
while ('\0' != p[pos]) |
|
if ( ! data(tbl, dp, ln, p, &pos)) |
|
return(0); |
|
|
int |
|
tbl_data_close(struct tbl *tbl, const char *f, int ln) |
|
{ |
|
struct tbl_span *span; |
|
|
|
/* LINTED */ |
|
span = TAILQ_LAST(&tbl->span, tbl_spanh); |
|
if (NULL == span) |
|
return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0)); |
|
if (TAILQ_NEXT(span->row, entries)) |
|
return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0)); |
|
|
|
tbl->part = TBL_PART_LAYOUT; |
|
return(1); |
return(1); |
} |
} |