Annotation of docbook2mdoc/docbook2mdoc.c, Revision 1.123
1.123 ! schwarze 1: /* $Id: docbook2mdoc.c,v 1.122 2019/04/14 18:28:41 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>
1.103 schwarze 22: #include <string.h>
1.1 kristaps 23:
1.74 schwarze 24: #include "node.h"
1.75 schwarze 25: #include "macro.h"
1.74 schwarze 26: #include "format.h"
27:
28: /*
29: * The implementation of the mdoc(7) formatter.
30: */
1.12 kristaps 31:
1.74 schwarze 32: static void pnode_print(struct format *, struct pnode *);
1.119 schwarze 33: static void pnode_printrefentry(struct format *, struct pnode *);
1.25 kristaps 34:
1.37 kristaps 35:
1.54 schwarze 36: static void
1.93 schwarze 37: pnode_printtext(struct format *f, struct pnode *n)
38: {
1.94 schwarze 39: struct pnode *nn;
1.93 schwarze 40: char *cp;
1.103 schwarze 41: int accept_arg;
1.93 schwarze 42:
1.103 schwarze 43: cp = n->b;
44: accept_arg = f->flags & FMT_ARG;
1.107 schwarze 45: if (f->linestate == LINE_MACRO && !n->spc && !accept_arg) {
1.103 schwarze 46: for (;;) {
47: if (*cp == '\0')
48: return;
49: if (strchr("!),.:;?]", *cp) == NULL)
50: break;
51: printf(" %c", *cp++);
52: }
53: if (isspace((unsigned char)*cp)) {
54: while (isspace((unsigned char)*cp))
55: cp++;
56: macro_close(f);
57: } else {
58: fputs(" Ns", stdout);
59: f->flags &= FMT_IMPL;
60: accept_arg = 1;
61: }
1.94 schwarze 62: }
1.103 schwarze 63: if (f->linestate == LINE_MACRO && !accept_arg &&
64: (f->flags & (FMT_CHILD | FMT_IMPL)) == 0)
65: macro_close(f);
1.94 schwarze 66:
67: /*
68: * Text preceding a macro without intervening whitespace
69: * requires a .Pf macro.
70: * Set the spacing flag to avoid a redundant .Ns macro.
71: */
72:
73: if (f->linestate != LINE_MACRO &&
1.113 schwarze 74: (nn = TAILQ_NEXT(n, child)) != NULL && nn->spc == 0) {
75: switch (pnode_class(nn->node)) {
76: case CLASS_LINE:
77: case CLASS_ENCL:
78: macro_open(f, "Pf");
79: accept_arg = 1;
80: f->flags |= FMT_CHILD;
81: nn->spc = 1;
82: break;
83: default:
84: break;
85: }
1.93 schwarze 86: }
87:
1.103 schwarze 88: switch (f->linestate) {
1.107 schwarze 89: case LINE_NEW:
90: break;
1.103 schwarze 91: case LINE_TEXT:
1.105 schwarze 92: if (n->spc) {
1.107 schwarze 93: if (n->node == NODE_TEXT)
94: macro_close(f);
95: else
96: putchar(' ');
1.105 schwarze 97: }
1.103 schwarze 98: break;
99: case LINE_MACRO:
1.107 schwarze 100: if (accept_arg)
1.93 schwarze 101: putchar(' ');
1.107 schwarze 102: else
103: macro_close(f);
1.103 schwarze 104: break;
1.93 schwarze 105: }
106:
107: if (n->node == NODE_ESCAPE) {
108: fputs(n->b, stdout);
1.107 schwarze 109: if (f->linestate == LINE_NEW)
110: f->linestate = LINE_TEXT;
1.93 schwarze 111: return;
112: }
113:
114: /*
115: * Remove the prefix '-' from <option> elements
116: * because the arguments of .Fl macros do not need it.
117: */
118:
119: if (n->parent != NULL && n->parent->node == NODE_OPTION && *cp == '-')
120: cp++;
121:
1.107 schwarze 122: if (f->linestate == LINE_MACRO)
123: macro_addarg(f, cp, 0);
124: else
125: print_text(f, cp, 0);
1.93 schwarze 126: }
127:
128: static void
1.101 schwarze 129: pnode_printpara(struct format *f, struct pnode *n)
1.54 schwarze 130: {
1.101 schwarze 131: struct pnode *np;
1.54 schwarze 132:
1.101 schwarze 133: if (n->parent == NULL)
1.54 schwarze 134: return;
135:
1.101 schwarze 136: if ((np = TAILQ_PREV(n, pnodeq, child)) == NULL)
137: np = n->parent;
1.97 schwarze 138:
1.103 schwarze 139: f->flags = 0;
140:
1.101 schwarze 141: switch (np->node) {
1.61 schwarze 142: case NODE_ENTRY:
1.99 schwarze 143: case NODE_GLOSSTERM:
1.61 schwarze 144: case NODE_LISTITEM:
1.99 schwarze 145: case NODE_TERM:
1.61 schwarze 146: return;
1.100 schwarze 147: case NODE_APPENDIX:
148: case NODE_LEGALNOTICE:
1.61 schwarze 149: case NODE_PREFACE:
150: case NODE_SECTION:
1.101 schwarze 151: if (f->level < 3)
1.61 schwarze 152: return;
153: break;
154: default:
155: break;
156: }
1.101 schwarze 157: macro_line(f, "Pp");
1.54 schwarze 158: }
159:
1.110 schwarze 160: static void
161: pnode_printrefnamediv(struct format *f, struct pnode *n)
162: {
163: struct pnode *nc, *nn;
164: int comma;
165:
166: macro_line(f, "Sh NAME");
167: comma = 0;
168: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
169: if (nc->node != NODE_REFNAME)
170: continue;
171: if (comma)
172: macro_addarg(f, ",", ARG_SPACE);
173: macro_open(f, "Nm");
174: macro_addnode(f, nc, ARG_SPACE);
175: pnode_unlink(nc);
176: comma = 1;
177: }
178: macro_close(f);
179: }
180:
1.37 kristaps 181: /*
1.10 kristaps 182: * If the SYNOPSIS macro has a superfluous title, kill it.
1.8 kristaps 183: */
1.1 kristaps 184: static void
1.101 schwarze 185: pnode_printrefsynopsisdiv(struct format *f, struct pnode *n)
1.6 kristaps 186: {
1.101 schwarze 187: struct pnode *nc, *nn;
1.6 kristaps 188:
1.101 schwarze 189: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn)
190: if (nc->node == NODE_TITLE)
191: pnode_unlink(nc);
1.71 schwarze 192:
1.101 schwarze 193: macro_line(f, "Sh SYNOPSIS");
1.6 kristaps 194: }
195:
1.8 kristaps 196: /*
197: * Start a hopefully-named `Sh' section.
198: */
1.6 kristaps 199: static void
1.119 schwarze 200: pnode_printsection(struct format *f, struct pnode *n)
1.1 kristaps 201: {
1.115 schwarze 202: struct pnode *nc, *ncc;
1.52 schwarze 203: const char *title;
204: int flags, level;
205:
1.119 schwarze 206: if (n->parent == NULL) {
207: pnode_printrefentry(f, n);
1.56 schwarze 208: return;
1.119 schwarze 209: }
1.56 schwarze 210:
1.101 schwarze 211: level = ++f->level;
1.72 schwarze 212: flags = ARG_SPACE;
1.121 schwarze 213: switch (n->node) {
214: case NODE_PREFACE:
215: case NODE_SECTION:
216: case NODE_APPENDIX:
217: if (level == 1)
218: flags |= ARG_UPPER;
219: break;
220: case NODE_SIMPLESECT:
221: case NODE_LEGALNOTICE:
222: if (level < 2)
223: level = 2;
224: break;
225: default:
226: if (level < 3)
1.52 schwarze 227: level = 3;
1.121 schwarze 228: break;
1.52 schwarze 229: }
1.1 kristaps 230:
1.101 schwarze 231: TAILQ_FOREACH(nc, &n->childq, child)
232: if (nc->node == NODE_TITLE)
1.1 kristaps 233: break;
234:
1.101 schwarze 235: if (nc == NULL) {
236: switch (n->node) {
1.62 schwarze 237: case NODE_PREFACE:
1.52 schwarze 238: title = "Preface";
239: break;
1.100 schwarze 240: case NODE_APPENDIX:
241: title = "Appendix";
242: break;
243: case NODE_LEGALNOTICE:
244: title = "Legal Notice";
245: break;
1.62 schwarze 246: case NODE_CAUTION:
1.52 schwarze 247: title = "Caution";
248: break;
1.62 schwarze 249: case NODE_NOTE:
1.52 schwarze 250: title = "Note";
251: break;
1.62 schwarze 252: case NODE_TIP:
1.52 schwarze 253: title = "Tip";
254: break;
1.62 schwarze 255: case NODE_WARNING:
1.52 schwarze 256: title = "Warning";
257: break;
258: default:
259: title = "Unknown";
260: break;
261: }
262: }
263:
264: switch (level) {
1.62 schwarze 265: case 1:
1.101 schwarze 266: macro_close(f);
267: macro_open(f, "Sh");
1.29 kristaps 268: break;
1.62 schwarze 269: case 2:
1.101 schwarze 270: macro_close(f);
271: macro_open(f, "Ss");
1.29 kristaps 272: break;
1.52 schwarze 273: default:
1.101 schwarze 274: pnode_printpara(f, n);
275: macro_open(f, "Sy");
1.29 kristaps 276: break;
277: }
1.20 kristaps 278:
1.115 schwarze 279: if (nc != NULL)
1.101 schwarze 280: macro_addnode(f, nc, flags);
1.115 schwarze 281: else
1.101 schwarze 282: macro_addarg(f, title, flags | ARG_QUOTED);
283: macro_close(f);
1.115 schwarze 284:
285: /*
286: * DocBook has no equivalent for -split mode,
287: * so just switch the default in the AUTHORS section.
288: */
289:
290: if (nc != NULL) {
291: ncc = TAILQ_FIRST(&nc->childq);
292: if (ncc != NULL && ncc->node == NODE_TEXT &&
293: strcasecmp(ncc->b, "AUTHORS") == 0)
294: macro_line(f, "An -nosplit");
295: pnode_unlink(nc);
296: }
1.1 kristaps 297: }
298:
1.8 kristaps 299: /*
300: * Start a reference, extracting the title and volume.
301: */
1.1 kristaps 302: static void
1.101 schwarze 303: pnode_printciterefentry(struct format *f, struct pnode *n)
1.1 kristaps 304: {
1.101 schwarze 305: struct pnode *nc, *title, *manvol;
1.1 kristaps 306:
307: title = manvol = NULL;
1.101 schwarze 308: TAILQ_FOREACH(nc, &n->childq, child) {
309: if (nc->node == NODE_MANVOLNUM)
310: manvol = nc;
311: else if (nc->node == NODE_REFENTRYTITLE)
312: title = nc;
1.69 schwarze 313: }
1.101 schwarze 314: macro_open(f, "Xr");
1.69 schwarze 315: if (title == NULL)
1.101 schwarze 316: macro_addarg(f, "unknown", ARG_SPACE);
1.69 schwarze 317: else
1.101 schwarze 318: macro_addnode(f, title, ARG_SPACE | ARG_SINGLE);
1.69 schwarze 319: if (manvol == NULL)
1.101 schwarze 320: macro_addarg(f, "1", ARG_SPACE);
1.64 schwarze 321: else
1.101 schwarze 322: macro_addnode(f, manvol, ARG_SPACE | ARG_SINGLE);
323: pnode_unlinksub(n);
1.1 kristaps 324: }
325:
326: static void
1.86 schwarze 327: pnode_printfuncdef(struct format *f, struct pnode *n)
1.3 kristaps 328: {
1.86 schwarze 329: struct pnode *nc;
1.3 kristaps 330:
1.86 schwarze 331: nc = TAILQ_FIRST(&n->childq);
332: if (nc != NULL && nc->node == NODE_TEXT) {
333: macro_argline(f, "Ft", nc->b);
334: pnode_unlink(nc);
1.13 kristaps 335: }
1.86 schwarze 336: macro_nodeline(f, "Fo", n, ARG_SINGLE);
337: pnode_unlinksub(n);
1.3 kristaps 338: }
339:
1.40 kristaps 340: /*
1.41 kristaps 341: * The <mml:mfenced> node is a little peculiar.
342: * First, it can have arbitrary open and closing tokens, which default
343: * to parentheses.
344: * Second, >1 arguments are separated by commas.
345: */
346: static void
1.101 schwarze 347: pnode_printmathfenced(struct format *f, struct pnode *n)
1.41 kristaps 348: {
1.101 schwarze 349: struct pnode *nc;
1.41 kristaps 350:
1.101 schwarze 351: printf("left %s ", pnode_getattr_raw(n, ATTRKEY_OPEN, "("));
1.41 kristaps 352:
1.101 schwarze 353: nc = TAILQ_FIRST(&n->childq);
354: pnode_print(f, nc);
1.41 kristaps 355:
1.101 schwarze 356: while ((nc = TAILQ_NEXT(nc, child)) != NULL) {
1.41 kristaps 357: putchar(',');
1.101 schwarze 358: pnode_print(f, nc);
1.41 kristaps 359: }
1.101 schwarze 360: printf("right %s ", pnode_getattr_raw(n, ATTRKEY_CLOSE, ")"));
361: pnode_unlinksub(n);
1.41 kristaps 362: }
363:
364: /*
1.40 kristaps 365: * These math nodes require special handling because they have infix
366: * syntax, instead of the usual prefix or prefix.
367: * So we need to break up the first and second child node with a
368: * particular eqn(7) word.
369: */
370: static void
1.101 schwarze 371: pnode_printmath(struct format *f, struct pnode *n)
1.40 kristaps 372: {
1.101 schwarze 373: struct pnode *nc;
1.40 kristaps 374:
1.101 schwarze 375: nc = TAILQ_FIRST(&n->childq);
376: pnode_print(f, nc);
1.40 kristaps 377:
1.101 schwarze 378: switch (n->node) {
1.62 schwarze 379: case NODE_MML_MSUP:
1.42 kristaps 380: fputs(" sup ", stdout);
1.40 kristaps 381: break;
1.62 schwarze 382: case NODE_MML_MFRAC:
1.42 kristaps 383: fputs(" over ", stdout);
1.40 kristaps 384: break;
1.62 schwarze 385: case NODE_MML_MSUB:
1.42 kristaps 386: fputs(" sub ", stdout);
1.40 kristaps 387: break;
388: default:
389: break;
390: }
391:
1.101 schwarze 392: nc = TAILQ_NEXT(nc, child);
393: pnode_print(f, nc);
394: pnode_unlinksub(n);
1.40 kristaps 395: }
396:
1.3 kristaps 397: static void
1.101 schwarze 398: pnode_printfuncprototype(struct format *f, struct pnode *n)
1.3 kristaps 399: {
1.101 schwarze 400: struct pnode *nc, *fdef;
1.3 kristaps 401:
1.101 schwarze 402: TAILQ_FOREACH(fdef, &n->childq, child)
1.64 schwarze 403: if (fdef->node == NODE_FUNCDEF)
1.3 kristaps 404: break;
405:
1.86 schwarze 406: if (fdef != NULL) {
1.101 schwarze 407: pnode_printfuncdef(f, fdef);
1.86 schwarze 408: pnode_unlink(fdef);
409: } else
1.101 schwarze 410: macro_line(f, "Fo UNKNOWN");
1.3 kristaps 411:
1.101 schwarze 412: TAILQ_FOREACH(nc, &n->childq, child)
413: macro_nodeline(f, "Fa", nc, ARG_SINGLE);
1.3 kristaps 414:
1.101 schwarze 415: macro_line(f, "Fc");
416: pnode_unlinksub(n);
1.3 kristaps 417: }
418:
1.44 schwarze 419: /*
1.10 kristaps 420: * The <arg> element is more complicated than it should be because text
421: * nodes are treated like ".Ar foo", but non-text nodes need to be
422: * re-sent into the printer (i.e., without the preceding ".Ar").
1.12 kristaps 423: * This also handles the case of "repetition" (or in other words, the
424: * ellipsis following an argument) and optionality.
1.10 kristaps 425: */
1.4 kristaps 426: static void
1.101 schwarze 427: pnode_printarg(struct format *f, struct pnode *n)
1.4 kristaps 428: {
1.101 schwarze 429: struct pnode *nc;
430: struct pattr *a;
1.103 schwarze 431: int isop, isrep, was_impl;
1.12 kristaps 432:
433: isop = 1;
1.103 schwarze 434: isrep = was_impl = 0;
1.101 schwarze 435: TAILQ_FOREACH(a, &n->attrq, child) {
436: if (a->key == ATTRKEY_CHOICE &&
437: (a->val == ATTRVAL_PLAIN || a->val == ATTRVAL_REQ))
1.12 kristaps 438: isop = 0;
1.101 schwarze 439: else if (a->key == ATTRKEY_REP && a->val == ATTRVAL_REPEAT)
1.12 kristaps 440: isrep = 1;
441: }
1.103 schwarze 442: if (isop) {
443: if (f->flags & FMT_IMPL) {
444: was_impl = 1;
445: macro_open(f, "Oo");
446: } else {
447: macro_open(f, "Op");
448: f->flags |= FMT_IMPL;
449: }
450: }
1.101 schwarze 451: TAILQ_FOREACH(nc, &n->childq, child) {
452: if (nc->node == NODE_TEXT)
453: macro_open(f, "Ar");
454: pnode_print(f, nc);
1.10 kristaps 455: }
1.117 schwarze 456: if (isrep && f->linestate == LINE_MACRO)
457: macro_addarg(f, "...", ARG_SPACE);
1.103 schwarze 458: if (isop) {
459: if (was_impl)
460: macro_open(f, "Oc");
461: else
462: f->flags &= ~FMT_IMPL;
463: }
1.101 schwarze 464: pnode_unlinksub(n);
1.4 kristaps 465: }
466:
1.24 kristaps 467: static void
1.101 schwarze 468: pnode_printgroup(struct format *f, struct pnode *n)
1.24 kristaps 469: {
1.117 schwarze 470: struct pnode *nc;
1.101 schwarze 471: struct pattr *a;
1.117 schwarze 472: int bar, isop, isrep, was_impl;
1.24 kristaps 473:
474: isop = 1;
1.117 schwarze 475: isrep = was_impl = 0;
476: TAILQ_FOREACH(a, &n->attrq, child) {
1.101 schwarze 477: if (a->key == ATTRKEY_CHOICE &&
1.117 schwarze 478: (a->val == ATTRVAL_PLAIN || a->val == ATTRVAL_REQ))
1.24 kristaps 479: isop = 0;
1.117 schwarze 480: else if (a->key == ATTRKEY_REP && a->val == ATTRVAL_REPEAT)
481: isrep = 1;
482: }
483: if (isop) {
484: if (f->flags & FMT_IMPL) {
485: was_impl = 1;
486: macro_open(f, "Oo");
487: } else {
488: macro_open(f, "Op");
489: f->flags |= FMT_IMPL;
490: }
491: } else if (isrep) {
492: if (f->flags & FMT_IMPL) {
493: was_impl = 1;
494: macro_open(f, "Bro");
495: } else {
496: macro_open(f, "Brq");
497: f->flags |= FMT_IMPL;
1.24 kristaps 498: }
1.117 schwarze 499: }
500: bar = 0;
1.101 schwarze 501: TAILQ_FOREACH(nc, &n->childq, child) {
1.117 schwarze 502: if (bar && f->linestate == LINE_MACRO)
503: macro_addarg(f, "|", ARG_SPACE);
1.101 schwarze 504: pnode_print(f, nc);
1.117 schwarze 505: bar = 1;
506: }
507: if (isop) {
508: if (was_impl)
509: macro_open(f, "Oc");
510: else
511: f->flags &= ~FMT_IMPL;
512: } else if (isrep) {
513: if (was_impl)
514: macro_open(f, "Brc");
515: else
516: f->flags &= ~FMT_IMPL;
1.24 kristaps 517: }
1.117 schwarze 518: if (isrep && f->linestate == LINE_MACRO)
519: macro_addarg(f, "...", ARG_SPACE);
1.101 schwarze 520: pnode_unlinksub(n);
1.24 kristaps 521: }
522:
1.7 kristaps 523: static void
1.118 schwarze 524: pnode_printsystemitem(struct format *f, struct pnode *n)
525: {
526: switch (pnode_getattr(n, ATTRKEY_CLASS)) {
527: case ATTRVAL_IPADDRESS:
528: break;
529: case ATTRVAL_SYSTEMNAME:
530: macro_open(f, "Pa");
531: break;
532: case ATTRVAL_EVENT:
533: default:
534: macro_open(f, "Sy");
535: break;
536: }
537: }
538:
539: static void
1.78 schwarze 540: pnode_printauthor(struct format *f, struct pnode *n)
541: {
1.101 schwarze 542: struct pnode *nc, *nn;
1.78 schwarze 543: int have_contrib, have_name;
544:
545: /*
546: * Print <contrib> children up front, before the .An scope,
547: * and figure out whether we a name of a person.
548: */
549:
550: have_contrib = have_name = 0;
1.101 schwarze 551: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
1.78 schwarze 552: switch (nc->node) {
553: case NODE_CONTRIB:
554: if (have_contrib)
555: print_text(f, ",", 0);
556: print_textnode(f, nc);
557: pnode_unlink(nc);
558: have_contrib = 1;
559: break;
560: case NODE_PERSONNAME:
561: have_name = 1;
562: break;
563: default:
564: break;
565: }
566: }
567: if (TAILQ_FIRST(&n->childq) == NULL)
568: return;
569:
570: if (have_contrib)
571: print_text(f, ":", 0);
572:
573: /*
574: * If we have a name, print it in the .An scope and leave
575: * all other content for child handlers, to print after the
576: * scope. Otherwise, print everything in the scope.
577: */
578:
579: macro_open(f, "An");
1.101 schwarze 580: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
1.78 schwarze 581: if (nc->node == NODE_PERSONNAME || have_name == 0) {
582: macro_addnode(f, nc, ARG_SPACE);
583: pnode_unlink(nc);
584: }
1.80 schwarze 585: }
586:
587: /*
588: * If there is an email address,
589: * print it on the same macro line.
590: */
591:
592: if ((nc = pnode_findfirst(n, NODE_EMAIL)) != NULL) {
1.103 schwarze 593: f->flags |= FMT_CHILD;
1.115 schwarze 594: macro_open(f, "Aq Mt");
595: macro_addnode(f, nc, ARG_SPACE);
1.80 schwarze 596: pnode_unlink(nc);
1.78 schwarze 597: }
598:
599: /*
600: * If there are still unprinted children, end the scope
601: * with a comma. Otherwise, leave the scope open in case
602: * a text node follows that starts with closing punctuation.
603: */
604:
605: if (TAILQ_FIRST(&n->childq) != NULL) {
606: macro_addarg(f, ",", ARG_SPACE);
607: macro_close(f);
608: }
609: }
610:
611: static void
1.96 schwarze 612: pnode_printlink(struct format *f, struct pnode *n)
613: {
1.109 schwarze 614: struct pnode *nc;
1.96 schwarze 615: const char *uri, *text;
616:
617: uri = pnode_getattr_raw(n, ATTRKEY_LINKEND, NULL);
618: if (uri != NULL) {
619: if (TAILQ_FIRST(&n->childq) != NULL) {
1.109 schwarze 620: TAILQ_FOREACH(nc, &n->childq, child)
621: pnode_print(f, nc);
1.96 schwarze 622: text = "";
1.109 schwarze 623: } else if ((text = pnode_getattr_raw(n,
624: ATTRKEY_ENDTERM, NULL)) != NULL) {
625: if (f->linestate == LINE_MACRO && f->flags & FMT_ARG)
626: macro_addarg(f, text, ARG_SPACE);
627: else
1.96 schwarze 628: print_text(f, text, ARG_SPACE);
629: }
1.103 schwarze 630: if (text != NULL) {
1.109 schwarze 631: if (f->flags & FMT_IMPL)
632: macro_open(f, "Po");
633: else {
634: macro_open(f, "Pq");
635: f->flags |= FMT_CHILD;
636: }
1.103 schwarze 637: }
1.96 schwarze 638: macro_open(f, "Sx");
639: macro_addarg(f, uri, ARG_SPACE);
1.109 schwarze 640: if (text != NULL && f->flags & FMT_IMPL)
641: macro_open(f, "Pc");
1.96 schwarze 642: pnode_unlinksub(n);
643: return;
644: }
645: uri = pnode_getattr_raw(n, ATTRKEY_XLINK_HREF, NULL);
646: if (uri == NULL)
647: uri = pnode_getattr_raw(n, ATTRKEY_URL, NULL);
648: if (uri != NULL) {
649: macro_open(f, "Lk");
650: macro_addarg(f, uri, ARG_SPACE | ARG_SINGLE);
651: if (TAILQ_FIRST(&n->childq) != NULL)
652: macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
653: pnode_unlinksub(n);
654: return;
655: }
656: }
657:
658: static void
1.116 schwarze 659: pnode_printprologue(struct format *f, struct pnode *root)
1.7 kristaps 660: {
1.119 schwarze 661: struct pnode *date, *refmeta, *name, *vol, *descr, *nc, *nn;
1.116 schwarze 662: const char *sname;
1.7 kristaps 663:
1.116 schwarze 664: /* Collect information. */
1.9 kristaps 665:
1.116 schwarze 666: if ((date = pnode_takefirst(root, NODE_PUBDATE)) == NULL)
667: date = pnode_takefirst(root, NODE_DATE);
668:
669: name = vol = NULL;
1.119 schwarze 670: if ((refmeta = pnode_findfirst(root, NODE_REFMETA)) != NULL) {
671: TAILQ_FOREACH_SAFE(nc, &refmeta->childq, child, nn) {
1.116 schwarze 672: switch (nc->node) {
673: case NODE_REFENTRYTITLE:
674: name = nc;
675: break;
676: case NODE_MANVOLNUM:
677: vol = nc;
678: break;
679: default:
1.119 schwarze 680: continue;
1.116 schwarze 681: }
1.119 schwarze 682: TAILQ_REMOVE(&refmeta->childq, nc, child);
1.116 schwarze 683: }
684: }
685:
686: if (pnode_findfirst(root, NODE_REFNAMEDIV) == NULL &&
687: ((nc = pnode_findfirst(root, NODE_BOOKINFO)) != NULL ||
688: (nc = pnode_findfirst(root, NODE_REFENTRYINFO)) != NULL))
689: descr = pnode_takefirst(nc, NODE_TITLE);
690: else
691: descr = NULL;
692:
693: /* Print prologue. */
694:
695: if (date == NULL)
696: macro_line(f, "Dd $Mdocdate" "$");
697: else
698: macro_nodeline(f, "Dd", date, 0);
699:
700: macro_open(f, "Dt");
701: if (name == NULL) {
702: sname = pnode_getattr_raw(root, ATTRKEY_ID, "UNKNOWN");
703: macro_addarg(f, sname, ARG_SPACE | ARG_SINGLE | ARG_UPPER);
704: } else
705: macro_addnode(f, name, ARG_SPACE | ARG_SINGLE | ARG_UPPER);
706: if (vol == NULL)
1.101 schwarze 707: macro_addarg(f, "1", ARG_SPACE);
1.116 schwarze 708: else
709: macro_addnode(f, vol, ARG_SPACE | ARG_SINGLE);
710:
1.101 schwarze 711: macro_line(f, "Os");
1.116 schwarze 712:
713: if (descr != NULL) {
714: macro_line(f, "Sh NAME");
715: if (name == NULL)
716: macro_argline(f, "Nm", sname);
717: else
718: macro_nodeline(f, "Nm", name, ARG_SINGLE);
719: macro_nodeline(f, "Nd", descr, 0);
720: }
721:
722: /* Clean up. */
723:
724: pnode_unlink(date);
1.119 schwarze 725: pnode_unlink(name);
726: pnode_unlink(vol);
1.116 schwarze 727: pnode_unlink(descr);
1.7 kristaps 728: }
729:
1.119 schwarze 730: static void
731: pnode_printrefentry(struct format *f, struct pnode *n)
732: {
733: struct pnode *info, *meta, *nc, *title;
734: struct pnode *match, *later;
735:
736: /* Collect nodes that remained behind when writing the prologue. */
737:
738: meta = NULL;
739: info = pnode_takefirst(n, NODE_BOOKINFO);
740: if (info != NULL && TAILQ_FIRST(&info->childq) == NULL) {
741: pnode_unlink(info);
742: info = NULL;
743: }
744: if (info == NULL) {
745: info = pnode_takefirst(n, NODE_REFENTRYINFO);
746: if (info != NULL && TAILQ_FIRST(&info->childq) == NULL) {
747: pnode_unlink(info);
748: info = NULL;
749: }
750: meta = pnode_takefirst(n, NODE_REFMETA);
751: if (meta != NULL && TAILQ_FIRST(&meta->childq) == NULL) {
752: pnode_unlink(meta);
753: meta = NULL;
754: }
755: }
756: if (info == NULL && meta == NULL)
757: return;
758:
759: /*
760: * Find the best place to put this information.
761: * Use the last existing AUTHORS node, if any.
762: * Otherwise, put it behind all standard sections that
763: * conventionally precede AUTHORS, and also behind any
764: * non-standard sections that follow the last of these,
765: * but before the next standard section.
766: */
767:
768: match = later = NULL;
769: TAILQ_FOREACH(nc, &n->childq, child) {
770: switch (nc->node) {
771: case NODE_REFENTRY:
772: case NODE_REFNAMEDIV:
773: case NODE_REFSYNOPSISDIV:
774: case NODE_PREFACE:
775: later = NULL;
776: continue;
777: case NODE_APPENDIX:
778: case NODE_INDEX:
779: if (later == NULL)
780: later = nc;
781: continue;
782: default:
783: break;
784: }
785: if ((title = pnode_findfirst(nc, NODE_TITLE)) == NULL ||
786: (title = TAILQ_FIRST(&title->childq)) == NULL ||
787: title->node != NODE_TEXT)
788: continue;
789: if (strcasecmp(title->b, "AUTHORS") == 0 ||
790: strcasecmp(title->b, "AUTHOR") == 0)
791: match = nc;
792: else if (strcasecmp(title->b, "NAME") == 0 ||
793: strcasecmp(title->b, "SYNOPSIS") == 0 ||
794: strcasecmp(title->b, "DESCRIPTION") == 0 ||
795: strcasecmp(title->b, "RETURN VALUES") == 0 ||
796: strcasecmp(title->b, "ENVIRONMENT") == 0 ||
797: strcasecmp(title->b, "FILES") == 0 ||
798: strcasecmp(title->b, "EXIT STATUS") == 0 ||
799: strcasecmp(title->b, "EXAMPLES") == 0 ||
800: strcasecmp(title->b, "DIAGNOSTICS") == 0 ||
801: strcasecmp(title->b, "ERRORS") == 0 ||
802: strcasecmp(title->b, "SEE ALSO") == 0 ||
803: strcasecmp(title->b, "STANDARDS") == 0 ||
804: strcasecmp(title->b, "HISTORY") == 0)
805: later = NULL;
806: else if ((strcasecmp(title->b, "CAVEATS") == 0 ||
807: strcasecmp(title->b, "BUGS") == 0) &&
808: later == NULL)
809: later = nc;
810: }
811:
812: /*
813: * If no AUTHORS section was found, create one from scratch,
814: * and insert that at the place selected earlier.
815: */
816:
817: if (match == NULL) {
818: if ((match = calloc(1, sizeof(*match))) == NULL) {
819: perror(NULL);
820: exit(1);
821: }
822: match->node = NODE_SECTION;
823: match->spc = 1;
824: match->parent = n;
825: TAILQ_INIT(&match->childq);
826: TAILQ_INIT(&match->attrq);
827: if ((nc = pnode_alloc(match)) == NULL) {
828: perror(NULL);
829: exit(1);
830: }
831: nc->node = NODE_TITLE;
832: nc->spc = 1;
833: if ((nc = pnode_alloc(nc)) == NULL) {
834: perror(NULL);
835: exit(1);
836: }
837: nc->node = NODE_TEXT;
838: if ((nc->b = strdup("AUTHORS")) == NULL) {
839: perror(NULL);
840: exit(1);
841: }
842: nc->spc = 1;
843: if (later == NULL)
844: TAILQ_INSERT_TAIL(&n->childq, match, child);
845: else
846: TAILQ_INSERT_BEFORE(later, match, child);
847: }
848:
849: /*
850: * Dump the stuff excised at the beginning
851: * into this AUTHORS section.
852: */
853:
854: if (info != NULL)
855: TAILQ_INSERT_TAIL(&match->childq, info, child);
856: if (meta != NULL)
857: TAILQ_INSERT_TAIL(&match->childq, meta, child);
858: }
859:
1.42 kristaps 860: /*
861: * We can have multiple <term> elements within a <varlistentry>, which
862: * we should comma-separate as list headers.
863: */
1.13 kristaps 864: static void
1.101 schwarze 865: pnode_printvarlistentry(struct format *f, struct pnode *n)
1.13 kristaps 866: {
1.108 schwarze 867: struct pnode *nc, *nn;
1.42 kristaps 868: int first = 1;
1.13 kristaps 869:
1.101 schwarze 870: macro_open(f, "It");
1.103 schwarze 871: f->flags |= FMT_IMPL;
1.108 schwarze 872: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
1.101 schwarze 873: if (nc->node != NODE_TERM && nc->node != NODE_GLOSSTERM)
1.69 schwarze 874: continue;
1.108 schwarze 875: if (first == 0) {
876: switch (f->linestate) {
877: case LINE_NEW:
878: break;
879: case LINE_TEXT:
880: print_text(f, ",", 0);
881: break;
882: case LINE_MACRO:
883: macro_addarg(f, ",", 0);
884: break;
885: }
886: }
1.101 schwarze 887: pnode_print(f, nc);
1.108 schwarze 888: pnode_unlink(nc);
1.69 schwarze 889: first = 0;
890: }
1.101 schwarze 891: macro_close(f);
1.108 schwarze 892: while ((nc = TAILQ_FIRST(&n->childq)) != NULL) {
893: pnode_print(f, nc);
894: pnode_unlink(nc);
895: }
896: macro_close(f);
1.71 schwarze 897: }
898:
899: static void
1.101 schwarze 900: pnode_printtitle(struct format *f, struct pnode *n)
1.71 schwarze 901: {
1.101 schwarze 902: struct pnode *nc, *nn;
1.71 schwarze 903:
1.101 schwarze 904: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
905: if (nc->node == NODE_TITLE) {
906: pnode_printpara(f, nc);
907: pnode_print(f, nc);
908: pnode_unlink(nc);
1.71 schwarze 909: }
910: }
1.13 kristaps 911: }
912:
913: static void
1.101 schwarze 914: pnode_printrow(struct format *f, struct pnode *n)
1.25 kristaps 915: {
1.101 schwarze 916: struct pnode *nc;
1.25 kristaps 917:
1.101 schwarze 918: macro_line(f, "Bl -dash -compact");
919: TAILQ_FOREACH(nc, &n->childq, child) {
920: macro_line(f, "It");
921: pnode_print(f, nc);
1.25 kristaps 922: }
1.101 schwarze 923: macro_line(f, "El");
924: pnode_unlink(n);
1.25 kristaps 925: }
926:
927: static void
1.83 schwarze 928: pnode_printtgroup1(struct format *f, struct pnode *n)
1.16 kristaps 929: {
1.82 schwarze 930: struct pnode *nc;
931:
1.83 schwarze 932: macro_line(f, "Bl -bullet -compact");
1.82 schwarze 933: while ((nc = pnode_findfirst(n, NODE_ENTRY)) != NULL) {
1.83 schwarze 934: macro_line(f, "It");
935: pnode_print(f, nc);
1.82 schwarze 936: pnode_unlink(nc);
937: }
1.83 schwarze 938: macro_line(f, "El");
939: pnode_unlinksub(n);
940: }
941:
942: static void
943: pnode_printtgroup2(struct format *f, struct pnode *n)
944: {
945: struct pnode *nr, *ne;
946:
947: macro_line(f, "Bl -tag -width Ds");
948: while ((nr = pnode_findfirst(n, NODE_ROW)) != NULL) {
949: if ((ne = pnode_findfirst(n, NODE_ENTRY)) == NULL)
950: break;
951: macro_open(f, "It");
1.103 schwarze 952: f->flags |= FMT_IMPL;
1.83 schwarze 953: pnode_print(f, ne);
1.84 schwarze 954: macro_close(f);
1.83 schwarze 955: pnode_unlink(ne);
956: pnode_print(f, nr);
957: pnode_unlink(nr);
958: }
959: macro_line(f, "El");
1.82 schwarze 960: pnode_unlinksub(n);
961: }
962:
963: static void
1.83 schwarze 964: pnode_printtgroup(struct format *f, struct pnode *n)
1.82 schwarze 965: {
966: struct pnode *nc;
967:
968: switch (atoi(pnode_getattr_raw(n, ATTRKEY_COLS, "0"))) {
969: case 1:
1.83 schwarze 970: pnode_printtgroup1(f, n);
971: return;
972: case 2:
973: pnode_printtgroup2(f, n);
1.82 schwarze 974: return;
975: default:
976: break;
977: }
1.16 kristaps 978:
1.83 schwarze 979: macro_line(f, "Bl -ohang");
1.82 schwarze 980: while ((nc = pnode_findfirst(n, NODE_ROW)) != NULL) {
1.83 schwarze 981: macro_line(f, "It Table Row");
982: pnode_printrow(f, nc);
1.25 kristaps 983: }
1.83 schwarze 984: macro_line(f, "El");
1.82 schwarze 985: pnode_unlinksub(n);
1.25 kristaps 986: }
987:
988: static void
1.101 schwarze 989: pnode_printlist(struct format *f, struct pnode *n)
1.25 kristaps 990: {
1.101 schwarze 991: struct pnode *nc;
1.16 kristaps 992:
1.101 schwarze 993: pnode_printtitle(f, n);
994: macro_argline(f, "Bl",
995: n->node == NODE_ORDEREDLIST ? "-enum" : "-bullet");
996: TAILQ_FOREACH(nc, &n->childq, child) {
997: macro_line(f, "It");
998: pnode_print(f, nc);
1.16 kristaps 999: }
1.101 schwarze 1000: macro_line(f, "El");
1001: pnode_unlinksub(n);
1.16 kristaps 1002: }
1003:
1004: static void
1.101 schwarze 1005: pnode_printvariablelist(struct format *f, struct pnode *n)
1.13 kristaps 1006: {
1.101 schwarze 1007: struct pnode *nc;
1.13 kristaps 1008:
1.101 schwarze 1009: pnode_printtitle(f, n);
1010: macro_line(f, "Bl -tag -width Ds");
1011: TAILQ_FOREACH(nc, &n->childq, child) {
1012: if (nc->node == NODE_VARLISTENTRY)
1013: pnode_printvarlistentry(f, nc);
1.69 schwarze 1014: else
1.101 schwarze 1015: macro_nodeline(f, "It", nc, 0);
1.69 schwarze 1016: }
1.101 schwarze 1017: macro_line(f, "El");
1018: pnode_unlinksub(n);
1.13 kristaps 1019: }
1020:
1.1 kristaps 1021: /*
1022: * Print a parsed node (or ignore it--whatever).
1023: * This is a recursive function.
1.23 kristaps 1024: * FIXME: if we're in a literal context (<screen> or <programlisting> or
1025: * whatever), don't print inline macros.
1.1 kristaps 1026: */
1027: static void
1.101 schwarze 1028: pnode_print(struct format *f, struct pnode *n)
1.1 kristaps 1029: {
1.102 schwarze 1030: struct pnode *nc, *nn;
1.112 schwarze 1031: int was_impl;
1.1 kristaps 1032:
1.101 schwarze 1033: if (n == NULL)
1.1 kristaps 1034: return;
1035:
1.112 schwarze 1036: was_impl = f->flags & FMT_IMPL;
1.103 schwarze 1037: if (n->spc)
1038: f->flags &= ~FMT_NOSPC;
1039: else
1040: f->flags |= FMT_NOSPC;
1.1 kristaps 1041:
1.101 schwarze 1042: switch (n->node) {
1.62 schwarze 1043: case NODE_ARG:
1.101 schwarze 1044: pnode_printarg(f, n);
1.4 kristaps 1045: break;
1.62 schwarze 1046: case NODE_AUTHOR:
1.101 schwarze 1047: pnode_printauthor(f, n);
1.50 schwarze 1048: break;
1.62 schwarze 1049: case NODE_AUTHORGROUP:
1.101 schwarze 1050: macro_line(f, "An -split");
1.50 schwarze 1051: break;
1.98 schwarze 1052: case NODE_BLOCKQUOTE:
1.101 schwarze 1053: macro_line(f, "Bd -ragged -offset indent");
1.98 schwarze 1054: break;
1.62 schwarze 1055: case NODE_CITEREFENTRY:
1.101 schwarze 1056: pnode_printciterefentry(f, n);
1.1 kristaps 1057: break;
1.68 schwarze 1058: case NODE_CITETITLE:
1.101 schwarze 1059: macro_open(f, "%T");
1.68 schwarze 1060: break;
1.62 schwarze 1061: case NODE_COMMAND:
1.101 schwarze 1062: macro_open(f, "Nm");
1.13 kristaps 1063: break;
1.62 schwarze 1064: case NODE_CONSTANT:
1.101 schwarze 1065: macro_open(f, "Dv");
1.33 kristaps 1066: break;
1.121 schwarze 1067: case NODE_COPYRIGHT:
1068: print_text(f, "Copyright", ARG_SPACE);
1069: fputs(" \\(co", stdout);
1070: break;
1.62 schwarze 1071: case NODE_EDITOR:
1.101 schwarze 1072: print_text(f, "editor:", ARG_SPACE);
1.121 schwarze 1073: pnode_printauthor(f, n);
1.50 schwarze 1074: break;
1.65 schwarze 1075: case NODE_EMAIL:
1.115 schwarze 1076: if (was_impl)
1077: macro_open(f, "Ao Mt");
1078: else {
1079: macro_open(f, "Aq Mt");
1080: f->flags |= FMT_IMPL;
1081: }
1.65 schwarze 1082: break;
1.62 schwarze 1083: case NODE_EMPHASIS:
1084: case NODE_FIRSTTERM:
1.99 schwarze 1085: case NODE_GLOSSTERM:
1.123 ! schwarze 1086: if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
! 1087: pnode_class(nc->node) < CLASS_LINE)
! 1088: macro_open(f, "Em");
1.1 kristaps 1089: break;
1.62 schwarze 1090: case NODE_ENVAR:
1.101 schwarze 1091: macro_open(f, "Ev");
1.79 schwarze 1092: break;
1.90 schwarze 1093: case NODE_ERRORNAME:
1.101 schwarze 1094: macro_open(f, "Er");
1.90 schwarze 1095: break;
1.62 schwarze 1096: case NODE_FILENAME:
1.101 schwarze 1097: macro_open(f, "Pa");
1.17 kristaps 1098: break;
1.62 schwarze 1099: case NODE_FUNCTION:
1.101 schwarze 1100: macro_open(f, "Fn");
1.3 kristaps 1101: break;
1.62 schwarze 1102: case NODE_FUNCPROTOTYPE:
1.101 schwarze 1103: pnode_printfuncprototype(f, n);
1.3 kristaps 1104: break;
1.62 schwarze 1105: case NODE_FUNCSYNOPSISINFO:
1.101 schwarze 1106: macro_open(f, "Fd");
1.16 kristaps 1107: break;
1.62 schwarze 1108: case NODE_INFORMALEQUATION:
1.111 schwarze 1109: macro_line(f, "Bd -ragged -offset indent");
1110: /* FALLTHROUGH */
1111: case NODE_INLINEEQUATION:
1.101 schwarze 1112: macro_line(f, "EQ");
1.43 kristaps 1113: break;
1.62 schwarze 1114: case NODE_ITEMIZEDLIST:
1.101 schwarze 1115: pnode_printlist(f, n);
1.24 kristaps 1116: break;
1.62 schwarze 1117: case NODE_GROUP:
1.101 schwarze 1118: pnode_printgroup(f, n);
1.10 kristaps 1119: break;
1.67 schwarze 1120: case NODE_KEYSYM:
1.101 schwarze 1121: macro_open(f, "Sy");
1.67 schwarze 1122: break;
1.62 schwarze 1123: case NODE_LINK:
1.101 schwarze 1124: pnode_printlink(f, n);
1.96 schwarze 1125: break;
1.62 schwarze 1126: case NODE_LITERAL:
1.122 schwarze 1127: if (n->parent != NULL && n->parent->node == NODE_QUOTE)
1128: macro_open(f, "Li");
1129: else if (was_impl)
1130: macro_open(f, "So Li");
1.112 schwarze 1131: else {
1132: macro_open(f, "Ql");
1133: f->flags |= FMT_IMPL;
1134: }
1.19 kristaps 1135: break;
1.62 schwarze 1136: case NODE_LITERALLAYOUT:
1.101 schwarze 1137: macro_close(f);
1138: macro_argline(f, "Bd", pnode_getattr(n, ATTRKEY_CLASS) ==
1.66 schwarze 1139: ATTRVAL_MONOSPACED ? "-literal" : "-unfilled");
1.60 schwarze 1140: break;
1.106 schwarze 1141: case NODE_MARKUP:
1142: macro_open(f, "Ic");
1143: break;
1.62 schwarze 1144: case NODE_MML_MFENCED:
1.101 schwarze 1145: pnode_printmathfenced(f, n);
1.40 kristaps 1146: break;
1.62 schwarze 1147: case NODE_MML_MROW:
1148: case NODE_MML_MI:
1149: case NODE_MML_MN:
1150: case NODE_MML_MO:
1.101 schwarze 1151: if (TAILQ_EMPTY(&n->childq))
1.43 kristaps 1152: break;
1153: fputs(" { ", stdout);
1.40 kristaps 1154: break;
1.62 schwarze 1155: case NODE_MML_MFRAC:
1156: case NODE_MML_MSUB:
1157: case NODE_MML_MSUP:
1.101 schwarze 1158: pnode_printmath(f, n);
1.40 kristaps 1159: break;
1.62 schwarze 1160: case NODE_OPTION:
1.123 ! schwarze 1161: if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
! 1162: pnode_class(nc->node) < CLASS_LINE)
! 1163: macro_open(f, "Fl");
1.1 kristaps 1164: break;
1.62 schwarze 1165: case NODE_ORDEREDLIST:
1.101 schwarze 1166: pnode_printlist(f, n);
1.25 kristaps 1167: break;
1.62 schwarze 1168: case NODE_PARA:
1.101 schwarze 1169: pnode_printpara(f, n);
1.3 kristaps 1170: break;
1.87 schwarze 1171: case NODE_PARAMDEF:
1.62 schwarze 1172: case NODE_PARAMETER:
1.104 schwarze 1173: /* More often, these appear inside NODE_FUNCPROTOTYPE. */
1174: macro_open(f, "Fa");
1175: macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
1.101 schwarze 1176: pnode_unlinksub(n);
1.1 kristaps 1177: break;
1.62 schwarze 1178: case NODE_QUOTE:
1.112 schwarze 1179: if (was_impl)
1180: macro_open(f, "Do");
1181: else {
1182: macro_open(f, "Dq");
1183: f->flags |= FMT_IMPL;
1184: }
1.28 kristaps 1185: break;
1.62 schwarze 1186: case NODE_PROGRAMLISTING:
1187: case NODE_SCREEN:
1.88 schwarze 1188: case NODE_SYNOPSIS:
1.101 schwarze 1189: macro_line(f, "Bd -literal");
1.118 schwarze 1190: break;
1191: case NODE_SYSTEMITEM:
1192: pnode_printsystemitem(f, n);
1.15 kristaps 1193: break;
1.119 schwarze 1194: case NODE_REFENTRY:
1195: pnode_printrefentry(f, n);
1.1 kristaps 1196: break;
1.62 schwarze 1197: case NODE_REFNAME:
1.110 schwarze 1198: /* More often, these appear inside NODE_REFNAMEDIV. */
1.101 schwarze 1199: macro_open(f, "Nm");
1.10 kristaps 1200: break;
1.62 schwarze 1201: case NODE_REFNAMEDIV:
1.110 schwarze 1202: pnode_printrefnamediv(f, n);
1.1 kristaps 1203: break;
1.62 schwarze 1204: case NODE_REFPURPOSE:
1.101 schwarze 1205: macro_open(f, "Nd");
1.10 kristaps 1206: break;
1.62 schwarze 1207: case NODE_REFSYNOPSISDIV:
1.101 schwarze 1208: pnode_printrefsynopsisdiv(f, n);
1.1 kristaps 1209: break;
1.62 schwarze 1210: case NODE_PREFACE:
1211: case NODE_SECTION:
1.121 schwarze 1212: case NODE_SIMPLESECT:
1.100 schwarze 1213: case NODE_APPENDIX:
1214: case NODE_LEGALNOTICE:
1.62 schwarze 1215: case NODE_NOTE:
1216: case NODE_TIP:
1217: case NODE_CAUTION:
1218: case NODE_WARNING:
1.119 schwarze 1219: pnode_printsection(f, n);
1.1 kristaps 1220: break;
1.62 schwarze 1221: case NODE_REPLACEABLE:
1.101 schwarze 1222: macro_open(f, "Ar");
1.13 kristaps 1223: break;
1.62 schwarze 1224: case NODE_SBR:
1.101 schwarze 1225: macro_line(f, "br");
1.25 kristaps 1226: break;
1.62 schwarze 1227: case NODE_TEXT:
1.93 schwarze 1228: case NODE_ESCAPE:
1.101 schwarze 1229: pnode_printtext(f, n);
1.1 kristaps 1230: break;
1.82 schwarze 1231: case NODE_TGROUP:
1.101 schwarze 1232: pnode_printtgroup(f, n);
1.82 schwarze 1233: break;
1.62 schwarze 1234: case NODE_TITLE:
1.121 schwarze 1235: case NODE_SUBTITLE:
1.101 schwarze 1236: pnode_printpara(f, n);
1237: macro_nodeline(f, "Sy", n, 0);
1238: pnode_unlinksub(n);
1.50 schwarze 1239: break;
1.62 schwarze 1240: case NODE_TYPE:
1.101 schwarze 1241: macro_open(f, "Vt");
1.39 kristaps 1242: break;
1.62 schwarze 1243: case NODE_VARIABLELIST:
1.101 schwarze 1244: pnode_printvariablelist(f, n);
1.13 kristaps 1245: break;
1.62 schwarze 1246: case NODE_VARNAME:
1.101 schwarze 1247: macro_open(f, "Va");
1.23 kristaps 1248: break;
1.1 kristaps 1249: default:
1250: break;
1251: }
1252:
1.102 schwarze 1253: TAILQ_FOREACH(nc, &n->childq, child)
1254: pnode_print(f, nc);
1.1 kristaps 1255:
1.101 schwarze 1256: switch (n->node) {
1.115 schwarze 1257: case NODE_EMAIL:
1258: if (was_impl) {
1259: f->flags &= ~FMT_NOSPC;
1260: macro_open(f, "Ac");
1261: } else
1262: f->flags &= ~FMT_IMPL;
1263: break;
1.103 schwarze 1264: case NODE_ESCAPE:
1265: case NODE_TERM:
1266: case NODE_TEXT:
1267: /* Accept more arguments to the previous macro. */
1268: return;
1.62 schwarze 1269: case NODE_INFORMALEQUATION:
1.101 schwarze 1270: macro_line(f, "EN");
1.111 schwarze 1271: macro_line(f, "Ed");
1.40 kristaps 1272: break;
1.62 schwarze 1273: case NODE_INLINEEQUATION:
1.111 schwarze 1274: macro_line(f, "EN");
1.43 kristaps 1275: break;
1.112 schwarze 1276: case NODE_LITERAL:
1.122 schwarze 1277: if (n->parent != NULL && n->parent->node == NODE_QUOTE)
1278: /* nothing */;
1279: else if (was_impl) {
1.115 schwarze 1280: f->flags &= ~FMT_NOSPC;
1.112 schwarze 1281: macro_open(f, "Sc");
1.115 schwarze 1282: } else
1.112 schwarze 1283: f->flags &= ~FMT_IMPL;
1284: break;
1.91 schwarze 1285: case NODE_MEMBER:
1.102 schwarze 1286: if ((nn = TAILQ_NEXT(n, child)) != NULL &&
1287: nn->node != NODE_MEMBER)
1288: nn = NULL;
1.101 schwarze 1289: switch (f->linestate) {
1.91 schwarze 1290: case LINE_TEXT:
1.102 schwarze 1291: if (nn != NULL)
1.101 schwarze 1292: print_text(f, ",", 0);
1.91 schwarze 1293: break;
1294: case LINE_MACRO:
1.102 schwarze 1295: if (nn != NULL)
1.101 schwarze 1296: macro_addarg(f, ",", ARG_SPACE);
1297: macro_close(f);
1.91 schwarze 1298: break;
1299: case LINE_NEW:
1300: break;
1301: }
1302: break;
1.62 schwarze 1303: case NODE_MML_MROW:
1304: case NODE_MML_MI:
1305: case NODE_MML_MN:
1306: case NODE_MML_MO:
1.101 schwarze 1307: if (TAILQ_EMPTY(&n->childq))
1.43 kristaps 1308: break;
1309: fputs(" } ", stdout);
1.40 kristaps 1310: break;
1.62 schwarze 1311: case NODE_QUOTE:
1.115 schwarze 1312: if (was_impl) {
1313: f->flags &= ~FMT_NOSPC;
1.112 schwarze 1314: macro_open(f, "Dc");
1.115 schwarze 1315: } else
1.112 schwarze 1316: f->flags &= ~FMT_IMPL;
1.52 schwarze 1317: break;
1.62 schwarze 1318: case NODE_PREFACE:
1319: case NODE_SECTION:
1.100 schwarze 1320: case NODE_APPENDIX:
1321: case NODE_LEGALNOTICE:
1.62 schwarze 1322: case NODE_NOTE:
1323: case NODE_TIP:
1324: case NODE_CAUTION:
1325: case NODE_WARNING:
1.101 schwarze 1326: f->level--;
1.12 kristaps 1327: break;
1.98 schwarze 1328: case NODE_BLOCKQUOTE:
1.62 schwarze 1329: case NODE_LITERALLAYOUT:
1330: case NODE_PROGRAMLISTING:
1331: case NODE_SCREEN:
1.88 schwarze 1332: case NODE_SYNOPSIS:
1.101 schwarze 1333: macro_line(f, "Ed");
1.50 schwarze 1334: break;
1.1 kristaps 1335: default:
1336: break;
1337: }
1.103 schwarze 1338: f->flags &= ~FMT_ARG;
1.1 kristaps 1339: }
1340:
1.74 schwarze 1341: void
1.114 schwarze 1342: ptree_print_mdoc(struct ptree *tree)
1.74 schwarze 1343: {
1344: struct format formatter;
1.1 kristaps 1345:
1.74 schwarze 1346: formatter.level = 0;
1347: formatter.linestate = LINE_NEW;
1.116 schwarze 1348: pnode_printprologue(&formatter, tree->root);
1.74 schwarze 1349: pnode_print(&formatter, tree->root);
1350: if (formatter.linestate != LINE_NEW)
1351: putchar('\n');
1.1 kristaps 1352: }
CVSweb