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