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