1 /* $Vendor-Id: tbl_data.c,v 1.15 2011/01/09 23:14:41 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include <assert.h> 22 #include <ctype.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <time.h> 26 27 #include "mandoc.h" 28 #include "libmandoc.h" 29 #include "libroff.h" 30 31 static int data(struct tbl_node *, struct tbl_span *, 32 int, const char *, int *); 33 34 static int 35 data(struct tbl_node *tbl, struct tbl_span *dp, 36 int ln, const char *p, int *pos) 37 { 38 struct tbl_dat *dat; 39 struct tbl_cell *cp; 40 int sv; 41 42 cp = NULL; 43 if (dp->last && dp->last->layout) 44 cp = dp->last->layout->next; 45 else if (NULL == dp->last) 46 cp = dp->layout->first; 47 48 /* 49 * Skip over spanners and vertical lines to data formats, since 50 * we want to match data with data layout cells in the header. 51 */ 52 53 while (cp && (TBL_CELL_VERT == cp->pos || 54 TBL_CELL_DVERT == cp->pos || 55 TBL_CELL_SPAN == cp->pos)) 56 cp = cp->next; 57 58 dat = mandoc_calloc(1, sizeof(struct tbl_dat)); 59 dat->layout = cp; 60 dat->pos = TBL_DATA_NONE; 61 62 if (NULL == dat->layout) 63 TBL_MSG(tbl, MANDOCERR_TBLEXTRADAT, ln, *pos); 64 65 if (dp->last) { 66 dp->last->next = dat; 67 dp->last = dat; 68 } else 69 dp->last = dp->first = dat; 70 71 sv = *pos; 72 while (p[*pos] && p[*pos] != tbl->opts.tab) 73 (*pos)++; 74 75 /* 76 * Check for a continued-data scope opening. This consists of a 77 * trailing `T{' at the end of the line. Subsequent lines, 78 * until a standalone `T}', are included in our cell. 79 */ 80 81 if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) { 82 tbl->part = TBL_PART_CDATA; 83 return(0); 84 } 85 86 dat->string = mandoc_malloc(*pos - sv + 1); 87 memcpy(dat->string, &p[sv], *pos - sv); 88 dat->string[*pos - sv] = '\0'; 89 90 if (p[*pos]) 91 (*pos)++; 92 93 if ( ! strcmp(dat->string, "_")) 94 dat->pos = TBL_DATA_HORIZ; 95 else if ( ! strcmp(dat->string, "=")) 96 dat->pos = TBL_DATA_DHORIZ; 97 else if ( ! strcmp(dat->string, "\\_")) 98 dat->pos = TBL_DATA_NHORIZ; 99 else if ( ! strcmp(dat->string, "\\=")) 100 dat->pos = TBL_DATA_NDHORIZ; 101 else 102 dat->pos = TBL_DATA_DATA; 103 104 if (NULL == dat->layout) 105 return(1); 106 107 if (TBL_CELL_HORIZ == dat->layout->pos || 108 TBL_CELL_DHORIZ == dat->layout->pos) 109 if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string) 110 TBL_MSG(tbl, MANDOCERR_TBLIGNDATA, ln, sv); 111 112 return(1); 113 } 114 115 /* ARGSUSED */ 116 int 117 tbl_cdata(struct tbl_node *tbl, int ln, const char *p) 118 { 119 struct tbl_dat *dat; 120 size_t sz; 121 int pos; 122 123 pos = 0; 124 125 dat = tbl->last_span->last; 126 dat->pos = TBL_DATA_DATA; 127 128 if (p[pos] == 'T' && p[pos + 1] == '}') { 129 pos += 2; 130 if (p[pos] == tbl->opts.tab) { 131 tbl->part = TBL_PART_DATA; 132 pos++; 133 return(data(tbl, tbl->last_span, ln, p, &pos)); 134 } else if ('\0' == p[pos]) { 135 tbl->part = TBL_PART_DATA; 136 return(1); 137 } 138 139 /* Fallthrough: T} is part of a word. */ 140 } 141 142 if (dat->string) { 143 sz = strlen(p) + strlen(dat->string) + 2; 144 dat->string = mandoc_realloc(dat->string, sz); 145 strlcat(dat->string, " ", sz); 146 strlcat(dat->string, p, sz); 147 } else 148 dat->string = mandoc_strdup(p); 149 150 return(0); 151 } 152 153 int 154 tbl_data(struct tbl_node *tbl, int ln, const char *p) 155 { 156 struct tbl_span *dp; 157 struct tbl_row *rp; 158 int pos; 159 160 pos = 0; 161 162 if ('\0' == p[pos]) { 163 TBL_MSG(tbl, MANDOCERR_TBL, ln, pos); 164 return(0); 165 } 166 167 /* 168 * Choose a layout row: take the one following the last parsed 169 * span's. If that doesn't exist, use the last parsed span's. 170 * If there's no last parsed span, use the first row. Lastly, 171 * if the last span was a horizontal line, use the same layout 172 * (it doesn't "consume" the layout). 173 * 174 * In the end, this can be NULL! 175 */ 176 177 if (tbl->last_span) { 178 assert(tbl->last_span->layout); 179 if (tbl->last_span->pos == TBL_SPAN_DATA) 180 rp = tbl->last_span->layout->next; 181 else 182 rp = tbl->last_span->layout; 183 if (NULL == rp) 184 rp = tbl->last_span->layout; 185 } else 186 rp = tbl->first_row; 187 188 dp = mandoc_calloc(1, sizeof(struct tbl_span)); 189 dp->tbl = &tbl->opts; 190 dp->layout = rp; 191 dp->head = tbl->first_head; 192 193 if (tbl->last_span) { 194 tbl->last_span->next = dp; 195 tbl->last_span = dp; 196 } else { 197 tbl->last_span = tbl->first_span = dp; 198 dp->flags |= TBL_SPAN_FIRST; 199 } 200 201 if ( ! strcmp(p, "_")) { 202 dp->pos = TBL_SPAN_HORIZ; 203 return(1); 204 } else if ( ! strcmp(p, "=")) { 205 dp->pos = TBL_SPAN_DHORIZ; 206 return(1); 207 } 208 209 dp->pos = TBL_SPAN_DATA; 210 211 /* This returns 0 when TBL_PART_CDATA is entered. */ 212 213 while ('\0' != p[pos]) 214 if ( ! data(tbl, dp, ln, p, &pos)) 215 return(0); 216 217 return(1); 218 } 219