1 /* $Id: tbl.c,v 1.10 2014/04/20 16:44:44 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2011 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 <assert.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <time.h> 23 24 #include "mandoc.h" 25 #include "mandoc_aux.h" 26 #include "libmandoc.h" 27 #include "libroff.h" 28 29 30 enum rofferr 31 tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs) 32 { 33 int len; 34 const char *cp; 35 36 cp = &p[offs]; 37 len = (int)strlen(cp); 38 39 /* 40 * If we're in the options section and we don't have a 41 * terminating semicolon, assume we've moved directly into the 42 * layout section. No need to report a warning: this is, 43 * apparently, standard behaviour. 44 */ 45 46 if (TBL_PART_OPTS == tbl->part && len) 47 if (';' != cp[len - 1]) 48 tbl->part = TBL_PART_LAYOUT; 49 50 /* Now process each logical section of the table. */ 51 52 switch (tbl->part) { 53 case TBL_PART_OPTS: 54 return(tbl_option(tbl, ln, p) ? ROFF_IGN : ROFF_ERR); 55 case TBL_PART_LAYOUT: 56 return(tbl_layout(tbl, ln, p) ? ROFF_IGN : ROFF_ERR); 57 case TBL_PART_CDATA: 58 return(tbl_cdata(tbl, ln, p) ? ROFF_TBL : ROFF_IGN); 59 default: 60 break; 61 } 62 63 /* 64 * This only returns zero if the line is empty, so we ignore it 65 * and continue on. 66 */ 67 return(tbl_data(tbl, ln, p) ? ROFF_TBL : ROFF_IGN); 68 } 69 70 struct tbl_node * 71 tbl_alloc(int pos, int line, struct mparse *parse) 72 { 73 struct tbl_node *tbl; 74 75 tbl = mandoc_calloc(1, sizeof(struct tbl_node)); 76 tbl->line = line; 77 tbl->pos = pos; 78 tbl->parse = parse; 79 tbl->part = TBL_PART_OPTS; 80 tbl->opts.tab = '\t'; 81 tbl->opts.linesize = 12; 82 tbl->opts.decimal = '.'; 83 return(tbl); 84 } 85 86 void 87 tbl_free(struct tbl_node *tbl) 88 { 89 struct tbl_row *rp; 90 struct tbl_cell *cp; 91 struct tbl_span *sp; 92 struct tbl_dat *dp; 93 struct tbl_head *hp; 94 95 while (NULL != (rp = tbl->first_row)) { 96 tbl->first_row = rp->next; 97 while (rp->first) { 98 cp = rp->first; 99 rp->first = cp->next; 100 free(cp); 101 } 102 free(rp); 103 } 104 105 while (NULL != (sp = tbl->first_span)) { 106 tbl->first_span = sp->next; 107 while (sp->first) { 108 dp = sp->first; 109 sp->first = dp->next; 110 if (dp->string) 111 free(dp->string); 112 free(dp); 113 } 114 free(sp); 115 } 116 117 while (NULL != (hp = tbl->first_head)) { 118 tbl->first_head = hp->next; 119 free(hp); 120 } 121 122 free(tbl); 123 } 124 125 void 126 tbl_restart(int line, int pos, struct tbl_node *tbl) 127 { 128 if (TBL_PART_CDATA == tbl->part) 129 mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, 130 tbl->line, tbl->pos, NULL); 131 132 tbl->part = TBL_PART_LAYOUT; 133 tbl->line = line; 134 tbl->pos = pos; 135 136 if (NULL == tbl->first_span || NULL == tbl->first_span->first) 137 mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, 138 tbl->line, tbl->pos, NULL); 139 } 140 141 const struct tbl_span * 142 tbl_span(struct tbl_node *tbl) 143 { 144 struct tbl_span *span; 145 146 assert(tbl); 147 span = tbl->current_span ? tbl->current_span->next 148 : tbl->first_span; 149 if (span) 150 tbl->current_span = span; 151 return(span); 152 } 153 154 void 155 tbl_end(struct tbl_node **tblp) 156 { 157 struct tbl_node *tbl; 158 159 tbl = *tblp; 160 *tblp = NULL; 161 162 if (NULL == tbl->first_span || NULL == tbl->first_span->first) 163 mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, 164 tbl->line, tbl->pos, NULL); 165 166 if (tbl->last_span) 167 tbl->last_span->flags |= TBL_SPAN_LAST; 168 169 if (TBL_PART_CDATA == tbl->part) 170 mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, 171 tbl->line, tbl->pos, NULL); 172 } 173