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