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