xref: /openbsd-src/usr.bin/mandoc/tree.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: tree.c,v 1.53 2020/02/27 21:38:27 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2013-2015, 2017-2020 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_cellt(enum tbl_cellt);
36 static	void	print_man(const struct roff_node *, int);
37 static	void	print_meta(const struct roff_meta *);
38 static	void	print_mdoc(const struct roff_node *, int);
39 static	void	print_span(const struct tbl_span *, int);
40 
41 
42 void
43 tree_mdoc(void *arg, const struct roff_meta *mdoc)
44 {
45 	print_meta(mdoc);
46 	putchar('\n');
47 	print_mdoc(mdoc->first->child, 0);
48 }
49 
50 void
51 tree_man(void *arg, const struct roff_meta *man)
52 {
53 	print_meta(man);
54 	if (man->hasbody == 0)
55 		puts("body  = empty");
56 	putchar('\n');
57 	print_man(man->first->child, 0);
58 }
59 
60 static void
61 print_meta(const struct roff_meta *meta)
62 {
63 	if (meta->title != NULL)
64 		printf("title = \"%s\"\n", meta->title);
65 	if (meta->name != NULL)
66 		printf("name  = \"%s\"\n", meta->name);
67 	if (meta->msec != NULL)
68 		printf("sec   = \"%s\"\n", meta->msec);
69 	if (meta->vol != NULL)
70 		printf("vol   = \"%s\"\n", meta->vol);
71 	if (meta->arch != NULL)
72 		printf("arch  = \"%s\"\n", meta->arch);
73 	if (meta->os != NULL)
74 		printf("os    = \"%s\"\n", meta->os);
75 	if (meta->date != NULL)
76 		printf("date  = \"%s\"\n", meta->date);
77 }
78 
79 static void
80 print_mdoc(const struct roff_node *n, int indent)
81 {
82 	const char	 *p, *t;
83 	int		  i, j;
84 	size_t		  argc;
85 	struct mdoc_argv *argv;
86 
87 	if (n == NULL)
88 		return;
89 
90 	argv = NULL;
91 	argc = 0;
92 	t = p = NULL;
93 
94 	switch (n->type) {
95 	case ROFFT_ROOT:
96 		t = "root";
97 		break;
98 	case ROFFT_BLOCK:
99 		t = "block";
100 		break;
101 	case ROFFT_HEAD:
102 		t = "head";
103 		break;
104 	case ROFFT_BODY:
105 		if (n->end)
106 			t = "body-end";
107 		else
108 			t = "body";
109 		break;
110 	case ROFFT_TAIL:
111 		t = "tail";
112 		break;
113 	case ROFFT_ELEM:
114 		t = "elem";
115 		break;
116 	case ROFFT_TEXT:
117 		t = "text";
118 		break;
119 	case ROFFT_COMMENT:
120 		t = "comment";
121 		break;
122 	case ROFFT_TBL:
123 		break;
124 	case ROFFT_EQN:
125 		t = "eqn";
126 		break;
127 	default:
128 		abort();
129 	}
130 
131 	switch (n->type) {
132 	case ROFFT_TEXT:
133 	case ROFFT_COMMENT:
134 		p = n->string;
135 		break;
136 	case ROFFT_BODY:
137 		p = roff_name[n->tok];
138 		break;
139 	case ROFFT_HEAD:
140 		p = roff_name[n->tok];
141 		break;
142 	case ROFFT_TAIL:
143 		p = roff_name[n->tok];
144 		break;
145 	case ROFFT_ELEM:
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_BLOCK:
153 		p = roff_name[n->tok];
154 		if (n->args) {
155 			argv = n->args->argv;
156 			argc = n->args->argc;
157 		}
158 		break;
159 	case ROFFT_TBL:
160 		break;
161 	case ROFFT_EQN:
162 		p = "EQ";
163 		break;
164 	case ROFFT_ROOT:
165 		p = "root";
166 		break;
167 	default:
168 		abort();
169 	}
170 
171 	if (n->span) {
172 		assert(NULL == p && NULL == t);
173 		print_span(n->span, indent);
174 	} else {
175 		for (i = 0; i < indent; i++)
176 			putchar(' ');
177 
178 		printf("%s (%s)", p, t);
179 
180 		for (i = 0; i < (int)argc; i++) {
181 			printf(" -%s", mdoc_argnames[argv[i].arg]);
182 			if (argv[i].sz > 0)
183 				printf(" [");
184 			for (j = 0; j < (int)argv[i].sz; j++)
185 				printf(" [%s]", argv[i].value[j]);
186 			if (argv[i].sz > 0)
187 				printf(" ]");
188 		}
189 
190 		putchar(' ');
191 		if (n->flags & NODE_DELIMO)
192 			putchar('(');
193 		if (n->flags & NODE_LINE)
194 			putchar('*');
195 		printf("%d:%d", n->line, n->pos + 1);
196 		if (n->flags & NODE_DELIMC)
197 			putchar(')');
198 		if (n->flags & NODE_EOS)
199 			putchar('.');
200 		if (n->flags & NODE_ID) {
201 			printf(" ID");
202 			if (n->string != NULL)
203 				printf("=%s", n->string);
204 		}
205 		if (n->flags & NODE_HREF)
206 			printf(" HREF");
207 		if (n->flags & NODE_BROKEN)
208 			printf(" BROKEN");
209 		if (n->flags & NODE_NOFILL)
210 			printf(" NOFILL");
211 		if (n->flags & NODE_NOSRC)
212 			printf(" NOSRC");
213 		if (n->flags & NODE_NOPRT)
214 			printf(" NOPRT");
215 		putchar('\n');
216 	}
217 
218 	if (n->eqn)
219 		print_box(n->eqn->first, indent + 4);
220 	if (n->child)
221 		print_mdoc(n->child, indent +
222 		    (n->type == ROFFT_BLOCK ? 2 : 4));
223 	if (n->next)
224 		print_mdoc(n->next, indent);
225 }
226 
227 static void
228 print_man(const struct roff_node *n, int indent)
229 {
230 	const char	 *p, *t;
231 	int		  i;
232 
233 	if (n == NULL)
234 		return;
235 
236 	t = p = NULL;
237 
238 	switch (n->type) {
239 	case ROFFT_ROOT:
240 		t = "root";
241 		break;
242 	case ROFFT_ELEM:
243 		t = "elem";
244 		break;
245 	case ROFFT_TEXT:
246 		t = "text";
247 		break;
248 	case ROFFT_COMMENT:
249 		t = "comment";
250 		break;
251 	case ROFFT_BLOCK:
252 		t = "block";
253 		break;
254 	case ROFFT_HEAD:
255 		t = "head";
256 		break;
257 	case ROFFT_BODY:
258 		t = "body";
259 		break;
260 	case ROFFT_TBL:
261 		break;
262 	case ROFFT_EQN:
263 		t = "eqn";
264 		break;
265 	default:
266 		abort();
267 	}
268 
269 	switch (n->type) {
270 	case ROFFT_TEXT:
271 	case ROFFT_COMMENT:
272 		p = n->string;
273 		break;
274 	case ROFFT_ELEM:
275 	case ROFFT_BLOCK:
276 	case ROFFT_HEAD:
277 	case ROFFT_BODY:
278 		p = roff_name[n->tok];
279 		break;
280 	case ROFFT_ROOT:
281 		p = "root";
282 		break;
283 	case ROFFT_TBL:
284 		break;
285 	case ROFFT_EQN:
286 		p = "EQ";
287 		break;
288 	default:
289 		abort();
290 	}
291 
292 	if (n->span) {
293 		assert(NULL == p && NULL == t);
294 		print_span(n->span, indent);
295 	} else {
296 		for (i = 0; i < indent; i++)
297 			putchar(' ');
298 		printf("%s (%s) ", p, t);
299 		if (n->flags & NODE_LINE)
300 			putchar('*');
301 		printf("%d:%d", n->line, n->pos + 1);
302 		if (n->flags & NODE_DELIMC)
303 			putchar(')');
304 		if (n->flags & NODE_EOS)
305 			putchar('.');
306 		if (n->flags & NODE_NOFILL)
307 			printf(" NOFILL");
308 		putchar('\n');
309 	}
310 
311 	if (n->eqn)
312 		print_box(n->eqn->first, indent + 4);
313 	if (n->child)
314 		print_man(n->child, indent +
315 		    (n->type == ROFFT_BLOCK ? 2 : 4));
316 	if (n->next)
317 		print_man(n->next, indent);
318 }
319 
320 static void
321 print_box(const struct eqn_box *ep, int indent)
322 {
323 	int		 i;
324 	const char	*t;
325 
326 	static const char *posnames[] = {
327 	    NULL, "sup", "subsup", "sub",
328 	    "to", "from", "fromto",
329 	    "over", "sqrt", NULL };
330 
331 	if (NULL == ep)
332 		return;
333 	for (i = 0; i < indent; i++)
334 		putchar(' ');
335 
336 	t = NULL;
337 	switch (ep->type) {
338 	case EQN_LIST:
339 		t = "eqn-list";
340 		break;
341 	case EQN_SUBEXPR:
342 		t = "eqn-expr";
343 		break;
344 	case EQN_TEXT:
345 		t = "eqn-text";
346 		break;
347 	case EQN_PILE:
348 		t = "eqn-pile";
349 		break;
350 	case EQN_MATRIX:
351 		t = "eqn-matrix";
352 		break;
353 	}
354 
355 	fputs(t, stdout);
356 	if (ep->pos)
357 		printf(" pos=%s", posnames[ep->pos]);
358 	if (ep->left)
359 		printf(" left=\"%s\"", ep->left);
360 	if (ep->right)
361 		printf(" right=\"%s\"", ep->right);
362 	if (ep->top)
363 		printf(" top=\"%s\"", ep->top);
364 	if (ep->bottom)
365 		printf(" bottom=\"%s\"", ep->bottom);
366 	if (ep->text)
367 		printf(" text=\"%s\"", ep->text);
368 	if (ep->font)
369 		printf(" font=%d", ep->font);
370 	if (ep->size != EQN_DEFSIZE)
371 		printf(" size=%d", ep->size);
372 	if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
373 		printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
374 	else if (ep->args)
375 		printf(" args=%zu", ep->args);
376 	putchar('\n');
377 
378 	print_box(ep->first, indent + 4);
379 	print_box(ep->next, indent);
380 }
381 
382 static void
383 print_cellt(enum tbl_cellt pos)
384 {
385 	switch(pos) {
386 	case TBL_CELL_LEFT:
387 		putchar('L');
388 		break;
389 	case TBL_CELL_LONG:
390 		putchar('a');
391 		break;
392 	case TBL_CELL_CENTRE:
393 		putchar('c');
394 		break;
395 	case TBL_CELL_RIGHT:
396 		putchar('r');
397 		break;
398 	case TBL_CELL_NUMBER:
399 		putchar('n');
400 		break;
401 	case TBL_CELL_SPAN:
402 		putchar('s');
403 		break;
404 	case TBL_CELL_DOWN:
405 		putchar('^');
406 		break;
407 	case TBL_CELL_HORIZ:
408 		putchar('-');
409 		break;
410 	case TBL_CELL_DHORIZ:
411 		putchar('=');
412 		break;
413 	case TBL_CELL_MAX:
414 		putchar('#');
415 		break;
416 	}
417 }
418 
419 static void
420 print_span(const struct tbl_span *sp, int indent)
421 {
422 	const struct tbl_dat *dp;
423 	const struct tbl_cell *cp;
424 	int		 i;
425 
426 	if (sp->prev == NULL) {
427 		for (i = 0; i < indent; i++)
428 			putchar(' ');
429 		printf("%d", sp->opts->cols);
430 		if (sp->opts->opts & TBL_OPT_CENTRE)
431 			fputs(" center", stdout);
432 		if (sp->opts->opts & TBL_OPT_EXPAND)
433 			fputs(" expand", stdout);
434 		if (sp->opts->opts & TBL_OPT_ALLBOX)
435 			fputs(" allbox", stdout);
436 		if (sp->opts->opts & TBL_OPT_BOX)
437 			fputs(" box", stdout);
438 		if (sp->opts->opts & TBL_OPT_DBOX)
439 			fputs(" doublebox", stdout);
440 		if (sp->opts->opts & TBL_OPT_NOKEEP)
441 			fputs(" nokeep", stdout);
442 		if (sp->opts->opts & TBL_OPT_NOSPACE)
443 			fputs(" nospaces", stdout);
444 		if (sp->opts->opts & TBL_OPT_NOWARN)
445 			fputs(" nowarn", stdout);
446 		printf(" (tbl options) %d:1\n", sp->line);
447 	}
448 
449 	for (i = 0; i < indent; i++)
450 		putchar(' ');
451 
452 	switch (sp->pos) {
453 	case TBL_SPAN_HORIZ:
454 		putchar('-');
455 		putchar(' ');
456 		break;
457 	case TBL_SPAN_DHORIZ:
458 		putchar('=');
459 		putchar(' ');
460 		break;
461 	default:
462 		for (cp = sp->layout->first; cp != NULL; cp = cp->next)
463 			print_cellt(cp->pos);
464 		putchar(' ');
465 		for (dp = sp->first; dp; dp = dp->next) {
466 			if ((cp = dp->layout) == NULL)
467 				putchar('*');
468 			else {
469 				printf("%d", cp->col);
470 				print_cellt(dp->layout->pos);
471 				if (cp->flags & TBL_CELL_BOLD)
472 					putchar('b');
473 				if (cp->flags & TBL_CELL_ITALIC)
474 					putchar('i');
475 				if (cp->flags & TBL_CELL_TALIGN)
476 					putchar('t');
477 				if (cp->flags & TBL_CELL_UP)
478 					putchar('u');
479 				if (cp->flags & TBL_CELL_BALIGN)
480 					putchar('d');
481 				if (cp->flags & TBL_CELL_WIGN)
482 					putchar('z');
483 				if (cp->flags & TBL_CELL_EQUAL)
484 					putchar('e');
485 				if (cp->flags & TBL_CELL_WMAX)
486 					putchar('x');
487 			}
488 			switch (dp->pos) {
489 			case TBL_DATA_HORIZ:
490 			case TBL_DATA_NHORIZ:
491 				putchar('-');
492 				break;
493 			case TBL_DATA_DHORIZ:
494 			case TBL_DATA_NDHORIZ:
495 				putchar('=');
496 				break;
497 			default:
498 				putchar(dp->block ? '{' : '[');
499 				if (dp->string != NULL)
500 					fputs(dp->string, stdout);
501 				putchar(dp->block ? '}' : ']');
502 				break;
503 			}
504 			if (dp->hspans)
505 				printf(">%d", dp->hspans);
506 			if (dp->vspans)
507 				printf("v%d", dp->vspans);
508 			putchar(' ');
509 		}
510 		break;
511 	}
512 	printf("(tbl) %d:1\n", sp->line);
513 }
514