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