1 /* $Vendor-Id: tbl.c,v 1.21 2011/01/04 15:02:00 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <assert.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <time.h> 22 23 #include "mandoc.h" 24 #include "roff.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, void *data, const mandocmsg msg) 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->data = data; 77 p->msg = msg; 78 p->part = TBL_PART_OPTS; 79 p->opts.tab = '\t'; 80 p->opts.linesize = 12; 81 p->opts.decimal = '.'; 82 return(p); 83 } 84 85 void 86 tbl_free(struct tbl_node *p) 87 { 88 struct tbl_row *rp; 89 struct tbl_cell *cp; 90 struct tbl_span *sp; 91 struct tbl_dat *dp; 92 struct tbl_head *hp; 93 94 while (NULL != (rp = p->first_row)) { 95 p->first_row = rp->next; 96 while (rp->first) { 97 cp = rp->first; 98 rp->first = cp->next; 99 free(cp); 100 } 101 free(rp); 102 } 103 104 while (NULL != (sp = p->first_span)) { 105 p->first_span = sp->next; 106 while (sp->first) { 107 dp = sp->first; 108 sp->first = dp->next; 109 if (dp->string) 110 free(dp->string); 111 free(dp); 112 } 113 free(sp); 114 } 115 116 while (NULL != (hp = p->first_head)) { 117 p->first_head = hp->next; 118 free(hp); 119 } 120 121 free(p); 122 } 123 124 void 125 tbl_restart(int line, int pos, struct tbl_node *tbl) 126 { 127 if (TBL_PART_CDATA == tbl->part) 128 TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); 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 TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); 136 } 137 138 const struct tbl_span * 139 tbl_span(const struct tbl_node *tbl) 140 { 141 142 assert(tbl); 143 return(tbl->last_span); 144 } 145 146 void 147 tbl_end(struct tbl_node *tbl) 148 { 149 150 if (NULL == tbl->first_span || NULL == tbl->first_span->first) 151 TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); 152 153 if (tbl->last_span) 154 tbl->last_span->flags |= TBL_SPAN_LAST; 155 156 if (TBL_PART_CDATA == tbl->part) 157 TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); 158 } 159 160