xref: /openbsd-src/usr.bin/mandoc/tree.c (revision f6b75673f6c960a9743bfd16c1e52dd100265c68)
1 /*	$OpenBSD: tree.c,v 1.47 2018/11/25 19:23:59 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2013,2014,2015,2017,2018 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_COMMENT:
117 		t = "comment";
118 		break;
119 	case ROFFT_TBL:
120 		break;
121 	case ROFFT_EQN:
122 		t = "eqn";
123 		break;
124 	default:
125 		abort();
126 	}
127 
128 	switch (n->type) {
129 	case ROFFT_TEXT:
130 	case ROFFT_COMMENT:
131 		p = n->string;
132 		break;
133 	case ROFFT_BODY:
134 		p = roff_name[n->tok];
135 		break;
136 	case ROFFT_HEAD:
137 		p = roff_name[n->tok];
138 		break;
139 	case ROFFT_TAIL:
140 		p = roff_name[n->tok];
141 		break;
142 	case ROFFT_ELEM:
143 		p = roff_name[n->tok];
144 		if (n->args) {
145 			argv = n->args->argv;
146 			argc = n->args->argc;
147 		}
148 		break;
149 	case ROFFT_BLOCK:
150 		p = roff_name[n->tok];
151 		if (n->args) {
152 			argv = n->args->argv;
153 			argc = n->args->argc;
154 		}
155 		break;
156 	case ROFFT_TBL:
157 		break;
158 	case ROFFT_EQN:
159 		p = "EQ";
160 		break;
161 	case ROFFT_ROOT:
162 		p = "root";
163 		break;
164 	default:
165 		abort();
166 	}
167 
168 	if (n->span) {
169 		assert(NULL == p && NULL == t);
170 		print_span(n->span, indent);
171 	} else {
172 		for (i = 0; i < indent; i++)
173 			putchar(' ');
174 
175 		printf("%s (%s)", p, t);
176 
177 		for (i = 0; i < (int)argc; i++) {
178 			printf(" -%s", mdoc_argnames[argv[i].arg]);
179 			if (argv[i].sz > 0)
180 				printf(" [");
181 			for (j = 0; j < (int)argv[i].sz; j++)
182 				printf(" [%s]", argv[i].value[j]);
183 			if (argv[i].sz > 0)
184 				printf(" ]");
185 		}
186 
187 		putchar(' ');
188 		if (NODE_DELIMO & n->flags)
189 			putchar('(');
190 		if (NODE_LINE & n->flags)
191 			putchar('*');
192 		printf("%d:%d", n->line, n->pos + 1);
193 		if (NODE_DELIMC & n->flags)
194 			putchar(')');
195 		if (NODE_EOS & n->flags)
196 			putchar('.');
197 		if (NODE_BROKEN & n->flags)
198 			printf(" BROKEN");
199 		if (NODE_NOSRC & n->flags)
200 			printf(" NOSRC");
201 		if (NODE_NOPRT & n->flags)
202 			printf(" NOPRT");
203 		putchar('\n');
204 	}
205 
206 	if (n->eqn)
207 		print_box(n->eqn->first, indent + 4);
208 	if (n->child)
209 		print_mdoc(n->child, indent +
210 		    (n->type == ROFFT_BLOCK ? 2 : 4));
211 	if (n->next)
212 		print_mdoc(n->next, indent);
213 }
214 
215 static void
216 print_man(const struct roff_node *n, int indent)
217 {
218 	const char	 *p, *t;
219 	int		  i;
220 
221 	if (n == NULL)
222 		return;
223 
224 	t = p = NULL;
225 
226 	switch (n->type) {
227 	case ROFFT_ROOT:
228 		t = "root";
229 		break;
230 	case ROFFT_ELEM:
231 		t = "elem";
232 		break;
233 	case ROFFT_TEXT:
234 		t = "text";
235 		break;
236 	case ROFFT_COMMENT:
237 		t = "comment";
238 		break;
239 	case ROFFT_BLOCK:
240 		t = "block";
241 		break;
242 	case ROFFT_HEAD:
243 		t = "head";
244 		break;
245 	case ROFFT_BODY:
246 		t = "body";
247 		break;
248 	case ROFFT_TBL:
249 		break;
250 	case ROFFT_EQN:
251 		t = "eqn";
252 		break;
253 	default:
254 		abort();
255 	}
256 
257 	switch (n->type) {
258 	case ROFFT_TEXT:
259 	case ROFFT_COMMENT:
260 		p = n->string;
261 		break;
262 	case ROFFT_ELEM:
263 	case ROFFT_BLOCK:
264 	case ROFFT_HEAD:
265 	case ROFFT_BODY:
266 		p = roff_name[n->tok];
267 		break;
268 	case ROFFT_ROOT:
269 		p = "root";
270 		break;
271 	case ROFFT_TBL:
272 		break;
273 	case ROFFT_EQN:
274 		p = "EQ";
275 		break;
276 	default:
277 		abort();
278 	}
279 
280 	if (n->span) {
281 		assert(NULL == p && NULL == t);
282 		print_span(n->span, indent);
283 	} else {
284 		for (i = 0; i < indent; i++)
285 			putchar(' ');
286 		printf("%s (%s) ", p, t);
287 		if (NODE_LINE & n->flags)
288 			putchar('*');
289 		printf("%d:%d", n->line, n->pos + 1);
290 		if (NODE_DELIMC & n->flags)
291 			putchar(')');
292 		if (NODE_EOS & n->flags)
293 			putchar('.');
294 		putchar('\n');
295 	}
296 
297 	if (n->eqn)
298 		print_box(n->eqn->first, indent + 4);
299 	if (n->child)
300 		print_man(n->child, indent +
301 		    (n->type == ROFFT_BLOCK ? 2 : 4));
302 	if (n->next)
303 		print_man(n->next, indent);
304 }
305 
306 static void
307 print_box(const struct eqn_box *ep, int indent)
308 {
309 	int		 i;
310 	const char	*t;
311 
312 	static const char *posnames[] = {
313 	    NULL, "sup", "subsup", "sub",
314 	    "to", "from", "fromto",
315 	    "over", "sqrt", NULL };
316 
317 	if (NULL == ep)
318 		return;
319 	for (i = 0; i < indent; i++)
320 		putchar(' ');
321 
322 	t = NULL;
323 	switch (ep->type) {
324 	case EQN_LIST:
325 		t = "eqn-list";
326 		break;
327 	case EQN_SUBEXPR:
328 		t = "eqn-expr";
329 		break;
330 	case EQN_TEXT:
331 		t = "eqn-text";
332 		break;
333 	case EQN_PILE:
334 		t = "eqn-pile";
335 		break;
336 	case EQN_MATRIX:
337 		t = "eqn-matrix";
338 		break;
339 	}
340 
341 	fputs(t, stdout);
342 	if (ep->pos)
343 		printf(" pos=%s", posnames[ep->pos]);
344 	if (ep->left)
345 		printf(" left=\"%s\"", ep->left);
346 	if (ep->right)
347 		printf(" right=\"%s\"", ep->right);
348 	if (ep->top)
349 		printf(" top=\"%s\"", ep->top);
350 	if (ep->bottom)
351 		printf(" bottom=\"%s\"", ep->bottom);
352 	if (ep->text)
353 		printf(" text=\"%s\"", ep->text);
354 	if (ep->font)
355 		printf(" font=%d", ep->font);
356 	if (ep->size != EQN_DEFSIZE)
357 		printf(" size=%d", ep->size);
358 	if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
359 		printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
360 	else if (ep->args)
361 		printf(" args=%zu", ep->args);
362 	putchar('\n');
363 
364 	print_box(ep->first, indent + 4);
365 	print_box(ep->next, indent);
366 }
367 
368 static void
369 print_span(const struct tbl_span *sp, int indent)
370 {
371 	const struct tbl_dat *dp;
372 	int		 i;
373 
374 	for (i = 0; i < indent; i++)
375 		putchar(' ');
376 
377 	switch (sp->pos) {
378 	case TBL_SPAN_HORIZ:
379 		putchar('-');
380 		putchar(' ');
381 		break;
382 	case TBL_SPAN_DHORIZ:
383 		putchar('=');
384 		putchar(' ');
385 		break;
386 	default:
387 		for (dp = sp->first; dp; dp = dp->next) {
388 			switch (dp->pos) {
389 			case TBL_DATA_HORIZ:
390 			case TBL_DATA_NHORIZ:
391 				putchar('-');
392 				putchar(' ');
393 				continue;
394 			case TBL_DATA_DHORIZ:
395 			case TBL_DATA_NDHORIZ:
396 				putchar('=');
397 				putchar(' ');
398 				continue;
399 			default:
400 				break;
401 			}
402 			printf("[\"%s\"", dp->string ? dp->string : "");
403 			if (dp->hspans)
404 				printf(">%d", dp->hspans);
405 			if (dp->vspans)
406 				printf("v%d", dp->vspans);
407 			if (dp->layout == NULL)
408 				putchar('*');
409 			else if (dp->layout->pos == TBL_CELL_DOWN)
410 				putchar('^');
411 			putchar(']');
412 			putchar(' ');
413 		}
414 		break;
415 	}
416 	printf("(tbl) %d:1\n", sp->line);
417 }
418