=================================================================== RCS file: /cvs/docbook2mdoc/macro.c,v retrieving revision 1.4 retrieving revision 1.7 diff -u -p -r1.4 -r1.7 --- docbook2mdoc/macro.c 2019/04/03 13:42:35 1.4 +++ docbook2mdoc/macro.c 2019/04/07 15:06:56 1.7 @@ -1,4 +1,4 @@ -/* $Id: macro.c,v 1.4 2019/04/03 13:42:35 schwarze Exp $ */ +/* $Id: macro.c,v 1.7 2019/04/07 15:06:56 schwarze Exp $ */ /* * Copyright (c) 2019 Ingo Schwarze * @@ -17,6 +17,7 @@ #include #include #include +#include #include "node.h" #include "macro.h" @@ -39,6 +40,8 @@ macro_open(struct format *f, const char *name) break; case LINE_MACRO: putchar(' '); + if (f->spc == 0) + fputs("Ns ", stdout); break; } fputs(name, stdout); @@ -56,25 +59,74 @@ macro_close(struct format *f) void macro_line(struct format *f, const char *name) { + macro_close(f); macro_open(f, name); macro_close(f); } /* - * If the next node is a text node starting with closing punctuation, - * emit the closing punctuation as a trailing macro argument. + * At the end of a macro, decide whether the line needs to remain open + * because the next node follows without intervening whitespace; + * otherwise, close the line. */ void macro_closepunct(struct format *f, struct pnode *pn) { - if ((pn = TAILQ_NEXT(pn, child)) != NULL && - pn->node == NODE_TEXT && pn->bsz > 0 && - (pn->b[0] == ',' || pn->b[0] == '.') && - (pn->bsz == 1 || isspace((unsigned char)pn->b[1]))) { - putchar(' '); - putchar(pn->b[0]); - pn->b++; - pn->bsz--; + char *cp; + + if ((pn = TAILQ_NEXT(pn, child)) != NULL && pn->spc == 0) { + + /* + * If a non-text node follows without intervening + * whitespace, the handler of that node will decide + * whether and how to suppress whitespace. To allow + * that, the macro line needs to remain open. + */ + + if (pn->node != NODE_TEXT && pn->node != NODE_ESCAPE) + return; + + /* + * Give closing punctuation + * in the form of trailing macro arguments. + */ + + while (*pn->b != '\0' && + strchr("!),.:;?]", *pn->b) != NULL) { + putchar(' '); + putchar(*pn->b); + pn->b++; + pn->bsz--; + } + + /* + * Text follows without intervening whitespace. + * Append the first word with .Ns. + */ + + if (*pn->b != '\0' && isspace((unsigned char)*pn->b) == 0) { + fputs(" Ns", stdout); + for (cp = pn->b; *cp != '\0'; cp++) + if (isspace((unsigned char)*cp)) + break; + *cp = '\0'; + macro_addarg(f, pn->b, ARG_SPACE); + pn->bsz -= cp - pn->b; + pn->b = cp; + if (pn->bsz > 0) { + pn->b++; + pn->bsz--; + pn->spc = 1; + } + } + + /* Skip whitespace after the first word. */ + + while (isspace((unsigned char)*pn->b)) { + pn->b++; + pn->bsz--; + pn->spc = 1; + } } macro_close(f); } @@ -153,6 +205,7 @@ macro_argline(struct format *f, const char *name, cons void macro_addnode(struct format *f, struct pnode *pn, int flags) { + struct pnode *nc; int quote_now; assert(f->linestate == LINE_MACRO); @@ -162,10 +215,11 @@ macro_addnode(struct format *f, struct pnode *pn, int * that text, letting macro_addarg() decide about quoting. */ - if (pn->node == NODE_TEXT || pn->node == NODE_ESCAPE || - ((pn = TAILQ_FIRST(&pn->childq)) != NULL && - (pn->node == NODE_TEXT || pn->node == NODE_ESCAPE) && - TAILQ_NEXT(pn, child) == NULL)) { + while ((nc = TAILQ_FIRST(&pn->childq)) != NULL && + TAILQ_NEXT(nc, child) == NULL) + pn = nc; + + if (pn->node == NODE_TEXT || pn->node == NODE_ESCAPE) { macro_addarg(f, pn->b, flags); return; } @@ -194,9 +248,9 @@ macro_addnode(struct format *f, struct pnode *pn, int * inserting whitespace between nodes. */ - while (pn != NULL) { - macro_addnode(f, pn, flags); - pn = TAILQ_NEXT(pn, child); + while (nc != NULL) { + macro_addnode(f, nc, flags); + nc = TAILQ_NEXT(nc, child); flags |= ARG_SPACE; } if (quote_now)