1 /* $OpenBSD: tree.c,v 1.46 2018/08/14 01:26:12 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 <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 "main.h" 31 32 static void print_box(const struct eqn_box *, int); 33 static void print_man(const struct roff_node *, int); 34 static void print_meta(const struct roff_meta *); 35 static void print_mdoc(const struct roff_node *, int); 36 static void print_span(const struct tbl_span *, int); 37 38 39 void 40 tree_mdoc(void *arg, const struct roff_man *mdoc) 41 { 42 print_meta(&mdoc->meta); 43 putchar('\n'); 44 print_mdoc(mdoc->first->child, 0); 45 } 46 47 void 48 tree_man(void *arg, const struct roff_man *man) 49 { 50 print_meta(&man->meta); 51 if (man->meta.hasbody == 0) 52 puts("body = empty"); 53 putchar('\n'); 54 print_man(man->first->child, 0); 55 } 56 57 static void 58 print_meta(const struct roff_meta *meta) 59 { 60 if (meta->title != NULL) 61 printf("title = \"%s\"\n", meta->title); 62 if (meta->name != NULL) 63 printf("name = \"%s\"\n", meta->name); 64 if (meta->msec != NULL) 65 printf("sec = \"%s\"\n", meta->msec); 66 if (meta->vol != NULL) 67 printf("vol = \"%s\"\n", meta->vol); 68 if (meta->arch != NULL) 69 printf("arch = \"%s\"\n", meta->arch); 70 if (meta->os != NULL) 71 printf("os = \"%s\"\n", meta->os); 72 if (meta->date != NULL) 73 printf("date = \"%s\"\n", meta->date); 74 } 75 76 static void 77 print_mdoc(const struct roff_node *n, int indent) 78 { 79 const char *p, *t; 80 int i, j; 81 size_t argc; 82 struct mdoc_argv *argv; 83 84 if (n == NULL) 85 return; 86 87 argv = NULL; 88 argc = 0; 89 t = p = NULL; 90 91 switch (n->type) { 92 case ROFFT_ROOT: 93 t = "root"; 94 break; 95 case ROFFT_BLOCK: 96 t = "block"; 97 break; 98 case ROFFT_HEAD: 99 t = "head"; 100 break; 101 case ROFFT_BODY: 102 if (n->end) 103 t = "body-end"; 104 else 105 t = "body"; 106 break; 107 case ROFFT_TAIL: 108 t = "tail"; 109 break; 110 case ROFFT_ELEM: 111 t = "elem"; 112 break; 113 case ROFFT_TEXT: 114 t = "text"; 115 break; 116 case ROFFT_COMMENT: 117 t = "comment"; 118 break; 119 case ROFFT_TBL: 120 break; 121 case ROFFT_EQN: 122 t = "eqn"; 123 break; 124 default: 125 abort(); 126 } 127 128 switch (n->type) { 129 case ROFFT_TEXT: 130 case ROFFT_COMMENT: 131 p = n->string; 132 break; 133 case ROFFT_BODY: 134 p = roff_name[n->tok]; 135 break; 136 case ROFFT_HEAD: 137 p = roff_name[n->tok]; 138 break; 139 case ROFFT_TAIL: 140 p = roff_name[n->tok]; 141 break; 142 case ROFFT_ELEM: 143 p = roff_name[n->tok]; 144 if (n->args) { 145 argv = n->args->argv; 146 argc = n->args->argc; 147 } 148 break; 149 case ROFFT_BLOCK: 150 p = roff_name[n->tok]; 151 if (n->args) { 152 argv = n->args->argv; 153 argc = n->args->argc; 154 } 155 break; 156 case ROFFT_TBL: 157 break; 158 case ROFFT_EQN: 159 p = "EQ"; 160 break; 161 case ROFFT_ROOT: 162 p = "root"; 163 break; 164 default: 165 abort(); 166 } 167 168 if (n->span) { 169 assert(NULL == p && NULL == t); 170 print_span(n->span, indent); 171 } else { 172 for (i = 0; i < indent; i++) 173 putchar(' '); 174 175 printf("%s (%s)", p, t); 176 177 for (i = 0; i < (int)argc; i++) { 178 printf(" -%s", mdoc_argnames[argv[i].arg]); 179 if (argv[i].sz > 0) 180 printf(" ["); 181 for (j = 0; j < (int)argv[i].sz; j++) 182 printf(" [%s]", argv[i].value[j]); 183 if (argv[i].sz > 0) 184 printf(" ]"); 185 } 186 187 putchar(' '); 188 if (NODE_DELIMO & n->flags) 189 putchar('('); 190 if (NODE_LINE & n->flags) 191 putchar('*'); 192 printf("%d:%d", n->line, n->pos + 1); 193 if (NODE_DELIMC & n->flags) 194 putchar(')'); 195 if (NODE_EOS & n->flags) 196 putchar('.'); 197 if (NODE_BROKEN & n->flags) 198 printf(" BROKEN"); 199 if (NODE_NOSRC & n->flags) 200 printf(" NOSRC"); 201 if (NODE_NOPRT & n->flags) 202 printf(" NOPRT"); 203 putchar('\n'); 204 } 205 206 if (n->eqn) 207 print_box(n->eqn->first, indent + 4); 208 if (n->child) 209 print_mdoc(n->child, indent + 210 (n->type == ROFFT_BLOCK ? 2 : 4)); 211 if (n->next) 212 print_mdoc(n->next, indent); 213 } 214 215 static void 216 print_man(const struct roff_node *n, int indent) 217 { 218 const char *p, *t; 219 int i; 220 221 if (n == NULL) 222 return; 223 224 t = p = NULL; 225 226 switch (n->type) { 227 case ROFFT_ROOT: 228 t = "root"; 229 break; 230 case ROFFT_ELEM: 231 t = "elem"; 232 break; 233 case ROFFT_TEXT: 234 t = "text"; 235 break; 236 case ROFFT_COMMENT: 237 t = "comment"; 238 break; 239 case ROFFT_BLOCK: 240 t = "block"; 241 break; 242 case ROFFT_HEAD: 243 t = "head"; 244 break; 245 case ROFFT_BODY: 246 t = "body"; 247 break; 248 case ROFFT_TBL: 249 break; 250 case ROFFT_EQN: 251 t = "eqn"; 252 break; 253 default: 254 abort(); 255 } 256 257 switch (n->type) { 258 case ROFFT_TEXT: 259 case ROFFT_COMMENT: 260 p = n->string; 261 break; 262 case ROFFT_ELEM: 263 case ROFFT_BLOCK: 264 case ROFFT_HEAD: 265 case ROFFT_BODY: 266 p = roff_name[n->tok]; 267 break; 268 case ROFFT_ROOT: 269 p = "root"; 270 break; 271 case ROFFT_TBL: 272 break; 273 case ROFFT_EQN: 274 p = "EQ"; 275 break; 276 default: 277 abort(); 278 } 279 280 if (n->span) { 281 assert(NULL == p && NULL == t); 282 print_span(n->span, indent); 283 } else { 284 for (i = 0; i < indent; i++) 285 putchar(' '); 286 printf("%s (%s) ", p, t); 287 if (NODE_LINE & n->flags) 288 putchar('*'); 289 printf("%d:%d", n->line, n->pos + 1); 290 if (NODE_DELIMC & n->flags) 291 putchar(')'); 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 } 412