1 /* $OpenBSD: tree.c,v 1.45 2018/04/11 17:10:35 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_EOS & n->flags) 291 putchar('.'); 292 putchar('\n'); 293 } 294 295 if (n->eqn) 296 print_box(n->eqn->first, indent + 4); 297 if (n->child) 298 print_man(n->child, indent + 299 (n->type == ROFFT_BLOCK ? 2 : 4)); 300 if (n->next) 301 print_man(n->next, indent); 302 } 303 304 static void 305 print_box(const struct eqn_box *ep, int indent) 306 { 307 int i; 308 const char *t; 309 310 static const char *posnames[] = { 311 NULL, "sup", "subsup", "sub", 312 "to", "from", "fromto", 313 "over", "sqrt", NULL }; 314 315 if (NULL == ep) 316 return; 317 for (i = 0; i < indent; i++) 318 putchar(' '); 319 320 t = NULL; 321 switch (ep->type) { 322 case EQN_LIST: 323 t = "eqn-list"; 324 break; 325 case EQN_SUBEXPR: 326 t = "eqn-expr"; 327 break; 328 case EQN_TEXT: 329 t = "eqn-text"; 330 break; 331 case EQN_PILE: 332 t = "eqn-pile"; 333 break; 334 case EQN_MATRIX: 335 t = "eqn-matrix"; 336 break; 337 } 338 339 fputs(t, stdout); 340 if (ep->pos) 341 printf(" pos=%s", posnames[ep->pos]); 342 if (ep->left) 343 printf(" left=\"%s\"", ep->left); 344 if (ep->right) 345 printf(" right=\"%s\"", ep->right); 346 if (ep->top) 347 printf(" top=\"%s\"", ep->top); 348 if (ep->bottom) 349 printf(" bottom=\"%s\"", ep->bottom); 350 if (ep->text) 351 printf(" text=\"%s\"", ep->text); 352 if (ep->font) 353 printf(" font=%d", ep->font); 354 if (ep->size != EQN_DEFSIZE) 355 printf(" size=%d", ep->size); 356 if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args) 357 printf(" badargs=%zu(%zu)", ep->args, ep->expectargs); 358 else if (ep->args) 359 printf(" args=%zu", ep->args); 360 putchar('\n'); 361 362 print_box(ep->first, indent + 4); 363 print_box(ep->next, indent); 364 } 365 366 static void 367 print_span(const struct tbl_span *sp, int indent) 368 { 369 const struct tbl_dat *dp; 370 int i; 371 372 for (i = 0; i < indent; i++) 373 putchar(' '); 374 375 switch (sp->pos) { 376 case TBL_SPAN_HORIZ: 377 putchar('-'); 378 return; 379 case TBL_SPAN_DHORIZ: 380 putchar('='); 381 return; 382 default: 383 break; 384 } 385 386 for (dp = sp->first; dp; dp = dp->next) { 387 switch (dp->pos) { 388 case TBL_DATA_HORIZ: 389 case TBL_DATA_NHORIZ: 390 putchar('-'); 391 continue; 392 case TBL_DATA_DHORIZ: 393 case TBL_DATA_NDHORIZ: 394 putchar('='); 395 continue; 396 default: 397 break; 398 } 399 printf("[\"%s\"", dp->string ? dp->string : ""); 400 if (dp->spans) 401 printf("(%d)", dp->spans); 402 if (NULL == dp->layout) 403 putchar('*'); 404 putchar(']'); 405 putchar(' '); 406 } 407 408 printf("(tbl) %d:1\n", sp->line); 409 } 410