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