Annotation of mandoc/tree.c, Revision 1.89
1.89 ! schwarze 1: /* $Id: tree.c,v 1.88 2020/04/07 22:56:02 schwarze Exp $ */
1.1 kristaps 2: /*
1.87 schwarze 3: * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
1.58 schwarze 4: * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
1.12 kristaps 7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 9: *
1.63 schwarze 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1.12 kristaps 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1.63 schwarze 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1.12 kristaps 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.
1.87 schwarze 17: *
18: * Formatting module to let mandoc(1) show
19: * a human readable representation of the syntax tree.
1.1 kristaps 20: */
1.19 kristaps 21: #include "config.h"
1.54 schwarze 22:
23: #include <sys/types.h>
1.19 kristaps 24:
1.8 kristaps 25: #include <assert.h>
1.43 kristaps 26: #include <limits.h>
1.8 kristaps 27: #include <stdio.h>
1.1 kristaps 28: #include <stdlib.h>
1.17 kristaps 29: #include <time.h>
1.1 kristaps 30:
1.20 kristaps 31: #include "mandoc.h"
1.63 schwarze 32: #include "roff.h"
1.1 kristaps 33: #include "mdoc.h"
1.10 kristaps 34: #include "man.h"
1.81 schwarze 35: #include "tbl.h"
1.82 schwarze 36: #include "eqn.h"
1.16 kristaps 37: #include "main.h"
1.1 kristaps 38:
1.89 ! schwarze 39: static void print_attr(const struct roff_node *);
1.38 kristaps 40: static void print_box(const struct eqn_box *, int);
1.85 schwarze 41: static void print_cellt(enum tbl_cellt);
1.64 schwarze 42: static void print_man(const struct roff_node *, int);
1.72 schwarze 43: static void print_meta(const struct roff_meta *);
1.64 schwarze 44: static void print_mdoc(const struct roff_node *, int);
1.30 kristaps 45: static void print_span(const struct tbl_span *, int);
1.8 kristaps 46:
47:
1.15 kristaps 48: void
1.83 schwarze 49: tree_mdoc(void *arg, const struct roff_meta *mdoc)
1.8 kristaps 50: {
1.83 schwarze 51: print_meta(mdoc);
1.72 schwarze 52: putchar('\n');
1.66 schwarze 53: print_mdoc(mdoc->first->child, 0);
1.11 kristaps 54: }
55:
1.15 kristaps 56: void
1.83 schwarze 57: tree_man(void *arg, const struct roff_meta *man)
1.11 kristaps 58: {
1.83 schwarze 59: print_meta(man);
60: if (man->hasbody == 0)
1.72 schwarze 61: puts("body = empty");
62: putchar('\n');
63: print_man(man->first->child, 0);
64: }
1.11 kristaps 65:
1.72 schwarze 66: static void
67: print_meta(const struct roff_meta *meta)
68: {
69: if (meta->title != NULL)
70: printf("title = \"%s\"\n", meta->title);
71: if (meta->name != NULL)
72: printf("name = \"%s\"\n", meta->name);
73: if (meta->msec != NULL)
74: printf("sec = \"%s\"\n", meta->msec);
75: if (meta->vol != NULL)
76: printf("vol = \"%s\"\n", meta->vol);
77: if (meta->arch != NULL)
78: printf("arch = \"%s\"\n", meta->arch);
79: if (meta->os != NULL)
80: printf("os = \"%s\"\n", meta->os);
81: if (meta->date != NULL)
82: printf("date = \"%s\"\n", meta->date);
1.8 kristaps 83: }
1.2 kristaps 84:
1.1 kristaps 85: static void
1.64 schwarze 86: print_mdoc(const struct roff_node *n, int indent)
1.1 kristaps 87: {
88: const char *p, *t;
89: int i, j;
1.48 schwarze 90: size_t argc;
1.8 kristaps 91: struct mdoc_argv *argv;
1.1 kristaps 92:
1.61 schwarze 93: if (n == NULL)
94: return;
95:
1.1 kristaps 96: argv = NULL;
1.48 schwarze 97: argc = 0;
1.38 kristaps 98: t = p = NULL;
1.1 kristaps 99:
1.2 kristaps 100: switch (n->type) {
1.63 schwarze 101: case ROFFT_ROOT:
1.2 kristaps 102: t = "root";
103: break;
1.63 schwarze 104: case ROFFT_BLOCK:
1.2 kristaps 105: t = "block";
106: break;
1.63 schwarze 107: case ROFFT_HEAD:
1.68 schwarze 108: t = "head";
1.2 kristaps 109: break;
1.63 schwarze 110: case ROFFT_BODY:
1.23 schwarze 111: if (n->end)
112: t = "body-end";
113: else
1.68 schwarze 114: t = "body";
1.2 kristaps 115: break;
1.63 schwarze 116: case ROFFT_TAIL:
1.68 schwarze 117: t = "tail";
1.2 kristaps 118: break;
1.63 schwarze 119: case ROFFT_ELEM:
1.2 kristaps 120: t = "elem";
121: break;
1.63 schwarze 122: case ROFFT_TEXT:
1.2 kristaps 123: t = "text";
124: break;
1.78 schwarze 125: case ROFFT_COMMENT:
126: t = "comment";
127: break;
1.63 schwarze 128: case ROFFT_TBL:
1.59 schwarze 129: break;
1.63 schwarze 130: case ROFFT_EQN:
1.59 schwarze 131: t = "eqn";
1.33 kristaps 132: break;
1.2 kristaps 133: default:
134: abort();
135: }
1.1 kristaps 136:
137: switch (n->type) {
1.63 schwarze 138: case ROFFT_TEXT:
1.78 schwarze 139: case ROFFT_COMMENT:
1.8 kristaps 140: p = n->string;
1.1 kristaps 141: break;
1.63 schwarze 142: case ROFFT_BODY:
1.74 schwarze 143: p = roff_name[n->tok];
1.1 kristaps 144: break;
1.63 schwarze 145: case ROFFT_HEAD:
1.74 schwarze 146: p = roff_name[n->tok];
1.1 kristaps 147: break;
1.63 schwarze 148: case ROFFT_TAIL:
1.74 schwarze 149: p = roff_name[n->tok];
1.1 kristaps 150: break;
1.63 schwarze 151: case ROFFT_ELEM:
1.74 schwarze 152: p = roff_name[n->tok];
1.8 kristaps 153: if (n->args) {
154: argv = n->args->argv;
155: argc = n->args->argc;
156: }
1.1 kristaps 157: break;
1.63 schwarze 158: case ROFFT_BLOCK:
1.74 schwarze 159: p = roff_name[n->tok];
1.8 kristaps 160: if (n->args) {
161: argv = n->args->argv;
162: argc = n->args->argc;
163: }
1.1 kristaps 164: break;
1.63 schwarze 165: case ROFFT_TBL:
1.59 schwarze 166: break;
1.63 schwarze 167: case ROFFT_EQN:
1.59 schwarze 168: p = "EQ";
1.33 kristaps 169: break;
1.63 schwarze 170: case ROFFT_ROOT:
1.1 kristaps 171: p = "root";
172: break;
173: default:
174: abort();
175: }
176:
1.26 kristaps 177: if (n->span) {
1.38 kristaps 178: assert(NULL == p && NULL == t);
1.30 kristaps 179: print_span(n->span, indent);
1.26 kristaps 180: } else {
1.30 kristaps 181: for (i = 0; i < indent; i++)
1.61 schwarze 182: putchar(' ');
1.30 kristaps 183:
1.26 kristaps 184: printf("%s (%s)", p, t);
185:
186: for (i = 0; i < (int)argc; i++) {
187: printf(" -%s", mdoc_argnames[argv[i].arg]);
188: if (argv[i].sz > 0)
189: printf(" [");
190: for (j = 0; j < (int)argv[i].sz; j++)
191: printf(" [%s]", argv[i].value[j]);
192: if (argv[i].sz > 0)
193: printf(" ]");
194: }
1.89 ! schwarze 195: print_attr(n);
1.1 kristaps 196: }
1.59 schwarze 197: if (n->eqn)
1.77 schwarze 198: print_box(n->eqn->first, indent + 4);
1.1 kristaps 199: if (n->child)
1.61 schwarze 200: print_mdoc(n->child, indent +
1.63 schwarze 201: (n->type == ROFFT_BLOCK ? 2 : 4));
1.1 kristaps 202: if (n->next)
1.11 kristaps 203: print_mdoc(n->next, indent);
1.1 kristaps 204: }
1.2 kristaps 205:
1.10 kristaps 206: static void
1.64 schwarze 207: print_man(const struct roff_node *n, int indent)
1.10 kristaps 208: {
209: const char *p, *t;
210: int i;
211:
1.61 schwarze 212: if (n == NULL)
213: return;
214:
1.38 kristaps 215: t = p = NULL;
216:
1.10 kristaps 217: switch (n->type) {
1.63 schwarze 218: case ROFFT_ROOT:
1.10 kristaps 219: t = "root";
220: break;
1.63 schwarze 221: case ROFFT_ELEM:
1.10 kristaps 222: t = "elem";
223: break;
1.63 schwarze 224: case ROFFT_TEXT:
1.10 kristaps 225: t = "text";
226: break;
1.78 schwarze 227: case ROFFT_COMMENT:
228: t = "comment";
229: break;
1.63 schwarze 230: case ROFFT_BLOCK:
1.14 kristaps 231: t = "block";
232: break;
1.63 schwarze 233: case ROFFT_HEAD:
1.68 schwarze 234: t = "head";
1.14 kristaps 235: break;
1.63 schwarze 236: case ROFFT_BODY:
1.68 schwarze 237: t = "body";
1.14 kristaps 238: break;
1.63 schwarze 239: case ROFFT_TBL:
1.59 schwarze 240: break;
1.63 schwarze 241: case ROFFT_EQN:
1.59 schwarze 242: t = "eqn";
1.33 kristaps 243: break;
1.10 kristaps 244: default:
245: abort();
246: }
247:
248: switch (n->type) {
1.63 schwarze 249: case ROFFT_TEXT:
1.78 schwarze 250: case ROFFT_COMMENT:
1.10 kristaps 251: p = n->string;
252: break;
1.63 schwarze 253: case ROFFT_ELEM:
254: case ROFFT_BLOCK:
255: case ROFFT_HEAD:
256: case ROFFT_BODY:
1.74 schwarze 257: p = roff_name[n->tok];
1.10 kristaps 258: break;
1.63 schwarze 259: case ROFFT_ROOT:
1.10 kristaps 260: p = "root";
1.25 kristaps 261: break;
1.63 schwarze 262: case ROFFT_TBL:
1.59 schwarze 263: break;
1.63 schwarze 264: case ROFFT_EQN:
1.59 schwarze 265: p = "EQ";
1.10 kristaps 266: break;
267: default:
268: abort();
269: }
270:
1.26 kristaps 271: if (n->span) {
1.38 kristaps 272: assert(NULL == p && NULL == t);
1.30 kristaps 273: print_span(n->span, indent);
274: } else {
275: for (i = 0; i < indent; i++)
1.61 schwarze 276: putchar(' ');
1.89 ! schwarze 277: printf("%s (%s)", p, t);
! 278: print_attr(n);
1.30 kristaps 279: }
1.59 schwarze 280: if (n->eqn)
1.77 schwarze 281: print_box(n->eqn->first, indent + 4);
1.10 kristaps 282: if (n->child)
1.61 schwarze 283: print_man(n->child, indent +
1.63 schwarze 284: (n->type == ROFFT_BLOCK ? 2 : 4));
1.10 kristaps 285: if (n->next)
1.11 kristaps 286: print_man(n->next, indent);
1.89 ! schwarze 287: }
! 288:
! 289: static void
! 290: print_attr(const struct roff_node *n)
! 291: {
! 292: putchar(' ');
! 293: if (n->flags & NODE_DELIMO)
! 294: putchar('(');
! 295: if (n->flags & NODE_LINE)
! 296: putchar('*');
! 297: printf("%d:%d", n->line, n->pos + 1);
! 298: if (n->flags & NODE_DELIMC)
! 299: putchar(')');
! 300: if (n->flags & NODE_EOS)
! 301: putchar('.');
! 302: if (n->flags & NODE_ID) {
! 303: printf(" ID");
! 304: if (n->flags & NODE_HREF)
! 305: printf("=HREF");
! 306: } else if (n->flags & NODE_HREF)
! 307: printf(" HREF");
! 308: else if (n->tag != NULL)
! 309: printf(" STRAYTAG");
! 310: if (n->tag != NULL)
! 311: printf("=%s", n->tag);
! 312: if (n->flags & NODE_BROKEN)
! 313: printf(" BROKEN");
! 314: if (n->flags & NODE_NOFILL)
! 315: printf(" NOFILL");
! 316: if (n->flags & NODE_NOSRC)
! 317: printf(" NOSRC");
! 318: if (n->flags & NODE_NOPRT)
! 319: printf(" NOPRT");
! 320: putchar('\n');
1.28 kristaps 321: }
322:
323: static void
1.38 kristaps 324: print_box(const struct eqn_box *ep, int indent)
325: {
326: int i;
1.46 kristaps 327: const char *t;
1.38 kristaps 328:
1.57 schwarze 329: static const char *posnames[] = {
330: NULL, "sup", "subsup", "sub",
331: "to", "from", "fromto",
332: "over", "sqrt", NULL };
333:
1.38 kristaps 334: if (NULL == ep)
335: return;
336: for (i = 0; i < indent; i++)
1.61 schwarze 337: putchar(' ');
1.38 kristaps 338:
1.46 kristaps 339: t = NULL;
1.38 kristaps 340: switch (ep->type) {
1.52 schwarze 341: case EQN_LIST:
1.46 kristaps 342: t = "eqn-list";
1.39 kristaps 343: break;
1.52 schwarze 344: case EQN_SUBEXPR:
1.46 kristaps 345: t = "eqn-expr";
1.39 kristaps 346: break;
1.52 schwarze 347: case EQN_TEXT:
1.46 kristaps 348: t = "eqn-text";
1.39 kristaps 349: break;
1.56 kristaps 350: case EQN_PILE:
351: t = "eqn-pile";
352: break;
1.52 schwarze 353: case EQN_MATRIX:
1.46 kristaps 354: t = "eqn-matrix";
1.38 kristaps 355: break;
356: }
1.39 kristaps 357:
1.57 schwarze 358: fputs(t, stdout);
359: if (ep->pos)
360: printf(" pos=%s", posnames[ep->pos]);
361: if (ep->left)
362: printf(" left=\"%s\"", ep->left);
363: if (ep->right)
364: printf(" right=\"%s\"", ep->right);
365: if (ep->top)
366: printf(" top=\"%s\"", ep->top);
367: if (ep->bottom)
368: printf(" bottom=\"%s\"", ep->bottom);
369: if (ep->text)
370: printf(" text=\"%s\"", ep->text);
371: if (ep->font)
372: printf(" font=%d", ep->font);
373: if (ep->size != EQN_DEFSIZE)
374: printf(" size=%d", ep->size);
375: if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
376: printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
377: else if (ep->args)
378: printf(" args=%zu", ep->args);
379: putchar('\n');
1.46 kristaps 380:
1.61 schwarze 381: print_box(ep->first, indent + 4);
1.39 kristaps 382: print_box(ep->next, indent);
1.38 kristaps 383: }
384:
385: static void
1.85 schwarze 386: print_cellt(enum tbl_cellt pos)
387: {
388: switch(pos) {
389: case TBL_CELL_LEFT:
390: putchar('L');
391: break;
392: case TBL_CELL_LONG:
393: putchar('a');
394: break;
395: case TBL_CELL_CENTRE:
396: putchar('c');
397: break;
398: case TBL_CELL_RIGHT:
399: putchar('r');
400: break;
401: case TBL_CELL_NUMBER:
402: putchar('n');
403: break;
404: case TBL_CELL_SPAN:
405: putchar('s');
406: break;
407: case TBL_CELL_DOWN:
408: putchar('^');
409: break;
410: case TBL_CELL_HORIZ:
411: putchar('-');
412: break;
413: case TBL_CELL_DHORIZ:
414: putchar('=');
415: break;
416: case TBL_CELL_MAX:
417: putchar('#');
418: break;
419: }
420: }
421:
422: static void
1.30 kristaps 423: print_span(const struct tbl_span *sp, int indent)
1.28 kristaps 424: {
425: const struct tbl_dat *dp;
1.85 schwarze 426: const struct tbl_cell *cp;
1.30 kristaps 427: int i;
428:
1.85 schwarze 429: if (sp->prev == NULL) {
430: for (i = 0; i < indent; i++)
431: putchar(' ');
432: printf("%d", sp->opts->cols);
433: if (sp->opts->opts & TBL_OPT_CENTRE)
434: fputs(" center", stdout);
435: if (sp->opts->opts & TBL_OPT_EXPAND)
436: fputs(" expand", stdout);
437: if (sp->opts->opts & TBL_OPT_ALLBOX)
438: fputs(" allbox", stdout);
439: if (sp->opts->opts & TBL_OPT_BOX)
440: fputs(" box", stdout);
441: if (sp->opts->opts & TBL_OPT_DBOX)
442: fputs(" doublebox", stdout);
443: if (sp->opts->opts & TBL_OPT_NOKEEP)
444: fputs(" nokeep", stdout);
445: if (sp->opts->opts & TBL_OPT_NOSPACE)
446: fputs(" nospaces", stdout);
447: if (sp->opts->opts & TBL_OPT_NOWARN)
448: fputs(" nowarn", stdout);
449: printf(" (tbl options) %d:1\n", sp->line);
450: }
451:
1.30 kristaps 452: for (i = 0; i < indent; i++)
1.61 schwarze 453: putchar(' ');
1.28 kristaps 454:
455: switch (sp->pos) {
1.52 schwarze 456: case TBL_SPAN_HORIZ:
1.28 kristaps 457: putchar('-');
1.80 schwarze 458: putchar(' ');
459: break;
1.52 schwarze 460: case TBL_SPAN_DHORIZ:
1.28 kristaps 461: putchar('=');
1.80 schwarze 462: putchar(' ');
463: break;
1.28 kristaps 464: default:
1.85 schwarze 465: for (cp = sp->layout->first; cp != NULL; cp = cp->next)
466: print_cellt(cp->pos);
467: putchar(' ');
1.80 schwarze 468: for (dp = sp->first; dp; dp = dp->next) {
1.85 schwarze 469: if ((cp = dp->layout) == NULL)
470: putchar('*');
471: else {
472: printf("%d", cp->col);
473: print_cellt(dp->layout->pos);
474: if (cp->flags & TBL_CELL_BOLD)
475: putchar('b');
476: if (cp->flags & TBL_CELL_ITALIC)
477: putchar('i');
478: if (cp->flags & TBL_CELL_TALIGN)
479: putchar('t');
480: if (cp->flags & TBL_CELL_UP)
481: putchar('u');
482: if (cp->flags & TBL_CELL_BALIGN)
483: putchar('d');
484: if (cp->flags & TBL_CELL_WIGN)
485: putchar('z');
486: if (cp->flags & TBL_CELL_EQUAL)
487: putchar('e');
488: if (cp->flags & TBL_CELL_WMAX)
489: putchar('x');
490: }
1.80 schwarze 491: switch (dp->pos) {
492: case TBL_DATA_HORIZ:
493: case TBL_DATA_NHORIZ:
494: putchar('-');
1.85 schwarze 495: break;
1.80 schwarze 496: case TBL_DATA_DHORIZ:
497: case TBL_DATA_NDHORIZ:
498: putchar('=');
1.85 schwarze 499: break;
1.80 schwarze 500: default:
1.85 schwarze 501: putchar(dp->block ? '{' : '[');
502: if (dp->string != NULL)
503: fputs(dp->string, stdout);
504: putchar(dp->block ? '}' : ']');
1.80 schwarze 505: break;
506: }
507: if (dp->hspans)
508: printf(">%d", dp->hspans);
509: if (dp->vspans)
510: printf("v%d", dp->vspans);
511: putchar(' ');
512: }
1.28 kristaps 513: break;
514: }
1.38 kristaps 515: printf("(tbl) %d:1\n", sp->line);
1.10 kristaps 516: }
CVSweb