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