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