xref: /dflybsd-src/contrib/mdocml/tree.c (revision 1e4d43f9c96723e4e55543d240f182e1aac9a4c2)
1*99db7d0eSSascha Wildner /* $Id: tree.c,v 1.91 2021/09/07 10:59:18 schwarze Exp $ */
280387638SSascha Wildner /*
354ba9607SSascha Wildner  * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4*99db7d0eSSascha Wildner  * Copyright (c) 2013-2015, 2017-2021 Ingo Schwarze <schwarze@openbsd.org>
580387638SSascha Wildner  *
680387638SSascha Wildner  * Permission to use, copy, modify, and distribute this software for any
780387638SSascha Wildner  * purpose with or without fee is hereby granted, provided that the above
880387638SSascha Wildner  * copyright notice and this permission notice appear in all copies.
980387638SSascha Wildner  *
1054ba9607SSascha Wildner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1180387638SSascha Wildner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1254ba9607SSascha Wildner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1380387638SSascha Wildner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1480387638SSascha Wildner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1580387638SSascha Wildner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1680387638SSascha Wildner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*99db7d0eSSascha Wildner  *
18*99db7d0eSSascha Wildner  * Formatting module to let mandoc(1) show
19*99db7d0eSSascha Wildner  * a human readable representation of the syntax tree.
2080387638SSascha Wildner  */
2180387638SSascha Wildner #include "config.h"
2254ba9607SSascha Wildner 
2354ba9607SSascha Wildner #include <sys/types.h>
2480387638SSascha Wildner 
2580387638SSascha Wildner #include <assert.h>
2636342e81SSascha Wildner #include <limits.h>
2780387638SSascha Wildner #include <stdio.h>
2880387638SSascha Wildner #include <stdlib.h>
2980387638SSascha Wildner #include <time.h>
3080387638SSascha Wildner 
3180387638SSascha Wildner #include "mandoc.h"
3254ba9607SSascha Wildner #include "roff.h"
3380387638SSascha Wildner #include "mdoc.h"
3480387638SSascha Wildner #include "man.h"
3554ba9607SSascha Wildner #include "tbl.h"
3654ba9607SSascha Wildner #include "eqn.h"
3780387638SSascha Wildner #include "main.h"
3880387638SSascha Wildner 
39*99db7d0eSSascha Wildner static	void	print_attr(const struct roff_node *);
4036342e81SSascha Wildner static	void	print_box(const struct eqn_box *, int);
41*99db7d0eSSascha Wildner static	void	print_cellt(enum tbl_cellt);
4254ba9607SSascha Wildner static	void	print_man(const struct roff_node *, int);
4354ba9607SSascha Wildner static	void	print_meta(const struct roff_meta *);
4454ba9607SSascha Wildner static	void	print_mdoc(const struct roff_node *, int);
4580387638SSascha Wildner static	void	print_span(const struct tbl_span *, int);
4680387638SSascha Wildner 
4780387638SSascha Wildner 
4880387638SSascha Wildner void
tree_mdoc(void * arg,const struct roff_meta * mdoc)4954ba9607SSascha Wildner tree_mdoc(void *arg, const struct roff_meta *mdoc)
5080387638SSascha Wildner {
5154ba9607SSascha Wildner 	print_meta(mdoc);
5254ba9607SSascha Wildner 	putchar('\n');
5354ba9607SSascha Wildner 	print_mdoc(mdoc->first->child, 0);
5480387638SSascha Wildner }
5580387638SSascha Wildner 
5680387638SSascha Wildner void
tree_man(void * arg,const struct roff_meta * man)5754ba9607SSascha Wildner tree_man(void *arg, const struct roff_meta *man)
5880387638SSascha Wildner {
5954ba9607SSascha Wildner 	print_meta(man);
6054ba9607SSascha Wildner 	if (man->hasbody == 0)
6154ba9607SSascha Wildner 		puts("body  = empty");
6254ba9607SSascha Wildner 	putchar('\n');
6354ba9607SSascha Wildner 	print_man(man->first->child, 0);
6480387638SSascha Wildner }
6580387638SSascha Wildner 
6680387638SSascha Wildner static void
print_meta(const struct roff_meta * meta)6754ba9607SSascha Wildner print_meta(const struct roff_meta *meta)
6854ba9607SSascha Wildner {
6954ba9607SSascha Wildner 	if (meta->title != NULL)
7054ba9607SSascha Wildner 		printf("title = \"%s\"\n", meta->title);
7154ba9607SSascha Wildner 	if (meta->name != NULL)
7254ba9607SSascha Wildner 		printf("name  = \"%s\"\n", meta->name);
7354ba9607SSascha Wildner 	if (meta->msec != NULL)
7454ba9607SSascha Wildner 		printf("sec   = \"%s\"\n", meta->msec);
7554ba9607SSascha Wildner 	if (meta->vol != NULL)
7654ba9607SSascha Wildner 		printf("vol   = \"%s\"\n", meta->vol);
7754ba9607SSascha Wildner 	if (meta->arch != NULL)
7854ba9607SSascha Wildner 		printf("arch  = \"%s\"\n", meta->arch);
7954ba9607SSascha Wildner 	if (meta->os != NULL)
8054ba9607SSascha Wildner 		printf("os    = \"%s\"\n", meta->os);
8154ba9607SSascha Wildner 	if (meta->date != NULL)
8254ba9607SSascha Wildner 		printf("date  = \"%s\"\n", meta->date);
8354ba9607SSascha Wildner }
8454ba9607SSascha Wildner 
8554ba9607SSascha Wildner static void
print_mdoc(const struct roff_node * n,int indent)8654ba9607SSascha Wildner print_mdoc(const struct roff_node *n, int indent)
8780387638SSascha Wildner {
8880387638SSascha Wildner 	const char	 *p, *t;
8980387638SSascha Wildner 	int		  i, j;
90f88b6c16SFranco Fichtner 	size_t		  argc;
9180387638SSascha Wildner 	struct mdoc_argv *argv;
9280387638SSascha Wildner 
9354ba9607SSascha Wildner 	if (n == NULL)
9454ba9607SSascha Wildner 		return;
9554ba9607SSascha Wildner 
9680387638SSascha Wildner 	argv = NULL;
97f88b6c16SFranco Fichtner 	argc = 0;
9836342e81SSascha Wildner 	t = p = NULL;
9980387638SSascha Wildner 
10080387638SSascha Wildner 	switch (n->type) {
10154ba9607SSascha Wildner 	case ROFFT_ROOT:
10280387638SSascha Wildner 		t = "root";
10380387638SSascha Wildner 		break;
10454ba9607SSascha Wildner 	case ROFFT_BLOCK:
10580387638SSascha Wildner 		t = "block";
10680387638SSascha Wildner 		break;
10754ba9607SSascha Wildner 	case ROFFT_HEAD:
10854ba9607SSascha Wildner 		t = "head";
10980387638SSascha Wildner 		break;
11054ba9607SSascha Wildner 	case ROFFT_BODY:
11180387638SSascha Wildner 		if (n->end)
11280387638SSascha Wildner 			t = "body-end";
11380387638SSascha Wildner 		else
11454ba9607SSascha Wildner 			t = "body";
11580387638SSascha Wildner 		break;
11654ba9607SSascha Wildner 	case ROFFT_TAIL:
11754ba9607SSascha Wildner 		t = "tail";
11880387638SSascha Wildner 		break;
11954ba9607SSascha Wildner 	case ROFFT_ELEM:
12080387638SSascha Wildner 		t = "elem";
12180387638SSascha Wildner 		break;
12254ba9607SSascha Wildner 	case ROFFT_TEXT:
12380387638SSascha Wildner 		t = "text";
12480387638SSascha Wildner 		break;
12554ba9607SSascha Wildner 	case ROFFT_COMMENT:
12654ba9607SSascha Wildner 		t = "comment";
12754ba9607SSascha Wildner 		break;
12854ba9607SSascha Wildner 	case ROFFT_TBL:
12954ba9607SSascha Wildner 		break;
13054ba9607SSascha Wildner 	case ROFFT_EQN:
13154ba9607SSascha Wildner 		t = "eqn";
13260e1e752SSascha Wildner 		break;
13380387638SSascha Wildner 	default:
13480387638SSascha Wildner 		abort();
13580387638SSascha Wildner 	}
13680387638SSascha Wildner 
13780387638SSascha Wildner 	switch (n->type) {
13854ba9607SSascha Wildner 	case ROFFT_TEXT:
13954ba9607SSascha Wildner 	case ROFFT_COMMENT:
14080387638SSascha Wildner 		p = n->string;
14180387638SSascha Wildner 		break;
14254ba9607SSascha Wildner 	case ROFFT_BODY:
14354ba9607SSascha Wildner 		p = roff_name[n->tok];
14480387638SSascha Wildner 		break;
14554ba9607SSascha Wildner 	case ROFFT_HEAD:
14654ba9607SSascha Wildner 		p = roff_name[n->tok];
14780387638SSascha Wildner 		break;
14854ba9607SSascha Wildner 	case ROFFT_TAIL:
14954ba9607SSascha Wildner 		p = roff_name[n->tok];
15080387638SSascha Wildner 		break;
15154ba9607SSascha Wildner 	case ROFFT_ELEM:
15254ba9607SSascha Wildner 		p = roff_name[n->tok];
15380387638SSascha Wildner 		if (n->args) {
15480387638SSascha Wildner 			argv = n->args->argv;
15580387638SSascha Wildner 			argc = n->args->argc;
15680387638SSascha Wildner 		}
15780387638SSascha Wildner 		break;
15854ba9607SSascha Wildner 	case ROFFT_BLOCK:
15954ba9607SSascha Wildner 		p = roff_name[n->tok];
16080387638SSascha Wildner 		if (n->args) {
16180387638SSascha Wildner 			argv = n->args->argv;
16280387638SSascha Wildner 			argc = n->args->argc;
16380387638SSascha Wildner 		}
16480387638SSascha Wildner 		break;
16554ba9607SSascha Wildner 	case ROFFT_TBL:
16660e1e752SSascha Wildner 		break;
16754ba9607SSascha Wildner 	case ROFFT_EQN:
16854ba9607SSascha Wildner 		p = "EQ";
16954ba9607SSascha Wildner 		break;
17054ba9607SSascha Wildner 	case ROFFT_ROOT:
17180387638SSascha Wildner 		p = "root";
17280387638SSascha Wildner 		break;
17380387638SSascha Wildner 	default:
17480387638SSascha Wildner 		abort();
17580387638SSascha Wildner 	}
17680387638SSascha Wildner 
17780387638SSascha Wildner 	if (n->span) {
17836342e81SSascha Wildner 		assert(NULL == p && NULL == t);
17980387638SSascha Wildner 		print_span(n->span, indent);
18080387638SSascha Wildner 	} else {
18180387638SSascha Wildner 		for (i = 0; i < indent; i++)
18254ba9607SSascha Wildner 			putchar(' ');
18380387638SSascha Wildner 
18480387638SSascha Wildner 		printf("%s (%s)", p, t);
18580387638SSascha Wildner 
18680387638SSascha Wildner 		for (i = 0; i < (int)argc; i++) {
18780387638SSascha Wildner 			printf(" -%s", mdoc_argnames[argv[i].arg]);
18880387638SSascha Wildner 			if (argv[i].sz > 0)
18980387638SSascha Wildner 				printf(" [");
19080387638SSascha Wildner 			for (j = 0; j < (int)argv[i].sz; j++)
19180387638SSascha Wildner 				printf(" [%s]", argv[i].value[j]);
19280387638SSascha Wildner 			if (argv[i].sz > 0)
19380387638SSascha Wildner 				printf(" ]");
19480387638SSascha Wildner 		}
195*99db7d0eSSascha Wildner 		print_attr(n);
19680387638SSascha Wildner 	}
19754ba9607SSascha Wildner 	if (n->eqn)
19854ba9607SSascha Wildner 		print_box(n->eqn->first, indent + 4);
19980387638SSascha Wildner 	if (n->child)
20054ba9607SSascha Wildner 		print_mdoc(n->child, indent +
20154ba9607SSascha Wildner 		    (n->type == ROFFT_BLOCK ? 2 : 4));
20280387638SSascha Wildner 	if (n->next)
20380387638SSascha Wildner 		print_mdoc(n->next, indent);
20480387638SSascha Wildner }
20580387638SSascha Wildner 
20680387638SSascha Wildner static void
print_man(const struct roff_node * n,int indent)20754ba9607SSascha Wildner print_man(const struct roff_node *n, int indent)
20880387638SSascha Wildner {
20980387638SSascha Wildner 	const char	 *p, *t;
21080387638SSascha Wildner 	int		  i;
21180387638SSascha Wildner 
21254ba9607SSascha Wildner 	if (n == NULL)
21354ba9607SSascha Wildner 		return;
21454ba9607SSascha Wildner 
21536342e81SSascha Wildner 	t = p = NULL;
21636342e81SSascha Wildner 
21780387638SSascha Wildner 	switch (n->type) {
21854ba9607SSascha Wildner 	case ROFFT_ROOT:
21980387638SSascha Wildner 		t = "root";
22080387638SSascha Wildner 		break;
22154ba9607SSascha Wildner 	case ROFFT_ELEM:
22280387638SSascha Wildner 		t = "elem";
22380387638SSascha Wildner 		break;
22454ba9607SSascha Wildner 	case ROFFT_TEXT:
22580387638SSascha Wildner 		t = "text";
22680387638SSascha Wildner 		break;
22754ba9607SSascha Wildner 	case ROFFT_COMMENT:
22854ba9607SSascha Wildner 		t = "comment";
22954ba9607SSascha Wildner 		break;
23054ba9607SSascha Wildner 	case ROFFT_BLOCK:
23180387638SSascha Wildner 		t = "block";
23280387638SSascha Wildner 		break;
23354ba9607SSascha Wildner 	case ROFFT_HEAD:
23454ba9607SSascha Wildner 		t = "head";
23580387638SSascha Wildner 		break;
23654ba9607SSascha Wildner 	case ROFFT_BODY:
23754ba9607SSascha Wildner 		t = "body";
23880387638SSascha Wildner 		break;
23954ba9607SSascha Wildner 	case ROFFT_TBL:
24060e1e752SSascha Wildner 		break;
24154ba9607SSascha Wildner 	case ROFFT_EQN:
24254ba9607SSascha Wildner 		t = "eqn";
24360e1e752SSascha Wildner 		break;
24480387638SSascha Wildner 	default:
24580387638SSascha Wildner 		abort();
24680387638SSascha Wildner 	}
24780387638SSascha Wildner 
24880387638SSascha Wildner 	switch (n->type) {
24954ba9607SSascha Wildner 	case ROFFT_TEXT:
25054ba9607SSascha Wildner 	case ROFFT_COMMENT:
25180387638SSascha Wildner 		p = n->string;
25280387638SSascha Wildner 		break;
25354ba9607SSascha Wildner 	case ROFFT_ELEM:
25454ba9607SSascha Wildner 	case ROFFT_BLOCK:
25554ba9607SSascha Wildner 	case ROFFT_HEAD:
25654ba9607SSascha Wildner 	case ROFFT_BODY:
25754ba9607SSascha Wildner 		p = roff_name[n->tok];
25880387638SSascha Wildner 		break;
25954ba9607SSascha Wildner 	case ROFFT_ROOT:
26080387638SSascha Wildner 		p = "root";
26180387638SSascha Wildner 		break;
26254ba9607SSascha Wildner 	case ROFFT_TBL:
26354ba9607SSascha Wildner 		break;
26454ba9607SSascha Wildner 	case ROFFT_EQN:
26554ba9607SSascha Wildner 		p = "EQ";
26660e1e752SSascha Wildner 		break;
26780387638SSascha Wildner 	default:
26880387638SSascha Wildner 		abort();
26980387638SSascha Wildner 	}
27080387638SSascha Wildner 
27180387638SSascha Wildner 	if (n->span) {
27236342e81SSascha Wildner 		assert(NULL == p && NULL == t);
27380387638SSascha Wildner 		print_span(n->span, indent);
27480387638SSascha Wildner 	} else {
27580387638SSascha Wildner 		for (i = 0; i < indent; i++)
27654ba9607SSascha Wildner 			putchar(' ');
277070c62a6SFranco Fichtner 		printf("%s (%s)", p, t);
278*99db7d0eSSascha Wildner 		print_attr(n);
27980387638SSascha Wildner 	}
28054ba9607SSascha Wildner 	if (n->eqn)
28154ba9607SSascha Wildner 		print_box(n->eqn->first, indent + 4);
28280387638SSascha Wildner 	if (n->child)
28354ba9607SSascha Wildner 		print_man(n->child, indent +
28454ba9607SSascha Wildner 		    (n->type == ROFFT_BLOCK ? 2 : 4));
28580387638SSascha Wildner 	if (n->next)
28680387638SSascha Wildner 		print_man(n->next, indent);
28780387638SSascha Wildner }
28880387638SSascha Wildner 
28980387638SSascha Wildner static void
print_attr(const struct roff_node * n)290*99db7d0eSSascha Wildner print_attr(const struct roff_node *n)
291*99db7d0eSSascha Wildner {
292*99db7d0eSSascha Wildner 	putchar(' ');
293*99db7d0eSSascha Wildner 	if (n->flags & NODE_DELIMO)
294*99db7d0eSSascha Wildner 		putchar('(');
295*99db7d0eSSascha Wildner 	if (n->flags & NODE_LINE)
296*99db7d0eSSascha Wildner 		putchar('*');
297*99db7d0eSSascha Wildner 	printf("%d:%d", n->line, n->pos + 1);
298*99db7d0eSSascha Wildner 	if (n->flags & NODE_DELIMC)
299*99db7d0eSSascha Wildner 		putchar(')');
300*99db7d0eSSascha Wildner 	if (n->flags & NODE_EOS)
301*99db7d0eSSascha Wildner 		putchar('.');
302*99db7d0eSSascha Wildner 	if (n->flags & NODE_ID) {
303*99db7d0eSSascha Wildner 		printf(" ID");
304*99db7d0eSSascha Wildner 		if (n->flags & NODE_HREF)
305*99db7d0eSSascha Wildner 			printf("=HREF");
306*99db7d0eSSascha Wildner 	} else if (n->flags & NODE_HREF)
307*99db7d0eSSascha Wildner 		printf(" HREF");
308*99db7d0eSSascha Wildner 	else if (n->tag != NULL)
309*99db7d0eSSascha Wildner 		printf(" STRAYTAG");
310*99db7d0eSSascha Wildner 	if (n->tag != NULL)
311*99db7d0eSSascha Wildner 		printf("=%s", n->tag);
312*99db7d0eSSascha Wildner 	if (n->flags & NODE_BROKEN)
313*99db7d0eSSascha Wildner 		printf(" BROKEN");
314*99db7d0eSSascha Wildner 	if (n->flags & NODE_NOFILL)
315*99db7d0eSSascha Wildner 		printf(" NOFILL");
316*99db7d0eSSascha Wildner 	if (n->flags & NODE_NOSRC)
317*99db7d0eSSascha Wildner 		printf(" NOSRC");
318*99db7d0eSSascha Wildner 	if (n->flags & NODE_NOPRT)
319*99db7d0eSSascha Wildner 		printf(" NOPRT");
320*99db7d0eSSascha Wildner 	putchar('\n');
321*99db7d0eSSascha Wildner }
322*99db7d0eSSascha Wildner 
323*99db7d0eSSascha Wildner static void
print_box(const struct eqn_box * ep,int indent)32436342e81SSascha Wildner print_box(const struct eqn_box *ep, int indent)
32536342e81SSascha Wildner {
32636342e81SSascha Wildner 	int		 i;
32736342e81SSascha Wildner 	const char	*t;
32836342e81SSascha Wildner 
32954ba9607SSascha Wildner 	static const char *posnames[] = {
33054ba9607SSascha Wildner 	    NULL, "sup", "subsup", "sub",
33154ba9607SSascha Wildner 	    "to", "from", "fromto",
33254ba9607SSascha Wildner 	    "over", "sqrt", NULL };
33354ba9607SSascha Wildner 
33436342e81SSascha Wildner 	if (NULL == ep)
33536342e81SSascha Wildner 		return;
33636342e81SSascha Wildner 	for (i = 0; i < indent; i++)
33754ba9607SSascha Wildner 		putchar(' ');
33836342e81SSascha Wildner 
33936342e81SSascha Wildner 	t = NULL;
34036342e81SSascha Wildner 	switch (ep->type) {
341070c62a6SFranco Fichtner 	case EQN_LIST:
34236342e81SSascha Wildner 		t = "eqn-list";
34336342e81SSascha Wildner 		break;
344070c62a6SFranco Fichtner 	case EQN_SUBEXPR:
34536342e81SSascha Wildner 		t = "eqn-expr";
34636342e81SSascha Wildner 		break;
347070c62a6SFranco Fichtner 	case EQN_TEXT:
34836342e81SSascha Wildner 		t = "eqn-text";
34936342e81SSascha Wildner 		break;
35054ba9607SSascha Wildner 	case EQN_PILE:
35154ba9607SSascha Wildner 		t = "eqn-pile";
35254ba9607SSascha Wildner 		break;
353070c62a6SFranco Fichtner 	case EQN_MATRIX:
35436342e81SSascha Wildner 		t = "eqn-matrix";
35536342e81SSascha Wildner 		break;
35636342e81SSascha Wildner 	}
35736342e81SSascha Wildner 
35854ba9607SSascha Wildner 	fputs(t, stdout);
35954ba9607SSascha Wildner 	if (ep->pos)
36054ba9607SSascha Wildner 		printf(" pos=%s", posnames[ep->pos]);
36154ba9607SSascha Wildner 	if (ep->left)
36254ba9607SSascha Wildner 		printf(" left=\"%s\"", ep->left);
36354ba9607SSascha Wildner 	if (ep->right)
36454ba9607SSascha Wildner 		printf(" right=\"%s\"", ep->right);
36554ba9607SSascha Wildner 	if (ep->top)
36654ba9607SSascha Wildner 		printf(" top=\"%s\"", ep->top);
36754ba9607SSascha Wildner 	if (ep->bottom)
36854ba9607SSascha Wildner 		printf(" bottom=\"%s\"", ep->bottom);
36954ba9607SSascha Wildner 	if (ep->text)
37054ba9607SSascha Wildner 		printf(" text=\"%s\"", ep->text);
37154ba9607SSascha Wildner 	if (ep->font)
37254ba9607SSascha Wildner 		printf(" font=%d", ep->font);
37354ba9607SSascha Wildner 	if (ep->size != EQN_DEFSIZE)
37454ba9607SSascha Wildner 		printf(" size=%d", ep->size);
37554ba9607SSascha Wildner 	if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
37654ba9607SSascha Wildner 		printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
37754ba9607SSascha Wildner 	else if (ep->args)
37854ba9607SSascha Wildner 		printf(" args=%zu", ep->args);
37954ba9607SSascha Wildner 	putchar('\n');
38036342e81SSascha Wildner 
38154ba9607SSascha Wildner 	print_box(ep->first, indent + 4);
38236342e81SSascha Wildner 	print_box(ep->next, indent);
38336342e81SSascha Wildner }
38436342e81SSascha Wildner 
38536342e81SSascha Wildner static void
print_cellt(enum tbl_cellt pos)386*99db7d0eSSascha Wildner print_cellt(enum tbl_cellt pos)
387*99db7d0eSSascha Wildner {
388*99db7d0eSSascha Wildner 	switch(pos) {
389*99db7d0eSSascha Wildner 	case TBL_CELL_LEFT:
390*99db7d0eSSascha Wildner 		putchar('L');
391*99db7d0eSSascha Wildner 		break;
392*99db7d0eSSascha Wildner 	case TBL_CELL_LONG:
393*99db7d0eSSascha Wildner 		putchar('a');
394*99db7d0eSSascha Wildner 		break;
395*99db7d0eSSascha Wildner 	case TBL_CELL_CENTRE:
396*99db7d0eSSascha Wildner 		putchar('c');
397*99db7d0eSSascha Wildner 		break;
398*99db7d0eSSascha Wildner 	case TBL_CELL_RIGHT:
399*99db7d0eSSascha Wildner 		putchar('r');
400*99db7d0eSSascha Wildner 		break;
401*99db7d0eSSascha Wildner 	case TBL_CELL_NUMBER:
402*99db7d0eSSascha Wildner 		putchar('n');
403*99db7d0eSSascha Wildner 		break;
404*99db7d0eSSascha Wildner 	case TBL_CELL_SPAN:
405*99db7d0eSSascha Wildner 		putchar('s');
406*99db7d0eSSascha Wildner 		break;
407*99db7d0eSSascha Wildner 	case TBL_CELL_DOWN:
408*99db7d0eSSascha Wildner 		putchar('^');
409*99db7d0eSSascha Wildner 		break;
410*99db7d0eSSascha Wildner 	case TBL_CELL_HORIZ:
411*99db7d0eSSascha Wildner 		putchar('-');
412*99db7d0eSSascha Wildner 		break;
413*99db7d0eSSascha Wildner 	case TBL_CELL_DHORIZ:
414*99db7d0eSSascha Wildner 		putchar('=');
415*99db7d0eSSascha Wildner 		break;
416*99db7d0eSSascha Wildner 	case TBL_CELL_MAX:
417*99db7d0eSSascha Wildner 		putchar('#');
418*99db7d0eSSascha Wildner 		break;
419*99db7d0eSSascha Wildner 	}
420*99db7d0eSSascha Wildner }
421*99db7d0eSSascha Wildner 
422*99db7d0eSSascha Wildner static void
print_span(const struct tbl_span * sp,int indent)42380387638SSascha Wildner print_span(const struct tbl_span *sp, int indent)
42480387638SSascha Wildner {
42580387638SSascha Wildner 	const struct tbl_dat *dp;
426*99db7d0eSSascha Wildner 	const struct tbl_cell *cp;
42780387638SSascha Wildner 	int		 i;
42880387638SSascha Wildner 
429*99db7d0eSSascha Wildner 	if (sp->prev == NULL) {
430*99db7d0eSSascha Wildner 		for (i = 0; i < indent; i++)
431*99db7d0eSSascha Wildner 			putchar(' ');
432*99db7d0eSSascha Wildner 		printf("%d", sp->opts->cols);
433*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_CENTRE)
434*99db7d0eSSascha Wildner 			fputs(" center", stdout);
435*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_EXPAND)
436*99db7d0eSSascha Wildner 			fputs(" expand", stdout);
437*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_ALLBOX)
438*99db7d0eSSascha Wildner 			fputs(" allbox", stdout);
439*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_BOX)
440*99db7d0eSSascha Wildner 			fputs(" box", stdout);
441*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_DBOX)
442*99db7d0eSSascha Wildner 			fputs(" doublebox", stdout);
443*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_NOKEEP)
444*99db7d0eSSascha Wildner 			fputs(" nokeep", stdout);
445*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_NOSPACE)
446*99db7d0eSSascha Wildner 			fputs(" nospaces", stdout);
447*99db7d0eSSascha Wildner 		if (sp->opts->opts & TBL_OPT_NOWARN)
448*99db7d0eSSascha Wildner 			fputs(" nowarn", stdout);
449*99db7d0eSSascha Wildner 		printf(" (tbl options) %d:1\n", sp->line);
450*99db7d0eSSascha Wildner 	}
451*99db7d0eSSascha Wildner 
45280387638SSascha Wildner 	for (i = 0; i < indent; i++)
45354ba9607SSascha Wildner 		putchar(' ');
45480387638SSascha Wildner 
45580387638SSascha Wildner 	switch (sp->pos) {
456070c62a6SFranco Fichtner 	case TBL_SPAN_HORIZ:
45780387638SSascha Wildner 		putchar('-');
45854ba9607SSascha Wildner 		putchar(' ');
45954ba9607SSascha Wildner 		break;
460070c62a6SFranco Fichtner 	case TBL_SPAN_DHORIZ:
46180387638SSascha Wildner 		putchar('=');
46254ba9607SSascha Wildner 		putchar(' ');
46380387638SSascha Wildner 		break;
46454ba9607SSascha Wildner 	default:
465*99db7d0eSSascha Wildner 		for (cp = sp->layout->first; cp != NULL; cp = cp->next)
466*99db7d0eSSascha Wildner 			print_cellt(cp->pos);
467*99db7d0eSSascha Wildner 		putchar(' ');
46880387638SSascha Wildner 		for (dp = sp->first; dp; dp = dp->next) {
469*99db7d0eSSascha Wildner 			if ((cp = dp->layout) == NULL)
470*99db7d0eSSascha Wildner 				putchar('*');
471*99db7d0eSSascha Wildner 			else {
472*99db7d0eSSascha Wildner 				printf("%d", cp->col);
473*99db7d0eSSascha Wildner 				print_cellt(dp->layout->pos);
474*99db7d0eSSascha Wildner 				switch (cp->font) {
475*99db7d0eSSascha Wildner 				case ESCAPE_FONTROMAN:
476*99db7d0eSSascha Wildner 					break;
477*99db7d0eSSascha Wildner 				case ESCAPE_FONTBOLD:
478*99db7d0eSSascha Wildner 					putchar('b');
479*99db7d0eSSascha Wildner 					break;
480*99db7d0eSSascha Wildner 				case ESCAPE_FONTITALIC:
481*99db7d0eSSascha Wildner 					putchar('i');
482*99db7d0eSSascha Wildner 					break;
483*99db7d0eSSascha Wildner 				case ESCAPE_FONTBI:
484*99db7d0eSSascha Wildner 					fputs("bi", stdout);
485*99db7d0eSSascha Wildner 					break;
486*99db7d0eSSascha Wildner 				case ESCAPE_FONTCR:
487*99db7d0eSSascha Wildner 					putchar('c');
488*99db7d0eSSascha Wildner 					break;
489*99db7d0eSSascha Wildner 				case ESCAPE_FONTCB:
490*99db7d0eSSascha Wildner 					fputs("cb", stdout);
491*99db7d0eSSascha Wildner 					break;
492*99db7d0eSSascha Wildner 				case ESCAPE_FONTCI:
493*99db7d0eSSascha Wildner 					fputs("ci", stdout);
494*99db7d0eSSascha Wildner 					break;
495*99db7d0eSSascha Wildner 				default:
496*99db7d0eSSascha Wildner 					abort();
497*99db7d0eSSascha Wildner 				}
498*99db7d0eSSascha Wildner 				if (cp->flags & TBL_CELL_TALIGN)
499*99db7d0eSSascha Wildner 					putchar('t');
500*99db7d0eSSascha Wildner 				if (cp->flags & TBL_CELL_UP)
501*99db7d0eSSascha Wildner 					putchar('u');
502*99db7d0eSSascha Wildner 				if (cp->flags & TBL_CELL_BALIGN)
503*99db7d0eSSascha Wildner 					putchar('d');
504*99db7d0eSSascha Wildner 				if (cp->flags & TBL_CELL_WIGN)
505*99db7d0eSSascha Wildner 					putchar('z');
506*99db7d0eSSascha Wildner 				if (cp->flags & TBL_CELL_EQUAL)
507*99db7d0eSSascha Wildner 					putchar('e');
508*99db7d0eSSascha Wildner 				if (cp->flags & TBL_CELL_WMAX)
509*99db7d0eSSascha Wildner 					putchar('x');
510*99db7d0eSSascha Wildner 			}
51180387638SSascha Wildner 			switch (dp->pos) {
512070c62a6SFranco Fichtner 			case TBL_DATA_HORIZ:
513070c62a6SFranco Fichtner 			case TBL_DATA_NHORIZ:
51480387638SSascha Wildner 				putchar('-');
515*99db7d0eSSascha Wildner 				break;
516070c62a6SFranco Fichtner 			case TBL_DATA_DHORIZ:
517070c62a6SFranco Fichtner 			case TBL_DATA_NDHORIZ:
51880387638SSascha Wildner 				putchar('=');
519*99db7d0eSSascha Wildner 				break;
52080387638SSascha Wildner 			default:
521*99db7d0eSSascha Wildner 				putchar(dp->block ? '{' : '[');
522*99db7d0eSSascha Wildner 				if (dp->string != NULL)
523*99db7d0eSSascha Wildner 					fputs(dp->string, stdout);
524*99db7d0eSSascha Wildner 				putchar(dp->block ? '}' : ']');
52580387638SSascha Wildner 				break;
52680387638SSascha Wildner 			}
52754ba9607SSascha Wildner 			if (dp->hspans)
52854ba9607SSascha Wildner 				printf(">%d", dp->hspans);
52954ba9607SSascha Wildner 			if (dp->vspans)
53054ba9607SSascha Wildner 				printf("v%d", dp->vspans);
53180387638SSascha Wildner 			putchar(' ');
53280387638SSascha Wildner 		}
53354ba9607SSascha Wildner 		break;
53454ba9607SSascha Wildner 	}
53536342e81SSascha Wildner 	printf("(tbl) %d:1\n", sp->line);
53680387638SSascha Wildner }
537