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