source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* 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).