1 /* $OpenBSD: tree.c,v 1.52 2020/01/11 16:02:48 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_BROKEN) 201 printf(" BROKEN"); 202 if (n->flags & NODE_NOFILL) 203 printf(" NOFILL"); 204 if (n->flags & NODE_NOSRC) 205 printf(" NOSRC"); 206 if (n->flags & NODE_NOPRT) 207 printf(" NOPRT"); 208 putchar('\n'); 209 } 210 211 if (n->eqn) 212 print_box(n->eqn->first, indent + 4); 213 if (n->child) 214 print_mdoc(n->child, indent + 215 (n->type == ROFFT_BLOCK ? 2 : 4)); 216 if (n->next) 217 print_mdoc(n->next, indent); 218 } 219 220 static void 221 print_man(const struct roff_node *n, int indent) 222 { 223 const char *p, *t; 224 int i; 225 226 if (n == NULL) 227 return; 228 229 t = p = NULL; 230 231 switch (n->type) { 232 case ROFFT_ROOT: 233 t = "root"; 234 break; 235 case ROFFT_ELEM: 236 t = "elem"; 237 break; 238 case ROFFT_TEXT: 239 t = "text"; 240 break; 241 case ROFFT_COMMENT: 242 t = "comment"; 243 break; 244 case ROFFT_BLOCK: 245 t = "block"; 246 break; 247 case ROFFT_HEAD: 248 t = "head"; 249 break; 250 case ROFFT_BODY: 251 t = "body"; 252 break; 253 case ROFFT_TBL: 254 break; 255 case ROFFT_EQN: 256 t = "eqn"; 257 break; 258 default: 259 abort(); 260 } 261 262 switch (n->type) { 263 case ROFFT_TEXT: 264 case ROFFT_COMMENT: 265 p = n->string; 266 break; 267 case ROFFT_ELEM: 268 case ROFFT_BLOCK: 269 case ROFFT_HEAD: 270 case ROFFT_BODY: 271 p = roff_name[n->tok]; 272 break; 273 case ROFFT_ROOT: 274 p = "root"; 275 break; 276 case ROFFT_TBL: 277 break; 278 case ROFFT_EQN: 279 p = "EQ"; 280 break; 281 default: 282 abort(); 283 } 284 285 if (n->span) { 286 assert(NULL == p && NULL == t); 287 print_span(n->span, indent); 288 } else { 289 for (i = 0; i < indent; i++) 290 putchar(' '); 291 printf("%s (%s) ", p, t); 292 if (n->flags & NODE_LINE) 293 putchar('*'); 294 printf("%d:%d", n->line, n->pos + 1); 295 if (n->flags & NODE_DELIMC) 296 putchar(')'); 297 if (n->flags & NODE_EOS) 298 putchar('.'); 299 if (n->flags & NODE_NOFILL) 300 printf(" NOFILL"); 301 putchar('\n'); 302 } 303 304 if (n->eqn) 305 print_box(n->eqn->first, indent + 4); 306 if (n->child) 307 print_man(n->child, indent + 308 (n->type == ROFFT_BLOCK ? 2 : 4)); 309 if (n->next) 310 print_man(n->next, indent); 311 } 312 313 static void 314 print_box(const struct eqn_box *ep, int indent) 315 { 316 int i; 317 const char *t; 318 319 static const char *posnames[] = { 320 NULL, "sup", "subsup", "sub", 321 "to", "from", "fromto", 322 "over", "sqrt", NULL }; 323 324 if (NULL == ep) 325 return; 326 for (i = 0; i < indent; i++) 327 putchar(' '); 328 329 t = NULL; 330 switch (ep->type) { 331 case EQN_LIST: 332 t = "eqn-list"; 333 break; 334 case EQN_SUBEXPR: 335 t = "eqn-expr"; 336 break; 337 case EQN_TEXT: 338 t = "eqn-text"; 339 break; 340 case EQN_PILE: 341 t = "eqn-pile"; 342 break; 343 case EQN_MATRIX: 344 t = "eqn-matrix"; 345 break; 346 } 347 348 fputs(t, stdout); 349 if (ep->pos) 350 printf(" pos=%s", posnames[ep->pos]); 351 if (ep->left) 352 printf(" left=\"%s\"", ep->left); 353 if (ep->right) 354 printf(" right=\"%s\"", ep->right); 355 if (ep->top) 356 printf(" top=\"%s\"", ep->top); 357 if (ep->bottom) 358 printf(" bottom=\"%s\"", ep->bottom); 359 if (ep->text) 360 printf(" text=\"%s\"", ep->text); 361 if (ep->font) 362 printf(" font=%d", ep->font); 363 if (ep->size != EQN_DEFSIZE) 364 printf(" size=%d", ep->size); 365 if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args) 366 printf(" badargs=%zu(%zu)", ep->args, ep->expectargs); 367 else if (ep->args) 368 printf(" args=%zu", ep->args); 369 putchar('\n'); 370 371 print_box(ep->first, indent + 4); 372 print_box(ep->next, indent); 373 } 374 375 static void 376 print_cellt(enum tbl_cellt pos) 377 { 378 switch(pos) { 379 case TBL_CELL_LEFT: 380 putchar('L'); 381 break; 382 case TBL_CELL_LONG: 383 putchar('a'); 384 break; 385 case TBL_CELL_CENTRE: 386 putchar('c'); 387 break; 388 case TBL_CELL_RIGHT: 389 putchar('r'); 390 break; 391 case TBL_CELL_NUMBER: 392 putchar('n'); 393 break; 394 case TBL_CELL_SPAN: 395 putchar('s'); 396 break; 397 case TBL_CELL_DOWN: 398 putchar('^'); 399 break; 400 case TBL_CELL_HORIZ: 401 putchar('-'); 402 break; 403 case TBL_CELL_DHORIZ: 404 putchar('='); 405 break; 406 case TBL_CELL_MAX: 407 putchar('#'); 408 break; 409 } 410 } 411 412 static void 413 print_span(const struct tbl_span *sp, int indent) 414 { 415 const struct tbl_dat *dp; 416 const struct tbl_cell *cp; 417 int i; 418 419 if (sp->prev == NULL) { 420 for (i = 0; i < indent; i++) 421 putchar(' '); 422 printf("%d", sp->opts->cols); 423 if (sp->opts->opts & TBL_OPT_CENTRE) 424 fputs(" center", stdout); 425 if (sp->opts->opts & TBL_OPT_EXPAND) 426 fputs(" expand", stdout); 427 if (sp->opts->opts & TBL_OPT_ALLBOX) 428 fputs(" allbox", stdout); 429 if (sp->opts->opts & TBL_OPT_BOX) 430 fputs(" box", stdout); 431 if (sp->opts->opts & TBL_OPT_DBOX) 432 fputs(" doublebox", stdout); 433 if (sp->opts->opts & TBL_OPT_NOKEEP) 434 fputs(" nokeep", stdout); 435 if (sp->opts->opts & TBL_OPT_NOSPACE) 436 fputs(" nospaces", stdout); 437 if (sp->opts->opts & TBL_OPT_NOWARN) 438 fputs(" nowarn", stdout); 439 printf(" (tbl options) %d:1\n", sp->line); 440 } 441 442 for (i = 0; i < indent; i++) 443 putchar(' '); 444 445 switch (sp->pos) { 446 case TBL_SPAN_HORIZ: 447 putchar('-'); 448 putchar(' '); 449 break; 450 case TBL_SPAN_DHORIZ: 451 putchar('='); 452 putchar(' '); 453 break; 454 default: 455 for (cp = sp->layout->first; cp != NULL; cp = cp->next) 456 print_cellt(cp->pos); 457 putchar(' '); 458 for (dp = sp->first; dp; dp = dp->next) { 459 if ((cp = dp->layout) == NULL) 460 putchar('*'); 461 else { 462 printf("%d", cp->col); 463 print_cellt(dp->layout->pos); 464 if (cp->flags & TBL_CELL_BOLD) 465 putchar('b'); 466 if (cp->flags & TBL_CELL_ITALIC) 467 putchar('i'); 468 if (cp->flags & TBL_CELL_TALIGN) 469 putchar('t'); 470 if (cp->flags & TBL_CELL_UP) 471 putchar('u'); 472 if (cp->flags & TBL_CELL_BALIGN) 473 putchar('d'); 474 if (cp->flags & TBL_CELL_WIGN) 475 putchar('z'); 476 if (cp->flags & TBL_CELL_EQUAL) 477 putchar('e'); 478 if (cp->flags & TBL_CELL_WMAX) 479 putchar('x'); 480 } 481 switch (dp->pos) { 482 case TBL_DATA_HORIZ: 483 case TBL_DATA_NHORIZ: 484 putchar('-'); 485 break; 486 case TBL_DATA_DHORIZ: 487 case TBL_DATA_NDHORIZ: 488 putchar('='); 489 break; 490 default: 491 putchar(dp->block ? '{' : '['); 492 if (dp->string != NULL) 493 fputs(dp->string, stdout); 494 putchar(dp->block ? '}' : ']'); 495 break; 496 } 497 if (dp->hspans) 498 printf(">%d", dp->hspans); 499 if (dp->vspans) 500 printf("v%d", dp->vspans); 501 putchar(' '); 502 } 503 break; 504 } 505 printf("(tbl) %d:1\n", sp->line); 506 } 507