=================================================================== RCS file: /cvs/docbook2mdoc/docbook2mdoc.c,v retrieving revision 1.74 retrieving revision 1.75 diff -u -p -r1.74 -r1.75 --- docbook2mdoc/docbook2mdoc.c 2019/03/26 18:32:07 1.74 +++ docbook2mdoc/docbook2mdoc.c 2019/03/26 19:17:29 1.75 @@ -1,4 +1,4 @@ -/* $Id: docbook2mdoc.c,v 1.74 2019/03/26 18:32:07 schwarze Exp $ */ +/* $Id: docbook2mdoc.c,v 1.75 2019/03/26 19:17:29 schwarze Exp $ */ /* * Copyright (c) 2014 Kristaps Dzonsons * Copyright (c) 2019 Ingo Schwarze @@ -21,215 +21,15 @@ #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) -{ - 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); -} - -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)) - break; - if (*cp != '\0') { - if (flags & ARG_SPACE) { - putchar(' '); - flags &= ~ ARG_SPACE; - } - putchar('"'); - flags = ARG_QUOTED; - } - } - - 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; - } - - /* 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'); - } -} - -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. - */ - - 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 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) { - putchar(' '); - flags &= ~ARG_SPACE; - } - putchar('"'); - flags |= ARG_QUOTED; - quote_now = 1; - } - flags &= ~ARG_SINGLE; - } - - /* - * Iterate to child and sibling nodes, - * inserting whitespace between nodes. - */ - - while (pn != NULL) { - if (pn->node == NODE_TEXT) - macro_addarg(p, pn->b, flags); - else - macro_addnode(p, pn, flags); - pn = TAILQ_NEXT(pn, child); - flags |= ARG_SPACE; - } - if (quote_now) - putchar('"'); -} - -static void -macro_nodeline(struct format *p, const char *name, struct pnode *pn, int flags) -{ - macro_open(p, name); - macro_addnode(p, pn, ARG_SPACE | flags); - macro_close(p); -} - -/* - * If the next node is a text node starting with closing punctuation, - * emit the closing punctuation as a trailing macro argument. - */ -static void -macro_closepunct(struct format *p, 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--; - } - macro_close(p); -} static void print_text(struct format *p, const char *word)