1 /* $Id: tbl.c,v 1.46 2018/12/14 06:33:14 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 <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <time.h> 27 28 #include "mandoc_aux.h" 29 #include "mandoc.h" 30 #include "tbl.h" 31 #include "libmandoc.h" 32 #include "tbl_parse.h" 33 #include "tbl_int.h" 34 35 36 void 37 tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos) 38 { 39 const char *cp; 40 int active; 41 42 /* 43 * In the options section, proceed to the layout section 44 * after a semicolon, or right away if there is no semicolon. 45 * Ignore semicolons in arguments. 46 */ 47 48 if (tbl->part == TBL_PART_OPTS) { 49 tbl->part = TBL_PART_LAYOUT; 50 active = 1; 51 for (cp = p + pos; *cp != '\0'; cp++) { 52 switch (*cp) { 53 case '(': 54 active = 0; 55 continue; 56 case ')': 57 active = 1; 58 continue; 59 case ';': 60 if (active) 61 break; 62 continue; 63 default: 64 continue; 65 } 66 break; 67 } 68 if (*cp == ';') { 69 tbl_option(tbl, ln, p, &pos); 70 if (p[pos] == '\0') 71 return; 72 } 73 } 74 75 /* Process the other section types. */ 76 77 switch (tbl->part) { 78 case TBL_PART_LAYOUT: 79 tbl_layout(tbl, ln, p, pos); 80 break; 81 case TBL_PART_CDATA: 82 tbl_cdata(tbl, ln, p, pos); 83 break; 84 default: 85 tbl_data(tbl, ln, p, pos); 86 break; 87 } 88 } 89 90 struct tbl_node * 91 tbl_alloc(int pos, int line, struct tbl_node *last_tbl) 92 { 93 struct tbl_node *tbl; 94 95 tbl = mandoc_calloc(1, sizeof(*tbl)); 96 if (last_tbl != NULL) 97 last_tbl->next = tbl; 98 tbl->line = line; 99 tbl->pos = pos; 100 tbl->part = TBL_PART_OPTS; 101 tbl->opts.tab = '\t'; 102 tbl->opts.decimal = '.'; 103 return tbl; 104 } 105 106 void 107 tbl_free(struct tbl_node *tbl) 108 { 109 struct tbl_node *old_tbl; 110 struct tbl_row *rp; 111 struct tbl_cell *cp; 112 struct tbl_span *sp; 113 struct tbl_dat *dp; 114 115 while (tbl != NULL) { 116 while ((rp = tbl->first_row) != NULL) { 117 tbl->first_row = rp->next; 118 while (rp->first != NULL) { 119 cp = rp->first; 120 rp->first = cp->next; 121 free(cp->wstr); 122 free(cp); 123 } 124 free(rp); 125 } 126 while ((sp = tbl->first_span) != NULL) { 127 tbl->first_span = sp->next; 128 while (sp->first != NULL) { 129 dp = sp->first; 130 sp->first = dp->next; 131 free(dp->string); 132 free(dp); 133 } 134 free(sp); 135 } 136 old_tbl = tbl; 137 tbl = tbl->next; 138 free(old_tbl); 139 } 140 } 141 142 void 143 tbl_restart(int line, int pos, struct tbl_node *tbl) 144 { 145 if (tbl->part == TBL_PART_CDATA) 146 mandoc_msg(MANDOCERR_TBLDATA_BLK, line, pos, "T&"); 147 148 tbl->part = TBL_PART_LAYOUT; 149 tbl->line = line; 150 tbl->pos = pos; 151 } 152 153 struct tbl_span * 154 tbl_span(struct tbl_node *tbl) 155 { 156 struct tbl_span *span; 157 158 span = tbl->current_span ? tbl->current_span->next 159 : tbl->first_span; 160 if (span != NULL) 161 tbl->current_span = span; 162 return span; 163 } 164 165 int 166 tbl_end(struct tbl_node *tbl, int still_open) 167 { 168 struct tbl_span *sp; 169 170 if (still_open) 171 mandoc_msg(MANDOCERR_BLK_NOEND, tbl->line, tbl->pos, "TS"); 172 else if (tbl->part == TBL_PART_CDATA) 173 mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->line, tbl->pos, "TE"); 174 175 sp = tbl->first_span; 176 while (sp != NULL && sp->first == NULL) 177 sp = sp->next; 178 if (sp == NULL) { 179 mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->line, tbl->pos, NULL); 180 return 0; 181 } 182 return 1; 183 } 184