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