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