xref: /openbsd-src/usr.bin/mandoc/tree.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: tree.c,v 1.44 2017/07/08 14:51:01 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 = roff_name[n->tok];
131 		break;
132 	case ROFFT_HEAD:
133 		p = roff_name[n->tok];
134 		break;
135 	case ROFFT_TAIL:
136 		p = roff_name[n->tok];
137 		break;
138 	case ROFFT_ELEM:
139 		p = roff_name[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 = roff_name[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_BROKEN & n->flags)
194 			printf(" BROKEN");
195 		if (NODE_NOSRC & n->flags)
196 			printf(" NOSRC");
197 		if (NODE_NOPRT & n->flags)
198 			printf(" NOPRT");
199 		putchar('\n');
200 	}
201 
202 	if (n->eqn)
203 		print_box(n->eqn->first, indent + 4);
204 	if (n->child)
205 		print_mdoc(n->child, indent +
206 		    (n->type == ROFFT_BLOCK ? 2 : 4));
207 	if (n->next)
208 		print_mdoc(n->next, indent);
209 }
210 
211 static void
212 print_man(const struct roff_node *n, int indent)
213 {
214 	const char	 *p, *t;
215 	int		  i;
216 
217 	if (n == NULL)
218 		return;
219 
220 	t = p = NULL;
221 
222 	switch (n->type) {
223 	case ROFFT_ROOT:
224 		t = "root";
225 		break;
226 	case ROFFT_ELEM:
227 		t = "elem";
228 		break;
229 	case ROFFT_TEXT:
230 		t = "text";
231 		break;
232 	case ROFFT_BLOCK:
233 		t = "block";
234 		break;
235 	case ROFFT_HEAD:
236 		t = "head";
237 		break;
238 	case ROFFT_BODY:
239 		t = "body";
240 		break;
241 	case ROFFT_TBL:
242 		break;
243 	case ROFFT_EQN:
244 		t = "eqn";
245 		break;
246 	default:
247 		abort();
248 	}
249 
250 	switch (n->type) {
251 	case ROFFT_TEXT:
252 		p = n->string;
253 		break;
254 	case ROFFT_ELEM:
255 	case ROFFT_BLOCK:
256 	case ROFFT_HEAD:
257 	case ROFFT_BODY:
258 		p = roff_name[n->tok];
259 		break;
260 	case ROFFT_ROOT:
261 		p = "root";
262 		break;
263 	case ROFFT_TBL:
264 		break;
265 	case ROFFT_EQN:
266 		p = "EQ";
267 		break;
268 	default:
269 		abort();
270 	}
271 
272 	if (n->span) {
273 		assert(NULL == p && NULL == t);
274 		print_span(n->span, indent);
275 	} else {
276 		for (i = 0; i < indent; i++)
277 			putchar(' ');
278 		printf("%s (%s) ", p, t);
279 		if (NODE_LINE & n->flags)
280 			putchar('*');
281 		printf("%d:%d", n->line, n->pos + 1);
282 		if (NODE_EOS & n->flags)
283 			putchar('.');
284 		putchar('\n');
285 	}
286 
287 	if (n->eqn)
288 		print_box(n->eqn->first, indent + 4);
289 	if (n->child)
290 		print_man(n->child, indent +
291 		    (n->type == ROFFT_BLOCK ? 2 : 4));
292 	if (n->next)
293 		print_man(n->next, indent);
294 }
295 
296 static void
297 print_box(const struct eqn_box *ep, int indent)
298 {
299 	int		 i;
300 	const char	*t;
301 
302 	static const char *posnames[] = {
303 	    NULL, "sup", "subsup", "sub",
304 	    "to", "from", "fromto",
305 	    "over", "sqrt", NULL };
306 
307 	if (NULL == ep)
308 		return;
309 	for (i = 0; i < indent; i++)
310 		putchar(' ');
311 
312 	t = NULL;
313 	switch (ep->type) {
314 	case EQN_LIST:
315 		t = "eqn-list";
316 		break;
317 	case EQN_SUBEXPR:
318 		t = "eqn-expr";
319 		break;
320 	case EQN_TEXT:
321 		t = "eqn-text";
322 		break;
323 	case EQN_PILE:
324 		t = "eqn-pile";
325 		break;
326 	case EQN_MATRIX:
327 		t = "eqn-matrix";
328 		break;
329 	}
330 
331 	fputs(t, stdout);
332 	if (ep->pos)
333 		printf(" pos=%s", posnames[ep->pos]);
334 	if (ep->left)
335 		printf(" left=\"%s\"", ep->left);
336 	if (ep->right)
337 		printf(" right=\"%s\"", ep->right);
338 	if (ep->top)
339 		printf(" top=\"%s\"", ep->top);
340 	if (ep->bottom)
341 		printf(" bottom=\"%s\"", ep->bottom);
342 	if (ep->text)
343 		printf(" text=\"%s\"", ep->text);
344 	if (ep->font)
345 		printf(" font=%d", ep->font);
346 	if (ep->size != EQN_DEFSIZE)
347 		printf(" size=%d", ep->size);
348 	if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
349 		printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
350 	else if (ep->args)
351 		printf(" args=%zu", ep->args);
352 	putchar('\n');
353 
354 	print_box(ep->first, indent + 4);
355 	print_box(ep->next, indent);
356 }
357 
358 static void
359 print_span(const struct tbl_span *sp, int indent)
360 {
361 	const struct tbl_dat *dp;
362 	int		 i;
363 
364 	for (i = 0; i < indent; i++)
365 		putchar(' ');
366 
367 	switch (sp->pos) {
368 	case TBL_SPAN_HORIZ:
369 		putchar('-');
370 		return;
371 	case TBL_SPAN_DHORIZ:
372 		putchar('=');
373 		return;
374 	default:
375 		break;
376 	}
377 
378 	for (dp = sp->first; dp; dp = dp->next) {
379 		switch (dp->pos) {
380 		case TBL_DATA_HORIZ:
381 		case TBL_DATA_NHORIZ:
382 			putchar('-');
383 			continue;
384 		case TBL_DATA_DHORIZ:
385 		case TBL_DATA_NDHORIZ:
386 			putchar('=');
387 			continue;
388 		default:
389 			break;
390 		}
391 		printf("[\"%s\"", dp->string ? dp->string : "");
392 		if (dp->spans)
393 			printf("(%d)", dp->spans);
394 		if (NULL == dp->layout)
395 			putchar('*');
396 		putchar(']');
397 		putchar(' ');
398 	}
399 
400 	printf("(tbl) %d:1\n", sp->line);
401 }
402