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