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