Annotation of src/usr.bin/mandoc/tbl_data.c, Revision 1.32
1.32 ! schwarze 1: /* $OpenBSD: tbl_data.c,v 1.31 2017/07/04 20:59:17 schwarze Exp $ */
1.1 schwarze 2: /*
1.4 schwarze 3: * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.29 schwarze 4: * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 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: */
1.19 schwarze 18: #include <sys/types.h>
19:
1.1 schwarze 20: #include <assert.h>
21: #include <ctype.h>
22: #include <stdlib.h>
23: #include <string.h>
1.4 schwarze 24: #include <time.h>
1.1 schwarze 25:
1.4 schwarze 26: #include "mandoc.h"
1.16 schwarze 27: #include "mandoc_aux.h"
1.4 schwarze 28: #include "libmandoc.h"
29: #include "libroff.h"
30:
1.20 schwarze 31: static void getdata(struct tbl_node *, struct tbl_span *,
1.9 schwarze 32: int, const char *, int *);
1.17 schwarze 33: static struct tbl_span *newspan(struct tbl_node *, int,
1.9 schwarze 34: struct tbl_row *);
1.4 schwarze 35:
1.17 schwarze 36:
1.20 schwarze 37: static void
1.17 schwarze 38: getdata(struct tbl_node *tbl, struct tbl_span *dp,
1.4 schwarze 39: int ln, const char *p, int *pos)
1.1 schwarze 40: {
1.4 schwarze 41: struct tbl_dat *dat;
42: struct tbl_cell *cp;
1.24 schwarze 43: int sv;
1.4 schwarze 44:
1.25 schwarze 45: /* Advance to the next layout cell, skipping spanners. */
46:
1.24 schwarze 47: cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
48: while (cp != NULL && cp->pos == TBL_CELL_SPAN)
1.4 schwarze 49: cp = cp->next;
50:
1.6 schwarze 51: /*
1.30 schwarze 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.
1.6 schwarze 56: */
57:
1.24 schwarze 58: if (cp == NULL) {
1.30 schwarze 59: if (dp->layout->last->col + 1 < dp->opts->cols) {
60: cp = mandoc_calloc(1, sizeof(*cp));
61: cp->pos = TBL_CELL_LEFT;
62: dp->layout->last->next = cp;
63: cp->col = dp->layout->last->col + 1;
64: dp->layout->last = cp;
65: } else {
66: mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
67: ln, *pos, p + *pos);
68: while (p[*pos])
69: (*pos)++;
70: return;
71: }
1.6 schwarze 72: }
73:
1.24 schwarze 74: dat = mandoc_calloc(1, sizeof(*dat));
1.4 schwarze 75: dat->layout = cp;
76: dat->pos = TBL_DATA_NONE;
1.24 schwarze 77: dat->spans = 0;
78: for (cp = cp->next; cp != NULL; cp = cp->next)
79: if (cp->pos == TBL_CELL_SPAN)
80: dat->spans++;
1.6 schwarze 81: else
82: break;
1.17 schwarze 83:
1.24 schwarze 84: if (dp->last == NULL)
85: dp->first = dat;
86: else
1.4 schwarze 87: dp->last->next = dat;
1.24 schwarze 88: dp->last = dat;
1.4 schwarze 89:
90: sv = *pos;
91: while (p[*pos] && p[*pos] != tbl->opts.tab)
92: (*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: */
1.1 schwarze 99:
1.24 schwarze 100: if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
1.4 schwarze 101: tbl->part = TBL_PART_CDATA;
1.20 schwarze 102: return;
1.4 schwarze 103: }
1.1 schwarze 104:
1.24 schwarze 105: dat->string = mandoc_strndup(p + sv, *pos - sv);
1.1 schwarze 106:
1.4 schwarze 107: if (p[*pos])
108: (*pos)++;
1.1 schwarze 109:
110: if ( ! strcmp(dat->string, "_"))
1.4 schwarze 111: dat->pos = TBL_DATA_HORIZ;
1.1 schwarze 112: else if ( ! strcmp(dat->string, "="))
1.4 schwarze 113: dat->pos = TBL_DATA_DHORIZ;
1.1 schwarze 114: else if ( ! strcmp(dat->string, "\\_"))
1.4 schwarze 115: dat->pos = TBL_DATA_NHORIZ;
1.1 schwarze 116: else if ( ! strcmp(dat->string, "\\="))
1.4 schwarze 117: dat->pos = TBL_DATA_NDHORIZ;
1.1 schwarze 118: else
1.4 schwarze 119: dat->pos = TBL_DATA_DATA;
120:
1.24 schwarze 121: if ((dat->layout->pos == TBL_CELL_HORIZ ||
122: dat->layout->pos == TBL_CELL_DHORIZ ||
123: dat->layout->pos == TBL_CELL_DOWN) &&
124: dat->pos == TBL_DATA_DATA && *dat->string != '\0')
125: mandoc_msg(MANDOCERR_TBLDATA_SPAN,
126: tbl->parse, ln, sv, dat->string);
1.1 schwarze 127: }
128:
1.32 ! schwarze 129: void
1.22 schwarze 130: tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
1.4 schwarze 131: {
132: struct tbl_dat *dat;
1.17 schwarze 133: size_t sz;
1.4 schwarze 134:
135: dat = tbl->last_span->last;
1.5 schwarze 136:
137: if (p[pos] == 'T' && p[pos + 1] == '}') {
138: pos += 2;
139: if (p[pos] == tbl->opts.tab) {
140: tbl->part = TBL_PART_DATA;
141: pos++;
1.27 schwarze 142: while (p[pos] != '\0')
143: getdata(tbl, tbl->last_span, ln, p, &pos);
1.32 ! schwarze 144: return;
1.24 schwarze 145: } else if (p[pos] == '\0') {
1.5 schwarze 146: tbl->part = TBL_PART_DATA;
1.32 ! schwarze 147: return;
1.5 schwarze 148: }
149:
150: /* Fallthrough: T} is part of a word. */
151: }
1.4 schwarze 152:
1.6 schwarze 153: dat->pos = TBL_DATA_DATA;
1.29 schwarze 154: dat->block = 1;
1.6 schwarze 155:
1.24 schwarze 156: if (dat->string != NULL) {
1.23 schwarze 157: sz = strlen(p + pos) + strlen(dat->string) + 2;
1.4 schwarze 158: dat->string = mandoc_realloc(dat->string, sz);
1.18 schwarze 159: (void)strlcat(dat->string, " ", sz);
1.23 schwarze 160: (void)strlcat(dat->string, p + pos, sz);
1.4 schwarze 161: } else
1.23 schwarze 162: dat->string = mandoc_strdup(p + pos);
1.4 schwarze 163:
1.24 schwarze 164: if (dat->layout->pos == TBL_CELL_DOWN)
1.23 schwarze 165: mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
166: ln, pos, dat->string);
1.4 schwarze 167: }
1.1 schwarze 168:
1.7 schwarze 169: static struct tbl_span *
1.9 schwarze 170: newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
1.7 schwarze 171: {
172: struct tbl_span *dp;
173:
1.24 schwarze 174: dp = mandoc_calloc(1, sizeof(*dp));
1.9 schwarze 175: dp->line = line;
1.13 schwarze 176: dp->opts = &tbl->opts;
1.7 schwarze 177: dp->layout = rp;
1.21 schwarze 178: dp->prev = tbl->last_span;
1.7 schwarze 179:
1.21 schwarze 180: if (dp->prev == NULL) {
181: tbl->first_span = dp;
1.8 schwarze 182: tbl->current_span = NULL;
1.21 schwarze 183: } else
184: dp->prev->next = dp;
185: tbl->last_span = dp;
1.7 schwarze 186:
1.28 schwarze 187: return dp;
1.7 schwarze 188: }
189:
1.20 schwarze 190: void
1.22 schwarze 191: tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
1.1 schwarze 192: {
1.4 schwarze 193: struct tbl_row *rp;
1.30 schwarze 194: struct tbl_cell *cp;
1.31 schwarze 195: struct tbl_span *sp;
1.4 schwarze 196:
1.30 schwarze 197: rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
198: sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
199: sp->layout->next : sp->layout;
1.6 schwarze 200:
1.30 schwarze 201: assert(rp != NULL);
1.4 schwarze 202:
1.1 schwarze 203: if ( ! strcmp(p, "_")) {
1.31 schwarze 204: sp = newspan(tbl, ln, rp);
1.30 schwarze 205: sp->pos = TBL_SPAN_HORIZ;
1.20 schwarze 206: return;
1.1 schwarze 207: } else if ( ! strcmp(p, "=")) {
1.31 schwarze 208: sp = newspan(tbl, ln, rp);
1.30 schwarze 209: sp->pos = TBL_SPAN_DHORIZ;
1.20 schwarze 210: return;
1.1 schwarze 211: }
1.30 schwarze 212:
213: /*
1.31 schwarze 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.
1.30 schwarze 217: */
218:
1.31 schwarze 219: while (rp->next != NULL) {
220: if (rp->last->col + 1 < tbl->opts.cols)
221: break;
222: for (cp = rp->first; cp != NULL; cp = cp->next)
223: if (cp->pos != TBL_CELL_HORIZ &&
224: cp->pos != TBL_CELL_DHORIZ)
225: break;
226: if (cp != NULL)
227: break;
228: sp = newspan(tbl, ln, rp);
229: sp->pos = TBL_SPAN_DATA;
230: rp = rp->next;
1.30 schwarze 231: }
1.1 schwarze 232:
1.31 schwarze 233: /* Process a real data row. */
1.1 schwarze 234:
1.31 schwarze 235: sp = newspan(tbl, ln, rp);
236: sp->pos = TBL_SPAN_DATA;
237: while (p[pos] != '\0')
238: getdata(tbl, sp, ln, p, &pos);
1.1 schwarze 239: }