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