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