xref: /openbsd-src/usr.bin/mandoc/tree.c (revision d4741794dd2f512d997014f8bd85fbb24d935059)
1 /*	$OpenBSD: tree.c,v 1.39 2017/01/12 17:29:34 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2013, 2014, 2015, 2017 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 AUTHORS DISCLAIM ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 "roff.h"
28 #include "mdoc.h"
29 #include "man.h"
30 #include "main.h"
31 
32 static	void	print_box(const struct eqn_box *, int);
33 static	void	print_man(const struct roff_node *, int);
34 static	void	print_meta(const struct roff_meta *);
35 static	void	print_mdoc(const struct roff_node *, int);
36 static	void	print_span(const struct tbl_span *, int);
37 
38 
39 void
40 tree_mdoc(void *arg, const struct roff_man *mdoc)
41 {
42 	print_meta(&mdoc->meta);
43 	putchar('\n');
44 	print_mdoc(mdoc->first->child, 0);
45 }
46 
47 void
48 tree_man(void *arg, const struct roff_man *man)
49 {
50 	print_meta(&man->meta);
51 	if (man->meta.hasbody == 0)
52 		puts("body  = empty");
53 	putchar('\n');
54 	print_man(man->first->child, 0);
55 }
56 
57 static void
58 print_meta(const struct roff_meta *meta)
59 {
60 	if (meta->title != NULL)
61 		printf("title = \"%s\"\n", meta->title);
62 	if (meta->name != NULL)
63 		printf("name  = \"%s\"\n", meta->name);
64 	if (meta->msec != NULL)
65 		printf("sec   = \"%s\"\n", meta->msec);
66 	if (meta->vol != NULL)
67 		printf("vol   = \"%s\"\n", meta->vol);
68 	if (meta->arch != NULL)
69 		printf("arch  = \"%s\"\n", meta->arch);
70 	if (meta->os != NULL)
71 		printf("os    = \"%s\"\n", meta->os);
72 	if (meta->date != NULL)
73 		printf("date  = \"%s\"\n", meta->date);
74 }
75 
76 static void
77 print_mdoc(const struct roff_node *n, int indent)
78 {
79 	const char	 *p, *t;
80 	int		  i, j;
81 	size_t		  argc;
82 	struct mdoc_argv *argv;
83 
84 	if (n == NULL)
85 		return;
86 
87 	argv = NULL;
88 	argc = 0;
89 	t = p = NULL;
90 
91 	switch (n->type) {
92 	case ROFFT_ROOT:
93 		t = "root";
94 		break;
95 	case ROFFT_BLOCK:
96 		t = "block";
97 		break;
98 	case ROFFT_HEAD:
99 		t = "head";
100 		break;
101 	case ROFFT_BODY:
102 		if (n->end)
103 			t = "body-end";
104 		else
105 			t = "body";
106 		break;
107 	case ROFFT_TAIL:
108 		t = "tail";
109 		break;
110 	case ROFFT_ELEM:
111 		t = "elem";
112 		break;
113 	case ROFFT_TEXT:
114 		t = "text";
115 		break;
116 	case ROFFT_TBL:
117 		break;
118 	case ROFFT_EQN:
119 		t = "eqn";
120 		break;
121 	default:
122 		abort();
123 	}
124 
125 	switch (n->type) {
126 	case ROFFT_TEXT:
127 		p = n->string;
128 		break;
129 	case ROFFT_BODY:
130 		p = mdoc_macronames[n->tok];
131 		break;
132 	case ROFFT_HEAD:
133 		p = mdoc_macronames[n->tok];
134 		break;
135 	case ROFFT_TAIL:
136 		p = mdoc_macronames[n->tok];
137 		break;
138 	case ROFFT_ELEM:
139 		p = mdoc_macronames[n->tok];
140 		if (n->args) {
141 			argv = n->args->argv;
142 			argc = n->args->argc;
143 		}
144 		break;
145 	case ROFFT_BLOCK:
146 		p = mdoc_macronames[n->tok];
147 		if (n->args) {
148 			argv = n->args->argv;
149 			argc = n->args->argc;
150 		}
151 		break;
152 	case ROFFT_TBL:
153 		break;
154 	case ROFFT_EQN:
155 		p = "EQ";
156 		break;
157 	case ROFFT_ROOT:
158 		p = "root";
159 		break;
160 	default:
161 		abort();
162 	}
163 
164 	if (n->span) {
165 		assert(NULL == p && NULL == t);
166 		print_span(n->span, indent);
167 	} else {
168 		for (i = 0; i < indent; i++)
169 			putchar(' ');
170 
171 		printf("%s (%s)", p, t);
172 
173 		for (i = 0; i < (int)argc; i++) {
174 			printf(" -%s", mdoc_argnames[argv[i].arg]);
175 			if (argv[i].sz > 0)
176 				printf(" [");
177 			for (j = 0; j < (int)argv[i].sz; j++)
178 				printf(" [%s]", argv[i].value[j]);
179 			if (argv[i].sz > 0)
180 				printf(" ]");
181 		}
182 
183 		putchar(' ');
184 		if (NODE_DELIMO & n->flags)
185 			putchar('(');
186 		if (NODE_LINE & n->flags)
187 			putchar('*');
188 		printf("%d:%d", n->line, n->pos + 1);
189 		if (NODE_DELIMC & n->flags)
190 			putchar(')');
191 		if (NODE_EOS & n->flags)
192 			putchar('.');
193 		if (NODE_NOSRC & n->flags)
194 			printf(" NOSRC");
195 		if (NODE_NOPRT & n->flags)
196 			printf(" NOPRT");
197 		putchar('\n');
198 	}
199 
200 	if (n->eqn)
201 		print_box(n->eqn->root->first, indent + 4);
202 	if (n->child)
203 		print_mdoc(n->child, indent +
204 		    (n->type == ROFFT_BLOCK ? 2 : 4));
205 	if (n->next)
206 		print_mdoc(n->next, indent);
207 }
208 
209 static void
210 print_man(const struct roff_node *n, int indent)
211 {
212 	const char	 *p, *t;
213 	int		  i;
214 
215 	if (n == NULL)
216 		return;
217 
218 	t = p = NULL;
219 
220 	switch (n->type) {
221 	case ROFFT_ROOT:
222 		t = "root";
223 		break;
224 	case ROFFT_ELEM:
225 		t = "elem";
226 		break;
227 	case ROFFT_TEXT:
228 		t = "text";
229 		break;
230 	case ROFFT_BLOCK:
231 		t = "block";
232 		break;
233 	case ROFFT_HEAD:
234 		t = "head";
235 		break;
236 	case ROFFT_BODY:
237 		t = "body";
238 		break;
239 	case ROFFT_TBL:
240 		break;
241 	case ROFFT_EQN:
242 		t = "eqn";
243 		break;
244 	default:
245 		abort();
246 	}
247 
248 	switch (n->type) {
249 	case ROFFT_TEXT:
250 		p = n->string;
251 		break;
252 	case ROFFT_ELEM:
253 	case ROFFT_BLOCK:
254 	case ROFFT_HEAD:
255 	case ROFFT_BODY:
256 		p = man_macronames[n->tok];
257 		break;
258 	case ROFFT_ROOT:
259 		p = "root";
260 		break;
261 	case ROFFT_TBL:
262 		break;
263 	case ROFFT_EQN:
264 		p = "EQ";
265 		break;
266 	default:
267 		abort();
268 	}
269 
270 	if (n->span) {
271 		assert(NULL == p && NULL == t);
272 		print_span(n->span, indent);
273 	} else {
274 		for (i = 0; i < indent; i++)
275 			putchar(' ');
276 		printf("%s (%s) ", p, t);
277 		if (NODE_LINE & n->flags)
278 			putchar('*');
279 		printf("%d:%d", n->line, n->pos + 1);
280 		if (NODE_EOS & n->flags)
281 			putchar('.');
282 		putchar('\n');
283 	}
284 
285 	if (n->eqn)
286 		print_box(n->eqn->root->first, indent + 4);
287 	if (n->child)
288 		print_man(n->child, indent +
289 		    (n->type == ROFFT_BLOCK ? 2 : 4));
290 	if (n->next)
291 		print_man(n->next, indent);
292 }
293 
294 static void
295 print_box(const struct eqn_box *ep, int indent)
296 {
297 	int		 i;
298 	const char	*t;
299 
300 	static const char *posnames[] = {
301 	    NULL, "sup", "subsup", "sub",
302 	    "to", "from", "fromto",
303 	    "over", "sqrt", NULL };
304 
305 	if (NULL == ep)
306 		return;
307 	for (i = 0; i < indent; i++)
308 		putchar(' ');
309 
310 	t = NULL;
311 	switch (ep->type) {
312 	case EQN_ROOT:
313 		t = "eqn-root";
314 		break;
315 	case EQN_LISTONE:
316 	case EQN_LIST:
317 		t = "eqn-list";
318 		break;
319 	case EQN_SUBEXPR:
320 		t = "eqn-expr";
321 		break;
322 	case EQN_TEXT:
323 		t = "eqn-text";
324 		break;
325 	case EQN_PILE:
326 		t = "eqn-pile";
327 		break;
328 	case EQN_MATRIX:
329 		t = "eqn-matrix";
330 		break;
331 	}
332 
333 	fputs(t, stdout);
334 	if (ep->pos)
335 		printf(" pos=%s", posnames[ep->pos]);
336 	if (ep->left)
337 		printf(" left=\"%s\"", ep->left);
338 	if (ep->right)
339 		printf(" right=\"%s\"", ep->right);
340 	if (ep->top)
341 		printf(" top=\"%s\"", ep->top);
342 	if (ep->bottom)
343 		printf(" bottom=\"%s\"", ep->bottom);
344 	if (ep->text)
345 		printf(" text=\"%s\"", ep->text);
346 	if (ep->font)
347 		printf(" font=%d", ep->font);
348 	if (ep->size != EQN_DEFSIZE)
349 		printf(" size=%d", ep->size);
350 	if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
351 		printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
352 	else if (ep->args)
353 		printf(" args=%zu", ep->args);
354 	putchar('\n');
355 
356 	print_box(ep->first, indent + 4);
357 	print_box(ep->next, indent);
358 }
359 
360 static void
361 print_span(const struct tbl_span *sp, int indent)
362 {
363 	const struct tbl_dat *dp;
364 	int		 i;
365 
366 	for (i = 0; i < indent; i++)
367 		putchar(' ');
368 
369 	switch (sp->pos) {
370 	case TBL_SPAN_HORIZ:
371 		putchar('-');
372 		return;
373 	case TBL_SPAN_DHORIZ:
374 		putchar('=');
375 		return;
376 	default:
377 		break;
378 	}
379 
380 	for (dp = sp->first; dp; dp = dp->next) {
381 		switch (dp->pos) {
382 		case TBL_DATA_HORIZ:
383 		case TBL_DATA_NHORIZ:
384 			putchar('-');
385 			continue;
386 		case TBL_DATA_DHORIZ:
387 		case TBL_DATA_NDHORIZ:
388 			putchar('=');
389 			continue;
390 		default:
391 			break;
392 		}
393 		printf("[\"%s\"", dp->string ? dp->string : "");
394 		if (dp->spans)
395 			printf("(%d)", dp->spans);
396 		if (NULL == dp->layout)
397 			putchar('*');
398 		putchar(']');
399 		putchar(' ');
400 	}
401 
402 	printf("(tbl) %d:1\n", sp->line);
403 }
404