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