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