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