aboutsummaryrefslogtreecommitdiff
path: root/tbl_data.c
diff options
context:
space:
mode:
authorUlrich Spörlein <uqs@FreeBSD.org>2012-10-18 09:55:16 +0000
committerUlrich Spörlein <uqs@FreeBSD.org>2012-10-18 09:55:16 +0000
commit211d2d512b87f4d2be8961b75432e4f0d5206c9a (patch)
tree314af9fcc18a8f8023bbb995dd9ef62bad563089 /tbl_data.c
downloadsrc-211d2d512b87f4d2be8961b75432e4f0d5206c9a.tar.gz
src-211d2d512b87f4d2be8961b75432e4f0d5206c9a.zip
Notes
Diffstat (limited to 'tbl_data.c')
-rw-r--r--tbl_data.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/tbl_data.c b/tbl_data.c
new file mode 100644
index 000000000000..129695d8bb96
--- /dev/null
+++ b/tbl_data.c
@@ -0,0 +1,276 @@
+/* $Id: tbl_data.c,v 1.24 2011/03/20 16:02:05 kristaps Exp $ */
+/*
+ * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "mandoc.h"
+#include "libmandoc.h"
+#include "libroff.h"
+
+static int data(struct tbl_node *, struct tbl_span *,
+ int, const char *, int *);
+static struct tbl_span *newspan(struct tbl_node *, int,
+ struct tbl_row *);
+
+static int
+data(struct tbl_node *tbl, struct tbl_span *dp,
+ int ln, const char *p, int *pos)
+{
+ struct tbl_dat *dat;
+ struct tbl_cell *cp;
+ int sv, spans;
+
+ cp = NULL;
+ if (dp->last && dp->last->layout)
+ cp = dp->last->layout->next;
+ else if (NULL == dp->last)
+ cp = dp->layout->first;
+
+ /*
+ * Skip over spanners and vertical lines to data formats, since
+ * we want to match data with data layout cells in the header.
+ */
+
+ while (cp && (TBL_CELL_VERT == cp->pos ||
+ TBL_CELL_DVERT == cp->pos ||
+ TBL_CELL_SPAN == cp->pos))
+ cp = cp->next;
+
+ /*
+ * Stop processing when we reach the end of the available layout
+ * cells. This means that we have extra input.
+ */
+
+ if (NULL == cp) {
+ mandoc_msg(MANDOCERR_TBLEXTRADAT,
+ tbl->parse, ln, *pos, NULL);
+ /* Skip to the end... */
+ while (p[*pos])
+ (*pos)++;
+ return(1);
+ }
+
+ dat = mandoc_calloc(1, sizeof(struct tbl_dat));
+ dat->layout = cp;
+ dat->pos = TBL_DATA_NONE;
+
+ assert(TBL_CELL_SPAN != cp->pos);
+
+ for (spans = 0, cp = cp->next; cp; cp = cp->next)
+ if (TBL_CELL_SPAN == cp->pos)
+ spans++;
+ else
+ break;
+
+ dat->spans = spans;
+
+ if (dp->last) {
+ dp->last->next = dat;
+ dp->last = dat;
+ } else
+ dp->last = dp->first = dat;
+
+ 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);
+ }
+
+ assert(*pos - sv >= 0);
+
+ dat->string = mandoc_malloc((size_t)(*pos - sv + 1));
+ memcpy(dat->string, &p[sv], (size_t)(*pos - sv));
+ dat->string[*pos - sv] = '\0';
+
+ if (p[*pos])
+ (*pos)++;
+
+ if ( ! strcmp(dat->string, "_"))
+ dat->pos = TBL_DATA_HORIZ;
+ else if ( ! strcmp(dat->string, "="))
+ dat->pos = TBL_DATA_DHORIZ;
+ else if ( ! strcmp(dat->string, "\\_"))
+ dat->pos = TBL_DATA_NHORIZ;
+ else if ( ! strcmp(dat->string, "\\="))
+ dat->pos = TBL_DATA_NDHORIZ;
+ else
+ dat->pos = TBL_DATA_DATA;
+
+ if (TBL_CELL_HORIZ == dat->layout->pos ||
+ TBL_CELL_DHORIZ == dat->layout->pos ||
+ TBL_CELL_DOWN == dat->layout->pos)
+ if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string)
+ mandoc_msg(MANDOCERR_TBLIGNDATA,
+ tbl->parse, ln, sv, NULL);
+
+ return(1);
+}
+
+/* ARGSUSED */
+int
+tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
+{
+ struct tbl_dat *dat;
+ size_t sz;
+ int pos;
+
+ pos = 0;
+
+ dat = tbl->last_span->last;
+
+ if (p[pos] == 'T' && p[pos + 1] == '}') {
+ pos += 2;
+ if (p[pos] == tbl->opts.tab) {
+ tbl->part = TBL_PART_DATA;
+ pos++;
+ return(data(tbl, tbl->last_span, ln, p, &pos));
+ } else if ('\0' == p[pos]) {
+ tbl->part = TBL_PART_DATA;
+ return(1);
+ }
+
+ /* Fallthrough: T} is part of a word. */
+ }
+
+ 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);
+
+ if (TBL_CELL_DOWN == dat->layout->pos)
+ mandoc_msg(MANDOCERR_TBLIGNDATA,
+ tbl->parse, ln, pos, NULL);
+
+ return(0);
+}
+
+static struct tbl_span *
+newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
+{
+ struct tbl_span *dp;
+
+ dp = mandoc_calloc(1, sizeof(struct tbl_span));
+ dp->line = line;
+ 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;
+ tbl->current_span = NULL;
+ dp->flags |= TBL_SPAN_FIRST;
+ }
+
+ return(dp);
+}
+
+int
+tbl_data(struct tbl_node *tbl, int ln, const char *p)
+{
+ struct tbl_span *dp;
+ struct tbl_row *rp;
+ int pos;
+
+ pos = 0;
+
+ if ('\0' == p[pos]) {
+ mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, pos, NULL);
+ 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. Lastly,
+ * if the last span was a horizontal line, use the same layout
+ * (it doesn't "consume" the layout).
+ */
+
+ if (tbl->last_span) {
+ assert(tbl->last_span->layout);
+ if (tbl->last_span->pos == TBL_SPAN_DATA) {
+ for (rp = tbl->last_span->layout->next;
+ rp && rp->first; rp = rp->next) {
+ switch (rp->first->pos) {
+ case (TBL_CELL_HORIZ):
+ dp = newspan(tbl, ln, rp);
+ dp->pos = TBL_SPAN_HORIZ;
+ continue;
+ case (TBL_CELL_DHORIZ):
+ dp = newspan(tbl, ln, rp);
+ dp->pos = TBL_SPAN_DHORIZ;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ } else
+ rp = tbl->last_span->layout;
+
+ if (NULL == rp)
+ rp = tbl->last_span->layout;
+ } else
+ rp = tbl->first_row;
+
+ assert(rp);
+
+ dp = newspan(tbl, ln, rp);
+
+ if ( ! strcmp(p, "_")) {
+ dp->pos = TBL_SPAN_HORIZ;
+ return(1);
+ } else if ( ! strcmp(p, "=")) {
+ dp->pos = TBL_SPAN_DHORIZ;
+ return(1);
+ }
+
+ dp->pos = TBL_SPAN_DATA;
+
+ /* This returns 0 when TBL_PART_CDATA is entered. */
+
+ while ('\0' != p[pos])
+ if ( ! data(tbl, dp, ln, p, &pos))
+ return(0);
+
+ return(1);
+}