xref: /openbsd-src/usr.bin/mandoc/tree.c (revision 5b859c19fe53bbea08f5c342e0a4470e99f883e1)
1 /*	$OpenBSD: tree.c,v 1.27 2014/11/28 05:51:29 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2013, 2014 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 <sys/types.h>
19 
20 #include <assert.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <time.h>
25 
26 #include "mandoc.h"
27 #include "mdoc.h"
28 #include "man.h"
29 #include "main.h"
30 
31 static	void	print_box(const struct eqn_box *, int);
32 static	void	print_man(const struct man_node *, int);
33 static	void	print_mdoc(const struct mdoc_node *, int);
34 static	void	print_span(const struct tbl_span *, int);
35 
36 
37 void
38 tree_mdoc(void *arg, const struct mdoc *mdoc)
39 {
40 
41 	print_mdoc(mdoc_node(mdoc), 0);
42 }
43 
44 void
45 tree_man(void *arg, const struct man *man)
46 {
47 
48 	print_man(man_node(man), 0);
49 }
50 
51 static void
52 print_mdoc(const struct mdoc_node *n, int indent)
53 {
54 	const char	 *p, *t;
55 	int		  i, j;
56 	size_t		  argc;
57 	struct mdoc_argv *argv;
58 
59 	argv = NULL;
60 	argc = 0;
61 	t = p = NULL;
62 
63 	switch (n->type) {
64 	case MDOC_ROOT:
65 		t = "root";
66 		break;
67 	case MDOC_BLOCK:
68 		t = "block";
69 		break;
70 	case MDOC_HEAD:
71 		t = "block-head";
72 		break;
73 	case MDOC_BODY:
74 		if (n->end)
75 			t = "body-end";
76 		else
77 			t = "block-body";
78 		break;
79 	case MDOC_TAIL:
80 		t = "block-tail";
81 		break;
82 	case MDOC_ELEM:
83 		t = "elem";
84 		break;
85 	case MDOC_TEXT:
86 		t = "text";
87 		break;
88 	case MDOC_TBL:
89 		break;
90 	case MDOC_EQN:
91 		t = "eqn";
92 		break;
93 	default:
94 		abort();
95 		/* NOTREACHED */
96 	}
97 
98 	switch (n->type) {
99 	case MDOC_TEXT:
100 		p = n->string;
101 		break;
102 	case MDOC_BODY:
103 		p = mdoc_macronames[n->tok];
104 		break;
105 	case MDOC_HEAD:
106 		p = mdoc_macronames[n->tok];
107 		break;
108 	case MDOC_TAIL:
109 		p = mdoc_macronames[n->tok];
110 		break;
111 	case MDOC_ELEM:
112 		p = mdoc_macronames[n->tok];
113 		if (n->args) {
114 			argv = n->args->argv;
115 			argc = n->args->argc;
116 		}
117 		break;
118 	case MDOC_BLOCK:
119 		p = mdoc_macronames[n->tok];
120 		if (n->args) {
121 			argv = n->args->argv;
122 			argc = n->args->argc;
123 		}
124 		break;
125 	case MDOC_TBL:
126 		break;
127 	case MDOC_EQN:
128 		p = "EQ";
129 		break;
130 	case MDOC_ROOT:
131 		p = "root";
132 		break;
133 	default:
134 		abort();
135 		/* NOTREACHED */
136 	}
137 
138 	if (n->span) {
139 		assert(NULL == p && NULL == t);
140 		print_span(n->span, indent);
141 	} else {
142 		for (i = 0; i < indent; i++)
143 			putchar('\t');
144 
145 		printf("%s (%s)", p, t);
146 
147 		for (i = 0; i < (int)argc; i++) {
148 			printf(" -%s", mdoc_argnames[argv[i].arg]);
149 			if (argv[i].sz > 0)
150 				printf(" [");
151 			for (j = 0; j < (int)argv[i].sz; j++)
152 				printf(" [%s]", argv[i].value[j]);
153 			if (argv[i].sz > 0)
154 				printf(" ]");
155 		}
156 
157 		putchar(' ');
158 		if (MDOC_LINE & n->flags)
159 			putchar('*');
160 		printf("%d:%d", n->line, n->pos + 1);
161 		if (n->lastline != n->line)
162 			printf("-%d", n->lastline);
163 		putchar('\n');
164 	}
165 
166 	if (n->eqn)
167 		print_box(n->eqn->root->first, indent + 1);
168 	if (n->child)
169 		print_mdoc(n->child, indent + 1);
170 	if (n->next)
171 		print_mdoc(n->next, indent);
172 }
173 
174 static void
175 print_man(const struct man_node *n, int indent)
176 {
177 	const char	 *p, *t;
178 	int		  i;
179 
180 	t = p = NULL;
181 
182 	switch (n->type) {
183 	case MAN_ROOT:
184 		t = "root";
185 		break;
186 	case MAN_ELEM:
187 		t = "elem";
188 		break;
189 	case MAN_TEXT:
190 		t = "text";
191 		break;
192 	case MAN_BLOCK:
193 		t = "block";
194 		break;
195 	case MAN_HEAD:
196 		t = "block-head";
197 		break;
198 	case MAN_BODY:
199 		t = "block-body";
200 		break;
201 	case MAN_TBL:
202 		break;
203 	case MAN_EQN:
204 		t = "eqn";
205 		break;
206 	default:
207 		abort();
208 		/* NOTREACHED */
209 	}
210 
211 	switch (n->type) {
212 	case MAN_TEXT:
213 		p = n->string;
214 		break;
215 	case MAN_ELEM:
216 		/* FALLTHROUGH */
217 	case MAN_BLOCK:
218 		/* FALLTHROUGH */
219 	case MAN_HEAD:
220 		/* FALLTHROUGH */
221 	case MAN_BODY:
222 		p = man_macronames[n->tok];
223 		break;
224 	case MAN_ROOT:
225 		p = "root";
226 		break;
227 	case MAN_TBL:
228 		break;
229 	case MAN_EQN:
230 		p = "EQ";
231 		break;
232 	default:
233 		abort();
234 		/* NOTREACHED */
235 	}
236 
237 	if (n->span) {
238 		assert(NULL == p && NULL == t);
239 		print_span(n->span, indent);
240 	} else {
241 		for (i = 0; i < indent; i++)
242 			putchar('\t');
243 		printf("%s (%s) ", p, t);
244 		if (MAN_LINE & n->flags)
245 			putchar('*');
246 		printf("%d:%d\n", n->line, n->pos + 1);
247 	}
248 
249 	if (n->eqn)
250 		print_box(n->eqn->root->first, indent + 1);
251 	if (n->child)
252 		print_man(n->child, indent + 1);
253 	if (n->next)
254 		print_man(n->next, indent);
255 }
256 
257 static void
258 print_box(const struct eqn_box *ep, int indent)
259 {
260 	int		 i;
261 	const char	*t;
262 
263 	static const char *posnames[] = {
264 	    NULL, "sup", "subsup", "sub",
265 	    "to", "from", "fromto",
266 	    "over", "sqrt", NULL };
267 
268 	if (NULL == ep)
269 		return;
270 	for (i = 0; i < indent; i++)
271 		putchar('\t');
272 
273 	t = NULL;
274 	switch (ep->type) {
275 	case EQN_ROOT:
276 		t = "eqn-root";
277 		break;
278 	case EQN_LISTONE:
279 	case EQN_LIST:
280 		t = "eqn-list";
281 		break;
282 	case EQN_SUBEXPR:
283 		t = "eqn-expr";
284 		break;
285 	case EQN_TEXT:
286 		t = "eqn-text";
287 		break;
288 	case EQN_PILE:
289 		t = "eqn-pile";
290 		break;
291 	case EQN_MATRIX:
292 		t = "eqn-matrix";
293 		break;
294 	}
295 
296 	fputs(t, stdout);
297 	if (ep->pos)
298 		printf(" pos=%s", posnames[ep->pos]);
299 	if (ep->left)
300 		printf(" left=\"%s\"", ep->left);
301 	if (ep->right)
302 		printf(" right=\"%s\"", ep->right);
303 	if (ep->top)
304 		printf(" top=\"%s\"", ep->top);
305 	if (ep->bottom)
306 		printf(" bottom=\"%s\"", ep->bottom);
307 	if (ep->text)
308 		printf(" text=\"%s\"", ep->text);
309 	if (ep->font)
310 		printf(" font=%d", ep->font);
311 	if (ep->size != EQN_DEFSIZE)
312 		printf(" size=%d", ep->size);
313 	if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
314 		printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
315 	else if (ep->args)
316 		printf(" args=%zu", ep->args);
317 	putchar('\n');
318 
319 	print_box(ep->first, indent + 1);
320 	print_box(ep->next, indent);
321 }
322 
323 static void
324 print_span(const struct tbl_span *sp, int indent)
325 {
326 	const struct tbl_dat *dp;
327 	int		 i;
328 
329 	for (i = 0; i < indent; i++)
330 		putchar('\t');
331 
332 	switch (sp->pos) {
333 	case TBL_SPAN_HORIZ:
334 		putchar('-');
335 		return;
336 	case TBL_SPAN_DHORIZ:
337 		putchar('=');
338 		return;
339 	default:
340 		break;
341 	}
342 
343 	for (dp = sp->first; dp; dp = dp->next) {
344 		switch (dp->pos) {
345 		case TBL_DATA_HORIZ:
346 			/* FALLTHROUGH */
347 		case TBL_DATA_NHORIZ:
348 			putchar('-');
349 			continue;
350 		case TBL_DATA_DHORIZ:
351 			/* FALLTHROUGH */
352 		case TBL_DATA_NDHORIZ:
353 			putchar('=');
354 			continue;
355 		default:
356 			break;
357 		}
358 		printf("[\"%s\"", dp->string ? dp->string : "");
359 		if (dp->spans)
360 			printf("(%d)", dp->spans);
361 		if (NULL == dp->layout)
362 			putchar('*');
363 		putchar(']');
364 		putchar(' ');
365 	}
366 
367 	printf("(tbl) %d:1\n", sp->line);
368 }
369