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