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