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