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