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