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