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