* docbook2mdoc: Introduce FMT_* formatter flags to control what can be
@ 2019-04-11 4:23 schwarze
0 siblings, 0 replies; only message in thread
From: schwarze @ 2019-04-11 4:23 UTC (permalink / raw)
To: source
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 <ctype.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2019-04-11 4:23 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-11 4:23 docbook2mdoc: Introduce FMT_* formatter flags to control what can be schwarze
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).