=================================================================== RCS file: /cvs/docbook2mdoc/docbook2mdoc.c,v retrieving revision 1.98 retrieving revision 1.147 diff -u -p -r1.98 -r1.147 --- docbook2mdoc/docbook2mdoc.c 2019/04/07 17:55:18 1.98 +++ docbook2mdoc/docbook2mdoc.c 2019/05/01 17:20:47 1.147 @@ -1,4 +1,4 @@ -/* $Id: docbook2mdoc.c,v 1.98 2019/04/07 17:55:18 schwarze Exp $ */ +/* $Id: docbook2mdoc.c,v 1.147 2019/05/01 17:20:47 schwarze Exp $ */ /* * Copyright (c) 2014 Kristaps Dzonsons * Copyright (c) 2019 Ingo Schwarze @@ -19,7 +19,9 @@ #include #include #include +#include +#include "xmalloc.h" #include "node.h" #include "macro.h" #include "format.h" @@ -36,12 +38,33 @@ pnode_printtext(struct format *f, struct pnode *n) { struct pnode *nn; char *cp; - char last; + int accept_arg; - if (n->bsz == 0) { - assert(n->real < n->b); - return; + para_check(f); + cp = n->b; + accept_arg = f->flags & FMT_ARG; + if (f->linestate == LINE_MACRO && !accept_arg && + (n->flags & NFLAG_SPC) == 0) { + for (;;) { + if (*cp == '\0') + return; + if (strchr("!),.:;?]", *cp) == NULL) + break; + printf(" %c", *cp++); + } + if (isspace((unsigned char)*cp)) { + while (isspace((unsigned char)*cp)) + cp++; + macro_close(f); + } else { + fputs(" Ns", stdout); + f->flags &= FMT_IMPL; + accept_arg = 1; + } } + if (f->linestate == LINE_MACRO && !accept_arg && + (f->flags & (FMT_CHILD | FMT_IMPL)) == 0) + macro_close(f); /* * Text preceding a macro without intervening whitespace @@ -50,23 +73,48 @@ pnode_printtext(struct format *f, struct pnode *n) */ if (f->linestate != LINE_MACRO && - (nn = TAILQ_NEXT(n, child)) != NULL && nn->spc == 0 && - (nn->node != NODE_TEXT && nn->node != NODE_ESCAPE)) { - macro_open(f, "Pf"); - nn->spc = 1; + (nn = TAILQ_NEXT(n, child)) != NULL && + (nn->flags & NFLAG_SPC) == 0) { + switch (pnode_class(nn->node)) { + case CLASS_LINE: + case CLASS_ENCL: + macro_open(f, "Pf"); + accept_arg = 1; + f->flags |= FMT_CHILD; + nn->flags |= NFLAG_SPC; + break; + default: + break; + } } - if (f->linestate == LINE_NEW) { - last = '\n'; - f->linestate = LINE_TEXT; - } else { - last = ' '; - if (n->spc || f->linestate == LINE_MACRO) + switch (f->linestate) { + case LINE_NEW: + break; + case LINE_TEXT: + if (n->flags & NFLAG_SPC) { + if (n->flags & NFLAG_LINE && + pnode_class(n->node) == CLASS_TEXT) + macro_close(f); + else + putchar(' '); + } + break; + case LINE_MACRO: + if (accept_arg == 0) + macro_close(f); + else if (n->flags & NFLAG_SPC || + (f->flags & FMT_ARG) == 0 || + (nn = TAILQ_PREV(n, pnodeq, child)) == NULL || + pnode_class(nn->node) != CLASS_TEXT) putchar(' '); + break; } if (n->node == NODE_ESCAPE) { fputs(n->b, stdout); + if (f->linestate == LINE_NEW) + f->linestate = LINE_TEXT; return; } @@ -75,214 +123,166 @@ pnode_printtext(struct format *f, struct pnode *n) * because the arguments of .Fl macros do not need it. */ - cp = n->b; if (n->parent != NULL && n->parent->node == NODE_OPTION && *cp == '-') cp++; - /* - * Print the text, skipping whitespace on new lines, - * escaping control characters on new lines, - * and escaping backslashes. - */ - - for (; *cp != '\0'; cp++) { - if (last == '\n') { - if (isspace((unsigned char)*cp)) - continue; - if (*cp == '\'' || *cp == '.') - fputs("\\&", stdout); - } - putchar(last = *cp); - if (last == '\\') - putchar('e'); - } + if (f->linestate == LINE_MACRO) + macro_addarg(f, cp, 0); + else + print_text(f, cp, 0); } static void -pnode_printpara(struct format *p, struct pnode *pn) +pnode_printimagedata(struct format *f, struct pnode *n) { - struct pnode *pp; + const char *cp; - if (pn->parent == NULL) - return; + if ((cp = pnode_getattr_raw(n, ATTRKEY_FILEREF, NULL)) == NULL) + cp = pnode_getattr_raw(n, ATTRKEY_ENTITYREF, NULL); + if (cp != NULL) { + print_text(f, "[image:", ARG_SPACE); + print_text(f, cp, ARG_SPACE); + print_text(f, "]", 0); + } else + print_text(f, "[image]", ARG_SPACE); +} - if ((pp = TAILQ_PREV(pn, pnodeq, child)) == NULL) - pp = pn->parent; +static void +pnode_printrefnamediv(struct format *f, struct pnode *n) +{ + struct pnode *nc, *nn; + int comma; - switch (pp->node) { - case NODE_ENTRY: - case NODE_LISTITEM: - return; - case NODE_PREFACE: - case NODE_SECTION: - if (p->level < 3) - return; - break; - default: - break; + f->parastate = PARA_HAVE; + macro_line(f, "Sh NAME"); + f->parastate = PARA_HAVE; + comma = 0; + TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) { + if (nc->node != NODE_REFNAME) + continue; + if (comma) + macro_addarg(f, ",", ARG_SPACE); + macro_open(f, "Nm"); + macro_addnode(f, nc, ARG_SPACE); + pnode_unlink(nc); + comma = 1; } - macro_line(p, "Pp"); + macro_close(f); } /* * If the SYNOPSIS macro has a superfluous title, kill it. */ static void -pnode_printrefsynopsisdiv(struct format *p, struct pnode *pn) +pnode_printrefsynopsisdiv(struct format *f, struct pnode *n) { - struct pnode *pp, *pq; + struct pnode *nc, *nn; - TAILQ_FOREACH_SAFE(pp, &pn->childq, child, pq) - if (pp->node == NODE_TITLE) - pnode_unlink(pp); + TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) + if (nc->node == NODE_TITLE) + pnode_unlink(nc); - macro_line(p, "Sh SYNOPSIS"); + f->parastate = PARA_HAVE; + macro_line(f, "Sh SYNOPSIS"); + f->parastate = PARA_HAVE; } /* * Start a hopefully-named `Sh' section. */ static void -pnode_printrefsect(struct format *p, struct pnode *pn) +pnode_printsection(struct format *f, struct pnode *n) { - struct pnode *pp; - const char *title; + struct pnode *nc, *ncc; int flags, level; - if (pn->parent == NULL) + if (n->parent == NULL) return; - level = ++p->level; + level = ++f->level; flags = ARG_SPACE; - if (level == 1) - flags |= ARG_UPPER; - if (level < 3) { - switch (pn->node) { - case NODE_CAUTION: - case NODE_NOTE: - case NODE_TIP: - case NODE_WARNING: + switch (n->node) { + case NODE_SECTION: + case NODE_APPENDIX: + if (level == 1) + flags |= ARG_UPPER; + break; + case NODE_SIMPLESECT: + if (level < 2) + level = 2; + break; + case NODE_NOTE: + if (level < 3) level = 3; - break; - default: - break; - } + break; + default: + abort(); } - TAILQ_FOREACH(pp, &pn->childq, child) - if (pp->node == NODE_TITLE) + TAILQ_FOREACH(nc, &n->childq, child) + if (nc->node == NODE_TITLE) break; - if (pp == NULL) { - switch (pn->node) { - case NODE_PREFACE: - title = "Preface"; - break; - case NODE_CAUTION: - title = "Caution"; - break; - case NODE_NOTE: - title = "Note"; - break; - case NODE_TIP: - title = "Tip"; - break; - case NODE_WARNING: - title = "Warning"; - break; - default: - title = "Unknown"; - break; - } - } - switch (level) { case 1: - macro_close(p); - macro_open(p, "Sh"); + macro_close(f); + f->parastate = PARA_HAVE; + macro_open(f, "Sh"); break; case 2: - macro_close(p); - macro_open(p, "Ss"); + macro_close(f); + f->parastate = PARA_HAVE; + macro_open(f, "Ss"); break; default: - pnode_printpara(p, pn); - macro_open(p, "Sy"); + if (f->parastate == PARA_MID) + f->parastate = PARA_WANT; + macro_open(f, "Sy"); break; } + macro_addnode(f, nc, flags); + macro_close(f); - if (pp != NULL) { - macro_addnode(p, pp, flags); - pnode_unlink(pp); - } else - macro_addarg(p, title, ARG_SPACE | ARG_QUOTED); - macro_close(p); + /* + * DocBook has no equivalent for -split mode, + * so just switch the default in the AUTHORS section. + */ + + if (nc != NULL) { + if (level == 1 && + (ncc = TAILQ_FIRST(&nc->childq)) != NULL && + ncc->node == NODE_TEXT && + strcasecmp(ncc->b, "AUTHORS") == 0) + macro_line(f, "An -nosplit"); + pnode_unlink(nc); + } + f->parastate = level > 2 ? PARA_WANT : PARA_HAVE; } /* * Start a reference, extracting the title and volume. */ static void -pnode_printciterefentry(struct format *p, struct pnode *pn) +pnode_printciterefentry(struct format *f, struct pnode *n) { - struct pnode *pp, *title, *manvol; + struct pnode *nc, *title, *manvol; title = manvol = NULL; - TAILQ_FOREACH(pp, &pn->childq, child) { - if (pp->node == NODE_MANVOLNUM) - manvol = pp; - else if (pp->node == NODE_REFENTRYTITLE) - title = pp; + TAILQ_FOREACH(nc, &n->childq, child) { + if (nc->node == NODE_MANVOLNUM) + manvol = nc; + else if (nc->node == NODE_REFENTRYTITLE) + title = nc; } - macro_open(p, "Xr"); + macro_open(f, "Xr"); if (title == NULL) - macro_addarg(p, "unknown", ARG_SPACE); + macro_addarg(f, "unknown", ARG_SPACE); else - macro_addnode(p, title, ARG_SPACE | ARG_SINGLE); + macro_addnode(f, title, ARG_SPACE | ARG_SINGLE); if (manvol == NULL) - macro_addarg(p, "1", ARG_SPACE); + macro_addarg(f, "1", ARG_SPACE); else - macro_addnode(p, manvol, ARG_SPACE | ARG_SINGLE); - pnode_unlinksub(pn); -} - -static void -pnode_printrefmeta(struct format *p, struct pnode *pn) -{ - struct pnode *pp, *title, *manvol; - - title = manvol = NULL; - TAILQ_FOREACH(pp, &pn->childq, child) { - if (pp->node == NODE_MANVOLNUM) - manvol = pp; - else if (pp->node == NODE_REFENTRYTITLE) - title = pp; - } - macro_close(p); - macro_open(p, "Dt"); - if (title == NULL) - macro_addarg(p, "UNKNOWN", ARG_SPACE); - else - macro_addnode(p, title, ARG_SPACE | ARG_SINGLE | ARG_UPPER); - if (manvol == NULL) - macro_addarg(p, "1", ARG_SPACE); - else - macro_addnode(p, manvol, ARG_SPACE | ARG_SINGLE); - macro_close(p); - pnode_unlink(pn); -} - -static void -pnode_printfuncdef(struct format *f, struct pnode *n) -{ - struct pnode *nc; - - nc = TAILQ_FIRST(&n->childq); - if (nc != NULL && nc->node == NODE_TEXT) { - macro_argline(f, "Ft", nc->b); - pnode_unlink(nc); - } - macro_nodeline(f, "Fo", n, ARG_SINGLE); + macro_addnode(f, manvol, ARG_SPACE | ARG_SINGLE); pnode_unlinksub(n); } @@ -293,21 +293,21 @@ pnode_printfuncdef(struct format *f, struct pnode *n) * Second, >1 arguments are separated by commas. */ static void -pnode_printmathfenced(struct format *p, struct pnode *pn) +pnode_printmathfenced(struct format *f, struct pnode *n) { - struct pnode *pp; + struct pnode *nc; - printf("left %s ", pnode_getattr_raw(pn, ATTRKEY_OPEN, "(")); + printf("left %s ", pnode_getattr_raw(n, ATTRKEY_OPEN, "(")); - pp = TAILQ_FIRST(&pn->childq); - pnode_print(p, pp); + nc = TAILQ_FIRST(&n->childq); + pnode_print(f, nc); - while ((pp = TAILQ_NEXT(pp, child)) != NULL) { + while ((nc = TAILQ_NEXT(nc, child)) != NULL) { putchar(','); - pnode_print(p, pp); + pnode_print(f, nc); } - printf("right %s ", pnode_getattr_raw(pn, ATTRKEY_CLOSE, ")")); - pnode_unlinksub(pn); + printf("right %s ", pnode_getattr_raw(n, ATTRKEY_CLOSE, ")")); + pnode_unlinksub(n); } /* @@ -317,14 +317,14 @@ pnode_printmathfenced(struct format *p, struct pnode * * particular eqn(7) word. */ static void -pnode_printmath(struct format *p, struct pnode *pn) +pnode_printmath(struct format *f, struct pnode *n) { - struct pnode *pp; + struct pnode *nc; - pp = TAILQ_FIRST(&pn->childq); - pnode_print(p, pp); + nc = TAILQ_FIRST(&n->childq); + pnode_print(f, nc); - switch (pn->node) { + switch (n->node) { case NODE_MML_MSUP: fputs(" sup ", stdout); break; @@ -338,31 +338,82 @@ pnode_printmath(struct format *p, struct pnode *pn) break; } - pp = TAILQ_NEXT(pp, child); - pnode_print(p, pp); - pnode_unlinksub(pn); + nc = TAILQ_NEXT(nc, child); + pnode_print(f, nc); + pnode_unlinksub(n); } static void -pnode_printfuncprototype(struct format *p, struct pnode *pn) +pnode_printfuncprototype(struct format *f, struct pnode *n) { - struct pnode *pp, *fdef; + struct pnode *fdef, *fps, *ftype, *nc, *nn; - TAILQ_FOREACH(fdef, &pn->childq, child) - if (fdef->node == NODE_FUNCDEF) + /* + * Extract child and ignore child. + * Leave other children in place, to be treated as parameters. + */ + + fdef = NULL; + TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) { + switch (nc->node) { + case NODE_FUNCDEF: + if (fdef == NULL) { + fdef = nc; + TAILQ_REMOVE(&n->childq, nc, child); + nc->parent = NULL; + } break; + case NODE_VOID: + pnode_unlink(nc); + break; + default: + break; + } + } + /* + * If no children are left, the function is void; use .Fn. + * Otherwise, use .Fo. + */ + + nc = TAILQ_FIRST(&n->childq); if (fdef != NULL) { - pnode_printfuncdef(p, fdef); + ftype = TAILQ_FIRST(&fdef->childq); + if (ftype != NULL && ftype->node == NODE_TEXT) { + macro_argline(f, "Ft", ftype->b); + pnode_unlink(ftype); + } + if (nc == NULL) { + macro_open(f, "Fn"); + macro_addnode(f, fdef, ARG_SPACE | ARG_SINGLE); + macro_addarg(f, "void", ARG_SPACE); + macro_close(f); + } else + macro_nodeline(f, "Fo", fdef, ARG_SINGLE); pnode_unlink(fdef); - } else - macro_line(p, "Fo UNKNOWN"); + } else if (nc == NULL) + macro_line(f, "Fn UNKNOWN void"); + else + macro_line(f, "Fo UNKNOWN"); - TAILQ_FOREACH(pp, &pn->childq, child) - macro_nodeline(p, "Fa", pp, ARG_SINGLE); + if (nc == NULL) + return; - macro_line(p, "Fc"); - pnode_unlinksub(pn); + while (nc != NULL) { + if ((fps = pnode_takefirst(nc, NODE_FUNCPARAMS)) != NULL) { + macro_open(f, "Fa \""); + macro_addnode(f, nc, ARG_QUOTED); + macro_addarg(f, "(", ARG_QUOTED); + macro_addnode(f, fps, ARG_QUOTED); + macro_addarg(f, ")", ARG_QUOTED); + putchar('"'); + macro_close(f); + } else + macro_nodeline(f, "Fa", nc, ARG_SINGLE); + pnode_unlink(nc); + nc = TAILQ_FIRST(&n->childq); + } + macro_line(f, "Fc"); } /* @@ -373,89 +424,122 @@ pnode_printfuncprototype(struct format *p, struct pnod * ellipsis following an argument) and optionality. */ static void -pnode_printarg(struct format *p, struct pnode *pn) +pnode_printarg(struct format *f, struct pnode *n) { - struct pnode *pp; - struct pattr *ap; - int isop, isrep; + struct pnode *nc; + struct pattr *a; + int isop, isrep, was_impl; isop = 1; - isrep = 0; - TAILQ_FOREACH(ap, &pn->attrq, child) { - if (ap->key == ATTRKEY_CHOICE && - (ap->val == ATTRVAL_PLAIN || ap->val == ATTRVAL_REQ)) + isrep = was_impl = 0; + TAILQ_FOREACH(a, &n->attrq, child) { + if (a->key == ATTRKEY_CHOICE && + (a->val == ATTRVAL_PLAIN || a->val == ATTRVAL_REQ)) isop = 0; - else if (ap->key == ATTRKEY_REP && ap->val == ATTRVAL_REPEAT) + else if (a->key == ATTRKEY_REP && a->val == ATTRVAL_REPEAT) isrep = 1; } - if (isop) - macro_open(p, "Op"); - - TAILQ_FOREACH(pp, &pn->childq, child) { - if (pp->node == NODE_TEXT) - macro_open(p, "Ar"); - pnode_print(p, pp); - if (isrep && pp->node == NODE_TEXT) - macro_addarg(p, "...", ARG_SPACE); + if (isop) { + if (f->flags & FMT_IMPL) { + was_impl = 1; + macro_open(f, "Oo"); + } else { + macro_open(f, "Op"); + f->flags |= FMT_IMPL; + } } - pnode_unlinksub(pn); + TAILQ_FOREACH(nc, &n->childq, child) { + if (nc->node == NODE_TEXT) + macro_open(f, "Ar"); + pnode_print(f, nc); + } + if (isrep && f->linestate == LINE_MACRO) + macro_addarg(f, "...", ARG_SPACE); + if (isop) { + if (was_impl) + macro_open(f, "Oc"); + else + f->flags &= ~FMT_IMPL; + } + pnode_unlinksub(n); } static void -pnode_printgroup(struct format *p, struct pnode *pn) +pnode_printgroup(struct format *f, struct pnode *n) { - struct pnode *pp, *np; - struct pattr *ap; - int isop, sv; + struct pnode *nc; + struct pattr *a; + int bar, isop, isrep, was_impl; isop = 1; - TAILQ_FOREACH(ap, &pn->attrq, child) - if (ap->key == ATTRKEY_CHOICE && - (ap->val == ATTRVAL_PLAIN || ap->val == ATTRVAL_REQ)) { + isrep = was_impl = 0; + TAILQ_FOREACH(a, &n->attrq, child) { + if (a->key == ATTRKEY_CHOICE && + (a->val == ATTRVAL_PLAIN || a->val == ATTRVAL_REQ)) isop = 0; - break; + else if (a->key == ATTRKEY_REP && a->val == ATTRVAL_REPEAT) + isrep = 1; + } + if (isop) { + if (f->flags & FMT_IMPL) { + was_impl = 1; + macro_open(f, "Oo"); + } else { + macro_open(f, "Op"); + f->flags |= FMT_IMPL; } - - /* - * Make sure we're on a macro line. - * This will prevent pnode_print() for putting us on a - * subsequent line. - */ - sv = p->linestate == LINE_NEW; - if (isop) - macro_open(p, "Op"); - else if (sv) - macro_open(p, "No"); - - /* - * Keep on printing text separated by the vertical bar as long - * as we're within the same origin node as the group. - * This is kind of a nightmare. - * Eh, DocBook... - * FIXME: if there's a "Fl", we don't cut off the leading "-" - * like we do in pnode_print(). - */ - TAILQ_FOREACH(pp, &pn->childq, child) { - pnode_print(p, pp); - np = TAILQ_NEXT(pp, child); - while (np != NULL) { - if (pp->node != np->node) - break; - macro_addarg(p, "|", ARG_SPACE); - macro_addnode(p, np, ARG_SPACE); - pp = np; - np = TAILQ_NEXT(np, child); + } else if (isrep) { + if (f->flags & FMT_IMPL) { + was_impl = 1; + macro_open(f, "Bro"); + } else { + macro_open(f, "Brq"); + f->flags |= FMT_IMPL; } } - if (sv) - macro_close(p); - pnode_unlinksub(pn); + bar = 0; + TAILQ_FOREACH(nc, &n->childq, child) { + if (bar && f->linestate == LINE_MACRO) + macro_addarg(f, "|", ARG_SPACE); + pnode_print(f, nc); + bar = 1; + } + if (isop) { + if (was_impl) + macro_open(f, "Oc"); + else + f->flags &= ~FMT_IMPL; + } else if (isrep) { + if (was_impl) + macro_open(f, "Brc"); + else + f->flags &= ~FMT_IMPL; + } + if (isrep && f->linestate == LINE_MACRO) + macro_addarg(f, "...", ARG_SPACE); + pnode_unlinksub(n); } static void +pnode_printsystemitem(struct format *f, struct pnode *n) +{ + switch (pnode_getattr(n, ATTRKEY_CLASS)) { + case ATTRVAL_IPADDRESS: + break; + case ATTRVAL_SYSTEMNAME: + macro_open(f, "Pa"); + break; + case ATTRVAL_EVENT: + default: + macro_open(f, "Sy"); + break; + } +} + +static void pnode_printauthor(struct format *f, struct pnode *n) { - struct pnode *nc, *ncn; + struct pnode *nc, *nn; int have_contrib, have_name; /* @@ -464,7 +548,7 @@ pnode_printauthor(struct format *f, struct pnode *n) */ have_contrib = have_name = 0; - TAILQ_FOREACH_SAFE(nc, &n->childq, child, ncn) { + TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) { switch (nc->node) { case NODE_CONTRIB: if (have_contrib) @@ -493,7 +577,7 @@ pnode_printauthor(struct format *f, struct pnode *n) */ macro_open(f, "An"); - TAILQ_FOREACH_SAFE(nc, &n->childq, child, ncn) { + TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) { if (nc->node == NODE_PERSONNAME || have_name == 0) { macro_addnode(f, nc, ARG_SPACE); pnode_unlink(nc); @@ -506,7 +590,9 @@ pnode_printauthor(struct format *f, struct pnode *n) */ if ((nc = pnode_findfirst(n, NODE_EMAIL)) != NULL) { - pnode_print(f, nc); + f->flags |= FMT_CHILD; + macro_open(f, "Aq Mt"); + macro_addnode(f, nc, ARG_SPACE); pnode_unlink(nc); } @@ -523,24 +609,48 @@ pnode_printauthor(struct format *f, struct pnode *n) } static void +pnode_printxref(struct format *f, struct pnode *n) +{ + const char *linkend; + + linkend = pnode_getattr_raw(n, ATTRKEY_LINKEND, NULL); + if (linkend != NULL) { + macro_open(f, "Sx"); + macro_addarg(f, linkend, ARG_SPACE); + } +} + +static void pnode_printlink(struct format *f, struct pnode *n) { + struct pnode *nc; const char *uri, *text; uri = pnode_getattr_raw(n, ATTRKEY_LINKEND, NULL); if (uri != NULL) { if (TAILQ_FIRST(&n->childq) != NULL) { - print_textnode(f, n); + TAILQ_FOREACH(nc, &n->childq, child) + pnode_print(f, nc); text = ""; - } else { - text = pnode_getattr_raw(n, ATTRKEY_ENDTERM, NULL); - if (text != NULL) + } else if ((text = pnode_getattr_raw(n, + ATTRKEY_ENDTERM, NULL)) != NULL) { + if (f->linestate == LINE_MACRO && f->flags & FMT_ARG) + macro_addarg(f, text, ARG_SPACE); + else print_text(f, text, ARG_SPACE); } - if (text != NULL) - macro_open(f, "Pq"); + if (text != NULL) { + if (f->flags & FMT_IMPL) + macro_open(f, "Po"); + else { + macro_open(f, "Pq"); + f->flags |= FMT_CHILD; + } + } macro_open(f, "Sx"); macro_addarg(f, uri, ARG_SPACE); + if (text != NULL && f->flags & FMT_IMPL) + macro_open(f, "Pc"); pnode_unlinksub(n); return; } @@ -553,35 +663,74 @@ pnode_printlink(struct format *f, struct pnode *n) if (TAILQ_FIRST(&n->childq) != NULL) macro_addnode(f, n, ARG_SPACE | ARG_SINGLE); pnode_unlinksub(n); + } +} + +static void +pnode_printolink(struct format *f, struct pnode *n) +{ + const char *uri, *ptr, *local; + + uri = pnode_getattr_raw(n, ATTRKEY_TARGETDOC, NULL); + ptr = pnode_getattr_raw(n, ATTRKEY_TARGETPTR, NULL); + local = pnode_getattr_raw(n, ATTRKEY_LOCALINFO, NULL); + if (uri == NULL) { + uri = ptr; + ptr = NULL; + } + if (uri == NULL) { + uri = local; + local = NULL; + } + if (uri == NULL) return; + + macro_open(f, "Lk"); + macro_addarg(f, uri, ARG_SPACE | ARG_SINGLE); + macro_addnode(f, n, ARG_SPACE | ARG_SINGLE); + if (ptr != NULL || local != NULL) { + macro_close(f); + macro_open(f, "Pq"); + if (ptr != NULL) + macro_addarg(f, ptr, ARG_SPACE); + if (local != NULL) + macro_addarg(f, local, ARG_SPACE); } + pnode_unlinksub(n); } static void -pnode_printprologue(struct format *p, struct ptree *tree) +pnode_printprologue(struct format *f, struct pnode *root) { - struct pnode *refmeta; + struct pnode *name, *nc; - refmeta = tree->root == NULL ? NULL : - pnode_findfirst(tree->root, NODE_REFMETA); + nc = TAILQ_FIRST(&root->childq); + assert(nc->node == NODE_DATE); + macro_nodeline(f, "Dd", nc, 0); + pnode_unlink(nc); - macro_line(p, "Dd $Mdocdate" "$"); - if (refmeta == NULL) { - macro_open(p, "Dt"); - macro_addarg(p, - pnode_getattr_raw(tree->root, ATTRKEY_ID, "UNKNOWN"), - ARG_SPACE | ARG_SINGLE | ARG_UPPER); - macro_addarg(p, "1", ARG_SPACE); - macro_close(p); - } else - pnode_printrefmeta(p, refmeta); - macro_line(p, "Os"); + macro_open(f, "Dt"); + name = TAILQ_FIRST(&root->childq); + assert(name->node == NODE_REFENTRYTITLE); + macro_addnode(f, name, ARG_SPACE | ARG_SINGLE | ARG_UPPER); + TAILQ_REMOVE(&root->childq, name, child); + name->parent = NULL; + nc = TAILQ_FIRST(&root->childq); + assert (nc->node == NODE_MANVOLNUM); + macro_addnode(f, nc, ARG_SPACE | ARG_SINGLE); + pnode_unlink(nc); - if (tree->flags & TREE_EQN) { - macro_line(p, "EQ"); - print_text(p, "delim $$", 0); - macro_line(p, "EN"); + macro_line(f, "Os"); + + nc = TAILQ_FIRST(&root->childq); + if (nc != NULL && nc->node == NODE_TITLE) { + macro_line(f, "Sh NAME"); + macro_nodeline(f, "Nm", name, ARG_SINGLE); + macro_nodeline(f, "Nd", nc, 0); + pnode_unlink(nc); } + pnode_unlink(name); + f->parastate = PARA_HAVE; } /* @@ -589,54 +738,73 @@ pnode_printprologue(struct format *p, struct ptree *tr * we should comma-separate as list headers. */ static void -pnode_printvarlistentry(struct format *p, struct pnode *pn) +pnode_printvarlistentry(struct format *f, struct pnode *n) { - struct pnode *pp; - int first = 1; + struct pnode *nc, *nn, *ncc; + int comma; - macro_close(p); - macro_open(p, "It"); - TAILQ_FOREACH(pp, &pn->childq, child) { - if (pp->node != NODE_TERM) + macro_open(f, "It"); + f->parastate = PARA_HAVE; + f->flags |= FMT_IMPL; + comma = -1; + TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) { + if (nc->node != NODE_TERM && nc->node != NODE_GLOSSTERM) continue; - if ( ! first) - macro_addarg(p, ",", 0); - pnode_print(p, pp); - first = 0; + if (comma != -1) { + switch (f->linestate) { + case LINE_NEW: + break; + case LINE_TEXT: + print_text(f, ",", 0); + break; + case LINE_MACRO: + macro_addarg(f, ",", comma); + break; + } + } + f->parastate = PARA_HAVE; + comma = (ncc = TAILQ_FIRST(&nc->childq)) == NULL || + pnode_class(ncc->node) == CLASS_TEXT ? 0 : ARG_SPACE; + pnode_print(f, nc); + pnode_unlink(nc); } - macro_close(p); - TAILQ_FOREACH(pp, &pn->childq, child) - if (pp->node != NODE_TERM) - pnode_print(p, pp); - pnode_unlinksub(pn); + macro_close(f); + f->parastate = PARA_HAVE; + while ((nc = TAILQ_FIRST(&n->childq)) != NULL) { + pnode_print(f, nc); + pnode_unlink(nc); + } + macro_close(f); + f->parastate = PARA_HAVE; } static void -pnode_printtitle(struct format *p, struct pnode *pn) +pnode_printtitle(struct format *f, struct pnode *n) { - struct pnode *pp, *pq; + struct pnode *nc, *nn; - TAILQ_FOREACH_SAFE(pp, &pn->childq, child, pq) { - if (pp->node == NODE_TITLE) { - pnode_printpara(p, pp); - pnode_print(p, pp); - pnode_unlink(pp); + TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) { + if (nc->node == NODE_TITLE) { + if (f->parastate == PARA_MID) + f->parastate = PARA_WANT; + macro_nodeline(f, "Sy", nc, 0); + pnode_unlink(nc); } } } static void -pnode_printrow(struct format *p, struct pnode *pn) +pnode_printrow(struct format *f, struct pnode *n) { - struct pnode *pp; + struct pnode *nc; - macro_line(p, "Bl -dash -compact"); - TAILQ_FOREACH(pp, &pn->childq, child) { - macro_line(p, "It"); - pnode_print(p, pp); + macro_line(f, "Bl -dash -compact"); + TAILQ_FOREACH(nc, &n->childq, child) { + macro_line(f, "It"); + pnode_print(f, nc); } - macro_line(p, "El"); - pnode_unlink(pn); + macro_line(f, "El"); + pnode_unlink(n); } static void @@ -647,7 +815,9 @@ pnode_printtgroup1(struct format *f, struct pnode *n) macro_line(f, "Bl -bullet -compact"); while ((nc = pnode_findfirst(n, NODE_ENTRY)) != NULL) { macro_line(f, "It"); + f->parastate = PARA_HAVE; pnode_print(f, nc); + f->parastate = PARA_HAVE; pnode_unlink(nc); } macro_line(f, "El"); @@ -659,19 +829,24 @@ pnode_printtgroup2(struct format *f, struct pnode *n) { struct pnode *nr, *ne; + f->parastate = PARA_HAVE; macro_line(f, "Bl -tag -width Ds"); while ((nr = pnode_findfirst(n, NODE_ROW)) != NULL) { if ((ne = pnode_findfirst(n, NODE_ENTRY)) == NULL) break; - macro_close(f); macro_open(f, "It"); + f->flags |= FMT_IMPL; + f->parastate = PARA_HAVE; pnode_print(f, ne); macro_close(f); pnode_unlink(ne); + f->parastate = PARA_HAVE; pnode_print(f, nr); + f->parastate = PARA_HAVE; pnode_unlink(nr); } macro_line(f, "El"); + f->parastate = PARA_WANT; pnode_unlinksub(n); } @@ -691,46 +866,54 @@ pnode_printtgroup(struct format *f, struct pnode *n) break; } + f->parastate = PARA_HAVE; macro_line(f, "Bl -ohang"); while ((nc = pnode_findfirst(n, NODE_ROW)) != NULL) { macro_line(f, "It Table Row"); pnode_printrow(f, nc); } macro_line(f, "El"); + f->parastate = PARA_WANT; pnode_unlinksub(n); } static void -pnode_printlist(struct format *p, struct pnode *pn) +pnode_printlist(struct format *f, struct pnode *n) { - struct pnode *pp; + struct pnode *nc; - pnode_printtitle(p, pn); - macro_argline(p, "Bl", - pn->node == NODE_ORDEREDLIST ? "-enum" : "-bullet"); - TAILQ_FOREACH(pp, &pn->childq, child) { - macro_line(p, "It"); - pnode_print(p, pp); + pnode_printtitle(f, n); + f->parastate = PARA_HAVE; + macro_argline(f, "Bl", + n->node == NODE_ORDEREDLIST ? "-enum" : "-bullet"); + TAILQ_FOREACH(nc, &n->childq, child) { + macro_line(f, "It"); + f->parastate = PARA_HAVE; + pnode_print(f, nc); + f->parastate = PARA_HAVE; } - macro_line(p, "El"); - pnode_unlinksub(pn); + macro_line(f, "El"); + f->parastate = PARA_WANT; + pnode_unlinksub(n); } static void -pnode_printvariablelist(struct format *p, struct pnode *pn) +pnode_printvariablelist(struct format *f, struct pnode *n) { - struct pnode *pp; + struct pnode *nc; - pnode_printtitle(p, pn); - macro_line(p, "Bl -tag -width Ds"); - TAILQ_FOREACH(pp, &pn->childq, child) { - if (pp->node == NODE_VARLISTENTRY) - pnode_printvarlistentry(p, pp); + pnode_printtitle(f, n); + f->parastate = PARA_HAVE; + macro_line(f, "Bl -tag -width Ds"); + TAILQ_FOREACH(nc, &n->childq, child) { + if (nc->node == NODE_VARLISTENTRY) + pnode_printvarlistentry(f, nc); else - macro_nodeline(p, "It", pp, 0); + macro_nodeline(f, "It", nc, 0); } - macro_line(p, "El"); - pnode_unlinksub(pn); + macro_line(f, "El"); + f->parastate = PARA_WANT; + pnode_unlinksub(n); } /* @@ -740,237 +923,336 @@ pnode_printvariablelist(struct format *p, struct pnode * whatever), don't print inline macros. */ static void -pnode_print(struct format *p, struct pnode *pn) +pnode_print(struct format *f, struct pnode *n) { - struct pnode *pp; - enum linestate sv; + struct pnode *nc, *nn; + int was_impl; - if (pn == NULL) + if (n == NULL) return; - p->spc = pn->spc; - sv = p->linestate; + if (n->flags & NFLAG_LINE && + (f->nofill || (f->flags & (FMT_ARG | FMT_IMPL)) == 0)) + macro_close(f); - switch (pn->node) { - case NODE_APPLICATION: - macro_open(p, "Nm"); - break; + was_impl = f->flags & FMT_IMPL; + if (n->flags & NFLAG_SPC) + f->flags &= ~FMT_NOSPC; + else + f->flags |= FMT_NOSPC; + + switch (n->node) { case NODE_ARG: - pnode_printarg(p, pn); + pnode_printarg(f, n); break; case NODE_AUTHOR: - pnode_printauthor(p, pn); + pnode_printauthor(f, n); break; case NODE_AUTHORGROUP: - macro_line(p, "An -split"); + macro_line(f, "An -split"); break; case NODE_BLOCKQUOTE: - macro_line(p, "Bd -ragged -offset indent"); + f->parastate = PARA_HAVE; + macro_line(f, "Bd -ragged -offset indent"); + f->parastate = PARA_HAVE; break; - case NODE_BOOKINFO: - macro_line(p, "Sh NAME"); - break; case NODE_CITEREFENTRY: - pnode_printciterefentry(p, pn); + pnode_printciterefentry(f, n); break; case NODE_CITETITLE: - macro_open(p, "%T"); + macro_open(f, "%T"); break; case NODE_COMMAND: - macro_open(p, "Nm"); + macro_open(f, "Nm"); break; case NODE_CONSTANT: - macro_open(p, "Dv"); + macro_open(f, "Dv"); break; + case NODE_COPYRIGHT: + print_text(f, "Copyright", ARG_SPACE); + fputs(" \\(co", stdout); + break; case NODE_EDITOR: - print_text(p, "editor:", ARG_SPACE); - sv = LINE_TEXT; - macro_open(p, "An"); + print_text(f, "editor:", ARG_SPACE); + pnode_printauthor(f, n); break; case NODE_EMAIL: - macro_open(p, "Aq Mt"); + if (was_impl) + macro_open(f, "Ao Mt"); + else { + macro_open(f, "Aq Mt"); + f->flags |= FMT_IMPL; + } break; case NODE_EMPHASIS: case NODE_FIRSTTERM: - macro_open(p, "Em"); + case NODE_GLOSSTERM: + if ((nc = TAILQ_FIRST(&n->childq)) != NULL && + pnode_class(nc->node) < CLASS_LINE) + macro_open(f, "Em"); + if (n->node == NODE_GLOSSTERM) + f->parastate = PARA_HAVE; break; case NODE_ENVAR: - macro_open(p, "Ev"); + macro_open(f, "Ev"); break; case NODE_ERRORNAME: - macro_open(p, "Er"); + macro_open(f, "Er"); break; case NODE_FILENAME: - macro_open(p, "Pa"); + macro_open(f, "Pa"); break; + case NODE_FOOTNOTE: + macro_line(f, "Bo"); + f->parastate = PARA_HAVE; + break; case NODE_FUNCTION: - macro_open(p, "Fn"); + macro_open(f, "Fn"); break; case NODE_FUNCPROTOTYPE: - pnode_printfuncprototype(p, pn); + pnode_printfuncprototype(f, n); break; case NODE_FUNCSYNOPSISINFO: - macro_open(p, "Fd"); + macro_open(f, "Fd"); break; - case NODE_INFORMALEQUATION: - macro_line(p, "EQ"); + case NODE_IMAGEDATA: + pnode_printimagedata(f, n); break; + case NODE_INFORMALEQUATION: + f->parastate = PARA_HAVE; + macro_line(f, "Bd -ragged -offset indent"); + f->parastate = PARA_HAVE; + /* FALLTHROUGH */ case NODE_INLINEEQUATION: - if (p->linestate == LINE_NEW) - p->linestate = LINE_TEXT; - putchar('$'); + macro_line(f, "EQ"); break; case NODE_ITEMIZEDLIST: - pnode_printlist(p, pn); + pnode_printlist(f, n); break; case NODE_GROUP: - pnode_printgroup(p, pn); + pnode_printgroup(f, n); break; case NODE_KEYSYM: - macro_open(p, "Sy"); + case NODE_PRODUCTNAME: + macro_open(f, "Sy"); break; - case NODE_LEGALNOTICE: - macro_line(p, "Sh LEGAL NOTICE"); - break; case NODE_LINK: - pnode_printlink(p, pn); + pnode_printlink(f, n); break; case NODE_LITERAL: - macro_open(p, "Ql"); + if (n->parent != NULL && n->parent->node == NODE_QUOTE) + macro_open(f, "Li"); + else if (was_impl) + macro_open(f, "So Li"); + else { + macro_open(f, "Ql"); + f->flags |= FMT_IMPL; + } break; case NODE_LITERALLAYOUT: - macro_close(p); - macro_argline(p, "Bd", pnode_getattr(pn, ATTRKEY_CLASS) == + macro_close(f); + f->parastate = PARA_HAVE; + macro_argline(f, "Bd", pnode_getattr(n, ATTRKEY_CLASS) == ATTRVAL_MONOSPACED ? "-literal" : "-unfilled"); + f->parastate = PARA_HAVE; break; + case NODE_MARKUP: + macro_open(f, "Ic"); + break; case NODE_MML_MFENCED: - pnode_printmathfenced(p, pn); + pnode_printmathfenced(f, n); break; case NODE_MML_MROW: case NODE_MML_MI: case NODE_MML_MN: case NODE_MML_MO: - if (TAILQ_EMPTY(&pn->childq)) + if (TAILQ_EMPTY(&n->childq)) break; fputs(" { ", stdout); break; case NODE_MML_MFRAC: case NODE_MML_MSUB: case NODE_MML_MSUP: - pnode_printmath(p, pn); + pnode_printmath(f, n); break; + case NODE_OLINK: + pnode_printolink(f, n); + break; case NODE_OPTION: - macro_open(p, "Fl"); + if ((nc = TAILQ_FIRST(&n->childq)) != NULL && + pnode_class(nc->node) < CLASS_LINE) + macro_open(f, "Fl"); break; case NODE_ORDEREDLIST: - pnode_printlist(p, pn); + pnode_printlist(f, n); break; case NODE_PARA: - pnode_printpara(p, pn); + if (f->parastate == PARA_MID) + f->parastate = PARA_WANT; break; case NODE_PARAMDEF: case NODE_PARAMETER: - macro_nodeline(p, "Fa", pn, ARG_SINGLE); - pnode_unlinksub(pn); + /* More often, these appear inside NODE_FUNCPROTOTYPE. */ + macro_open(f, "Fa"); + macro_addnode(f, n, ARG_SPACE | ARG_SINGLE); + pnode_unlinksub(n); break; case NODE_QUOTE: - macro_open(p, "Qo"); + if ((nc = TAILQ_FIRST(&n->childq)) != NULL && + nc->node == NODE_FILENAME && + TAILQ_NEXT(nc, child) == NULL) { + if (n->flags & NFLAG_SPC) + nc->flags |= NFLAG_SPC; + } else if (was_impl) + macro_open(f, "Do"); + else { + macro_open(f, "Dq"); + f->flags |= FMT_IMPL; + } break; case NODE_PROGRAMLISTING: case NODE_SCREEN: case NODE_SYNOPSIS: - macro_line(p, "Bd -literal"); + f->parastate = PARA_HAVE; + macro_line(f, "Bd -literal"); + f->parastate = PARA_HAVE; break; - case NODE_REFENTRYINFO: - /* Suppress. */ - pnode_unlinksub(pn); + case NODE_SYSTEMITEM: + pnode_printsystemitem(f, n); break; case NODE_REFNAME: - /* Suppress non-text children... */ - macro_open(p, "Nm"); - macro_addnode(p, pn, ARG_SPACE | ARG_SINGLE); - pnode_unlinksub(pn); + /* More often, these appear inside NODE_REFNAMEDIV. */ + macro_open(f, "Nm"); break; case NODE_REFNAMEDIV: - macro_line(p, "Sh NAME"); + pnode_printrefnamediv(f, n); break; case NODE_REFPURPOSE: - macro_open(p, "Nd"); + macro_open(f, "Nd"); break; case NODE_REFSYNOPSISDIV: - pnode_printrefsynopsisdiv(p, pn); + pnode_printrefsynopsisdiv(f, n); break; - case NODE_PREFACE: case NODE_SECTION: + case NODE_SIMPLESECT: + case NODE_APPENDIX: case NODE_NOTE: - case NODE_TIP: - case NODE_CAUTION: - case NODE_WARNING: - pnode_printrefsect(p, pn); + pnode_printsection(f, n); break; case NODE_REPLACEABLE: - macro_open(p, "Ar"); + macro_open(f, "Ar"); break; case NODE_SBR: - macro_line(p, "br"); + if (f->parastate == PARA_MID) + macro_line(f, "br"); break; - case NODE_SGMLTAG: - macro_open(p, "Ic"); + case NODE_SUBSCRIPT: + if (f->linestate == LINE_MACRO) + macro_addarg(f, "_", 0); + else + print_text(f, "_", 0); + if ((nc = TAILQ_FIRST(&n->childq)) != NULL) + nc->flags &= ~(NFLAG_LINE | NFLAG_SPC); break; + case NODE_SUPERSCRIPT: + fputs("\\(ha", stdout); + if ((nc = TAILQ_FIRST(&n->childq)) != NULL) + nc->flags &= ~(NFLAG_LINE | NFLAG_SPC); + break; case NODE_TEXT: case NODE_ESCAPE: - pnode_printtext(p, pn); + pnode_printtext(f, n); break; case NODE_TGROUP: - pnode_printtgroup(p, pn); + pnode_printtgroup(f, n); break; case NODE_TITLE: - if (pn->parent != NULL && - pn->parent->node == NODE_BOOKINFO) { - macro_open(p, "Nd"); - break; - } - pnode_printpara(p, pn); - macro_nodeline(p, "Sy", pn, 0); - pnode_unlinksub(pn); + case NODE_SUBTITLE: + if (f->parastate == PARA_MID) + f->parastate = PARA_WANT; + macro_nodeline(f, "Sy", n, 0); + pnode_unlinksub(n); break; case NODE_TYPE: - macro_open(p, "Vt"); + macro_open(f, "Vt"); break; case NODE_VARIABLELIST: - pnode_printvariablelist(p, pn); + pnode_printvariablelist(f, n); break; case NODE_VARNAME: - macro_open(p, "Va"); + macro_open(f, "Va"); break; + case NODE_VOID: + print_text(f, "void", ARG_SPACE); + break; + case NODE_XREF: + pnode_printxref(f, n); + break; + case NODE_CAUTION: + case NODE_LEGALNOTICE: + case NODE_PREFACE: + case NODE_TIP: + case NODE_WARNING: + abort(); default: break; } - TAILQ_FOREACH(pp, &pn->childq, child) - pnode_print(p, pp); + if (pnode_class(n->node) == CLASS_NOFILL) + f->nofill++; - switch (pn->node) { + TAILQ_FOREACH(nc, &n->childq, child) + pnode_print(f, nc); + + switch (n->node) { + case NODE_EMAIL: + if (was_impl) { + f->flags &= ~FMT_NOSPC; + macro_open(f, "Ac"); + } else + f->flags &= ~FMT_IMPL; + break; + case NODE_ESCAPE: + case NODE_TERM: + case NODE_TEXT: + /* Accept more arguments to the previous macro. */ + return; + case NODE_FOOTNOTE: + f->parastate = PARA_HAVE; + macro_line(f, "Bc"); + break; + case NODE_GLOSSTERM: + f->parastate = PARA_HAVE; + break; case NODE_INFORMALEQUATION: - macro_line(p, "EN"); + macro_line(f, "EN"); + macro_line(f, "Ed"); break; case NODE_INLINEEQUATION: - fputs("$ ", stdout); - p->linestate = sv; + macro_line(f, "EN"); break; + case NODE_LITERAL: + if (n->parent != NULL && n->parent->node == NODE_QUOTE) + /* nothing */; + else if (was_impl) { + f->flags &= ~FMT_NOSPC; + macro_open(f, "Sc"); + } else + f->flags &= ~FMT_IMPL; + break; case NODE_MEMBER: - if ((pp = TAILQ_NEXT(pn, child)) != NULL && - pp->node != NODE_MEMBER) - pp = NULL; - switch (p->linestate) { + if ((nn = TAILQ_NEXT(n, child)) != NULL && + nn->node != NODE_MEMBER) + nn = NULL; + switch (f->linestate) { case LINE_TEXT: - if (pp != NULL) - print_text(p, ",", 0); + if (nn != NULL) + print_text(f, ",", 0); break; case LINE_MACRO: - if (pp != NULL) - macro_addarg(p, ",", ARG_SPACE); - macro_close(p); + if (nn != NULL) + macro_addarg(f, ",", ARG_SPACE); + macro_close(f); break; case LINE_NEW: break; @@ -980,95 +1262,71 @@ pnode_print(struct format *p, struct pnode *pn) case NODE_MML_MI: case NODE_MML_MN: case NODE_MML_MO: - if (TAILQ_EMPTY(&pn->childq)) + if (TAILQ_EMPTY(&n->childq)) break; fputs(" } ", stdout); break; - case NODE_APPLICATION: - case NODE_ARG: - case NODE_AUTHOR: - case NODE_CITEREFENTRY: - case NODE_CITETITLE: - case NODE_COMMAND: - case NODE_CONSTANT: - case NODE_EDITOR: - case NODE_EMAIL: - case NODE_EMPHASIS: - case NODE_ENVAR: - case NODE_ERRORNAME: - case NODE_FILENAME: - case NODE_FIRSTTERM: - case NODE_FUNCTION: - case NODE_FUNCSYNOPSISINFO: - case NODE_KEYSYM: - case NODE_LINK: - case NODE_LITERAL: - case NODE_OPTION: - case NODE_PARAMETER: - case NODE_REPLACEABLE: - case NODE_REFPURPOSE: - case NODE_SGMLTAG: - case NODE_TYPE: - case NODE_VARNAME: - if (sv != LINE_MACRO && p->linestate == LINE_MACRO && - (pn->parent == NULL || pn->parent->node != NODE_MEMBER)) - macro_closepunct(p, pn); + case NODE_PARA: + if (f->parastate == PARA_MID) + f->parastate = PARA_WANT; break; case NODE_QUOTE: - if (sv == LINE_NEW) - macro_close(p); - sv = p->linestate; - macro_open(p, "Qc"); - if (sv == LINE_NEW) - macro_close(p); + if ((nc = TAILQ_FIRST(&n->childq)) != NULL && + nc->node == NODE_FILENAME && + TAILQ_NEXT(nc, child) == NULL) + /* nothing */; + else if (was_impl) { + f->flags &= ~FMT_NOSPC; + macro_open(f, "Dc"); + } else + f->flags &= ~FMT_IMPL; break; - case NODE_REFNAME: - /* - * If we're in the NAME macro and we have multiple - * macros in sequence, then print out a - * trailing comma before the newline. - */ - if (pn->parent != NULL && - pn->parent->node == NODE_REFNAMEDIV && - TAILQ_NEXT(pn, child) != NULL && - TAILQ_NEXT(pn, child)->node == NODE_REFNAME) - macro_addarg(p, ",", ARG_SPACE); - if (sv == LINE_NEW) - macro_close(p); - break; - case NODE_PREFACE: case NODE_SECTION: + case NODE_SIMPLESECT: + case NODE_APPENDIX: case NODE_NOTE: - case NODE_TIP: - case NODE_CAUTION: - case NODE_WARNING: - p->level--; + if (n->parent != NULL) + f->level--; break; case NODE_BLOCKQUOTE: case NODE_LITERALLAYOUT: case NODE_PROGRAMLISTING: case NODE_SCREEN: case NODE_SYNOPSIS: - macro_line(p, "Ed"); + f->parastate = PARA_HAVE; + macro_line(f, "Ed"); + f->parastate = PARA_WANT; break; case NODE_TITLE: - if (pn->parent != NULL && - pn->parent->node == NODE_BOOKINFO) - macro_line(p, "Sh AUTHORS"); + case NODE_SUBTITLE: + f->parastate = PARA_WANT; break; + case NODE_YEAR: + if ((nn = TAILQ_NEXT(n, child)) != NULL && + nn->node == NODE_YEAR && + f->linestate == LINE_TEXT) { + print_text(f, ",", 0); + nn->flags |= NFLAG_SPC; + if ((nc = TAILQ_FIRST(&nn->childq)) != NULL) + nc->flags |= NFLAG_SPC; + } default: break; } + f->flags &= ~FMT_ARG; + if (pnode_class(n->node) == CLASS_NOFILL) + f->nofill--; } void -ptree_print(struct ptree *tree) +ptree_print_mdoc(struct ptree *tree) { struct format formatter; - formatter.level = 0; + formatter.level = formatter.nofill = 0; formatter.linestate = LINE_NEW; - pnode_printprologue(&formatter, tree); + formatter.parastate = PARA_HAVE; + pnode_printprologue(&formatter, tree->root); pnode_print(&formatter, tree->root); if (formatter.linestate != LINE_NEW) putchar('\n');