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