Annotation of docbook2mdoc/docbook2mdoc.c, Revision 1.128
1.128 ! schwarze 1: /* $Id: docbook2mdoc.c,v 1.127 2019/04/14 23:07:05 schwarze Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2014 Kristaps Dzonsons <kristaps@bsd.lv>
1.50 schwarze 4: * Copyright (c) 2019 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18: #include <assert.h>
19: #include <ctype.h>
20: #include <stdio.h>
21: #include <stdlib.h>
1.103 schwarze 22: #include <string.h>
1.1 kristaps 23:
1.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.96 schwarze 628: pnode_printlink(struct format *f, struct pnode *n)
629: {
1.109 schwarze 630: struct pnode *nc;
1.96 schwarze 631: const char *uri, *text;
632:
633: uri = pnode_getattr_raw(n, ATTRKEY_LINKEND, NULL);
634: if (uri != NULL) {
635: if (TAILQ_FIRST(&n->childq) != NULL) {
1.109 schwarze 636: TAILQ_FOREACH(nc, &n->childq, child)
637: pnode_print(f, nc);
1.96 schwarze 638: text = "";
1.109 schwarze 639: } else if ((text = pnode_getattr_raw(n,
640: ATTRKEY_ENDTERM, NULL)) != NULL) {
641: if (f->linestate == LINE_MACRO && f->flags & FMT_ARG)
642: macro_addarg(f, text, ARG_SPACE);
643: else
1.96 schwarze 644: print_text(f, text, ARG_SPACE);
645: }
1.103 schwarze 646: if (text != NULL) {
1.109 schwarze 647: if (f->flags & FMT_IMPL)
648: macro_open(f, "Po");
649: else {
650: macro_open(f, "Pq");
651: f->flags |= FMT_CHILD;
652: }
1.103 schwarze 653: }
1.96 schwarze 654: macro_open(f, "Sx");
655: macro_addarg(f, uri, ARG_SPACE);
1.109 schwarze 656: if (text != NULL && f->flags & FMT_IMPL)
657: macro_open(f, "Pc");
1.96 schwarze 658: pnode_unlinksub(n);
659: return;
660: }
661: uri = pnode_getattr_raw(n, ATTRKEY_XLINK_HREF, NULL);
662: if (uri == NULL)
663: uri = pnode_getattr_raw(n, ATTRKEY_URL, NULL);
664: if (uri != NULL) {
665: macro_open(f, "Lk");
666: macro_addarg(f, uri, ARG_SPACE | ARG_SINGLE);
667: if (TAILQ_FIRST(&n->childq) != NULL)
668: macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
669: pnode_unlinksub(n);
1.128 ! schwarze 670: }
! 671: }
! 672:
! 673: static void
! 674: pnode_printolink(struct format *f, struct pnode *n)
! 675: {
! 676: const char *uri, *ptr, *local;
! 677:
! 678: uri = pnode_getattr_raw(n, ATTRKEY_TARGETDOC, NULL);
! 679: ptr = pnode_getattr_raw(n, ATTRKEY_TARGETPTR, NULL);
! 680: local = pnode_getattr_raw(n, ATTRKEY_LOCALINFO, NULL);
! 681: if (uri == NULL) {
! 682: uri = ptr;
! 683: ptr = NULL;
! 684: }
! 685: if (uri == NULL) {
! 686: uri = local;
! 687: local = NULL;
! 688: }
! 689: if (uri == NULL)
1.96 schwarze 690: return;
1.128 ! schwarze 691:
! 692: macro_open(f, "Lk");
! 693: macro_addarg(f, uri, ARG_SPACE | ARG_SINGLE);
! 694: macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
! 695: if (ptr != NULL || local != NULL) {
! 696: macro_close(f);
! 697: macro_open(f, "Pq");
! 698: if (ptr != NULL)
! 699: macro_addarg(f, ptr, ARG_SPACE);
! 700: if (local != NULL)
! 701: macro_addarg(f, local, ARG_SPACE);
1.96 schwarze 702: }
1.128 ! schwarze 703: pnode_unlinksub(n);
1.96 schwarze 704: }
705:
706: static void
1.116 schwarze 707: pnode_printprologue(struct format *f, struct pnode *root)
1.7 kristaps 708: {
1.119 schwarze 709: struct pnode *date, *refmeta, *name, *vol, *descr, *nc, *nn;
1.116 schwarze 710: const char *sname;
1.7 kristaps 711:
1.116 schwarze 712: /* Collect information. */
1.9 kristaps 713:
1.116 schwarze 714: if ((date = pnode_takefirst(root, NODE_PUBDATE)) == NULL)
715: date = pnode_takefirst(root, NODE_DATE);
716:
717: name = vol = NULL;
1.119 schwarze 718: if ((refmeta = pnode_findfirst(root, NODE_REFMETA)) != NULL) {
719: TAILQ_FOREACH_SAFE(nc, &refmeta->childq, child, nn) {
1.116 schwarze 720: switch (nc->node) {
721: case NODE_REFENTRYTITLE:
722: name = nc;
723: break;
724: case NODE_MANVOLNUM:
725: vol = nc;
726: break;
727: default:
1.119 schwarze 728: continue;
1.116 schwarze 729: }
1.119 schwarze 730: TAILQ_REMOVE(&refmeta->childq, nc, child);
1.116 schwarze 731: }
732: }
733:
734: if (pnode_findfirst(root, NODE_REFNAMEDIV) == NULL &&
735: ((nc = pnode_findfirst(root, NODE_BOOKINFO)) != NULL ||
736: (nc = pnode_findfirst(root, NODE_REFENTRYINFO)) != NULL))
737: descr = pnode_takefirst(nc, NODE_TITLE);
738: else
739: descr = NULL;
740:
741: /* Print prologue. */
742:
743: if (date == NULL)
744: macro_line(f, "Dd $Mdocdate" "$");
745: else
746: macro_nodeline(f, "Dd", date, 0);
747:
748: macro_open(f, "Dt");
749: if (name == NULL) {
750: sname = pnode_getattr_raw(root, ATTRKEY_ID, "UNKNOWN");
751: macro_addarg(f, sname, ARG_SPACE | ARG_SINGLE | ARG_UPPER);
752: } else
753: macro_addnode(f, name, ARG_SPACE | ARG_SINGLE | ARG_UPPER);
754: if (vol == NULL)
1.101 schwarze 755: macro_addarg(f, "1", ARG_SPACE);
1.116 schwarze 756: else
757: macro_addnode(f, vol, ARG_SPACE | ARG_SINGLE);
758:
1.101 schwarze 759: macro_line(f, "Os");
1.116 schwarze 760:
761: if (descr != NULL) {
762: macro_line(f, "Sh NAME");
763: if (name == NULL)
764: macro_argline(f, "Nm", sname);
765: else
766: macro_nodeline(f, "Nm", name, ARG_SINGLE);
767: macro_nodeline(f, "Nd", descr, 0);
768: }
769:
770: /* Clean up. */
771:
772: pnode_unlink(date);
1.119 schwarze 773: pnode_unlink(name);
774: pnode_unlink(vol);
1.116 schwarze 775: pnode_unlink(descr);
1.7 kristaps 776: }
777:
1.119 schwarze 778: static void
779: pnode_printrefentry(struct format *f, struct pnode *n)
780: {
781: struct pnode *info, *meta, *nc, *title;
782: struct pnode *match, *later;
783:
784: /* Collect nodes that remained behind when writing the prologue. */
785:
786: meta = NULL;
787: info = pnode_takefirst(n, NODE_BOOKINFO);
788: if (info != NULL && TAILQ_FIRST(&info->childq) == NULL) {
789: pnode_unlink(info);
790: info = NULL;
791: }
792: if (info == NULL) {
793: info = pnode_takefirst(n, NODE_REFENTRYINFO);
794: if (info != NULL && TAILQ_FIRST(&info->childq) == NULL) {
795: pnode_unlink(info);
796: info = NULL;
797: }
798: meta = pnode_takefirst(n, NODE_REFMETA);
799: if (meta != NULL && TAILQ_FIRST(&meta->childq) == NULL) {
800: pnode_unlink(meta);
801: meta = NULL;
802: }
803: }
804: if (info == NULL && meta == NULL)
805: return;
806:
807: /*
808: * Find the best place to put this information.
809: * Use the last existing AUTHORS node, if any.
810: * Otherwise, put it behind all standard sections that
811: * conventionally precede AUTHORS, and also behind any
812: * non-standard sections that follow the last of these,
813: * but before the next standard section.
814: */
815:
816: match = later = NULL;
817: TAILQ_FOREACH(nc, &n->childq, child) {
818: switch (nc->node) {
819: case NODE_REFENTRY:
820: case NODE_REFNAMEDIV:
821: case NODE_REFSYNOPSISDIV:
822: case NODE_PREFACE:
823: later = NULL;
824: continue;
825: case NODE_APPENDIX:
826: case NODE_INDEX:
827: if (later == NULL)
828: later = nc;
829: continue;
830: default:
831: break;
832: }
833: if ((title = pnode_findfirst(nc, NODE_TITLE)) == NULL ||
834: (title = TAILQ_FIRST(&title->childq)) == NULL ||
835: title->node != NODE_TEXT)
836: continue;
837: if (strcasecmp(title->b, "AUTHORS") == 0 ||
838: strcasecmp(title->b, "AUTHOR") == 0)
839: match = nc;
840: else if (strcasecmp(title->b, "NAME") == 0 ||
841: strcasecmp(title->b, "SYNOPSIS") == 0 ||
842: strcasecmp(title->b, "DESCRIPTION") == 0 ||
843: strcasecmp(title->b, "RETURN VALUES") == 0 ||
844: strcasecmp(title->b, "ENVIRONMENT") == 0 ||
845: strcasecmp(title->b, "FILES") == 0 ||
846: strcasecmp(title->b, "EXIT STATUS") == 0 ||
847: strcasecmp(title->b, "EXAMPLES") == 0 ||
848: strcasecmp(title->b, "DIAGNOSTICS") == 0 ||
849: strcasecmp(title->b, "ERRORS") == 0 ||
850: strcasecmp(title->b, "SEE ALSO") == 0 ||
851: strcasecmp(title->b, "STANDARDS") == 0 ||
852: strcasecmp(title->b, "HISTORY") == 0)
853: later = NULL;
854: else if ((strcasecmp(title->b, "CAVEATS") == 0 ||
855: strcasecmp(title->b, "BUGS") == 0) &&
856: later == NULL)
857: later = nc;
858: }
859:
860: /*
861: * If no AUTHORS section was found, create one from scratch,
862: * and insert that at the place selected earlier.
863: */
864:
865: if (match == NULL) {
866: if ((match = calloc(1, sizeof(*match))) == NULL) {
867: perror(NULL);
868: exit(1);
869: }
870: match->node = NODE_SECTION;
871: match->spc = 1;
872: match->parent = n;
873: TAILQ_INIT(&match->childq);
874: TAILQ_INIT(&match->attrq);
875: if ((nc = pnode_alloc(match)) == NULL) {
876: perror(NULL);
877: exit(1);
878: }
879: nc->node = NODE_TITLE;
880: nc->spc = 1;
881: if ((nc = pnode_alloc(nc)) == NULL) {
882: perror(NULL);
883: exit(1);
884: }
885: nc->node = NODE_TEXT;
886: if ((nc->b = strdup("AUTHORS")) == NULL) {
887: perror(NULL);
888: exit(1);
889: }
890: nc->spc = 1;
891: if (later == NULL)
892: TAILQ_INSERT_TAIL(&n->childq, match, child);
893: else
894: TAILQ_INSERT_BEFORE(later, match, child);
895: }
896:
897: /*
898: * Dump the stuff excised at the beginning
899: * into this AUTHORS section.
900: */
901:
902: if (info != NULL)
903: TAILQ_INSERT_TAIL(&match->childq, info, child);
904: if (meta != NULL)
905: TAILQ_INSERT_TAIL(&match->childq, meta, child);
906: }
907:
1.42 kristaps 908: /*
909: * We can have multiple <term> elements within a <varlistentry>, which
910: * we should comma-separate as list headers.
911: */
1.13 kristaps 912: static void
1.101 schwarze 913: pnode_printvarlistentry(struct format *f, struct pnode *n)
1.13 kristaps 914: {
1.108 schwarze 915: struct pnode *nc, *nn;
1.42 kristaps 916: int first = 1;
1.13 kristaps 917:
1.101 schwarze 918: macro_open(f, "It");
1.103 schwarze 919: f->flags |= FMT_IMPL;
1.108 schwarze 920: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
1.101 schwarze 921: if (nc->node != NODE_TERM && nc->node != NODE_GLOSSTERM)
1.69 schwarze 922: continue;
1.108 schwarze 923: if (first == 0) {
924: switch (f->linestate) {
925: case LINE_NEW:
926: break;
927: case LINE_TEXT:
928: print_text(f, ",", 0);
929: break;
930: case LINE_MACRO:
931: macro_addarg(f, ",", 0);
932: break;
933: }
934: }
1.101 schwarze 935: pnode_print(f, nc);
1.108 schwarze 936: pnode_unlink(nc);
1.69 schwarze 937: first = 0;
938: }
1.101 schwarze 939: macro_close(f);
1.108 schwarze 940: while ((nc = TAILQ_FIRST(&n->childq)) != NULL) {
941: pnode_print(f, nc);
942: pnode_unlink(nc);
943: }
944: macro_close(f);
1.71 schwarze 945: }
946:
947: static void
1.101 schwarze 948: pnode_printtitle(struct format *f, struct pnode *n)
1.71 schwarze 949: {
1.101 schwarze 950: struct pnode *nc, *nn;
1.71 schwarze 951:
1.101 schwarze 952: TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
953: if (nc->node == NODE_TITLE) {
954: pnode_printpara(f, nc);
955: pnode_print(f, nc);
956: pnode_unlink(nc);
1.71 schwarze 957: }
958: }
1.13 kristaps 959: }
960:
961: static void
1.101 schwarze 962: pnode_printrow(struct format *f, struct pnode *n)
1.25 kristaps 963: {
1.101 schwarze 964: struct pnode *nc;
1.25 kristaps 965:
1.101 schwarze 966: macro_line(f, "Bl -dash -compact");
967: TAILQ_FOREACH(nc, &n->childq, child) {
968: macro_line(f, "It");
969: pnode_print(f, nc);
1.25 kristaps 970: }
1.101 schwarze 971: macro_line(f, "El");
972: pnode_unlink(n);
1.25 kristaps 973: }
974:
975: static void
1.83 schwarze 976: pnode_printtgroup1(struct format *f, struct pnode *n)
1.16 kristaps 977: {
1.82 schwarze 978: struct pnode *nc;
979:
1.83 schwarze 980: macro_line(f, "Bl -bullet -compact");
1.82 schwarze 981: while ((nc = pnode_findfirst(n, NODE_ENTRY)) != NULL) {
1.83 schwarze 982: macro_line(f, "It");
983: pnode_print(f, nc);
1.82 schwarze 984: pnode_unlink(nc);
985: }
1.83 schwarze 986: macro_line(f, "El");
987: pnode_unlinksub(n);
988: }
989:
990: static void
991: pnode_printtgroup2(struct format *f, struct pnode *n)
992: {
993: struct pnode *nr, *ne;
994:
995: macro_line(f, "Bl -tag -width Ds");
996: while ((nr = pnode_findfirst(n, NODE_ROW)) != NULL) {
997: if ((ne = pnode_findfirst(n, NODE_ENTRY)) == NULL)
998: break;
999: macro_open(f, "It");
1.103 schwarze 1000: f->flags |= FMT_IMPL;
1.83 schwarze 1001: pnode_print(f, ne);
1.84 schwarze 1002: macro_close(f);
1.83 schwarze 1003: pnode_unlink(ne);
1004: pnode_print(f, nr);
1005: pnode_unlink(nr);
1006: }
1007: macro_line(f, "El");
1.82 schwarze 1008: pnode_unlinksub(n);
1009: }
1010:
1011: static void
1.83 schwarze 1012: pnode_printtgroup(struct format *f, struct pnode *n)
1.82 schwarze 1013: {
1014: struct pnode *nc;
1015:
1016: switch (atoi(pnode_getattr_raw(n, ATTRKEY_COLS, "0"))) {
1017: case 1:
1.83 schwarze 1018: pnode_printtgroup1(f, n);
1019: return;
1020: case 2:
1021: pnode_printtgroup2(f, n);
1.82 schwarze 1022: return;
1023: default:
1024: break;
1025: }
1.16 kristaps 1026:
1.83 schwarze 1027: macro_line(f, "Bl -ohang");
1.82 schwarze 1028: while ((nc = pnode_findfirst(n, NODE_ROW)) != NULL) {
1.83 schwarze 1029: macro_line(f, "It Table Row");
1030: pnode_printrow(f, nc);
1.25 kristaps 1031: }
1.83 schwarze 1032: macro_line(f, "El");
1.82 schwarze 1033: pnode_unlinksub(n);
1.25 kristaps 1034: }
1035:
1036: static void
1.101 schwarze 1037: pnode_printlist(struct format *f, struct pnode *n)
1.25 kristaps 1038: {
1.101 schwarze 1039: struct pnode *nc;
1.16 kristaps 1040:
1.101 schwarze 1041: pnode_printtitle(f, n);
1042: macro_argline(f, "Bl",
1043: n->node == NODE_ORDEREDLIST ? "-enum" : "-bullet");
1044: TAILQ_FOREACH(nc, &n->childq, child) {
1045: macro_line(f, "It");
1046: pnode_print(f, nc);
1.16 kristaps 1047: }
1.101 schwarze 1048: macro_line(f, "El");
1049: pnode_unlinksub(n);
1.16 kristaps 1050: }
1051:
1052: static void
1.101 schwarze 1053: pnode_printvariablelist(struct format *f, struct pnode *n)
1.13 kristaps 1054: {
1.101 schwarze 1055: struct pnode *nc;
1.13 kristaps 1056:
1.101 schwarze 1057: pnode_printtitle(f, n);
1058: macro_line(f, "Bl -tag -width Ds");
1059: TAILQ_FOREACH(nc, &n->childq, child) {
1060: if (nc->node == NODE_VARLISTENTRY)
1061: pnode_printvarlistentry(f, nc);
1.69 schwarze 1062: else
1.101 schwarze 1063: macro_nodeline(f, "It", nc, 0);
1.69 schwarze 1064: }
1.101 schwarze 1065: macro_line(f, "El");
1066: pnode_unlinksub(n);
1.13 kristaps 1067: }
1068:
1.1 kristaps 1069: /*
1070: * Print a parsed node (or ignore it--whatever).
1071: * This is a recursive function.
1.23 kristaps 1072: * FIXME: if we're in a literal context (<screen> or <programlisting> or
1073: * whatever), don't print inline macros.
1.1 kristaps 1074: */
1075: static void
1.101 schwarze 1076: pnode_print(struct format *f, struct pnode *n)
1.1 kristaps 1077: {
1.102 schwarze 1078: struct pnode *nc, *nn;
1.112 schwarze 1079: int was_impl;
1.1 kristaps 1080:
1.101 schwarze 1081: if (n == NULL)
1.1 kristaps 1082: return;
1083:
1.112 schwarze 1084: was_impl = f->flags & FMT_IMPL;
1.103 schwarze 1085: if (n->spc)
1086: f->flags &= ~FMT_NOSPC;
1087: else
1088: f->flags |= FMT_NOSPC;
1.1 kristaps 1089:
1.101 schwarze 1090: switch (n->node) {
1.62 schwarze 1091: case NODE_ARG:
1.101 schwarze 1092: pnode_printarg(f, n);
1.4 kristaps 1093: break;
1.62 schwarze 1094: case NODE_AUTHOR:
1.101 schwarze 1095: pnode_printauthor(f, n);
1.50 schwarze 1096: break;
1.62 schwarze 1097: case NODE_AUTHORGROUP:
1.101 schwarze 1098: macro_line(f, "An -split");
1.50 schwarze 1099: break;
1.98 schwarze 1100: case NODE_BLOCKQUOTE:
1.101 schwarze 1101: macro_line(f, "Bd -ragged -offset indent");
1.98 schwarze 1102: break;
1.62 schwarze 1103: case NODE_CITEREFENTRY:
1.101 schwarze 1104: pnode_printciterefentry(f, n);
1.1 kristaps 1105: break;
1.68 schwarze 1106: case NODE_CITETITLE:
1.101 schwarze 1107: macro_open(f, "%T");
1.68 schwarze 1108: break;
1.62 schwarze 1109: case NODE_COMMAND:
1.101 schwarze 1110: macro_open(f, "Nm");
1.13 kristaps 1111: break;
1.62 schwarze 1112: case NODE_CONSTANT:
1.101 schwarze 1113: macro_open(f, "Dv");
1.33 kristaps 1114: break;
1.121 schwarze 1115: case NODE_COPYRIGHT:
1116: print_text(f, "Copyright", ARG_SPACE);
1117: fputs(" \\(co", stdout);
1118: break;
1.62 schwarze 1119: case NODE_EDITOR:
1.101 schwarze 1120: print_text(f, "editor:", ARG_SPACE);
1.121 schwarze 1121: pnode_printauthor(f, n);
1.50 schwarze 1122: break;
1.65 schwarze 1123: case NODE_EMAIL:
1.115 schwarze 1124: if (was_impl)
1125: macro_open(f, "Ao Mt");
1126: else {
1127: macro_open(f, "Aq Mt");
1128: f->flags |= FMT_IMPL;
1129: }
1.65 schwarze 1130: break;
1.62 schwarze 1131: case NODE_EMPHASIS:
1132: case NODE_FIRSTTERM:
1.99 schwarze 1133: case NODE_GLOSSTERM:
1.123 schwarze 1134: if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
1135: pnode_class(nc->node) < CLASS_LINE)
1136: macro_open(f, "Em");
1.1 kristaps 1137: break;
1.62 schwarze 1138: case NODE_ENVAR:
1.101 schwarze 1139: macro_open(f, "Ev");
1.79 schwarze 1140: break;
1.90 schwarze 1141: case NODE_ERRORNAME:
1.101 schwarze 1142: macro_open(f, "Er");
1.90 schwarze 1143: break;
1.62 schwarze 1144: case NODE_FILENAME:
1.101 schwarze 1145: macro_open(f, "Pa");
1.17 kristaps 1146: break;
1.125 schwarze 1147: case NODE_FOOTNOTE:
1148: macro_line(f, "Bo");
1149: break;
1.62 schwarze 1150: case NODE_FUNCTION:
1.101 schwarze 1151: macro_open(f, "Fn");
1.3 kristaps 1152: break;
1.62 schwarze 1153: case NODE_FUNCPROTOTYPE:
1.101 schwarze 1154: pnode_printfuncprototype(f, n);
1.3 kristaps 1155: break;
1.62 schwarze 1156: case NODE_FUNCSYNOPSISINFO:
1.101 schwarze 1157: macro_open(f, "Fd");
1.126 schwarze 1158: break;
1159: case NODE_IMAGEDATA:
1160: pnode_printimagedata(f, n);
1.16 kristaps 1161: break;
1.62 schwarze 1162: case NODE_INFORMALEQUATION:
1.111 schwarze 1163: macro_line(f, "Bd -ragged -offset indent");
1164: /* FALLTHROUGH */
1165: case NODE_INLINEEQUATION:
1.101 schwarze 1166: macro_line(f, "EQ");
1.43 kristaps 1167: break;
1.62 schwarze 1168: case NODE_ITEMIZEDLIST:
1.101 schwarze 1169: pnode_printlist(f, n);
1.24 kristaps 1170: break;
1.62 schwarze 1171: case NODE_GROUP:
1.101 schwarze 1172: pnode_printgroup(f, n);
1.10 kristaps 1173: break;
1.67 schwarze 1174: case NODE_KEYSYM:
1.101 schwarze 1175: macro_open(f, "Sy");
1.67 schwarze 1176: break;
1.62 schwarze 1177: case NODE_LINK:
1.101 schwarze 1178: pnode_printlink(f, n);
1.96 schwarze 1179: break;
1.62 schwarze 1180: case NODE_LITERAL:
1.122 schwarze 1181: if (n->parent != NULL && n->parent->node == NODE_QUOTE)
1182: macro_open(f, "Li");
1183: else if (was_impl)
1184: macro_open(f, "So Li");
1.112 schwarze 1185: else {
1186: macro_open(f, "Ql");
1187: f->flags |= FMT_IMPL;
1188: }
1.19 kristaps 1189: break;
1.62 schwarze 1190: case NODE_LITERALLAYOUT:
1.101 schwarze 1191: macro_close(f);
1192: macro_argline(f, "Bd", pnode_getattr(n, ATTRKEY_CLASS) ==
1.66 schwarze 1193: ATTRVAL_MONOSPACED ? "-literal" : "-unfilled");
1.60 schwarze 1194: break;
1.106 schwarze 1195: case NODE_MARKUP:
1196: macro_open(f, "Ic");
1197: break;
1.62 schwarze 1198: case NODE_MML_MFENCED:
1.101 schwarze 1199: pnode_printmathfenced(f, n);
1.40 kristaps 1200: break;
1.62 schwarze 1201: case NODE_MML_MROW:
1202: case NODE_MML_MI:
1203: case NODE_MML_MN:
1204: case NODE_MML_MO:
1.101 schwarze 1205: if (TAILQ_EMPTY(&n->childq))
1.43 kristaps 1206: break;
1207: fputs(" { ", stdout);
1.40 kristaps 1208: break;
1.62 schwarze 1209: case NODE_MML_MFRAC:
1210: case NODE_MML_MSUB:
1211: case NODE_MML_MSUP:
1.101 schwarze 1212: pnode_printmath(f, n);
1.128 ! schwarze 1213: break;
! 1214: case NODE_OLINK:
! 1215: pnode_printolink(f, n);
1.40 kristaps 1216: break;
1.62 schwarze 1217: case NODE_OPTION:
1.123 schwarze 1218: if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
1219: pnode_class(nc->node) < CLASS_LINE)
1220: macro_open(f, "Fl");
1.1 kristaps 1221: break;
1.62 schwarze 1222: case NODE_ORDEREDLIST:
1.101 schwarze 1223: pnode_printlist(f, n);
1.25 kristaps 1224: break;
1.62 schwarze 1225: case NODE_PARA:
1.101 schwarze 1226: pnode_printpara(f, n);
1.3 kristaps 1227: break;
1.87 schwarze 1228: case NODE_PARAMDEF:
1.62 schwarze 1229: case NODE_PARAMETER:
1.104 schwarze 1230: /* More often, these appear inside NODE_FUNCPROTOTYPE. */
1231: macro_open(f, "Fa");
1232: macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
1.101 schwarze 1233: pnode_unlinksub(n);
1.1 kristaps 1234: break;
1.62 schwarze 1235: case NODE_QUOTE:
1.127 schwarze 1236: if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
1237: nc->node == NODE_FILENAME &&
1238: TAILQ_NEXT(nc, child) == NULL) {
1239: if (n->spc)
1240: nc->spc = 1;
1241: } else if (was_impl)
1.112 schwarze 1242: macro_open(f, "Do");
1243: else {
1244: macro_open(f, "Dq");
1245: f->flags |= FMT_IMPL;
1246: }
1.28 kristaps 1247: break;
1.62 schwarze 1248: case NODE_PROGRAMLISTING:
1249: case NODE_SCREEN:
1.88 schwarze 1250: case NODE_SYNOPSIS:
1.101 schwarze 1251: macro_line(f, "Bd -literal");
1.118 schwarze 1252: break;
1253: case NODE_SYSTEMITEM:
1254: pnode_printsystemitem(f, n);
1.15 kristaps 1255: break;
1.119 schwarze 1256: case NODE_REFENTRY:
1257: pnode_printrefentry(f, n);
1.1 kristaps 1258: break;
1.62 schwarze 1259: case NODE_REFNAME:
1.110 schwarze 1260: /* More often, these appear inside NODE_REFNAMEDIV. */
1.101 schwarze 1261: macro_open(f, "Nm");
1.10 kristaps 1262: break;
1.62 schwarze 1263: case NODE_REFNAMEDIV:
1.110 schwarze 1264: pnode_printrefnamediv(f, n);
1.1 kristaps 1265: break;
1.62 schwarze 1266: case NODE_REFPURPOSE:
1.101 schwarze 1267: macro_open(f, "Nd");
1.10 kristaps 1268: break;
1.62 schwarze 1269: case NODE_REFSYNOPSISDIV:
1.101 schwarze 1270: pnode_printrefsynopsisdiv(f, n);
1.1 kristaps 1271: break;
1.62 schwarze 1272: case NODE_PREFACE:
1273: case NODE_SECTION:
1.121 schwarze 1274: case NODE_SIMPLESECT:
1.100 schwarze 1275: case NODE_APPENDIX:
1276: case NODE_LEGALNOTICE:
1.62 schwarze 1277: case NODE_NOTE:
1278: case NODE_TIP:
1279: case NODE_CAUTION:
1280: case NODE_WARNING:
1.119 schwarze 1281: pnode_printsection(f, n);
1.1 kristaps 1282: break;
1.62 schwarze 1283: case NODE_REPLACEABLE:
1.101 schwarze 1284: macro_open(f, "Ar");
1.13 kristaps 1285: break;
1.62 schwarze 1286: case NODE_SBR:
1.101 schwarze 1287: macro_line(f, "br");
1.124 schwarze 1288: break;
1289: case NODE_SUBSCRIPT:
1290: if (f->linestate == LINE_MACRO)
1291: macro_addarg(f, "_", 0);
1292: else
1293: print_text(f, "_", 0);
1294: if ((nc = TAILQ_FIRST(&n->childq)) != NULL)
1295: nc->spc = 0;
1296: break;
1297: case NODE_SUPERSCRIPT:
1298: fputs("\\(ha", stdout);
1299: if ((nc = TAILQ_FIRST(&n->childq)) != NULL)
1300: nc->spc = 0;
1.25 kristaps 1301: break;
1.62 schwarze 1302: case NODE_TEXT:
1.93 schwarze 1303: case NODE_ESCAPE:
1.101 schwarze 1304: pnode_printtext(f, n);
1.1 kristaps 1305: break;
1.82 schwarze 1306: case NODE_TGROUP:
1.101 schwarze 1307: pnode_printtgroup(f, n);
1.82 schwarze 1308: break;
1.62 schwarze 1309: case NODE_TITLE:
1.121 schwarze 1310: case NODE_SUBTITLE:
1.101 schwarze 1311: pnode_printpara(f, n);
1312: macro_nodeline(f, "Sy", n, 0);
1313: pnode_unlinksub(n);
1.50 schwarze 1314: break;
1.62 schwarze 1315: case NODE_TYPE:
1.101 schwarze 1316: macro_open(f, "Vt");
1.39 kristaps 1317: break;
1.62 schwarze 1318: case NODE_VARIABLELIST:
1.101 schwarze 1319: pnode_printvariablelist(f, n);
1.13 kristaps 1320: break;
1.62 schwarze 1321: case NODE_VARNAME:
1.101 schwarze 1322: macro_open(f, "Va");
1.23 kristaps 1323: break;
1.1 kristaps 1324: default:
1325: break;
1326: }
1327:
1.102 schwarze 1328: TAILQ_FOREACH(nc, &n->childq, child)
1329: pnode_print(f, nc);
1.1 kristaps 1330:
1.101 schwarze 1331: switch (n->node) {
1.115 schwarze 1332: case NODE_EMAIL:
1333: if (was_impl) {
1334: f->flags &= ~FMT_NOSPC;
1335: macro_open(f, "Ac");
1336: } else
1337: f->flags &= ~FMT_IMPL;
1338: break;
1.103 schwarze 1339: case NODE_ESCAPE:
1340: case NODE_TERM:
1341: case NODE_TEXT:
1342: /* Accept more arguments to the previous macro. */
1343: return;
1.125 schwarze 1344: case NODE_FOOTNOTE:
1345: macro_line(f, "Bc");
1346: break;
1.62 schwarze 1347: case NODE_INFORMALEQUATION:
1.101 schwarze 1348: macro_line(f, "EN");
1.111 schwarze 1349: macro_line(f, "Ed");
1.40 kristaps 1350: break;
1.62 schwarze 1351: case NODE_INLINEEQUATION:
1.111 schwarze 1352: macro_line(f, "EN");
1.43 kristaps 1353: break;
1.112 schwarze 1354: case NODE_LITERAL:
1.122 schwarze 1355: if (n->parent != NULL && n->parent->node == NODE_QUOTE)
1356: /* nothing */;
1357: else if (was_impl) {
1.115 schwarze 1358: f->flags &= ~FMT_NOSPC;
1.112 schwarze 1359: macro_open(f, "Sc");
1.115 schwarze 1360: } else
1.112 schwarze 1361: f->flags &= ~FMT_IMPL;
1362: break;
1.91 schwarze 1363: case NODE_MEMBER:
1.102 schwarze 1364: if ((nn = TAILQ_NEXT(n, child)) != NULL &&
1365: nn->node != NODE_MEMBER)
1366: nn = NULL;
1.101 schwarze 1367: switch (f->linestate) {
1.91 schwarze 1368: case LINE_TEXT:
1.102 schwarze 1369: if (nn != NULL)
1.101 schwarze 1370: print_text(f, ",", 0);
1.91 schwarze 1371: break;
1372: case LINE_MACRO:
1.102 schwarze 1373: if (nn != NULL)
1.101 schwarze 1374: macro_addarg(f, ",", ARG_SPACE);
1375: macro_close(f);
1.91 schwarze 1376: break;
1377: case LINE_NEW:
1378: break;
1379: }
1380: break;
1.62 schwarze 1381: case NODE_MML_MROW:
1382: case NODE_MML_MI:
1383: case NODE_MML_MN:
1384: case NODE_MML_MO:
1.101 schwarze 1385: if (TAILQ_EMPTY(&n->childq))
1.43 kristaps 1386: break;
1387: fputs(" } ", stdout);
1.40 kristaps 1388: break;
1.62 schwarze 1389: case NODE_QUOTE:
1.127 schwarze 1390: if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
1391: nc->node == NODE_FILENAME &&
1392: TAILQ_NEXT(nc, child) == NULL)
1393: /* nothing */;
1394: else if (was_impl) {
1.115 schwarze 1395: f->flags &= ~FMT_NOSPC;
1.112 schwarze 1396: macro_open(f, "Dc");
1.115 schwarze 1397: } else
1.112 schwarze 1398: f->flags &= ~FMT_IMPL;
1.52 schwarze 1399: break;
1.62 schwarze 1400: case NODE_PREFACE:
1401: case NODE_SECTION:
1.100 schwarze 1402: case NODE_APPENDIX:
1403: case NODE_LEGALNOTICE:
1.62 schwarze 1404: case NODE_NOTE:
1405: case NODE_TIP:
1406: case NODE_CAUTION:
1407: case NODE_WARNING:
1.101 schwarze 1408: f->level--;
1.12 kristaps 1409: break;
1.98 schwarze 1410: case NODE_BLOCKQUOTE:
1.62 schwarze 1411: case NODE_LITERALLAYOUT:
1412: case NODE_PROGRAMLISTING:
1413: case NODE_SCREEN:
1.88 schwarze 1414: case NODE_SYNOPSIS:
1.101 schwarze 1415: macro_line(f, "Ed");
1.50 schwarze 1416: break;
1.1 kristaps 1417: default:
1418: break;
1419: }
1.103 schwarze 1420: f->flags &= ~FMT_ARG;
1.1 kristaps 1421: }
1422:
1.74 schwarze 1423: void
1.114 schwarze 1424: ptree_print_mdoc(struct ptree *tree)
1.74 schwarze 1425: {
1426: struct format formatter;
1.1 kristaps 1427:
1.74 schwarze 1428: formatter.level = 0;
1429: formatter.linestate = LINE_NEW;
1.116 schwarze 1430: pnode_printprologue(&formatter, tree->root);
1.74 schwarze 1431: pnode_print(&formatter, tree->root);
1432: if (formatter.linestate != LINE_NEW)
1433: putchar('\n');
1.1 kristaps 1434: }
CVSweb