=================================================================== RCS file: /cvs/docbook2mdoc/docbook2mdoc.c,v retrieving revision 1.74 retrieving revision 1.109 diff -u -p -r1.74 -r1.109 --- docbook2mdoc/docbook2mdoc.c 2019/03/26 18:32:07 1.74 +++ docbook2mdoc/docbook2mdoc.c 2019/04/12 10:34:48 1.109 @@ -1,4 +1,4 @@ -/* $Id: docbook2mdoc.c,v 1.74 2019/03/26 18:32:07 schwarze Exp $ */ +/* $Id: docbook2mdoc.c,v 1.109 2019/04/12 10:34:48 schwarze Exp $ */ /* * Copyright (c) 2014 Kristaps Dzonsons * Copyright (c) 2019 Ingo Schwarze @@ -19,293 +19,171 @@ #include #include #include +#include #include "node.h" +#include "macro.h" #include "format.h" /* * The implementation of the mdoc(7) formatter. */ -enum linestate { - LINE_NEW = 0, - LINE_TEXT, - LINE_MACRO -}; - -struct format { - int level; /* Header level, starting at 1. */ - enum linestate linestate; -}; - static void pnode_print(struct format *, struct pnode *); static void -macro_open(struct format *p, const char *name) +pnode_printtext(struct format *f, struct pnode *n) { - switch (p->linestate) { - case LINE_TEXT: - putchar('\n'); - /* FALLTHROUGH */ - case LINE_NEW: - putchar('.'); - p->linestate = LINE_MACRO; - break; - case LINE_MACRO: - putchar(' '); - break; - } - fputs(name, stdout); -} + struct pnode *nn; + char *cp; + int accept_arg; -static void -macro_close(struct format *p) -{ - assert(p->linestate == LINE_MACRO); - putchar('\n'); - p->linestate = LINE_NEW; -} - -static void -macro_line(struct format *p, const char *name) -{ - macro_open(p, name); - macro_close(p); -} - -#define ARG_SPACE 1 /* Insert whitespace before this argument. */ -#define ARG_SINGLE 2 /* Quote argument if it contains whitespace. */ -#define ARG_QUOTED 4 /* We are already in a quoted argument. */ -#define ARG_UPPER 8 /* Covert argument to upper case. */ -/* - * Print an argument string on a macro line, collapsing whitespace. - */ -static void -macro_addarg(struct format *p, const char *arg, int flags) -{ - const char *cp; - - assert(p->linestate == LINE_MACRO); - - /* Quote if requested and necessary. */ - - if ((flags & (ARG_SINGLE | ARG_QUOTED)) == ARG_SINGLE) { - for (cp = arg; *cp != '\0'; cp++) - if (isspace((unsigned char)*cp)) + cp = n->b; + accept_arg = f->flags & FMT_ARG; + if (f->linestate == LINE_MACRO && !n->spc && !accept_arg) { + for (;;) { + if (*cp == '\0') + return; + if (strchr("!),.:;?]", *cp) == NULL) break; - if (*cp != '\0') { - if (flags & ARG_SPACE) { - putchar(' '); - flags &= ~ ARG_SPACE; - } - putchar('"'); - flags = ARG_QUOTED; + printf(" %c", *cp++); } - } - - for (cp = arg; *cp != '\0'; cp++) { - - /* Collapse whitespace. */ - if (isspace((unsigned char)*cp)) { - flags |= ARG_SPACE; - continue; - } else if (flags & ARG_SPACE) { - putchar(' '); - flags &= ~ ARG_SPACE; + while (isspace((unsigned char)*cp)) + cp++; + macro_close(f); + } else { + fputs(" Ns", stdout); + f->flags &= FMT_IMPL; + accept_arg = 1; } - - /* Escape us if we look like a macro. */ - - if ((flags & ARG_QUOTED) == 0 && - (cp == arg || isspace((unsigned char)cp[-1])) && - isupper((unsigned char)cp[0]) && - islower((unsigned char)cp[1]) && - (cp[2] == '\0' || cp[2] == ' ' || - (islower((unsigned char)cp[2]) && - (cp[3] == '\0' || cp[3] == ' ')))) - fputs("\\&", stdout); - - if (*cp == '"') - fputs("\\(dq", stdout); - else if (flags & ARG_UPPER) - putchar(toupper((unsigned char)*cp)); - else - putchar(*cp); - if (*cp == '\\') - putchar('e'); } -} + if (f->linestate == LINE_MACRO && !accept_arg && + (f->flags & (FMT_CHILD | FMT_IMPL)) == 0) + macro_close(f); -static void -macro_argline(struct format *p, const char *name, const char *arg) -{ - macro_open(p, name); - macro_addarg(p, arg, ARG_SPACE); - macro_close(p); -} - -/* - * Recursively append text from the children of a node to a macro line. - */ -static void -macro_addnode(struct format *p, struct pnode *pn, int flags) -{ - int quote_now; - - assert(p->linestate == LINE_MACRO); - /* - * If the only child is a text node, just add that text, - * letting macro_addarg() decide about quoting. + * Text preceding a macro without intervening whitespace + * requires a .Pf macro. + * Set the spacing flag to avoid a redundant .Ns macro. */ - pn = TAILQ_FIRST(&pn->childq); - if (pn != NULL && pn->node == NODE_TEXT && - TAILQ_NEXT(pn, child) == NULL) { - macro_addarg(p, pn->b, flags); - return; + 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"); + accept_arg = 1; + f->flags |= FMT_CHILD; + nn->spc = 1; } - /* - * If we want the argument quoted and are not already - * in a quoted context, quote now. - */ - - quote_now = 0; - if (flags & ARG_SINGLE) { - if ((flags & ARG_QUOTED) == 0) { - if (flags & ARG_SPACE) { + switch (f->linestate) { + case LINE_NEW: + break; + case LINE_TEXT: + if (n->spc) { + if (n->node == NODE_TEXT) + macro_close(f); + else putchar(' '); - flags &= ~ARG_SPACE; - } - putchar('"'); - flags |= ARG_QUOTED; - quote_now = 1; } - flags &= ~ARG_SINGLE; + break; + case LINE_MACRO: + if (accept_arg) + putchar(' '); + else + macro_close(f); + break; } + if (n->node == NODE_ESCAPE) { + fputs(n->b, stdout); + if (f->linestate == LINE_NEW) + f->linestate = LINE_TEXT; + return; + } + /* - * Iterate to child and sibling nodes, - * inserting whitespace between nodes. + * Remove the prefix '-' from