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