Annotation of docbook2mdoc/docbook2mdoc.c, Revision 1.75
1.75 ! schwarze 1: /* $Id: docbook2mdoc.c,v 1.74 2019/03/26 18:32:07 schwarze Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2014 Kristaps Dzonsons <kristaps@bsd.lv>
1.50 schwarze 4: * Copyright (c) 2019 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 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 <assert.h>
19: #include <ctype.h>
20: #include <stdio.h>
21: #include <stdlib.h>
22:
1.74 schwarze 23: #include "node.h"
1.75 ! schwarze 24: #include "macro.h"
1.74 schwarze 25: #include "format.h"
26:
27: /*
28: * The implementation of the mdoc(7) formatter.
29: */
1.12 kristaps 30:
1.74 schwarze 31: static void pnode_print(struct format *, struct pnode *);
1.25 kristaps 32:
1.37 kristaps 33:
1.54 schwarze 34: static void
1.74 schwarze 35: print_text(struct format *p, const char *word)
1.70 schwarze 36: {
37: switch (p->linestate) {
38: case LINE_NEW:
39: break;
40: case LINE_TEXT:
41: putchar(' ');
42: break;
43: case LINE_MACRO:
44: macro_close(p);
45: break;
46: }
47: fputs(word, stdout);
48: p->linestate = LINE_TEXT;
49: }
50:
51: static void
1.74 schwarze 52: pnode_printpara(struct format *p, struct pnode *pn)
1.54 schwarze 53: {
54: struct pnode *pp;
55:
1.61 schwarze 56: if ((pp = TAILQ_PREV(pn, pnodeq, child)) == NULL &&
57: (pp = pn->parent) == NULL)
1.54 schwarze 58: return;
59:
1.61 schwarze 60: switch (pp->node) {
61: case NODE_ENTRY:
62: case NODE_LISTITEM:
63: return;
64: case NODE_PREFACE:
65: case NODE_SECTION:
66: if (p->level < 3)
67: return;
68: break;
69: default:
70: break;
71: }
1.69 schwarze 72: macro_line(p, "Pp");
1.54 schwarze 73: }
74:
1.37 kristaps 75: /*
1.10 kristaps 76: * If the SYNOPSIS macro has a superfluous title, kill it.
1.8 kristaps 77: */
1.1 kristaps 78: static void
1.74 schwarze 79: pnode_printrefsynopsisdiv(struct format *p, struct pnode *pn)
1.6 kristaps 80: {
1.71 schwarze 81: struct pnode *pp, *pq;
1.6 kristaps 82:
1.71 schwarze 83: TAILQ_FOREACH_SAFE(pp, &pn->childq, child, pq)
84: if (pp->node == NODE_TITLE)
1.6 kristaps 85: pnode_unlink(pp);
1.71 schwarze 86:
87: macro_line(p, "Sh SYNOPSIS");
1.6 kristaps 88: }
89:
1.8 kristaps 90: /*
91: * Start a hopefully-named `Sh' section.
92: */
1.6 kristaps 93: static void
1.74 schwarze 94: pnode_printrefsect(struct format *p, struct pnode *pn)
1.1 kristaps 95: {
96: struct pnode *pp;
1.52 schwarze 97: const char *title;
98: int flags, level;
99:
1.64 schwarze 100: if (pn->parent == NULL)
1.56 schwarze 101: return;
102:
1.52 schwarze 103: level = ++p->level;
1.72 schwarze 104: flags = ARG_SPACE;
105: if (level == 1)
106: flags |= ARG_UPPER;
1.64 schwarze 107: if (level < 3) {
1.52 schwarze 108: switch (pn->node) {
1.62 schwarze 109: case NODE_CAUTION:
110: case NODE_NOTE:
111: case NODE_TIP:
112: case NODE_WARNING:
1.52 schwarze 113: level = 3;
114: break;
115: default:
116: break;
117: }
118: }
1.1 kristaps 119:
120: TAILQ_FOREACH(pp, &pn->childq, child)
1.64 schwarze 121: if (pp->node == NODE_TITLE)
1.1 kristaps 122: break;
123:
1.64 schwarze 124: if (pp == NULL) {
1.52 schwarze 125: switch (pn->node) {
1.62 schwarze 126: case NODE_PREFACE:
1.52 schwarze 127: title = "Preface";
128: break;
1.62 schwarze 129: case NODE_CAUTION:
1.52 schwarze 130: title = "Caution";
131: break;
1.62 schwarze 132: case NODE_NOTE:
1.52 schwarze 133: title = "Note";
134: break;
1.62 schwarze 135: case NODE_TIP:
1.52 schwarze 136: title = "Tip";
137: break;
1.62 schwarze 138: case NODE_WARNING:
1.52 schwarze 139: title = "Warning";
140: break;
141: default:
142: title = "Unknown";
143: break;
144: }
145: }
146:
147: switch (level) {
1.62 schwarze 148: case 1:
1.69 schwarze 149: macro_open(p, "Sh");
1.29 kristaps 150: break;
1.62 schwarze 151: case 2:
1.69 schwarze 152: macro_open(p, "Ss");
1.29 kristaps 153: break;
1.52 schwarze 154: default:
1.54 schwarze 155: pnode_printpara(p, pn);
1.69 schwarze 156: macro_open(p, "Sy");
1.29 kristaps 157: break;
158: }
1.20 kristaps 159:
1.64 schwarze 160: if (pp != NULL) {
1.69 schwarze 161: macro_addnode(p, pp, flags);
1.5 kristaps 162: pnode_unlink(pp);
1.52 schwarze 163: } else
1.72 schwarze 164: macro_addarg(p, title, ARG_SPACE | ARG_QUOTED);
1.69 schwarze 165: macro_close(p);
1.1 kristaps 166: }
167:
1.8 kristaps 168: /*
169: * Start a reference, extracting the title and volume.
170: */
1.1 kristaps 171: static void
1.74 schwarze 172: pnode_printciterefentry(struct format *p, struct pnode *pn)
1.1 kristaps 173: {
174: struct pnode *pp, *title, *manvol;
175:
176: title = manvol = NULL;
1.69 schwarze 177: TAILQ_FOREACH(pp, &pn->childq, child) {
1.64 schwarze 178: if (pp->node == NODE_MANVOLNUM)
1.1 kristaps 179: manvol = pp;
1.64 schwarze 180: else if (pp->node == NODE_REFENTRYTITLE)
1.1 kristaps 181: title = pp;
1.69 schwarze 182: }
183: macro_open(p, "Xr");
184: if (title == NULL)
1.72 schwarze 185: macro_addarg(p, "unknown", ARG_SPACE);
1.69 schwarze 186: else
1.72 schwarze 187: macro_addnode(p, title, ARG_SPACE | ARG_SINGLE);
1.69 schwarze 188: if (manvol == NULL)
1.72 schwarze 189: macro_addarg(p, "1", ARG_SPACE);
1.64 schwarze 190: else
1.72 schwarze 191: macro_addnode(p, manvol, ARG_SPACE | ARG_SINGLE);
1.69 schwarze 192: macro_close(p);
1.71 schwarze 193: pnode_unlinksub(pn);
1.1 kristaps 194: }
195:
196: static void
1.74 schwarze 197: pnode_printrefmeta(struct format *p, struct pnode *pn)
1.1 kristaps 198: {
199: struct pnode *pp, *title, *manvol;
200:
201: title = manvol = NULL;
1.69 schwarze 202: TAILQ_FOREACH(pp, &pn->childq, child) {
1.64 schwarze 203: if (pp->node == NODE_MANVOLNUM)
1.1 kristaps 204: manvol = pp;
1.64 schwarze 205: else if (pp->node == NODE_REFENTRYTITLE)
1.1 kristaps 206: title = pp;
1.69 schwarze 207: }
208: macro_open(p, "Dt");
209: if (title == NULL)
1.72 schwarze 210: macro_addarg(p, "UNKNOWN", ARG_SPACE);
1.69 schwarze 211: else
1.72 schwarze 212: macro_addnode(p, title, ARG_SPACE | ARG_SINGLE | ARG_UPPER);
1.69 schwarze 213: if (manvol == NULL)
1.72 schwarze 214: macro_addarg(p, "1", ARG_SPACE);
1.13 kristaps 215: else
1.72 schwarze 216: macro_addnode(p, manvol, ARG_SPACE | ARG_SINGLE);
1.69 schwarze 217: macro_close(p);
1.71 schwarze 218: pnode_unlink(pn);
1.1 kristaps 219: }
220:
1.3 kristaps 221: static void
1.74 schwarze 222: pnode_printfuncdef(struct format *p, struct pnode *pn)
1.3 kristaps 223: {
224: struct pnode *pp, *ftype, *func;
225:
226: ftype = func = NULL;
1.69 schwarze 227: TAILQ_FOREACH(pp, &pn->childq, child) {
1.64 schwarze 228: if (pp->node == NODE_TEXT)
1.3 kristaps 229: ftype = pp;
1.64 schwarze 230: else if (pp->node == NODE_FUNCTION)
1.3 kristaps 231: func = pp;
1.13 kristaps 232: }
1.69 schwarze 233: if (ftype != NULL)
1.72 schwarze 234: macro_argline(p, "Ft", ftype->b);
1.69 schwarze 235: macro_open(p, "Fo");
236: if (func == NULL)
1.72 schwarze 237: macro_addarg(p, "UNKNOWN", ARG_SPACE);
1.69 schwarze 238: else
1.72 schwarze 239: macro_addnode(p, func, ARG_SPACE | ARG_SINGLE);
1.69 schwarze 240: macro_close(p);
1.3 kristaps 241: }
242:
1.40 kristaps 243: /*
1.41 kristaps 244: * The <mml:mfenced> node is a little peculiar.
245: * First, it can have arbitrary open and closing tokens, which default
246: * to parentheses.
247: * Second, >1 arguments are separated by commas.
248: */
249: static void
1.74 schwarze 250: pnode_printmathfenced(struct format *p, struct pnode *pn)
1.41 kristaps 251: {
252: struct pnode *pp;
253:
1.59 schwarze 254: printf("left %s ", pnode_getattr_raw(pn, ATTRKEY_OPEN, "("));
1.41 kristaps 255:
256: pp = TAILQ_FIRST(&pn->childq);
257: pnode_print(p, pp);
258:
1.64 schwarze 259: while ((pp = TAILQ_NEXT(pp, child)) != NULL) {
1.41 kristaps 260: putchar(',');
261: pnode_print(p, pp);
262: }
1.59 schwarze 263: printf("right %s ", pnode_getattr_raw(pn, ATTRKEY_CLOSE, ")"));
1.71 schwarze 264: pnode_unlinksub(pn);
1.41 kristaps 265: }
266:
267: /*
1.40 kristaps 268: * These math nodes require special handling because they have infix
269: * syntax, instead of the usual prefix or prefix.
270: * So we need to break up the first and second child node with a
271: * particular eqn(7) word.
272: */
273: static void
1.74 schwarze 274: pnode_printmath(struct format *p, struct pnode *pn)
1.40 kristaps 275: {
276: struct pnode *pp;
277:
278: pp = TAILQ_FIRST(&pn->childq);
279: pnode_print(p, pp);
280:
281: switch (pn->node) {
1.62 schwarze 282: case NODE_MML_MSUP:
1.42 kristaps 283: fputs(" sup ", stdout);
1.40 kristaps 284: break;
1.62 schwarze 285: case NODE_MML_MFRAC:
1.42 kristaps 286: fputs(" over ", stdout);
1.40 kristaps 287: break;
1.62 schwarze 288: case NODE_MML_MSUB:
1.42 kristaps 289: fputs(" sub ", stdout);
1.40 kristaps 290: break;
291: default:
292: break;
293: }
294:
295: pp = TAILQ_NEXT(pp, child);
296: pnode_print(p, pp);
1.71 schwarze 297: pnode_unlinksub(pn);
1.40 kristaps 298: }
299:
1.3 kristaps 300: static void
1.74 schwarze 301: pnode_printfuncprototype(struct format *p, struct pnode *pn)
1.3 kristaps 302: {
303: struct pnode *pp, *fdef;
304:
305: TAILQ_FOREACH(fdef, &pn->childq, child)
1.64 schwarze 306: if (fdef->node == NODE_FUNCDEF)
1.3 kristaps 307: break;
308:
1.64 schwarze 309: if (fdef != NULL)
1.3 kristaps 310: pnode_printfuncdef(p, fdef);
1.4 kristaps 311: else
1.69 schwarze 312: macro_line(p, "Fo UNKNOWN");
1.3 kristaps 313:
1.44 schwarze 314: TAILQ_FOREACH(pp, &pn->childq, child)
1.64 schwarze 315: if (pp->node == NODE_PARAMDEF)
1.72 schwarze 316: macro_nodeline(p, "Fa", pp, ARG_SINGLE);
1.3 kristaps 317:
1.69 schwarze 318: macro_line(p, "Fc");
1.71 schwarze 319: pnode_unlinksub(pn);
1.3 kristaps 320: }
321:
1.44 schwarze 322: /*
1.10 kristaps 323: * The <arg> element is more complicated than it should be because text
324: * nodes are treated like ".Ar foo", but non-text nodes need to be
325: * re-sent into the printer (i.e., without the preceding ".Ar").
1.12 kristaps 326: * This also handles the case of "repetition" (or in other words, the
327: * ellipsis following an argument) and optionality.
1.10 kristaps 328: */
1.4 kristaps 329: static void
1.74 schwarze 330: pnode_printarg(struct format *p, struct pnode *pn)
1.4 kristaps 331: {
332: struct pnode *pp;
1.12 kristaps 333: struct pattr *ap;
334: int isop, isrep;
335:
336: isop = 1;
337: isrep = 0;
1.69 schwarze 338: TAILQ_FOREACH(ap, &pn->attrq, child) {
1.64 schwarze 339: if (ap->key == ATTRKEY_CHOICE &&
340: (ap->val == ATTRVAL_PLAIN || ap->val == ATTRVAL_REQ))
1.12 kristaps 341: isop = 0;
1.64 schwarze 342: else if (ap->key == ATTRKEY_REP && ap->val == ATTRVAL_REPEAT)
1.12 kristaps 343: isrep = 1;
344: }
1.69 schwarze 345: if (isop)
346: macro_open(p, "Op");
1.4 kristaps 347:
1.10 kristaps 348: TAILQ_FOREACH(pp, &pn->childq, child) {
1.69 schwarze 349: if (pp->node == NODE_TEXT)
350: macro_open(p, "Ar");
1.10 kristaps 351: pnode_print(p, pp);
1.64 schwarze 352: if (isrep && pp->node == NODE_TEXT)
1.72 schwarze 353: macro_addarg(p, "...", ARG_SPACE);
1.10 kristaps 354: }
1.71 schwarze 355: pnode_unlinksub(pn);
1.4 kristaps 356: }
357:
1.24 kristaps 358: static void
1.74 schwarze 359: pnode_printgroup(struct format *p, struct pnode *pn)
1.24 kristaps 360: {
361: struct pnode *pp, *np;
362: struct pattr *ap;
363: int isop, sv;
364:
365: isop = 1;
1.44 schwarze 366: TAILQ_FOREACH(ap, &pn->attrq, child)
1.64 schwarze 367: if (ap->key == ATTRKEY_CHOICE &&
368: (ap->val == ATTRVAL_PLAIN || ap->val == ATTRVAL_REQ)) {
1.24 kristaps 369: isop = 0;
370: break;
371: }
372:
1.44 schwarze 373: /*
1.24 kristaps 374: * Make sure we're on a macro line.
375: * This will prevent pnode_print() for putting us on a
376: * subsequent line.
377: */
1.69 schwarze 378: sv = p->linestate == LINE_NEW;
1.44 schwarze 379: if (isop)
1.69 schwarze 380: macro_open(p, "Op");
1.24 kristaps 381: else if (sv)
1.69 schwarze 382: macro_open(p, "No");
1.24 kristaps 383:
384: /*
385: * Keep on printing text separated by the vertical bar as long
386: * as we're within the same origin node as the group.
387: * This is kind of a nightmare.
388: * Eh, DocBook...
389: * FIXME: if there's a "Fl", we don't cut off the leading "-"
390: * like we do in pnode_print().
391: */
392: TAILQ_FOREACH(pp, &pn->childq, child) {
393: pnode_print(p, pp);
394: np = TAILQ_NEXT(pp, child);
1.64 schwarze 395: while (np != NULL) {
1.24 kristaps 396: if (pp->node != np->node)
397: break;
1.72 schwarze 398: macro_addarg(p, "|", ARG_SPACE);
399: macro_addnode(p, np, ARG_SPACE);
1.24 kristaps 400: pp = np;
401: np = TAILQ_NEXT(np, child);
402: }
403: }
1.69 schwarze 404: if (sv)
405: macro_close(p);
1.71 schwarze 406: pnode_unlinksub(pn);
1.24 kristaps 407: }
408:
1.7 kristaps 409: static void
1.74 schwarze 410: pnode_printprologue(struct format *p, struct ptree *tree)
1.7 kristaps 411: {
1.74 schwarze 412: struct pnode *refmeta;
1.7 kristaps 413:
1.74 schwarze 414: refmeta = tree->root == NULL ? NULL :
415: pnode_findfirst(tree->root, NODE_REFMETA);
1.9 kristaps 416:
1.69 schwarze 417: macro_line(p, "Dd $Mdocdate" "$");
1.74 schwarze 418: if (refmeta == NULL) {
1.69 schwarze 419: macro_open(p, "Dt");
420: macro_addarg(p,
1.74 schwarze 421: pnode_getattr_raw(tree->root, ATTRKEY_ID, "UNKNOWN"),
1.72 schwarze 422: ARG_SPACE | ARG_SINGLE | ARG_UPPER);
423: macro_addarg(p, "1", ARG_SPACE);
1.69 schwarze 424: macro_close(p);
1.74 schwarze 425: } else
426: pnode_printrefmeta(p, refmeta);
1.69 schwarze 427: macro_line(p, "Os");
1.43 kristaps 428:
1.74 schwarze 429: if (tree->flags & TREE_EQN) {
1.69 schwarze 430: macro_line(p, "EQ");
1.70 schwarze 431: print_text(p, "delim $$");
1.69 schwarze 432: macro_line(p, "EN");
1.43 kristaps 433: }
1.7 kristaps 434: }
435:
1.42 kristaps 436: /*
437: * We can have multiple <term> elements within a <varlistentry>, which
438: * we should comma-separate as list headers.
439: */
1.13 kristaps 440: static void
1.74 schwarze 441: pnode_printvarlistentry(struct format *p, struct pnode *pn)
1.13 kristaps 442: {
443: struct pnode *pp;
1.42 kristaps 444: int first = 1;
1.13 kristaps 445:
1.69 schwarze 446: macro_open(p, "It");
447: TAILQ_FOREACH(pp, &pn->childq, child) {
448: if (pp->node != NODE_TERM)
449: continue;
450: if ( ! first)
1.72 schwarze 451: macro_addarg(p, ",", 0);
1.69 schwarze 452: pnode_print(p, pp);
453: first = 0;
454: }
455: macro_close(p);
1.13 kristaps 456: TAILQ_FOREACH(pp, &pn->childq, child)
1.69 schwarze 457: if (pp->node != NODE_TERM)
1.13 kristaps 458: pnode_print(p, pp);
1.71 schwarze 459: pnode_unlinksub(pn);
460: }
461:
462: static void
1.74 schwarze 463: pnode_printtitle(struct format *p, struct pnode *pn)
1.71 schwarze 464: {
465: struct pnode *pp, *pq;
466:
467: TAILQ_FOREACH_SAFE(pp, &pn->childq, child, pq) {
468: if (pp->node == NODE_TITLE) {
469: pnode_printpara(p, pp);
470: pnode_print(p, pp);
471: pnode_unlink(pp);
472: }
473: }
1.13 kristaps 474: }
475:
476: static void
1.74 schwarze 477: pnode_printrow(struct format *p, struct pnode *pn)
1.25 kristaps 478: {
479: struct pnode *pp;
480:
1.69 schwarze 481: macro_line(p, "Bl -dash -compact");
1.25 kristaps 482: TAILQ_FOREACH(pp, &pn->childq, child) {
1.69 schwarze 483: macro_line(p, "It");
1.25 kristaps 484: pnode_print(p, pp);
485: }
1.69 schwarze 486: macro_line(p, "El");
1.71 schwarze 487: pnode_unlink(pn);
1.25 kristaps 488: }
489:
490: static void
1.74 schwarze 491: pnode_printtable(struct format *p, struct pnode *pn)
1.16 kristaps 492: {
493: struct pnode *pp;
494:
1.71 schwarze 495: pnode_printtitle(p, pn);
1.69 schwarze 496: macro_line(p, "Bl -ohang");
1.64 schwarze 497: while ((pp = pnode_findfirst(pn, NODE_ROW)) != NULL) {
1.69 schwarze 498: macro_line(p, "It Table Row");
1.25 kristaps 499: pnode_printrow(p, pp);
500: }
1.69 schwarze 501: macro_line(p, "El");
1.71 schwarze 502: pnode_unlinksub(pn);
1.25 kristaps 503: }
504:
505: static void
1.74 schwarze 506: pnode_printlist(struct format *p, struct pnode *pn)
1.25 kristaps 507: {
508: struct pnode *pp;
1.16 kristaps 509:
1.71 schwarze 510: pnode_printtitle(p, pn);
1.69 schwarze 511: macro_argline(p, "Bl",
512: pn->node == NODE_ORDEREDLIST ? "-enum" : "-bullet");
1.16 kristaps 513: TAILQ_FOREACH(pp, &pn->childq, child) {
1.69 schwarze 514: macro_line(p, "It");
1.16 kristaps 515: pnode_print(p, pp);
516: }
1.69 schwarze 517: macro_line(p, "El");
1.71 schwarze 518: pnode_unlinksub(pn);
1.16 kristaps 519: }
520:
521: static void
1.74 schwarze 522: pnode_printvariablelist(struct format *p, struct pnode *pn)
1.13 kristaps 523: {
524: struct pnode *pp;
525:
1.71 schwarze 526: pnode_printtitle(p, pn);
1.69 schwarze 527: macro_line(p, "Bl -tag -width Ds");
528: TAILQ_FOREACH(pp, &pn->childq, child) {
529: if (pp->node == NODE_VARLISTENTRY)
1.13 kristaps 530: pnode_print(p, pp);
1.69 schwarze 531: else
1.72 schwarze 532: macro_nodeline(p, "It", pp, 0);
1.69 schwarze 533: }
534: macro_line(p, "El");
1.71 schwarze 535: pnode_unlinksub(pn);
1.13 kristaps 536: }
537:
1.1 kristaps 538: /*
539: * Print a parsed node (or ignore it--whatever).
540: * This is a recursive function.
1.23 kristaps 541: * FIXME: if we're in a literal context (<screen> or <programlisting> or
542: * whatever), don't print inline macros.
1.1 kristaps 543: */
544: static void
1.74 schwarze 545: pnode_print(struct format *p, struct pnode *pn)
1.1 kristaps 546: {
547: struct pnode *pp;
1.59 schwarze 548: const char *ccp;
1.1 kristaps 549: char *cp;
1.69 schwarze 550: int last;
551: enum linestate sv;
1.1 kristaps 552:
1.64 schwarze 553: if (pn == NULL)
1.1 kristaps 554: return;
555:
1.69 schwarze 556: sv = p->linestate;
1.1 kristaps 557:
558: switch (pn->node) {
1.62 schwarze 559: case NODE_APPLICATION:
1.69 schwarze 560: macro_open(p, "Nm");
1.27 kristaps 561: break;
1.62 schwarze 562: case NODE_ANCHOR:
1.30 kristaps 563: /* Don't print anything! */
564: return;
1.62 schwarze 565: case NODE_ARG:
1.10 kristaps 566: pnode_printarg(p, pn);
1.4 kristaps 567: break;
1.62 schwarze 568: case NODE_AUTHOR:
1.69 schwarze 569: macro_open(p, "An");
1.50 schwarze 570: break;
1.62 schwarze 571: case NODE_AUTHORGROUP:
1.69 schwarze 572: macro_line(p, "An -split");
1.50 schwarze 573: break;
1.62 schwarze 574: case NODE_BOOKINFO:
1.69 schwarze 575: macro_line(p, "Sh NAME");
1.50 schwarze 576: break;
1.62 schwarze 577: case NODE_CITEREFENTRY:
1.1 kristaps 578: pnode_printciterefentry(p, pn);
579: break;
1.68 schwarze 580: case NODE_CITETITLE:
1.69 schwarze 581: macro_open(p, "%T");
1.68 schwarze 582: break;
1.62 schwarze 583: case NODE_CODE:
1.69 schwarze 584: macro_open(p, "Li");
1.4 kristaps 585: break;
1.62 schwarze 586: case NODE_COMMAND:
1.69 schwarze 587: macro_open(p, "Nm");
1.13 kristaps 588: break;
1.62 schwarze 589: case NODE_CONSTANT:
1.69 schwarze 590: macro_open(p, "Dv");
1.33 kristaps 591: break;
1.62 schwarze 592: case NODE_EDITOR:
1.70 schwarze 593: print_text(p, "editor:");
1.69 schwarze 594: macro_open(p, "An");
1.50 schwarze 595: break;
1.65 schwarze 596: case NODE_EMAIL:
1.69 schwarze 597: macro_open(p, "Aq Mt");
1.65 schwarze 598: break;
1.62 schwarze 599: case NODE_EMPHASIS:
600: case NODE_FIRSTTERM:
1.69 schwarze 601: macro_open(p, "Em");
1.1 kristaps 602: break;
1.62 schwarze 603: case NODE_ENVAR:
1.69 schwarze 604: macro_open(p, "Ev");
1.21 kristaps 605: break;
1.62 schwarze 606: case NODE_FILENAME:
1.69 schwarze 607: macro_open(p, "Pa");
1.17 kristaps 608: break;
1.62 schwarze 609: case NODE_FUNCTION:
1.69 schwarze 610: macro_open(p, "Fn");
1.3 kristaps 611: break;
1.62 schwarze 612: case NODE_FUNCPROTOTYPE:
1.3 kristaps 613: pnode_printfuncprototype(p, pn);
614: break;
1.62 schwarze 615: case NODE_FUNCSYNOPSISINFO:
1.69 schwarze 616: macro_open(p, "Fd");
1.16 kristaps 617: break;
1.62 schwarze 618: case NODE_INDEXTERM:
1.55 schwarze 619: return;
1.62 schwarze 620: case NODE_INFORMALEQUATION:
1.69 schwarze 621: macro_line(p, "EQ");
1.43 kristaps 622: break;
1.62 schwarze 623: case NODE_INLINEEQUATION:
1.69 schwarze 624: if (p->linestate == LINE_NEW)
625: p->linestate = LINE_TEXT;
626: putchar('$');
1.43 kristaps 627: break;
1.62 schwarze 628: case NODE_ITEMIZEDLIST:
1.25 kristaps 629: pnode_printlist(p, pn);
1.24 kristaps 630: break;
1.62 schwarze 631: case NODE_GROUP:
1.24 kristaps 632: pnode_printgroup(p, pn);
1.10 kristaps 633: break;
1.67 schwarze 634: case NODE_KEYSYM:
1.69 schwarze 635: macro_open(p, "Sy");
1.67 schwarze 636: break;
1.62 schwarze 637: case NODE_LEGALNOTICE:
1.69 schwarze 638: macro_line(p, "Sh LEGAL NOTICE");
1.50 schwarze 639: break;
1.62 schwarze 640: case NODE_LINK:
1.59 schwarze 641: ccp = pnode_getattr_raw(pn, ATTRKEY_LINKEND, NULL);
1.64 schwarze 642: if (ccp == NULL)
1.58 schwarze 643: break;
1.69 schwarze 644: macro_argline(p, "Sx", ccp);
1.58 schwarze 645: return;
1.62 schwarze 646: case NODE_LITERAL:
1.69 schwarze 647: macro_open(p, "Li");
1.19 kristaps 648: break;
1.62 schwarze 649: case NODE_LITERALLAYOUT:
1.69 schwarze 650: macro_argline(p, "Bd", pnode_getattr(pn, ATTRKEY_CLASS) ==
1.66 schwarze 651: ATTRVAL_MONOSPACED ? "-literal" : "-unfilled");
1.60 schwarze 652: break;
1.62 schwarze 653: case NODE_MML_MFENCED:
1.41 kristaps 654: pnode_printmathfenced(p, pn);
1.40 kristaps 655: break;
1.62 schwarze 656: case NODE_MML_MROW:
657: case NODE_MML_MI:
658: case NODE_MML_MN:
659: case NODE_MML_MO:
1.43 kristaps 660: if (TAILQ_EMPTY(&pn->childq))
661: break;
662: fputs(" { ", stdout);
1.40 kristaps 663: break;
1.62 schwarze 664: case NODE_MML_MFRAC:
665: case NODE_MML_MSUB:
666: case NODE_MML_MSUP:
1.40 kristaps 667: pnode_printmath(p, pn);
668: break;
1.62 schwarze 669: case NODE_OPTION:
1.69 schwarze 670: macro_open(p, "Fl");
1.1 kristaps 671: break;
1.62 schwarze 672: case NODE_ORDEREDLIST:
1.25 kristaps 673: pnode_printlist(p, pn);
674: break;
1.62 schwarze 675: case NODE_PARA:
1.54 schwarze 676: pnode_printpara(p, pn);
1.3 kristaps 677: break;
1.62 schwarze 678: case NODE_PARAMETER:
1.72 schwarze 679: macro_nodeline(p, "Fa", pn, ARG_SINGLE);
1.4 kristaps 680: pnode_unlinksub(pn);
1.1 kristaps 681: break;
1.62 schwarze 682: case NODE_QUOTE:
1.69 schwarze 683: macro_open(p, "Qo");
1.28 kristaps 684: break;
1.62 schwarze 685: case NODE_PROGRAMLISTING:
686: case NODE_SCREEN:
1.69 schwarze 687: macro_line(p, "Bd -literal");
1.15 kristaps 688: break;
1.62 schwarze 689: case NODE_REFENTRYINFO:
1.15 kristaps 690: /* Suppress. */
691: pnode_unlinksub(pn);
1.1 kristaps 692: break;
1.62 schwarze 693: case NODE_REFMETA:
1.7 kristaps 694: abort();
1.1 kristaps 695: break;
1.62 schwarze 696: case NODE_REFNAME:
1.10 kristaps 697: /* Suppress non-text children... */
1.70 schwarze 698: macro_open(p, "Nm");
1.72 schwarze 699: macro_addnode(p, pn, ARG_SPACE | ARG_SINGLE);
1.4 kristaps 700: pnode_unlinksub(pn);
1.10 kristaps 701: break;
1.62 schwarze 702: case NODE_REFNAMEDIV:
1.69 schwarze 703: macro_line(p, "Sh NAME");
1.1 kristaps 704: break;
1.62 schwarze 705: case NODE_REFPURPOSE:
1.69 schwarze 706: macro_open(p, "Nd");
1.10 kristaps 707: break;
1.62 schwarze 708: case NODE_REFSYNOPSISDIV:
1.6 kristaps 709: pnode_printrefsynopsisdiv(p, pn);
1.1 kristaps 710: break;
1.62 schwarze 711: case NODE_PREFACE:
712: case NODE_SECTION:
713: case NODE_NOTE:
714: case NODE_TIP:
715: case NODE_CAUTION:
716: case NODE_WARNING:
1.1 kristaps 717: pnode_printrefsect(p, pn);
718: break;
1.62 schwarze 719: case NODE_REPLACEABLE:
1.69 schwarze 720: macro_open(p, "Ar");
1.13 kristaps 721: break;
1.62 schwarze 722: case NODE_SBR:
1.69 schwarze 723: macro_line(p, "br");
1.19 kristaps 724: break;
1.62 schwarze 725: case NODE_SGMLTAG:
1.69 schwarze 726: macro_open(p, "Li");
1.30 kristaps 727: break;
1.62 schwarze 728: case NODE_STRUCTNAME:
1.69 schwarze 729: macro_open(p, "Vt");
1.25 kristaps 730: break;
1.62 schwarze 731: case NODE_TABLE:
732: case NODE_INFORMALTABLE:
1.25 kristaps 733: pnode_printtable(p, pn);
1.10 kristaps 734: break;
1.62 schwarze 735: case NODE_TEXT:
1.72 schwarze 736: if (pn->bsz == 0) {
1.37 kristaps 737: assert(pn->real != pn->b);
738: break;
739: }
1.69 schwarze 740: if (p->linestate == LINE_NEW)
741: p->linestate = LINE_TEXT;
742: else
743: putchar(' ');
1.37 kristaps 744:
1.1 kristaps 745: /*
746: * Output all characters, squeezing out whitespace
1.44 schwarze 747: * between newlines.
1.1 kristaps 748: * XXX: all whitespace, including tabs (?).
749: * Remember to escape control characters and escapes.
750: */
1.72 schwarze 751: cp = pn->b;
1.37 kristaps 752:
1.20 kristaps 753: /*
754: * There's often a superfluous "-" in its <option> tags
755: * before the actual flags themselves.
756: * "Fl" does this for us, so remove it.
757: */
1.64 schwarze 758: if (pn->parent != NULL &&
759: pn->parent->node == NODE_OPTION &&
760: *cp == '-')
1.20 kristaps 761: cp++;
1.64 schwarze 762: for (last = '\n'; *cp != '\0'; ) {
763: if (last == '\n') {
1.1 kristaps 764: /* Consume all whitespace. */
1.46 schwarze 765: if (isspace((unsigned char)*cp)) {
766: while (isspace((unsigned char)*cp))
1.1 kristaps 767: cp++;
768: continue;
1.64 schwarze 769: } else if (*cp == '\'' || *cp == '.')
1.1 kristaps 770: fputs("\\&", stdout);
771: }
772: putchar(last = *cp++);
773: /* If we're a character escape, escape us. */
1.64 schwarze 774: if (last == '\\')
1.1 kristaps 775: putchar('e');
776: }
777: break;
1.62 schwarze 778: case NODE_TITLE:
1.69 schwarze 779: if (pn->parent->node == NODE_BOOKINFO)
780: macro_open(p, "Nd");
1.50 schwarze 781: break;
1.62 schwarze 782: case NODE_TYPE:
1.69 schwarze 783: macro_open(p, "Vt");
1.39 kristaps 784: break;
1.62 schwarze 785: case NODE_USERINPUT:
1.69 schwarze 786: macro_open(p, "Li");
1.26 kristaps 787: break;
1.62 schwarze 788: case NODE_VARIABLELIST:
1.13 kristaps 789: pnode_printvariablelist(p, pn);
790: break;
1.62 schwarze 791: case NODE_VARLISTENTRY:
1.13 kristaps 792: pnode_printvarlistentry(p, pn);
793: break;
1.62 schwarze 794: case NODE_VARNAME:
1.69 schwarze 795: macro_open(p, "Va");
1.23 kristaps 796: break;
1.1 kristaps 797: default:
798: break;
799: }
800:
801: TAILQ_FOREACH(pp, &pn->childq, child)
802: pnode_print(p, pp);
803:
804: switch (pn->node) {
1.62 schwarze 805: case NODE_INFORMALEQUATION:
1.69 schwarze 806: macro_line(p, "EN");
1.40 kristaps 807: break;
1.62 schwarze 808: case NODE_INLINEEQUATION:
1.43 kristaps 809: fputs("$ ", stdout);
1.69 schwarze 810: p->linestate = sv;
1.43 kristaps 811: break;
1.62 schwarze 812: case NODE_MML_MROW:
813: case NODE_MML_MI:
814: case NODE_MML_MN:
815: case NODE_MML_MO:
1.43 kristaps 816: if (TAILQ_EMPTY(&pn->childq))
817: break;
818: fputs(" } ", stdout);
1.40 kristaps 819: break;
1.62 schwarze 820: case NODE_APPLICATION:
821: case NODE_ARG:
822: case NODE_AUTHOR:
823: case NODE_CITEREFENTRY:
1.68 schwarze 824: case NODE_CITETITLE:
1.62 schwarze 825: case NODE_CODE:
826: case NODE_COMMAND:
827: case NODE_CONSTANT:
828: case NODE_EDITOR:
1.65 schwarze 829: case NODE_EMAIL:
1.62 schwarze 830: case NODE_EMPHASIS:
831: case NODE_ENVAR:
832: case NODE_FILENAME:
833: case NODE_FIRSTTERM:
834: case NODE_FUNCTION:
835: case NODE_FUNCSYNOPSISINFO:
1.67 schwarze 836: case NODE_KEYSYM:
1.62 schwarze 837: case NODE_LITERAL:
838: case NODE_OPTION:
839: case NODE_PARAMETER:
840: case NODE_REPLACEABLE:
841: case NODE_REFPURPOSE:
842: case NODE_SGMLTAG:
843: case NODE_STRUCTNAME:
844: case NODE_TYPE:
845: case NODE_USERINPUT:
846: case NODE_VARNAME:
1.69 schwarze 847: if (sv != LINE_MACRO && p->linestate == LINE_MACRO)
848: macro_closepunct(p, pn);
1.28 kristaps 849: break;
1.62 schwarze 850: case NODE_QUOTE:
1.69 schwarze 851: if (sv == LINE_NEW)
852: macro_close(p);
853: sv = p->linestate;
854: macro_open(p, "Qc");
855: if (sv == LINE_NEW)
856: macro_close(p);
1.10 kristaps 857: break;
1.62 schwarze 858: case NODE_REFNAME:
1.12 kristaps 859: /*
860: * If we're in the NAME macro and we have multiple
861: * <refname> macros in sequence, then print out a
862: * trailing comma before the newline.
863: */
1.64 schwarze 864: if (pn->parent != NULL &&
865: pn->parent->node == NODE_REFNAMEDIV &&
866: TAILQ_NEXT(pn, child) != NULL &&
867: TAILQ_NEXT(pn, child)->node == NODE_REFNAME)
1.72 schwarze 868: macro_addarg(p, ",", ARG_SPACE);
1.69 schwarze 869: if (sv == LINE_NEW)
870: macro_close(p);
1.52 schwarze 871: break;
1.62 schwarze 872: case NODE_PREFACE:
873: case NODE_SECTION:
874: case NODE_NOTE:
875: case NODE_TIP:
876: case NODE_CAUTION:
877: case NODE_WARNING:
1.52 schwarze 878: p->level--;
1.12 kristaps 879: break;
1.62 schwarze 880: case NODE_LITERALLAYOUT:
881: case NODE_PROGRAMLISTING:
882: case NODE_SCREEN:
1.69 schwarze 883: macro_line(p, "Ed");
1.50 schwarze 884: break;
1.62 schwarze 885: case NODE_TITLE:
1.69 schwarze 886: if (pn->parent->node == NODE_BOOKINFO)
887: macro_line(p, "Sh AUTHORS");
1.1 kristaps 888: break;
889: default:
890: break;
891: }
892: }
893:
1.74 schwarze 894: void
895: ptree_print(struct ptree *tree)
896: {
897: struct format formatter;
1.1 kristaps 898:
1.74 schwarze 899: formatter.level = 0;
900: formatter.linestate = LINE_NEW;
901: pnode_printprologue(&formatter, tree);
902: pnode_print(&formatter, tree->root);
903: if (formatter.linestate != LINE_NEW)
904: putchar('\n');
1.1 kristaps 905: }
CVSweb