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