1 /* $OpenBSD: tree.c,v 1.36 2015/10/12 00:07:27 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 case ROFFT_BLOCK: 226 case ROFFT_HEAD: 227 case ROFFT_BODY: 228 p = man_macronames[n->tok]; 229 break; 230 case ROFFT_ROOT: 231 p = "root"; 232 break; 233 case ROFFT_TBL: 234 break; 235 case ROFFT_EQN: 236 p = "EQ"; 237 break; 238 default: 239 abort(); 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->line, n->pos + 1); 252 if (MAN_EOS & n->flags) 253 putchar('.'); 254 putchar('\n'); 255 } 256 257 if (n->eqn) 258 print_box(n->eqn->root->first, indent + 4); 259 if (n->child) 260 print_man(n->child, indent + 261 (n->type == ROFFT_BLOCK ? 2 : 4)); 262 if (n->next) 263 print_man(n->next, indent); 264 } 265 266 static void 267 print_box(const struct eqn_box *ep, int indent) 268 { 269 int i; 270 const char *t; 271 272 static const char *posnames[] = { 273 NULL, "sup", "subsup", "sub", 274 "to", "from", "fromto", 275 "over", "sqrt", NULL }; 276 277 if (NULL == ep) 278 return; 279 for (i = 0; i < indent; i++) 280 putchar(' '); 281 282 t = NULL; 283 switch (ep->type) { 284 case EQN_ROOT: 285 t = "eqn-root"; 286 break; 287 case EQN_LISTONE: 288 case EQN_LIST: 289 t = "eqn-list"; 290 break; 291 case EQN_SUBEXPR: 292 t = "eqn-expr"; 293 break; 294 case EQN_TEXT: 295 t = "eqn-text"; 296 break; 297 case EQN_PILE: 298 t = "eqn-pile"; 299 break; 300 case EQN_MATRIX: 301 t = "eqn-matrix"; 302 break; 303 } 304 305 fputs(t, stdout); 306 if (ep->pos) 307 printf(" pos=%s", posnames[ep->pos]); 308 if (ep->left) 309 printf(" left=\"%s\"", ep->left); 310 if (ep->right) 311 printf(" right=\"%s\"", ep->right); 312 if (ep->top) 313 printf(" top=\"%s\"", ep->top); 314 if (ep->bottom) 315 printf(" bottom=\"%s\"", ep->bottom); 316 if (ep->text) 317 printf(" text=\"%s\"", ep->text); 318 if (ep->font) 319 printf(" font=%d", ep->font); 320 if (ep->size != EQN_DEFSIZE) 321 printf(" size=%d", ep->size); 322 if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args) 323 printf(" badargs=%zu(%zu)", ep->args, ep->expectargs); 324 else if (ep->args) 325 printf(" args=%zu", ep->args); 326 putchar('\n'); 327 328 print_box(ep->first, indent + 4); 329 print_box(ep->next, indent); 330 } 331 332 static void 333 print_span(const struct tbl_span *sp, int indent) 334 { 335 const struct tbl_dat *dp; 336 int i; 337 338 for (i = 0; i < indent; i++) 339 putchar(' '); 340 341 switch (sp->pos) { 342 case TBL_SPAN_HORIZ: 343 putchar('-'); 344 return; 345 case TBL_SPAN_DHORIZ: 346 putchar('='); 347 return; 348 default: 349 break; 350 } 351 352 for (dp = sp->first; dp; dp = dp->next) { 353 switch (dp->pos) { 354 case TBL_DATA_HORIZ: 355 case TBL_DATA_NHORIZ: 356 putchar('-'); 357 continue; 358 case TBL_DATA_DHORIZ: 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