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