From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from localhost (fantadrom.bsd.lv [local]) by fantadrom.bsd.lv (OpenSMTPD) with ESMTPA id 302ea63c for ; Wed, 10 Apr 2019 23:23:53 -0500 (EST) Date: Wed, 10 Apr 2019 23:23:53 -0500 (EST) X-Mailinglist: mandoc-source Reply-To: source@mandoc.bsd.lv MIME-Version: 1.0 From: schwarze@mandoc.bsd.lv To: source@mandoc.bsd.lv Subject: docbook2mdoc: Introduce FMT_* formatter flags to control what can be X-Mailer: activitymail 1.26, http://search.cpan.org/dist/activitymail/ Content-Type: text/plain; charset=utf-8 Message-ID: Log Message: ----------- Introduce FMT_* formatter flags to control what can be added to the current macro line. Move trailing punctuation handling to the text formatter, allowing elimination of the function macro_closepunct() and of the "real" and "bsz" members from struct node. Substantial functional improvements, yet minus 25 lines of code. Modified Files: -------------- docbook2mdoc: README docbook2mdoc.c macro.c macro.h node.c node.h parse.c Revision Data ------------- Index: parse.c =================================================================== RCS file: /home/cvs/mdocml/docbook2mdoc/parse.c,v retrieving revision 1.31 retrieving revision 1.32 diff -Lparse.c -Lparse.c -u -p -r1.31 -r1.32 --- parse.c +++ parse.c @@ -325,17 +325,18 @@ static void xml_char(struct parse *p, const char *word, int sz) { struct pnode *n; - size_t newsz; + size_t oldsz, newsz; + assert(sz > 0); if (p->del > 0) return; - if (p->cur == NULL) { + if ((n = p->cur) == NULL) { error_msg(p, "discarding text before document: %.*s", sz, word); return; } - if (p->cur->node != NODE_TEXT) { + if (n->node != NODE_TEXT) { if ((n = calloc(1, sizeof(*n))) == NULL) fatal(p); n->node = NODE_TEXT; @@ -347,21 +348,21 @@ xml_char(struct parse *p, const char *wo p->cur = n; } - if (p->tree->flags & TREE_CLOSED && - p->cur->parent == p->tree->root) + if (p->tree->flags & TREE_CLOSED && n->parent == p->tree->root) warn_msg(p, "text after end of document: %.*s", sz, word); /* Append to the current text node. */ - assert(sz >= 0); - newsz = p->cur->bsz + (p->cur->bsz && (p->flags & PFLAG_SPC)) + sz; - if ((p->cur->b = realloc(p->cur->b, newsz + 1)) == NULL) + oldsz = n->b == NULL ? 0 : strlen(n->b); + newsz = oldsz + sz; + if (oldsz && (p->flags & PFLAG_SPC)) + newsz++; + if ((n->b = realloc(n->b, newsz + 1)) == NULL) fatal(p); - if (p->cur->bsz && (p->flags & PFLAG_SPC)) - p->cur->b[p->cur->bsz++] = ' '; - memcpy(p->cur->b + p->cur->bsz, word, sz); - p->cur->b[p->cur->bsz = newsz] = '\0'; - p->cur->real = p->cur->b; + if (oldsz && (p->flags & PFLAG_SPC)) + n->b[oldsz++] = ' '; + memcpy(n->b + oldsz, word, sz); + n->b[newsz] = '\0'; p->flags &= ~PFLAG_SPC; } @@ -372,14 +373,15 @@ static void pnode_closetext(struct parse *p) { struct pnode *n; + char *cp; if ((n = p->cur) == NULL || n->node != NODE_TEXT) return; p->cur = n->parent; - while (n->bsz > 0 && isspace((unsigned char)n->b[n->bsz - 1])) { - n->b[--n->bsz] = '\0'; + for (cp = strchr(n->b, '\0'); + cp > n->b && isspace((unsigned char)cp[-1]); + *--cp = '\0') p->flags |= PFLAG_SPC; - } } static void @@ -439,10 +441,9 @@ xml_entity(struct parse *p, const char * /* Create, append, and close out an entity node. */ if ((n = calloc(1, sizeof(*n))) == NULL || - (n->b = n->real = strdup(entity->roff)) == NULL) + (n->b = strdup(entity->roff)) == NULL) fatal(p); n->node = NODE_ESCAPE; - n->bsz = strlen(n->b); n->spc = (p->flags & PFLAG_SPC) != 0; n->parent = p->cur; TAILQ_INIT(&n->childq); @@ -680,6 +681,7 @@ xml_elem_end(struct parse *p, const char p->flags &= ~PFLAG_SPC; break; case NODE_DOCTYPE: + case NODE_SBR: p->flags &= ~PFLAG_EEND; /* FALLTHROUGH */ default: Index: macro.h =================================================================== RCS file: /home/cvs/mdocml/docbook2mdoc/macro.h,v retrieving revision 1.3 retrieving revision 1.4 diff -Lmacro.h -Lmacro.h -u -p -r1.3 -r1.4 --- macro.h +++ macro.h @@ -28,7 +28,11 @@ enum linestate { struct format { int level; /* Header level, starting at 1. */ - int spc; /* Whitespace before next macro. */ + int flags; +#define FMT_NOSPC (1 << 0) /* Suppress space before next node. */ +#define FMT_ARG (1 << 1) /* May add argument to current macro. */ +#define FMT_CHILD (1 << 2) /* Expect a single child macro. */ +#define FMT_IMPL (1 << 3) /* Partial implicit block is open. */ enum linestate linestate; }; @@ -41,7 +45,6 @@ struct format { void macro_open(struct format *, const char *); void macro_close(struct format *); void macro_line(struct format *, const char *); -void macro_closepunct(struct format *, struct pnode *); void macro_addarg(struct format *, const char *, int); void macro_argline(struct format *, const char *, const char *); Index: node.h =================================================================== RCS file: /home/cvs/mdocml/docbook2mdoc/node.h,v retrieving revision 1.15 retrieving revision 1.16 diff -Lnode.h -Lnode.h -u -p -r1.15 -r1.16 --- node.h +++ node.h @@ -207,8 +207,6 @@ struct pattr { struct pnode { enum nodeid node; /* Node type. */ char *b; /* String value. */ - char *real; /* Storage for "b". */ - size_t bsz; /* strlen(b) */ int spc; /* Whitespace before this node. */ struct pnode *parent; /* Parent node or NULL. */ struct pnodeq childq; /* Queue of children. */ Index: README =================================================================== RCS file: /home/cvs/mdocml/docbook2mdoc/README,v retrieving revision 1.4 retrieving revision 1.5 diff -LREADME -LREADME -u -p -r1.4 -r1.5 --- README +++ README @@ -60,9 +60,7 @@ include: * Nodes to be represented by in-line macros that are parsed and callable often get away with merely opening a macro scope with macro_open(), letting the subsequent loop take care of - any children. In this case, the second, smaller switch - statement often needs to call macro_closepunct() to handle - closing delimiters. + any children. * Nodes to be represented by one single stand-alone macro sometimes get away with calling macro_line(), or macro_nodeline() if an Index: docbook2mdoc.c =================================================================== RCS file: /home/cvs/mdocml/docbook2mdoc/docbook2mdoc.c,v retrieving revision 1.102 retrieving revision 1.103 diff -Ldocbook2mdoc.c -Ldocbook2mdoc.c -u -p -r1.102 -r1.103 --- docbook2mdoc.c +++ docbook2mdoc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "node.h" #include "macro.h" @@ -36,12 +37,32 @@ pnode_printtext(struct format *f, struct { struct pnode *nn; char *cp; + int accept_arg; char last; - if (n->bsz == 0) { - assert(n->real < n->b); - return; + cp = n->b; + accept_arg = f->flags & FMT_ARG; + if (f->linestate == LINE_MACRO && n->spc == 0 && !accept_arg) { + 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 @@ -53,16 +74,29 @@ pnode_printtext(struct format *f, struct (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 (f->linestate == LINE_NEW) { - last = '\n'; - f->linestate = LINE_TEXT; - } else { + switch (f->linestate) { + case LINE_TEXT: + if (n->spc) + putchar(' '); last = ' '; - if (n->spc || f->linestate == LINE_MACRO) + break; + case LINE_MACRO: + if (accept_arg) { putchar(' '); + last = ' '; + break; + } + macro_close(f); + /* FALLTHROUGH */ + case LINE_NEW: + f->linestate = LINE_TEXT; + last = '\n'; + break; } if (n->node == NODE_ESCAPE) { @@ -75,7 +109,6 @@ pnode_printtext(struct format *f, struct * because the arguments of .Fl macros do not need it. */ - cp = n->b; if (n->parent != NULL && n->parent->node == NODE_OPTION && *cp == '-') cp++; @@ -109,6 +142,8 @@ pnode_printpara(struct format *f, struct if ((np = TAILQ_PREV(n, pnodeq, child)) == NULL) np = n->parent; + f->flags = 0; + switch (np->node) { case NODE_ENTRY: case NODE_GLOSSTERM: @@ -387,10 +422,10 @@ pnode_printarg(struct format *f, struct { struct pnode *nc; struct pattr *a; - int isop, isrep; + int isop, isrep, was_impl; isop = 1; - isrep = 0; + isrep = was_impl = 0; TAILQ_FOREACH(a, &n->attrq, child) { if (a->key == ATTRKEY_CHOICE && (a->val == ATTRVAL_PLAIN || a->val == ATTRVAL_REQ)) @@ -398,8 +433,15 @@ pnode_printarg(struct format *f, struct else if (a->key == ATTRKEY_REP && a->val == ATTRVAL_REPEAT) isrep = 1; } - if (isop) - macro_open(f, "Op"); + if (isop) { + if (f->flags & FMT_IMPL) { + was_impl = 1; + macro_open(f, "Oo"); + } else { + macro_open(f, "Op"); + f->flags |= FMT_IMPL; + } + } TAILQ_FOREACH(nc, &n->childq, child) { if (nc->node == NODE_TEXT) @@ -408,6 +450,12 @@ pnode_printarg(struct format *f, struct if (isrep && nc->node == NODE_TEXT) macro_addarg(f, "...", ARG_SPACE); } + if (isop) { + if (was_impl) + macro_open(f, "Oc"); + else + f->flags &= ~FMT_IMPL; + } pnode_unlinksub(n); } @@ -436,6 +484,7 @@ pnode_printgroup(struct format *f, struc macro_open(f, "Op"); else if (sv) macro_open(f, "No"); + f->flags |= FMT_IMPL; /* * Keep on printing text separated by the vertical bar as long @@ -459,6 +508,7 @@ pnode_printgroup(struct format *f, struc } if (sv) macro_close(f); + f->flags &= ~FMT_IMPL; pnode_unlinksub(n); } @@ -516,6 +566,7 @@ pnode_printauthor(struct format *f, stru */ if ((nc = pnode_findfirst(n, NODE_EMAIL)) != NULL) { + f->flags |= FMT_CHILD; pnode_print(f, nc); pnode_unlink(nc); } @@ -547,8 +598,10 @@ pnode_printlink(struct format *f, struct if (text != NULL) print_text(f, text, ARG_SPACE); } - if (text != NULL) + if (text != NULL) { macro_open(f, "Pq"); + f->flags |= FMT_CHILD; + } macro_open(f, "Sx"); macro_addarg(f, uri, ARG_SPACE); pnode_unlinksub(n); @@ -606,6 +659,7 @@ pnode_printvarlistentry(struct format *f macro_close(f); macro_open(f, "It"); + f->flags |= FMT_IMPL; TAILQ_FOREACH(nc, &n->childq, child) { if (nc->node != NODE_TERM && nc->node != NODE_GLOSSTERM) continue; @@ -673,8 +727,8 @@ pnode_printtgroup2(struct format *f, str 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; pnode_print(f, ne); macro_close(f); pnode_unlink(ne); @@ -758,8 +812,11 @@ pnode_print(struct format *f, struct pno if (n == NULL) return; - f->spc = n->spc; sv = f->linestate; + if (n->spc) + f->flags &= ~FMT_NOSPC; + else + f->flags |= FMT_NOSPC; switch (n->node) { case NODE_APPLICATION: @@ -961,6 +1018,11 @@ pnode_print(struct format *f, struct pno pnode_print(f, nc); switch (n->node) { + case NODE_ESCAPE: + case NODE_TERM: + case NODE_TEXT: + /* Accept more arguments to the previous macro. */ + return; case NODE_INFORMALEQUATION: macro_line(f, "EN"); break; @@ -994,36 +1056,6 @@ pnode_print(struct format *f, struct pno 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 && f->linestate == LINE_MACRO && - (n->parent == NULL || n->parent->node != NODE_MEMBER)) - macro_closepunct(f, n); - break; case NODE_QUOTE: if (sv == LINE_NEW) macro_close(f); @@ -1071,6 +1103,7 @@ pnode_print(struct format *f, struct pno default: break; } + f->flags &= ~FMT_ARG; } void Index: node.c =================================================================== RCS file: /home/cvs/mdocml/docbook2mdoc/node.c,v retrieving revision 1.7 retrieving revision 1.8 diff -Lnode.c -Lnode.c -u -p -r1.7 -r1.8 --- node.c +++ node.c @@ -95,7 +95,7 @@ pnode_free(struct pnode *n) free(a->rawval); free(a); } - free(n->real); + free(n->b); free(n); } Index: macro.c =================================================================== RCS file: /home/cvs/mdocml/docbook2mdoc/macro.c,v retrieving revision 1.8 retrieving revision 1.9 diff -Lmacro.c -Lmacro.c -u -p -r1.8 -r1.9 --- macro.c +++ macro.c @@ -31,29 +31,37 @@ void macro_open(struct format *f, const char *name) { switch (f->linestate) { + case LINE_MACRO: + if (f->flags & FMT_NOSPC) { + fputs(" Ns ", stdout); + break; + } + if (f->flags & (FMT_CHILD | FMT_IMPL)) { + putchar(' '); + break; + } + /* FALLTHROUGH */ case LINE_TEXT: putchar('\n'); /* FALLTHROUGH */ case LINE_NEW: putchar('.'); f->linestate = LINE_MACRO; - break; - case LINE_MACRO: - putchar(' '); - if (f->spc == 0) - fputs("Ns ", stdout); + f->flags = 0; break; } fputs(name, stdout); + f->flags &= FMT_IMPL; + f->flags |= FMT_ARG; } void macro_close(struct format *f) { - if (f->linestate == LINE_NEW) - return; - putchar('\n'); + if (f->linestate != LINE_NEW) + putchar('\n'); f->linestate = LINE_NEW; + f->flags = 0; } void @@ -65,73 +73,6 @@ macro_line(struct format *f, const char } /* - * 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) -{ - 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); -} - -/* * Print an argument string on a macro line, collapsing whitespace. */ void @@ -285,6 +226,7 @@ print_text(struct format *f, const char } fputs(word, stdout); f->linestate = LINE_TEXT; + f->flags = 0; } /* -- To unsubscribe send an email to source+unsubscribe@mandoc.bsd.lv