1 /* $Id: tree.c,v 1.78 2018/04/11 17:11:13 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2013,2014,2015,2017,2018 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 "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_man *mdoc) 43 { 44 print_meta(&mdoc->meta); 45 putchar('\n'); 46 print_mdoc(mdoc->first->child, 0); 47 } 48 49 void 50 tree_man(void *arg, const struct roff_man *man) 51 { 52 print_meta(&man->meta); 53 if (man->meta.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 (NODE_DELIMO & n->flags) 191 putchar('('); 192 if (NODE_LINE & n->flags) 193 putchar('*'); 194 printf("%d:%d", n->line, n->pos + 1); 195 if (NODE_DELIMC & n->flags) 196 putchar(')'); 197 if (NODE_EOS & n->flags) 198 putchar('.'); 199 if (NODE_BROKEN & n->flags) 200 printf(" BROKEN"); 201 if (NODE_NOSRC & n->flags) 202 printf(" NOSRC"); 203 if (NODE_NOPRT & n->flags) 204 printf(" NOPRT"); 205 putchar('\n'); 206 } 207 208 if (n->eqn) 209 print_box(n->eqn->first, indent + 4); 210 if (n->child) 211 print_mdoc(n->child, indent + 212 (n->type == ROFFT_BLOCK ? 2 : 4)); 213 if (n->next) 214 print_mdoc(n->next, indent); 215 } 216 217 static void 218 print_man(const struct roff_node *n, int indent) 219 { 220 const char *p, *t; 221 int i; 222 223 if (n == NULL) 224 return; 225 226 t = p = NULL; 227 228 switch (n->type) { 229 case ROFFT_ROOT: 230 t = "root"; 231 break; 232 case ROFFT_ELEM: 233 t = "elem"; 234 break; 235 case ROFFT_TEXT: 236 t = "text"; 237 break; 238 case ROFFT_COMMENT: 239 t = "comment"; 240 break; 241 case ROFFT_BLOCK: 242 t = "block"; 243 break; 244 case ROFFT_HEAD: 245 t = "head"; 246 break; 247 case ROFFT_BODY: 248 t = "body"; 249 break; 250 case ROFFT_TBL: 251 break; 252 case ROFFT_EQN: 253 t = "eqn"; 254 break; 255 default: 256 abort(); 257 } 258 259 switch (n->type) { 260 case ROFFT_TEXT: 261 case ROFFT_COMMENT: 262 p = n->string; 263 break; 264 case ROFFT_ELEM: 265 case ROFFT_BLOCK: 266 case ROFFT_HEAD: 267 case ROFFT_BODY: 268 p = roff_name[n->tok]; 269 break; 270 case ROFFT_ROOT: 271 p = "root"; 272 break; 273 case ROFFT_TBL: 274 break; 275 case ROFFT_EQN: 276 p = "EQ"; 277 break; 278 default: 279 abort(); 280 } 281 282 if (n->span) { 283 assert(NULL == p && NULL == t); 284 print_span(n->span, indent); 285 } else { 286 for (i = 0; i < indent; i++) 287 putchar(' '); 288 printf("%s (%s) ", p, t); 289 if (NODE_LINE & n->flags) 290 putchar('*'); 291 printf("%d:%d", n->line, n->pos + 1); 292 if (NODE_EOS & n->flags) 293 putchar('.'); 294 putchar('\n'); 295 } 296 297 if (n->eqn) 298 print_box(n->eqn->first, indent + 4); 299 if (n->child) 300 print_man(n->child, indent + 301 (n->type == ROFFT_BLOCK ? 2 : 4)); 302 if (n->next) 303 print_man(n->next, indent); 304 } 305 306 static void 307 print_box(const struct eqn_box *ep, int indent) 308 { 309 int i; 310 const char *t; 311 312 static const char *posnames[] = { 313 NULL, "sup", "subsup", "sub", 314 "to", "from", "fromto", 315 "over", "sqrt", NULL }; 316 317 if (NULL == ep) 318 return; 319 for (i = 0; i < indent; i++) 320 putchar(' '); 321 322 t = NULL; 323 switch (ep->type) { 324 case EQN_LIST: 325 t = "eqn-list"; 326 break; 327 case EQN_SUBEXPR: 328 t = "eqn-expr"; 329 break; 330 case EQN_TEXT: 331 t = "eqn-text"; 332 break; 333 case EQN_PILE: 334 t = "eqn-pile"; 335 break; 336 case EQN_MATRIX: 337 t = "eqn-matrix"; 338 break; 339 } 340 341 fputs(t, stdout); 342 if (ep->pos) 343 printf(" pos=%s", posnames[ep->pos]); 344 if (ep->left) 345 printf(" left=\"%s\"", ep->left); 346 if (ep->right) 347 printf(" right=\"%s\"", ep->right); 348 if (ep->top) 349 printf(" top=\"%s\"", ep->top); 350 if (ep->bottom) 351 printf(" bottom=\"%s\"", ep->bottom); 352 if (ep->text) 353 printf(" text=\"%s\"", ep->text); 354 if (ep->font) 355 printf(" font=%d", ep->font); 356 if (ep->size != EQN_DEFSIZE) 357 printf(" size=%d", ep->size); 358 if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args) 359 printf(" badargs=%zu(%zu)", ep->args, ep->expectargs); 360 else if (ep->args) 361 printf(" args=%zu", ep->args); 362 putchar('\n'); 363 364 print_box(ep->first, indent + 4); 365 print_box(ep->next, indent); 366 } 367 368 static void 369 print_span(const struct tbl_span *sp, int indent) 370 { 371 const struct tbl_dat *dp; 372 int i; 373 374 for (i = 0; i < indent; i++) 375 putchar(' '); 376 377 switch (sp->pos) { 378 case TBL_SPAN_HORIZ: 379 putchar('-'); 380 return; 381 case TBL_SPAN_DHORIZ: 382 putchar('='); 383 return; 384 default: 385 break; 386 } 387 388 for (dp = sp->first; dp; dp = dp->next) { 389 switch (dp->pos) { 390 case TBL_DATA_HORIZ: 391 case TBL_DATA_NHORIZ: 392 putchar('-'); 393 continue; 394 case TBL_DATA_DHORIZ: 395 case TBL_DATA_NDHORIZ: 396 putchar('='); 397 continue; 398 default: 399 break; 400 } 401 printf("[\"%s\"", dp->string ? dp->string : ""); 402 if (dp->spans) 403 printf("(%d)", dp->spans); 404 if (NULL == dp->layout) 405 putchar('*'); 406 putchar(']'); 407 putchar(' '); 408 } 409 410 printf("(tbl) %d:1\n", sp->line); 411 }