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